diff options
Diffstat (limited to 'firmware/target/arm/tms320dm320/dsp/dma.c')
-rw-r--r-- | firmware/target/arm/tms320dm320/dsp/dma.c | 267 |
1 files changed, 145 insertions, 122 deletions
diff --git a/firmware/target/arm/tms320dm320/dsp/dma.c b/firmware/target/arm/tms320dm320/dsp/dma.c index 430cc909f7..590b35de80 100644 --- a/firmware/target/arm/tms320dm320/dsp/dma.c +++ b/firmware/target/arm/tms320dm320/dsp/dma.c | |||
@@ -23,185 +23,208 @@ | |||
23 | 23 | ||
24 | #include "registers.h" | 24 | #include "registers.h" |
25 | #include "arm.h" | 25 | #include "arm.h" |
26 | #include "dma.h" | 26 | #include "ipc.h" |
27 | |||
28 | /* Size of data buffer in words (16 bit) */ | ||
29 | #define DSP_BUFFER_SIZE (0x1000) | ||
27 | 30 | ||
28 | /* This is placed at the right (aligned) address using linker.cmd. */ | 31 | /* Put the "data" buffer in it's own .dma section so that it can |
32 | * be handled in the linker.cmd. */ | ||
29 | #pragma DATA_SECTION (data, ".dma") | 33 | #pragma DATA_SECTION (data, ".dma") |
30 | 34 | ||
31 | #define DSP_BUFFER_SIZE PCM_SIZE/2 | 35 | /* This is the "data" buffer on the DSP side used for SARAM to McBSP (IIS) */ |
32 | 36 | static signed short data[DSP_BUFFER_SIZE]; | |
33 | /* This is the buffer on the DSP side used for SARAM to McBSP (IIS) */ | ||
34 | signed short data[DSP_BUFFER_SIZE]; | ||
35 | 37 | ||
36 | /* These two describe the location of the buffer on the ARM (set in DSPHINT | 38 | /* These two describe the location of the buffer on the ARM (set in DSPHINT) */ |
37 | * and dspinit) | ||
38 | */ | ||
39 | volatile unsigned short sdem_addrh; | 39 | volatile unsigned short sdem_addrh; |
40 | volatile unsigned short sdem_addrl; | 40 | volatile unsigned short sdem_addrl; |
41 | 41 | ||
42 | /* This is the size of the ARM buffer (set in DSPHINT and dspinit) */ | 42 | /* This is the size of the ARM buffer (set in DSPHINT) */ |
43 | volatile unsigned short sdem_dsp_size; | 43 | volatile unsigned short sdem_dsp_size; |
44 | 44 | ||
45 | /* These two variables keep track of the buffer level in the DSP, dsp_level, | 45 | /* These two variables keep track of the buffer level in the DSP, dsp_level, |
46 | * (SARAM to McBSP) and the level on the ARM buffer (sdem_level). | 46 | * (SARAM to McBSP) and the level on the ARM buffer (sdem_level). |
47 | */ | 47 | * sdem_level is used in the main firmware to keep track of the current |
48 | unsigned short dsp_level=0; | 48 | * playback status. dsp_level is only used in this function. */ |
49 | unsigned short sdem_level=0; | 49 | static unsigned short dsp_level; |
50 | volatile unsigned short sdem_level; | ||
50 | 51 | ||
51 | /* This is used to keep track of the last SDRAM to SARAM transfer */ | 52 | /* This is used to keep track of the last SDRAM to SARAM transfer */ |
52 | unsigned short last_size; | 53 | static unsigned short last_size; |
53 | 54 | ||
54 | /* This tells us which half of the DSP buffer (data) is free */ | 55 | /* This tells us which half of the DSP buffer (data) is free */ |
55 | unsigned short dma0_unlocked; | 56 | static unsigned short dma0_unlocked; |
56 | 57 | ||
57 | volatile unsigned short dma0_stopped=1; | 58 | /* This is used by the ARM to flag playback status and start/stop the DMA |
59 | * transfers. */ | ||
60 | volatile unsigned short dma0_stopped; | ||
58 | 61 | ||
59 | short waiting=0; | 62 | /* This is used to effectively flag whether the ARM has new data ready or not */ |
60 | /* rebuffer sets up the next SDRAM to SARAM transfer and tells the ARM when it | 63 | short waiting; |
61 | * is done with a buffer. | 64 | |
62 | */ | 65 | |
63 | 66 | /* rebuffer sets up the next SDRAM to SARAM transfer and tells the ARM when DMA | |
64 | /* Notes: The upper limit on larger buffers is the size of a short. If larger | 67 | * needs a new buffer. |
68 | * | ||
69 | * Note: The upper limit on larger buffers is the size of a short. If larger | ||
65 | * buffer sizes are needed the code on the ARM side needs to be changed to | 70 | * buffer sizes are needed the code on the ARM side needs to be changed to |
66 | * update a full long. | 71 | * update a full long. |
67 | */ | 72 | */ |
68 | void rebuffer(void) | 73 | void rebuffer(void) |
69 | { | 74 | { |
70 | unsigned long sdem_addr; | 75 | unsigned long sdem_addr; |
71 | 76 | ||
72 | if(dma0_stopped==1) /* Stop */ | 77 | if(dma0_stopped==1 || dma0_stopped==2) /* Stop / Pause */ |
73 | { | 78 | { |
74 | DMPREC&=0xFFFE; /* Stop MCBSP DMA0 */ | 79 | /* Stop MCBSP DMA0 */ |
75 | audiohw_stop(); | 80 | DMPREC &= 0xFFFE; |
76 | DMSFC0 = 2 << 12 | 1 << 11; | 81 | /* Shut the transmitter down */ |
77 | sdem_level=0; | 82 | audiohw_stop(); |
78 | return; | 83 | |
79 | } | 84 | /* Stop the HPIB transfer if it is running */ |
80 | 85 | DMA_TRG = 0; | |
81 | if(dsp_level==DSP_BUFFER_SIZE || sdem_level==sdem_dsp_size) | 86 | |
82 | { | 87 | /* Reset the following variables for DMA restart */ |
83 | if(dma0_stopped==2) /* Pause */ | 88 | sdem_level = 0; |
84 | { | 89 | dsp_level = 0; |
85 | DMPREC&=0xFFFE; /* Stop MCBSP DMA0 */ | 90 | last_size = 0; |
86 | audiohw_stop(); | 91 | |
87 | return; | 92 | return; |
88 | } | 93 | } |
89 | } | ||
90 | |||
91 | /* If the sdem_level is equal to the buffer size the ARM code gave | ||
92 | * (sdem_dsp_size) then reset the size and ask the arm for another buffer | ||
93 | */ | ||
94 | if(sdem_level==sdem_dsp_size) | ||
95 | { | ||
96 | sdem_level=0; | ||
97 | |||
98 | /* Get a new buffer (location and size) from ARM */ | ||
99 | status.msg = MSG_REFILL; | ||
100 | waiting=1; | ||
101 | |||
102 | startack(); | ||
103 | } | ||
104 | |||
105 | if(!waiting) | ||
106 | { | ||
107 | /* Size is in bytes (but forced 32 bit transfers */ | ||
108 | if( (dsp_level + (sdem_dsp_size - sdem_level) ) > DSP_BUFFER_SIZE) | ||
109 | { | ||
110 | last_size = DSP_BUFFER_SIZE-dsp_level; | ||
111 | } | ||
112 | else | ||
113 | { | ||
114 | last_size = sdem_dsp_size-sdem_level; | ||
115 | } | ||
116 | |||
117 | /* DSP addresses are 16 bit (word) */ | ||
118 | DSP_ADDRL = (unsigned short)data + (dma0_unlocked >> 1) + (dsp_level>>1); | ||
119 | DSP_ADDRH = 0; | ||
120 | |||
121 | /* SDRAM addresses are 8 bit (byte) | ||
122 | * Warning: These addresses are forced to 32 bit alignment! | ||
123 | */ | ||
124 | sdem_addr = ((unsigned long)sdem_addrh << 16 | sdem_addrl) + sdem_level; | ||
125 | SDEM_ADDRL = sdem_addr & 0xffff; | ||
126 | SDEM_ADDRH = sdem_addr >> 16; | ||
127 | 94 | ||
128 | /* Set the size of the SDRAM to SARAM transfer (demac transfer) */ | 95 | /* If the sdem_level is equal to the buffer size the ARM code gave |
129 | DMA_SIZE = last_size; | 96 | * (sdem_dsp_size) then reset the size and ask the arm for another buffer |
97 | */ | ||
98 | if(sdem_level == sdem_dsp_size) | ||
99 | { | ||
100 | sdem_level=0; | ||
101 | |||
102 | /* Get a new buffer (location and size) from ARM */ | ||
103 | status.msg = MSG_REFILL; | ||
104 | waiting=1; | ||
105 | |||
106 | /* trigger DSPHINT on the ARM */ | ||
107 | int_arm(); | ||
108 | } | ||
109 | |||
110 | if(!waiting) | ||
111 | { | ||
112 | /* Size is in bytes (but forced 32 bit transfers). Comparison is | ||
113 | * against DSP_BUFFER_SIZE because it is in words and this needs to | ||
114 | * compare against half the total size in bytes. */ | ||
115 | if( dsp_level + sdem_dsp_size - sdem_level > DSP_BUFFER_SIZE) | ||
116 | { | ||
117 | last_size = DSP_BUFFER_SIZE - dsp_level; | ||
118 | } | ||
119 | else | ||
120 | { | ||
121 | last_size = sdem_dsp_size - sdem_level; | ||
122 | } | ||
123 | |||
124 | /* DSP addresses are 16 bit (word). dsp_level is in bytes so it needs to | ||
125 | * be converted to words. */ | ||
126 | DSP_ADDRL = (unsigned short)data + dma0_unlocked + (dsp_level >> 1); | ||
127 | DSP_ADDRH = 0; | ||
128 | |||
129 | /* SDRAM addresses are 8 bit (byte) | ||
130 | * Warning: These addresses are forced to 32 bit alignment! | ||
131 | */ | ||
132 | sdem_addr = ((unsigned long)sdem_addrh << 16 | sdem_addrl) + sdem_level; | ||
133 | SDEM_ADDRL = sdem_addr & 0xffff; | ||
134 | SDEM_ADDRH = sdem_addr >> 16; | ||
135 | |||
136 | /* Set the size of the SDRAM to SARAM transfer (demac transfer) */ | ||
137 | DMA_SIZE = last_size; | ||
130 | 138 | ||
131 | DMA_CTRL = 0; | 139 | DMA_CTRL = 0; |
132 | 140 | ||
133 | /* These are just debug signals that are not used/needed right now */ | 141 | /* These are just debug signals that are not used/needed right now */ |
134 | status.payload.refill._DMA_TRG = DMA_TRG; | 142 | status.payload.refill._DMA_TRG = DMA_TRG; |
135 | status.payload.refill._SDEM_ADDRH = SDEM_ADDRH; | 143 | status.payload.refill._SDEM_ADDRH = SDEM_ADDRH; |
136 | status.payload.refill._SDEM_ADDRL = SDEM_ADDRL; | 144 | status.payload.refill._SDEM_ADDRL = SDEM_ADDRL; |
137 | status.payload.refill._DSP_ADDRH = DSP_ADDRH; | 145 | status.payload.refill._DSP_ADDRH = DSP_ADDRH; |
138 | status.payload.refill._DSP_ADDRL = DSP_ADDRL; | 146 | status.payload.refill._DSP_ADDRL = DSP_ADDRL; |
139 | 147 | ||
140 | /* Start the demac transfer */ | 148 | /* Start the demac transfer */ |
141 | DMA_TRG = 1; | 149 | DMA_TRG = 1; |
142 | } | 150 | } |
143 | } | 151 | } |
144 | 152 | ||
145 | /* This interupt handler is for the SARAM (on DSP) to McBSP IIS DMA transfer. | 153 | /* This interupt handler is for the SARAM (on DSP) to McBSP IIS DMA transfer. |
146 | * It interupts at 1/2 empty and empty so that we can start filling a new buffer | 154 | * It interupts at 1/2 empty and empty so that we can start filling a new buffer |
147 | * from SDRAM when a half is free. dsp_level should always be full when this | 155 | * from SDRAM when a half is free. dsp_level should always be full when this |
148 | * interupt occurs except for the initial start. | 156 | * interupt occurs except for the initial start. */ |
149 | */ | ||
150 | interrupt void handle_dma0(void) | 157 | interrupt void handle_dma0(void) |
151 | { | 158 | { |
152 | /* Byte offset to half-buffer locked by DMA0. | 159 | /* Byte offset to half-buffer locked by DMA0. |
153 | 0 for top, PCM_SIZE/2 for bottom */ | 160 | 0 for top, DSP_BUFFER_SIZE/2 for bottom */ |
154 | unsigned short dma0_locked; | 161 | unsigned short dma0_locked; |
155 | 162 | ||
156 | IFR = 1 << 6; | 163 | IFR = 1 << 6; |
157 | 164 | ||
158 | /* DMSRC0 is the beginning of the DMA0-locked SARAM half-buffer. */ | 165 | /* DMSRC0 is the beginning of the DMA0-locked SARAM half-buffer. */ |
159 | DMSA = 0x00 /* DMSRC0 */; | 166 | DMSA = 0x00 /* DMSRC0 (banked register, see page 133 of SPRU302B */; |
160 | dma0_locked = (DMSDN << 1) & (DSP_BUFFER_SIZE); | ||
161 | dma0_unlocked = dma0_locked ^ (DSP_BUFFER_SIZE); | ||
162 | 167 | ||
163 | dsp_level = 0; | 168 | /* Note that these address offsets (dma0_locked and dma0_unlocked are in |
169 | * words. */ | ||
170 | dma0_locked = DMSDN & (DSP_BUFFER_SIZE>>1); | ||
171 | dma0_unlocked = dma0_locked ^ (DSP_BUFFER_SIZE>>1); | ||
172 | |||
173 | dsp_level = 0; | ||
164 | 174 | ||
165 | /* Start the SDRAM to SARAM copy */ | 175 | /* Start the SDRAM to SARAM copy */ |
166 | rebuffer(); | 176 | rebuffer(); |
167 | } | 177 | } |
168 | 178 | ||
169 | /* This interupt handler runs every time a DMA transfer is complete from SDRAM | 179 | /* This interupt handler runs every time a DMA transfer is complete from SDRAM |
170 | * to the SARAM buffer. It is used to update the SARAM buffer level | 180 | * to the SARAM buffer. It is used to update the SARAM buffer level |
171 | * (dsp_level), the SDRAM buffer level (sdem_level) and to rebuffer if the dsp | 181 | * (dsp_level), the SDRAM buffer level (sdem_level) and to rebuffer if the dsp |
172 | * buffer is not full. | 182 | * buffer is not full. */ |
173 | */ | ||
174 | interrupt void handle_dmac(void) { | 183 | interrupt void handle_dmac(void) { |
175 | IFR = 1 << 11; | 184 | IFR = 1 << 11; /* Clear interrupt */ |
176 | 185 | ||
177 | dsp_level+=last_size; | 186 | /* dsp_level and sdem_level are in bytes */ |
178 | sdem_level+=last_size; | 187 | dsp_level += last_size; |
179 | 188 | sdem_level += last_size; | |
180 | if(dsp_level<DSP_BUFFER_SIZE) | 189 | |
190 | /* compare to DSP_BUFFER_SIZE without a divide because it is in words and | ||
191 | * we want half the total size in bytes. */ | ||
192 | if(dsp_level < DSP_BUFFER_SIZE) | ||
181 | { | 193 | { |
182 | rebuffer(); | 194 | rebuffer(); |
183 | } | 195 | } |
184 | } | 196 | } |
185 | 197 | ||
186 | void dma_init(void) { | 198 | void dma_init(void) { |
187 | /* Configure SARAM to McBSP DMA */ | 199 | /* Initialize some of the global variables to known values avoiding the |
200 | * .cinit section. */ | ||
201 | dsp_level = 0; | ||
202 | sdem_level = 0; | ||
203 | |||
204 | last_size = 0; | ||
205 | dma0_unlocked = 0; | ||
206 | dma0_stopped = 1; | ||
188 | 207 | ||
208 | waiting = 0; | ||
209 | |||
210 | /* Configure SARAM to McBSP DMA */ | ||
211 | |||
189 | /* Event XEVT0, 32-bit transfers, 0 frame count */ | 212 | /* Event XEVT0, 32-bit transfers, 0 frame count */ |
190 | DMSFC0 = 2 << 12 | 1 << 11; | 213 | DMSFC0 = 2 << 12 | 1 << 11; |
191 | 214 | ||
192 | /* Interrupts generated, Half and full buffer. | 215 | /* Interrupts generated, Half and full buffer. |
193 | * ABU mode, From data space with postincrement, to data space with no | 216 | * ABU mode, From data space with postincrement, to data space with no |
194 | * change | 217 | * change |
195 | */ | 218 | */ |
196 | DMMCR0 = 1 << 14 | 1 << 13 | | 219 | DMMCR0 = 1 << 14 | 1 << 13 | |
197 | 1 << 12 | 1 << 8 | 1 << 6 | 1; | 220 | 1 << 12 | 1 << 8 | 1 << 6 | 1; |
198 | 221 | ||
199 | /* Set the source (incrementing) location */ | 222 | /* Set the source (incrementing) location */ |
200 | DMSRC0 = (unsigned short)&data; | 223 | DMSRC0 = (unsigned short)&data; |
201 | 224 | ||
202 | /* Set the destination (static) location to the McBSP IIS interface */ | 225 | /* Set the destination (static) location to the McBSP IIS interface */ |
203 | DMDST0 = (unsigned short)&DXR20; | 226 | DMDST0 = (unsigned short)&DXR20; |
204 | 227 | ||
205 | /* Set the size of the buffer */ | 228 | /* Set the size of the buffer */ |
206 | DMCTR0 = sizeof(data); | 229 | DMCTR0 = sizeof(data); |
207 | 230 | ||