diff options
Diffstat (limited to 'firmware/target/arm/tms320dm320/dsp/dma.c')
-rw-r--r-- | firmware/target/arm/tms320dm320/dsp/dma.c | 185 |
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") |
29 | signed 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) */ | ||
34 | signed 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 |
32 | unsigned short sdem_addrh; | 37 | * and dspinit) |
33 | unsigned short sdem_addrl; | 38 | */ |
39 | volatile unsigned short sdem_addrh; | ||
40 | volatile unsigned short sdem_addrl; | ||
41 | |||
42 | /* This is the size of the ARM buffer (set in DSPHINT and dspinit) */ | ||
43 | volatile 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 | */ | ||
48 | unsigned short dsp_level=0; | ||
49 | unsigned short sdem_level=0; | ||
50 | |||
51 | /* This is used to keep track of the last SDRAM to SARAM transfer */ | ||
52 | unsigned short last_size; | ||
53 | |||
54 | /* This tells us which half of the DSP buffer (data) is free */ | ||
55 | unsigned 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 | */ | ||
67 | void 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 | ||
35 | interrupt 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 | */ | ||
125 | interrupt 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 | ||
72 | interrupt 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 | */ | ||
149 | interrupt 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 | ||
76 | void dma_init(void) { | 162 | void 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) */ |