summaryrefslogtreecommitdiff
path: root/firmware/target/arm/tms320dm320/dsp/dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/tms320dm320/dsp/dma.c')
-rw-r--r--firmware/target/arm/tms320dm320/dsp/dma.c185
1 files changed, 141 insertions, 44 deletions
diff --git a/firmware/target/arm/tms320dm320/dsp/dma.c b/firmware/target/arm/tms320dm320/dsp/dma.c
index 8a05423d83..cd56754a86 100644
--- a/firmware/target/arm/tms320dm320/dsp/dma.c
+++ b/firmware/target/arm/tms320dm320/dsp/dma.c
@@ -8,7 +8,8 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2008 by Catalin Patulea 10 * Copyright (C) 2008 by Catalin Patulea
11 * Copyright (C) 2008 by Maurus Cuelenaere 11 * Copyright (C) 2008 by Maurus Cuelenaere
12 * Copyright (C) 2009 by Karl Kurbjun
12 * 13 *
13 * This program is free software; you can redistribute it and/or 14 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License 15 * modify it under the terms of the GNU General Public License
@@ -25,63 +26,159 @@
25#include "dma.h" 26#include "dma.h"
26 27
27/* This is placed at the right (aligned) address using linker.cmd. */ 28/* This is placed at the right (aligned) address using linker.cmd. */
28#pragma DATA_SECTION (data, ".dma") 29#pragma DATA_SECTION (data, ".dma")
29signed short data[PCM_SIZE / 2]; 30
31#define DSP_BUFFER_SIZE PCM_SIZE/2
32
33/* This is the buffer on the DSP side used for SARAM to McBSP (IIS) */
34signed short data[DSP_BUFFER_SIZE];
30 35
31/* Filled in by loader. */ 36/* These two describe the location of the buffer on the ARM (set in DSPHINT
32unsigned short sdem_addrh; 37 * and dspinit)
33unsigned short sdem_addrl; 38 */
39volatile unsigned short sdem_addrh;
40volatile unsigned short sdem_addrl;
41
42/* This is the size of the ARM buffer (set in DSPHINT and dspinit) */
43volatile unsigned short sdem_dsp_size;
44
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).
47 */
48unsigned short dsp_level=0;
49unsigned short sdem_level=0;
50
51/* This is used to keep track of the last SDRAM to SARAM transfer */
52unsigned short last_size;
53
54/* This tells us which half of the DSP buffer (data) is free */
55unsigned short dma0_unlocked;
56
57/* rebuffer sets up the next SDRAM to SARAM transfer and tells the ARM when it
58 * is done with a buffer.
59 */
60
61/* Notes: Right now this can handle buffer sizes that are smaller even multiples
62 * of DSP_BUFFER_SIZE cleanly. It won't fail with buffers that are larger or
63 * non-multiples, but it won't sound right. The upper limit on larger buffers
64 * is the size of a short. If larger buffer sizes are needed the code on the
65 * ARM side needs to be changed to update a full long.
66 */
67void rebuffer(void)
68{
69 unsigned long sdem_addr;
70
71 /* If the sdem_level is equal to the buffer size the ARM code gave
72 * (sdem_dsp_size) then reset the size and ask the arm for another buffer
73 */
74 if(sdem_level==sdem_dsp_size)
75 {
76 sdem_level=0;
77
78 /* ARM, decode into same half, in SDRAM. */
79 status.msg = MSG_REFILL;
80 int_arm();
81 }
82
83 /* Size is in bytes (but forced 32 bit transfers */
84 if( (dsp_level + (sdem_dsp_size - sdem_level) ) > DSP_BUFFER_SIZE)
85 {
86 last_size = DSP_BUFFER_SIZE-dsp_level;
87 }
88 else
89 {
90 last_size = sdem_dsp_size-sdem_level;
91 }
92
93 /* DSP addresses are 16 bit (word) */
94 DSP_ADDRL = (unsigned short)data + (dma0_unlocked >> 1) + (dsp_level>>1);
95 DSP_ADDRH = 0;
96
97 /* SDRAM addresses are 8 bit (byte)
98 * Warning: These addresses are forced to 32 bit alignment!
99 */
100 sdem_addr = ((unsigned long)sdem_addrh << 16 | sdem_addrl) + sdem_level;
101 SDEM_ADDRL = sdem_addr & 0xffff;
102 SDEM_ADDRH = sdem_addr >> 16;
103
104 /* Set the size of the SDRAM to SARAM transfer (demac transfer) */
105 DMA_SIZE = last_size;
34 106
35interrupt void handle_dma0(void) { 107 DMA_CTRL = 0;
36 unsigned long sdem_addr; 108
109 /* These are just debug signals that are not used/needed right now */
110 status.payload.refill._DMA_TRG = DMA_TRG;
111 status.payload.refill._SDEM_ADDRH = SDEM_ADDRH;
112 status.payload.refill._SDEM_ADDRL = SDEM_ADDRL;
113 status.payload.refill._DSP_ADDRH = DSP_ADDRH;
114 status.payload.refill._DSP_ADDRL = DSP_ADDRL;
115
116 /* Start the demac transfer */
117 DMA_TRG = 1;
118}
119
120/* This interupt handler is for the SARAM (on DSP) to McBSP IIS DMA transfer.
121 * It interupts at 1/2 empty and empty so that we can start filling a new buffer
122 * from SDRAM when a half is free. dsp_level should always be full when this
123 * interupt occurs except for the initial start.
124 */
125interrupt void handle_dma0(void)
126{
37 /* Byte offset to half-buffer locked by DMA0. 127 /* Byte offset to half-buffer locked by DMA0.
38 0 for top, PCM_SIZE/2(0x4000) for bottom */ 128 0 for top, PCM_SIZE/2(0x4000) for bottom */
39 unsigned short dma0_locked; 129 unsigned short dma0_locked;
40 unsigned short dma0_unlocked;
41 130
42 IFR = 1 << 6; 131 IFR = 1 << 6;
43 132
44 /* DMSRC0 is the beginning of the DMA0-locked SARAM half-buffer. */ 133 /* DMSRC0 is the beginning of the DMA0-locked SARAM half-buffer. */
45 DMSA = 0x00 /* DMSRC0 */; 134 DMSA = 0x00 /* DMSRC0 */;
46 dma0_locked = (DMSDN << 1) & (PCM_SIZE / 2); 135 dma0_locked = (DMSDN << 1) & (DSP_BUFFER_SIZE);
47 dma0_unlocked = dma0_locked ^ (PCM_SIZE / 2); 136 dma0_unlocked = dma0_locked ^ (DSP_BUFFER_SIZE);
48 137
49 /* ARM, decode into same half, in SDRAM. */ 138 dsp_level = 0;
50 status.msg = MSG_REFILL; 139
51 status.payload.refill.topbottom = dma0_locked; 140 /* Start the SDRAM to SARAM copy */
52 int_arm(); 141 rebuffer();
53
54 /* DMAC, copy opposite halves from SDRAM to SARAM. */
55 sdem_addr = ((unsigned long)sdem_addrh << 16 | sdem_addrl) + dma0_unlocked;
56 SDEM_ADDRL = sdem_addr & 0xffff;
57 SDEM_ADDRH = sdem_addr >> 16;
58 DSP_ADDRL = (unsigned short)data + (dma0_unlocked >> 1);
59 DSP_ADDRH = 0;
60 DMA_SIZE = PCM_SIZE / 2;
61 DMA_CTRL = 0;
62
63 status.payload.refill._DMA_TRG = DMA_TRG;
64 status.payload.refill._SDEM_ADDRH = SDEM_ADDRH;
65 status.payload.refill._SDEM_ADDRL = SDEM_ADDRL;
66 status.payload.refill._DSP_ADDRH = DSP_ADDRH;
67 status.payload.refill._DSP_ADDRL = DSP_ADDRL;
68
69 DMA_TRG = 1;
70} 142}
71 143
72interrupt void handle_dmac(void) { 144/* This interupt handler runs every time a DMA transfer is complete from SDRAM
73 IFR = 1 << 11; 145 * to the SARAM buffer. It is used to update the SARAM buffer level
146 * (dsp_level), the SDRAM buffer level (sdem_level) and to rebuffer if the dsp
147 * buffer is not full.
148 */
149interrupt void handle_dmac(void) {
150 unsigned long sdem_addr;
151 IFR = 1 << 11;
152
153 dsp_level+=last_size;
154 sdem_level+=last_size;
155
156 if(dsp_level<DSP_BUFFER_SIZE)
157 {
158 rebuffer();
159 }
74} 160}
75 161
76void dma_init(void) { 162void dma_init(void) {
77 /* Configure DMA */ 163 /* Configure SARAM to McBSP DMA */
78 DMSFC0 = 2 << 12 | 1 << 11; /* Event XEVT0, 32-bit transfers, 0 frame count */ 164
79 DMMCR0 = 1 << 14 | 1 << 13 | /* Interrupts generated, Half and full buffer */ 165 /* Event XEVT0, 32-bit transfers, 0 frame count */
80 1 << 12 | 1 << 8 | 1 << 6 | 1; /* ABU mode, 166 DMSFC0 = 2 << 12 | 1 << 11;
81 From data space with postincrement, 167
82 To data space with no mod */ 168 /* Interrupts generated, Half and full buffer.
83 DMSRC0 = (unsigned short)&data; 169 * ABU mode, From data space with postincrement, to data space with no
84 DMDST0 = (unsigned short)&DXR20; /* First of two-word register pair */ 170 * change
171 */
172 DMMCR0 = 1 << 14 | 1 << 13 |
173 1 << 12 | 1 << 8 | 1 << 6 | 1;
174
175 /* Set the source (incrementing) location */
176 DMSRC0 = (unsigned short)&data;
177
178 /* Set the destination (static) location to the McBSP IIS interface */
179 DMDST0 = (unsigned short)&DXR20;
180
181 /* Set the size of the buffer */
85 DMCTR0 = sizeof(data); 182 DMCTR0 = sizeof(data);
86 183
87 /* Run, Rudolf, run! (with DMA0 interrupts) */ 184 /* Run, Rudolf, run! (with DMA0 interrupts) */