aboutsummaryrefslogtreecommitdiff
path: root/sdk-modifications/libsrc/dma/dmacopy.c
blob: 83609d3548aee8917f309bca7e40e70b63aff080 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <stdlib.h>
#include "ds2_dma.h"
#include "ds2_types.h"

#define MAX_DMA_NUM 6  /* max 6 channels */


// DMA request source register
#define DMAC_DRSR_RS_BIT    0
#define DMAC_DRSR_RS_MASK   (0x2f << DMAC_DRSR_RS_BIT)
  #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT)
  #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT)
  #define DMAC_DRSR_RS_UART0IN  (21 << DMAC_DRSR_RS_BIT)
  #define DMAC_DRSR_RS_SSIOUT   (22 << DMAC_DRSR_RS_BIT)
  #define DMAC_DRSR_RS_SSIIN    (23 << DMAC_DRSR_RS_BIT)
  #define DMAC_DRSR_RS_AICOUT   (24 << DMAC_DRSR_RS_BIT)
  #define DMAC_DRSR_RS_AICIN    (25 << DMAC_DRSR_RS_BIT)
  #define DMAC_DRSR_RS_MSCOUT   (26 << DMAC_DRSR_RS_BIT)        //SD0
  #define DMAC_DRSR_RS_MSCIN    (27 << DMAC_DRSR_RS_BIT)


// DMA channel command register
#define DMAC_DCMD_SAI       (1 << 23) /* source address increment */
#define DMAC_DCMD_DAI       (1 << 22) /* dest address increment */
#define DMAC_DCMD_SWDH_BIT  14  /* source port width */
#define DMAC_DCMD_SWDH_MASK (0x03 << DMAC_DCMD_SWDH_BIT)
  #define DMAC_DCMD_SWDH_32 (0 << DMAC_DCMD_SWDH_BIT)
  #define DMAC_DCMD_SWDH_8  (1 << DMAC_DCMD_SWDH_BIT)
  #define DMAC_DCMD_SWDH_16 (2 << DMAC_DCMD_SWDH_BIT)
#define DMAC_DCMD_DWDH_BIT  12  /* dest port width */
#define DMAC_DCMD_DWDH_MASK (0x03 << DMAC_DCMD_DWDH_BIT)
  #define DMAC_DCMD_DWDH_32 (0 << DMAC_DCMD_DWDH_BIT)
  #define DMAC_DCMD_DWDH_8  (1 << DMAC_DCMD_DWDH_BIT)
  #define DMAC_DCMD_DWDH_16 (2 << DMAC_DCMD_DWDH_BIT)
#define DMAC_DCMD_DS_BIT    8  /* transfer data size of a data unit */
#define DMAC_DCMD_DS_MASK   (0x07 << DMAC_DCMD_DS_BIT)
  #define DMAC_DCMD_DS_32BIT    (0 << DMAC_DCMD_DS_BIT)
  #define DMAC_DCMD_DS_8BIT (1 << DMAC_DCMD_DS_BIT)
  #define DMAC_DCMD_DS_16BIT    (2 << DMAC_DCMD_DS_BIT)
  #define DMAC_DCMD_DS_16BYTE   (3 << DMAC_DCMD_DS_BIT)
  #define DMAC_DCMD_DS_32BYTE   (4 << DMAC_DCMD_DS_BIT)
#define DMAC_DCMD_TM        (1 << 7)  /* transfer mode: 0-single 1-block */
#define DMAC_DCCSR_TT   (1 << 3)  /* transfer terminated */

#define DMAC_BASE 0xB3020000
#define REG32(addr) *((volatile u32 *)(addr))
#define DMAC_DCCSR(n) (DMAC_BASE + (0x10 + (n) * 0x20)) /* DMA control/status */
#define REG_DMAC_DCCSR(n) REG32(DMAC_DCCSR((n)))

#define __dmac_channel_transmit_end_detected(n) \
  (  REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT )

/*
 * Copy 'size' bytes from src to dest, in blocks of 32 bytes.
 * size is in bytes and must be a multiple of 32.
 * Both src and dest must be aligned to 32 bytes.
 * Returns 0 on failure, non-zero on success.
 */
int dma_copy32Byte(int ch, void *dest, void *src, unsigned int size){
  int test = 0;
  if(!(test = dma_request(ch, NULL, 0,
                        //increment dest addr, increment source addr
                        DMAC_DCMD_DAI | DMAC_DCMD_SAI |
                        //set src width 32 bytes, set dest width 32 bytes
                        DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 |
                        //set copy mode to 32 bytes, copy in blocks
                        DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TM,
                        //auto request type
                        DMAC_DRSR_RS_AUTO)))
  {
    dma_start(ch, (unsigned int)src, (unsigned int)dest, size);
  }
  return test;
}

/*

int sampleUsage(in ch, void *dest, void *src, unsigned int size){
  //channel 0 is used for mmc stuff, so its best to avoid using it

  //initialize and start copy
  if(dma_copy32Byte(ch, dest, src, size)){
    dma_wait_finish(ch);//wait for copy to finish
    dma_stop(ch);//must stop after transfer is done to reset channel
    return 0;
  }
  return -1;
}

*/

/*
 * Copy 'size' bytes from src to dest, in blocks of 16 bytes.
 * size is in bytes and must be a multiple of 16.
 * Both src and dest must be aligned to 16 bytes.
 * Returns 0 on failure, non-zero on success.
 */
int dma_copy16Byte(int ch, void *dest, void *src, unsigned int size){
  int test = 0;
  if(!(test = dma_request(ch, NULL, 0,
              DMAC_DCMD_DAI | DMAC_DCMD_SAI | DMAC_DCMD_SWDH_16 |
              DMAC_DCMD_DWDH_16 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_TM,
              DMAC_DRSR_RS_AUTO)))
  {
    dma_start(ch, (unsigned int)src, (unsigned int)dest, size);
  }

  return test;
}

/*
 * Copy 'size' bytes from src to dest, in blocks of 32 bits (4 bytes).
 * size is in bytes and must be a multiple of 4.
 * Both src and dest must be aligned to 32 bits (4 bytes).
 * Returns 0 on failure, non-zero on success.
 */
int dma_copy32Bit(int ch, void *dest, void *src, unsigned int size){
  int test = 0;
  if(!(test = dma_request(ch, NULL, 0,
              DMAC_DCMD_DAI | DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 |
              DMAC_DCMD_DS_32BIT  | DMAC_DCMD_TM,
              DMAC_DRSR_RS_AUTO)))
  {
    dma_start(ch, (unsigned int)src, (unsigned int)dest, size);
  }

  return test;
}

/*
 * Copy 'size' bytes from src to dest, in blocks of 16 bits (2 bytes).
 * size is in bytes and must be a multiple of 2.
 * Both src and dest must be aligned to 16 bits (2 bytes).
 * Returns 0 on failure, non-zero on success.
 */
int dma_copy16Bit(int ch, void *dest, void *src, unsigned int size){
  int test = 0;

  if(!(test = dma_request(ch, NULL, 0,
              DMAC_DCMD_DAI | DMAC_DCMD_SAI | DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 |
              DMAC_DCMD_DS_16BIT,
              DMAC_DRSR_RS_AUTO)))
  {
    dma_start(ch, (unsigned int)src, (unsigned int)dest, size);
  }

  return test;
}


//returns if a channel is still copying
int dma_isBusy(int ch){
  if(ch < 1 || ch >= MAX_DMA_NUM)
    return 0;

  return !__dmac_channel_transmit_end_detected(ch);
}

//returns the first non busy channel
int dma_getFree(void){
  int i;
  for(i = 1; i < MAX_DMA_NUM; i++){
    if(!dma_isBusy(i))
      return i;
  }
  return -1;
}