diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2009-03-12 06:31:40 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2009-03-12 06:31:40 +0000 |
commit | a1a332e04bf937d164746f06c8f71fab547fc271 (patch) | |
tree | 71fbd805fb2689746e69fabf980e88ed661ab893 | |
parent | bc8cab4c24a0891182ac9711c67165a9e3373b1c (diff) | |
download | rockbox-a1a332e04bf937d164746f06c8f71fab547fc271.tar.gz rockbox-a1a332e04bf937d164746f06c8f71fab547fc271.zip |
Gigabeat S: Implement MDMA and UDMA disk access for bootloader and main binary. Add a needed SDMA API to check channel errors. Increase audio DMA channels' priority as required. Reads and writes measure faster accross all test_disk tests and especially at 4KB and 1MB.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20299 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | firmware/SOURCES | 2 | ||||
-rw-r--r-- | firmware/export/config-gigabeat-s.h | 3 | ||||
-rwxr-xr-x | firmware/export/imx31l.h | 4 | ||||
-rw-r--r-- | firmware/target/arm/imx31/boot.lds | 2 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/ata-imx31.c | 551 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/ata-target.h | 11 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/kernel-imx31.c | 2 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c | 4 | ||||
-rw-r--r-- | firmware/target/arm/imx31/sdma-imx31.c | 8 | ||||
-rw-r--r-- | firmware/target/arm/imx31/sdma-imx31.h | 3 |
10 files changed, 563 insertions, 27 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index 29ee03d040..d7d2b6939d 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -760,6 +760,7 @@ target/arm/lcd-as-memframe.S | |||
760 | target/arm/mmu-arm.S | 760 | target/arm/mmu-arm.S |
761 | target/arm/imx31/debug-imx31.c | 761 | target/arm/imx31/debug-imx31.c |
762 | target/arm/imx31/rolo_restart.S | 762 | target/arm/imx31/rolo_restart.S |
763 | target/arm/imx31/sdma-imx31.c | ||
763 | target/arm/imx31/gigabeat-s/adc-imx31.c | 764 | target/arm/imx31/gigabeat-s/adc-imx31.c |
764 | target/arm/imx31/gigabeat-s/ata-imx31.c | 765 | target/arm/imx31/gigabeat-s/ata-imx31.c |
765 | target/arm/imx31/gigabeat-s/avic-imx31.c | 766 | target/arm/imx31/gigabeat-s/avic-imx31.c |
@@ -782,7 +783,6 @@ target/arm/imx31/gigabeat-s/system-imx31.c | |||
782 | target/arm/imx31/gigabeat-s/usb-imx31.c | 783 | target/arm/imx31/gigabeat-s/usb-imx31.c |
783 | target/arm/imx31/gigabeat-s/wmcodec-imx31.c | 784 | target/arm/imx31/gigabeat-s/wmcodec-imx31.c |
784 | #ifndef BOOTLOADER | 785 | #ifndef BOOTLOADER |
785 | target/arm/imx31/sdma-imx31.c | ||
786 | target/arm/imx31/gigabeat-s/audio-gigabeat-s.c | 786 | target/arm/imx31/gigabeat-s/audio-gigabeat-s.c |
787 | target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c | 787 | target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c |
788 | target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c | 788 | target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c |
diff --git a/firmware/export/config-gigabeat-s.h b/firmware/export/config-gigabeat-s.h index f55a4fd382..17ee39352c 100644 --- a/firmware/export/config-gigabeat-s.h +++ b/firmware/export/config-gigabeat-s.h | |||
@@ -186,6 +186,9 @@ | |||
186 | /* Define this if you have ATA power-off control */ | 186 | /* Define this if you have ATA power-off control */ |
187 | #define HAVE_ATA_POWER_OFF | 187 | #define HAVE_ATA_POWER_OFF |
188 | 188 | ||
189 | /* Define this to add support for ATA DMA */ | ||
190 | #define HAVE_ATA_DMA | ||
191 | |||
189 | /* Virtual LED (icon) */ | 192 | /* Virtual LED (icon) */ |
190 | #define CONFIG_LED LED_VIRTUAL | 193 | #define CONFIG_LED LED_VIRTUAL |
191 | 194 | ||
diff --git a/firmware/export/imx31l.h b/firmware/export/imx31l.h index 49084c0d8e..ea2187e0c2 100755 --- a/firmware/export/imx31l.h +++ b/firmware/export/imx31l.h | |||
@@ -497,11 +497,11 @@ | |||
497 | #define ATA_IORDY_EN (1 << 0) | 497 | #define ATA_IORDY_EN (1 << 0) |
498 | 498 | ||
499 | /* ATA_INTERRUPT_PENDING, ATA_INTERRUPT_ENABLE, ATA_INTERRUPT_CLEAR flags */ | 499 | /* ATA_INTERRUPT_PENDING, ATA_INTERRUPT_ENABLE, ATA_INTERRUPT_CLEAR flags */ |
500 | #define ATA_INTRQ1 (1 << 7) | 500 | #define ATA_INTRQ1 (1 << 7) /* INTRQ to the DMA */ |
501 | #define ATA_FIFO_UNDERFLOW (1 << 6) | 501 | #define ATA_FIFO_UNDERFLOW (1 << 6) |
502 | #define ATA_FIFO_OVERFLOW (1 << 5) | 502 | #define ATA_FIFO_OVERFLOW (1 << 5) |
503 | #define ATA_CONTROLLER_IDLE (1 << 4) | 503 | #define ATA_CONTROLLER_IDLE (1 << 4) |
504 | #define ATA_INTRQ2 (1 << 3) | 504 | #define ATA_INTRQ2 (1 << 3) /* INTRQ to the MCU */ |
505 | 505 | ||
506 | /* EPIT */ | 506 | /* EPIT */ |
507 | #define EPITCR1 (*(REG32_PTR_T)(EPIT1_BASE_ADDR+0x00)) | 507 | #define EPITCR1 (*(REG32_PTR_T)(EPIT1_BASE_ADDR+0x00)) |
diff --git a/firmware/target/arm/imx31/boot.lds b/firmware/target/arm/imx31/boot.lds index b108ba181d..e08b4bfb7a 100644 --- a/firmware/target/arm/imx31/boot.lds +++ b/firmware/target/arm/imx31/boot.lds | |||
@@ -55,6 +55,8 @@ SECTIONS | |||
55 | *(.idata) | 55 | *(.idata) |
56 | *(.data*) | 56 | *(.data*) |
57 | . = ALIGN(0x4); | 57 | . = ALIGN(0x4); |
58 | *(.sdmacode) | ||
59 | . = ALIGN(0x4); | ||
58 | _dataend = . ; | 60 | _dataend = . ; |
59 | } > DRAM | 61 | } > DRAM |
60 | 62 | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/ata-imx31.c b/firmware/target/arm/imx31/gigabeat-s/ata-imx31.c index 59b89c02c9..c32dead30a 100644 --- a/firmware/target/arm/imx31/gigabeat-s/ata-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/ata-imx31.c | |||
@@ -28,7 +28,12 @@ | |||
28 | #include "ata.h" | 28 | #include "ata.h" |
29 | #include "ata-target.h" | 29 | #include "ata-target.h" |
30 | #include "clkctl-imx31.h" | 30 | #include "clkctl-imx31.h" |
31 | #ifdef HAVE_ATA_DMA | ||
32 | #include "sdma-imx31.h" | ||
33 | #include "mmu-imx31.h" | ||
34 | #endif | ||
31 | 35 | ||
36 | /* PIO modes timing info */ | ||
32 | static const struct ata_pio_timings | 37 | static const struct ata_pio_timings |
33 | { | 38 | { |
34 | uint16_t time_2w; /* t2 during write */ | 39 | uint16_t time_2w; /* t2 during write */ |
@@ -83,26 +88,217 @@ static const struct ata_pio_timings | |||
83 | .time_ax = 35, | 88 | .time_ax = 35, |
84 | .time_4 = 10, | 89 | .time_4 = 10, |
85 | .time_9 = 10 | 90 | .time_9 = 10 |
91 | } | ||
92 | }; | ||
93 | |||
94 | /* Track first init */ | ||
95 | static bool initialized = false; | ||
96 | |||
97 | #ifdef HAVE_ATA_DMA | ||
98 | /* One DMA channel for reads, the other for writes othewise one channel would | ||
99 | * have to be reinitialized every time the direction changed. (Different | ||
100 | * SDMA scripts are used for reading or writing) */ | ||
101 | #define ATA_DMA_CH_NUM_RD 3 | ||
102 | #define ATA_DMA_CH_NUM_WR 4 | ||
103 | /* Use default priority for these channels (1) - ATA isn't realtime urgent. */ | ||
104 | /* Maximum DMA size per buffer descriptor (32-byte aligned) */ | ||
105 | #define ATA_MAX_BD_SIZE (65534 & ~31) /* 65504 */ | ||
106 | |||
107 | /* Number of buffer descriptors required for a maximum sector count trasfer. | ||
108 | * NOTE: Assumes LBA28 and 512-byte sectors! */ | ||
109 | #define ATA_BASE_BD_COUNT ((256*512 + (ATA_MAX_BD_SIZE-1)) / ATA_MAX_BD_SIZE) | ||
110 | #define ATA_BD_COUNT (ATA_BASE_BD_COUNT + 2) | ||
111 | |||
112 | static const struct ata_mdma_timings | ||
113 | { | ||
114 | uint8_t time_m; /* tM */ | ||
115 | uint8_t time_jn; /* tH */ | ||
116 | uint8_t time_d; /* tD */ | ||
117 | uint8_t time_k; /* tKW */ | ||
118 | } mdma_timings[] = | ||
119 | { | ||
120 | [0] = /* MDMA mode 0 */ | ||
121 | { | ||
122 | .time_m = 50, | ||
123 | .time_jn = 20, | ||
124 | .time_d = 215, | ||
125 | .time_k = 215 | ||
86 | }, | 126 | }, |
127 | [1] = /* MDMA mode 1 */ | ||
128 | { | ||
129 | .time_m = 30, | ||
130 | .time_jn = 15, | ||
131 | .time_d = 80, | ||
132 | .time_k = 50 | ||
133 | }, | ||
134 | [2] = /* MDMA mode 2 */ | ||
135 | { | ||
136 | .time_m = 25, | ||
137 | .time_jn = 10, | ||
138 | .time_d = 70, | ||
139 | .time_k = 25 | ||
140 | } | ||
87 | }; | 141 | }; |
88 | 142 | ||
89 | static int pio_mode = 0; /* Setup mode 0 by default */ | 143 | static const struct ata_udma_timings |
144 | { | ||
145 | uint8_t time_ack; /* tACK */ | ||
146 | uint8_t time_env; /* tENV */ | ||
147 | uint8_t time_rpx; /* tRP */ | ||
148 | uint8_t time_zah; /* tZAH */ | ||
149 | uint8_t time_mlix; /* tMLI */ | ||
150 | uint8_t time_dvh; /* tDVH */ | ||
151 | uint8_t time_dzfs; /* tDVS+tDVH? */ | ||
152 | uint8_t time_dvs; /* tDVS */ | ||
153 | uint8_t time_cvh; /* ?? */ | ||
154 | uint8_t time_ss; /* tSS */ | ||
155 | uint8_t time_cyc; /* tCYC */ | ||
156 | } udma_timings[] = | ||
157 | { | ||
158 | [0] = /* UDMA mode 0 */ | ||
159 | { | ||
160 | .time_ack = 20, | ||
161 | .time_env = 20, | ||
162 | .time_rpx = 160, | ||
163 | .time_zah = 20, | ||
164 | .time_mlix = 20, | ||
165 | .time_dvh = 6, | ||
166 | .time_dzfs = 80, | ||
167 | .time_dvs = 70, | ||
168 | .time_cvh = 6, | ||
169 | .time_ss = 50, | ||
170 | .time_cyc = 114 | ||
171 | }, | ||
172 | [1] = /* UDMA mode 1 */ | ||
173 | { | ||
174 | .time_ack = 20, | ||
175 | .time_env = 20, | ||
176 | .time_rpx = 125, | ||
177 | .time_zah = 20, | ||
178 | .time_mlix = 20, | ||
179 | .time_dvh = 6, | ||
180 | .time_dzfs = 63, | ||
181 | .time_dvs = 48, | ||
182 | .time_cvh = 6, | ||
183 | .time_ss = 50, | ||
184 | .time_cyc = 75 | ||
185 | }, | ||
186 | [2] = /* UDMA mode 2 */ | ||
187 | { | ||
188 | .time_ack = 20, | ||
189 | .time_env = 20, | ||
190 | .time_rpx = 100, | ||
191 | .time_zah = 20, | ||
192 | .time_mlix = 20, | ||
193 | .time_dvh = 6, | ||
194 | .time_dzfs = 47, | ||
195 | .time_dvs = 34, | ||
196 | .time_cvh = 6, | ||
197 | .time_ss = 50, | ||
198 | .time_cyc = 55 | ||
199 | }, | ||
200 | [3] = /* UDMA mode 3 */ | ||
201 | { | ||
202 | .time_ack = 20, | ||
203 | .time_env = 20, | ||
204 | .time_rpx = 100, | ||
205 | .time_zah = 20, | ||
206 | .time_mlix = 20, | ||
207 | .time_dvh = 6, | ||
208 | .time_dzfs = 35, | ||
209 | .time_dvs = 20, | ||
210 | .time_cvh = 6, | ||
211 | .time_ss = 50, | ||
212 | .time_cyc = 39 | ||
213 | }, | ||
214 | [4] = /* UDMA mode 4 */ | ||
215 | { | ||
216 | .time_ack = 20, | ||
217 | .time_env = 20, | ||
218 | .time_rpx = 100, | ||
219 | .time_zah = 20, | ||
220 | .time_mlix = 20, | ||
221 | .time_dvh = 6, | ||
222 | .time_dzfs = 25, | ||
223 | .time_dvs = 7, | ||
224 | .time_cvh = 6, | ||
225 | .time_ss = 50, | ||
226 | .time_cyc = 25 | ||
227 | }, | ||
228 | #if 0 | ||
229 | [5] = /* UDMA mode 5 (bus clock 80MHz or higher only) */ | ||
230 | { | ||
231 | .time_ack = 20, | ||
232 | .time_env = 20, | ||
233 | .time_rpx = 85, | ||
234 | .time_zah = 20, | ||
235 | .time_mlix = 20, | ||
236 | .time_dvh = 6, | ||
237 | .time_dzfs = 40, | ||
238 | .time_dvs = 5, | ||
239 | .time_cvh = 10, | ||
240 | .time_ss = 50, | ||
241 | .time_cyc = 17 | ||
242 | } | ||
243 | #endif | ||
244 | }; | ||
245 | |||
246 | /** Threading **/ | ||
247 | /* Signal to tell thread when DMA is done */ | ||
248 | static struct wakeup ata_dma_wakeup; | ||
249 | |||
250 | /** SDMA **/ | ||
251 | /* Array of buffer descriptors for large transfers and alignnment */ | ||
252 | static struct buffer_descriptor ata_bda[ATA_BD_COUNT] DEVBSS_ATTR; | ||
253 | /* ATA channel descriptors */ | ||
254 | static struct channel_descriptor ata_cd_rd DEVBSS_ATTR; /* read channel */ | ||
255 | static struct channel_descriptor ata_cd_wr DEVBSS_ATTR; /* write channel */ | ||
256 | /* DMA channel to be started for transfer */ | ||
257 | static unsigned int current_channel = 0; | ||
258 | |||
259 | /** Buffers **/ | ||
260 | /* Scatter buffer for first and last 32 bytes of a non cache-aligned transfer | ||
261 | * to cached RAM. */ | ||
262 | static uint32_t scatter_buffer[32/4*2] DEVBSS_ATTR; | ||
263 | /* Address of ends in destination buffer for unaligned reads - copied after | ||
264 | * DMA completes. */ | ||
265 | static void *sb_dst[2] = { NULL, NULL }; | ||
266 | |||
267 | /** Modes **/ | ||
268 | #define ATA_DMA_MWDMA 0x00000000 /* Using multiword DMA */ | ||
269 | #define ATA_DMA_UDMA ATA_DMA_ULTRA_SELECTED /* Using Ultra DMA */ | ||
270 | #define ATA_DMA_PIO 0x80000000 /* Using PIO */ | ||
271 | #define ATA_DMA_DISABLED 0x80000001 /* DMA init error - use PIO */ | ||
272 | static unsigned long ata_dma_selected = ATA_DMA_PIO; | ||
273 | #endif /* HAVE_ATA_DMA */ | ||
274 | |||
275 | static unsigned int get_T(void) | ||
276 | { | ||
277 | /* T = ATA clock period in nanoseconds */ | ||
278 | return 1000 * 1000 * 1000 / imx31_clkctl_get_ata_clk(); | ||
279 | } | ||
90 | 280 | ||
91 | static void ata_wait_for_idle(void) | 281 | static void ata_wait_for_idle(void) |
92 | { | 282 | { |
93 | while (!(ATA_INTERRUPT_PENDING & ATA_CONTROLLER_IDLE)); | 283 | while (!(ATA_INTERRUPT_PENDING & ATA_CONTROLLER_IDLE)); |
94 | } | 284 | } |
95 | 285 | ||
286 | /* Route the INTRQ to either the MCU or SDMA depending upon whether there is | ||
287 | * a DMA transfer in progress. */ | ||
288 | static inline void ata_set_intrq(bool to_dma) | ||
289 | { | ||
290 | ATA_INTERRUPT_ENABLE = | ||
291 | (ATA_INTERRUPT_ENABLE & ~(ATA_INTRQ1 | ATA_INTRQ2)) | | ||
292 | (to_dma ? ATA_INTRQ1 : ATA_INTRQ2); | ||
293 | } | ||
294 | |||
96 | /* Setup the timing for PIO mode */ | 295 | /* Setup the timing for PIO mode */ |
97 | void ata_set_pio_timings(int mode) | 296 | void ata_set_pio_timings(int mode) |
98 | { | 297 | { |
99 | ata_wait_for_idle(); | ||
100 | |||
101 | const struct ata_pio_timings * const timings = &pio_timings[mode]; | 298 | const struct ata_pio_timings * const timings = &pio_timings[mode]; |
102 | /* T = period in nanoseconds */ | 299 | unsigned int T = get_T(); |
103 | int T = 1000 * 1000 * 1000 / imx31_clkctl_get_ata_clk(); | ||
104 | 300 | ||
105 | pio_mode = mode; | 301 | ata_wait_for_idle(); |
106 | 302 | ||
107 | ATA_TIME_1 = (timings->time_1 + T) / T; | 303 | ATA_TIME_1 = (timings->time_1 + T) / T; |
108 | ATA_TIME_2W = (timings->time_2w + T) / T; | 304 | ATA_TIME_2W = (timings->time_2w + T) / T; |
@@ -118,10 +314,10 @@ void ata_reset(void) | |||
118 | /* Be sure we're not busy */ | 314 | /* Be sure we're not busy */ |
119 | ata_wait_for_idle(); | 315 | ata_wait_for_idle(); |
120 | 316 | ||
121 | ATA_INTF_CONTROL &= ~ATA_ATA_RST; | 317 | ATA_INTF_CONTROL &= ~(ATA_ATA_RST | ATA_FIFO_RST); |
122 | sleep(1); | 318 | sleep(HZ/100); |
123 | ATA_INTF_CONTROL |= ATA_ATA_RST; | 319 | ATA_INTF_CONTROL = ATA_ATA_RST | ATA_FIFO_RST; |
124 | sleep(1); | 320 | sleep(HZ/100); |
125 | 321 | ||
126 | ata_wait_for_idle(); | 322 | ata_wait_for_idle(); |
127 | } | 323 | } |
@@ -130,16 +326,17 @@ void ata_enable(bool on) | |||
130 | { | 326 | { |
131 | /* Unconditionally clock module before writing regs */ | 327 | /* Unconditionally clock module before writing regs */ |
132 | imx31_clkctl_module_clock_gating(CG_ATA, CGM_ON_ALL); | 328 | imx31_clkctl_module_clock_gating(CG_ATA, CGM_ON_ALL); |
329 | ata_wait_for_idle(); | ||
133 | 330 | ||
134 | if (on) | 331 | if (on) |
135 | { | 332 | { |
136 | ATA_INTF_CONTROL |= ATA_ATA_RST; | 333 | ATA_INTF_CONTROL = ATA_ATA_RST | ATA_FIFO_RST; |
334 | sleep(HZ/100); | ||
137 | } | 335 | } |
138 | else | 336 | else |
139 | { | 337 | { |
140 | ata_wait_for_idle(); | 338 | ATA_INTF_CONTROL &= ~(ATA_ATA_RST | ATA_FIFO_RST); |
141 | 339 | sleep(HZ/100); | |
142 | ATA_INTF_CONTROL &= ~ATA_ATA_RST; | ||
143 | 340 | ||
144 | /* Disable off - unclock ATA module */ | 341 | /* Disable off - unclock ATA module */ |
145 | imx31_clkctl_module_clock_gating(CG_ATA, CGM_OFF); | 342 | imx31_clkctl_module_clock_gating(CG_ATA, CGM_OFF); |
@@ -151,16 +348,338 @@ bool ata_is_coldstart(void) | |||
151 | return true; | 348 | return true; |
152 | } | 349 | } |
153 | 350 | ||
351 | #ifdef HAVE_ATA_DMA | ||
352 | static void ata_set_mdma_timings(unsigned int mode) | ||
353 | { | ||
354 | const struct ata_mdma_timings * const timings = &mdma_timings[mode]; | ||
355 | unsigned int T = get_T(); | ||
356 | |||
357 | ATA_TIME_M = (timings->time_m + T) / T; | ||
358 | ATA_TIME_JN = (timings->time_jn + T) / T; | ||
359 | ATA_TIME_D = (timings->time_d + T) / T; | ||
360 | ATA_TIME_K = (timings->time_k + T) / T; | ||
361 | } | ||
362 | |||
363 | static void ata_set_udma_timings(unsigned int mode) | ||
364 | { | ||
365 | const struct ata_udma_timings * const timings = &udma_timings[mode]; | ||
366 | unsigned int T = get_T(); | ||
367 | |||
368 | ATA_TIME_ACK = (timings->time_ack + T) / T; | ||
369 | ATA_TIME_ENV = (timings->time_env + T) / T; | ||
370 | ATA_TIME_RPX = (timings->time_rpx + T) / T; | ||
371 | ATA_TIME_ZAH = (timings->time_zah + T) / T; | ||
372 | ATA_TIME_MLIX = (timings->time_mlix + T) / T; | ||
373 | ATA_TIME_DVH = (timings->time_dvh + T) / T + 1; | ||
374 | ATA_TIME_DZFS = (timings->time_dzfs + T) / T; | ||
375 | ATA_TIME_DVS = (timings->time_dvs + T) / T; | ||
376 | ATA_TIME_CVH = (timings->time_cvh + T) / T; | ||
377 | ATA_TIME_SS = (timings->time_ss + T) / T; | ||
378 | ATA_TIME_CYC = (timings->time_cyc + T) / T; | ||
379 | } | ||
380 | |||
381 | void ata_dma_set_mode(unsigned char mode) | ||
382 | { | ||
383 | unsigned int modeidx = mode & 0x07; | ||
384 | unsigned int dmamode = mode & 0xf8; | ||
385 | |||
386 | ata_wait_for_idle(); | ||
387 | |||
388 | if (ata_dma_selected == ATA_DMA_DISABLED) | ||
389 | { | ||
390 | /* Configuration error - no DMA */ | ||
391 | } | ||
392 | else if (dmamode == 0x40 && modeidx <= ATA_MAX_UDMA) | ||
393 | { | ||
394 | /* Using Ultra DMA */ | ||
395 | ata_set_udma_timings(dmamode); | ||
396 | ata_dma_selected = ATA_DMA_UDMA; | ||
397 | } | ||
398 | else if (dmamode == 0x20 && modeidx <= ATA_MAX_MWDMA) | ||
399 | { | ||
400 | /* Using Multiword DMA */ | ||
401 | ata_set_mdma_timings(dmamode); | ||
402 | ata_dma_selected = ATA_DMA_MWDMA; | ||
403 | } | ||
404 | else | ||
405 | { | ||
406 | /* Don't understand this - force PIO. */ | ||
407 | ata_dma_selected = ATA_DMA_PIO; | ||
408 | } | ||
409 | } | ||
410 | |||
411 | /* Called by SDMA when transfer is complete */ | ||
412 | static void ata_dma_callback(void) | ||
413 | { | ||
414 | /* Clear FIFO if not empty - shouldn't happen */ | ||
415 | while (ATA_FIFO_FILL != 0) | ||
416 | ATA_FIFO_DATA_32; | ||
417 | |||
418 | /* Clear FIFO interrupts (the only ones that can be) */ | ||
419 | ATA_INTERRUPT_CLEAR = ATA_INTERRUPT_PENDING; | ||
420 | |||
421 | ata_set_intrq(false); /* Return INTRQ to MCU */ | ||
422 | wakeup_signal(&ata_dma_wakeup); /* Signal waiting thread */ | ||
423 | } | ||
424 | |||
425 | bool ata_dma_setup(void *addr, unsigned long bytes, bool write) | ||
426 | { | ||
427 | struct buffer_descriptor *bd_p; | ||
428 | unsigned char *buf; | ||
429 | |||
430 | if (UNLIKELY(bytes > ATA_BASE_BD_COUNT*ATA_MAX_BD_SIZE || | ||
431 | (ata_dma_selected & ATA_DMA_PIO))) | ||
432 | { | ||
433 | /* Too much? Implies BD count should be reevaluated since this | ||
434 | * shouldn't be reached based upon size. Otherwise we simply didn't | ||
435 | * understand the DMA mode setup. Force PIO in both cases. */ | ||
436 | ATA_INTF_CONTROL = ATA_FIFO_RST | ATA_ATA_RST; | ||
437 | return false; | ||
438 | } | ||
439 | |||
440 | bd_p = &ata_bda[0]; | ||
441 | buf = (unsigned char *)addr_virt_to_phys((unsigned long)addr); | ||
442 | sb_dst[0] = NULL; /* Assume not needed */ | ||
443 | |||
444 | if (write) | ||
445 | { | ||
446 | /* No cache alignment concerns */ | ||
447 | current_channel = ATA_DMA_CH_NUM_WR; | ||
448 | |||
449 | if (LIKELY(buf != addr)) | ||
450 | { | ||
451 | /* addr is virtual */ | ||
452 | clean_dcache_range(addr, bytes); | ||
453 | } | ||
454 | |||
455 | /* Setup ATA controller for DMA transmit */ | ||
456 | ATA_INTF_CONTROL = ATA_FIFO_RST | ATA_ATA_RST | ATA_FIFO_TX_EN | | ||
457 | ATA_DMA_PENDING | ata_dma_selected | ATA_DMA_WRITE; | ||
458 | ATA_FIFO_ALARM = SDMA_ATA_WML / 2; | ||
459 | } | ||
460 | else | ||
461 | { | ||
462 | current_channel = ATA_DMA_CH_NUM_RD; | ||
463 | |||
464 | /* Setup ATA controller for DMA receive */ | ||
465 | ATA_INTF_CONTROL = ATA_FIFO_RST | ATA_ATA_RST | ATA_FIFO_RCV_EN | | ||
466 | ATA_DMA_PENDING | ata_dma_selected; | ||
467 | ATA_FIFO_ALARM = SDMA_ATA_WML / 2; | ||
468 | |||
469 | if (LIKELY(buf != addr)) | ||
470 | { | ||
471 | /* addr is virtual */ | ||
472 | dump_dcache_range(addr, bytes); | ||
473 | |||
474 | if ((unsigned long)addr & 31) | ||
475 | { | ||
476 | /* Not cache aligned, must use scatter buffers for first and | ||
477 | * last 32 bytes. */ | ||
478 | unsigned char *bufstart = buf; | ||
479 | |||
480 | sb_dst[0] = addr; | ||
481 | bd_p->buf_addr = scatter_buffer; | ||
482 | bd_p->mode.count = 32; | ||
483 | bd_p->mode.status = BD_DONE | BD_CONT; | ||
484 | |||
485 | buf += 32; | ||
486 | bytes -= 32; | ||
487 | bd_p++; | ||
488 | |||
489 | while (bytes > ATA_MAX_BD_SIZE) | ||
490 | { | ||
491 | bd_p->buf_addr = buf; | ||
492 | bd_p->mode.count = ATA_MAX_BD_SIZE; | ||
493 | bd_p->mode.status = BD_DONE | BD_CONT; | ||
494 | buf += ATA_MAX_BD_SIZE; | ||
495 | bytes -= ATA_MAX_BD_SIZE; | ||
496 | bd_p++; | ||
497 | } | ||
498 | |||
499 | if (bytes > 32) | ||
500 | { | ||
501 | unsigned long size = bytes - 32; | ||
502 | bd_p->buf_addr = buf; | ||
503 | bd_p->mode.count = size; | ||
504 | bd_p->mode.status = BD_DONE | BD_CONT; | ||
505 | buf += size; | ||
506 | bd_p++; | ||
507 | } | ||
508 | |||
509 | /* There will be exactly 32 bytes left */ | ||
510 | |||
511 | /* Final buffer - wrap to base bd, interrupt */ | ||
512 | sb_dst[1] = addr + (buf - bufstart); | ||
513 | bd_p->buf_addr = &scatter_buffer[32/4]; | ||
514 | bd_p->mode.count = 32; | ||
515 | bd_p->mode.status = BD_DONE | BD_WRAP | BD_INTR; | ||
516 | |||
517 | return true; | ||
518 | } | ||
519 | } | ||
520 | } | ||
521 | |||
522 | /* Setup buffer descriptors for both cache-aligned reads and all write | ||
523 | * operations. */ | ||
524 | while (bytes > ATA_MAX_BD_SIZE) | ||
525 | { | ||
526 | bd_p->buf_addr = buf; | ||
527 | bd_p->mode.count = ATA_MAX_BD_SIZE; | ||
528 | bd_p->mode.status = BD_DONE | BD_CONT; | ||
529 | buf += ATA_MAX_BD_SIZE; | ||
530 | bytes -= ATA_MAX_BD_SIZE; | ||
531 | bd_p++; | ||
532 | } | ||
533 | |||
534 | /* Final buffer - wrap to base bd, interrupt */ | ||
535 | bd_p->buf_addr = buf; | ||
536 | bd_p->mode.count = bytes; | ||
537 | bd_p->mode.status = BD_DONE | BD_WRAP | BD_INTR; | ||
538 | |||
539 | return true; | ||
540 | } | ||
541 | |||
542 | bool ata_dma_finish(void) | ||
543 | { | ||
544 | unsigned int channel = current_channel; | ||
545 | long timeout = current_tick + HZ*10; | ||
546 | |||
547 | current_channel = 0; | ||
548 | |||
549 | ata_set_intrq(true); /* Give INTRQ to DMA */ | ||
550 | sdma_channel_run(channel); /* Kick the channel to wait for events */ | ||
551 | |||
552 | while (1) | ||
553 | { | ||
554 | int oldirq; | ||
555 | |||
556 | if (LIKELY(wakeup_wait(&ata_dma_wakeup, HZ/2) == OBJ_WAIT_SUCCEEDED)) | ||
557 | break; | ||
558 | |||
559 | ata_keep_active(); | ||
560 | |||
561 | if (TIME_BEFORE(current_tick, timeout)) | ||
562 | continue; | ||
563 | |||
564 | /* Epic fail - timed out - maybe. */ | ||
565 | oldirq = disable_irq_save(); | ||
566 | ata_set_intrq(false); /* Strip INTRQ from DMA */ | ||
567 | sdma_channel_stop(channel); /* Stop DMA */ | ||
568 | restore_irq(oldirq); | ||
569 | |||
570 | if (wakeup_wait(&ata_dma_wakeup, TIMEOUT_NOBLOCK) == OBJ_WAIT_SUCCEEDED) | ||
571 | break; /* DMA really did finish after timeout */ | ||
572 | |||
573 | sdma_channel_reset(channel); /* Reset everything + clear error */ | ||
574 | return false; | ||
575 | } | ||
576 | |||
577 | if (sdma_channel_is_error(channel)) | ||
578 | { | ||
579 | /* Channel error in one or more descriptors */ | ||
580 | sdma_channel_reset(channel); /* Reset everything + clear error */ | ||
581 | return false; | ||
582 | } | ||
583 | |||
584 | if (sb_dst[0] != NULL) | ||
585 | { | ||
586 | /* NOTE: This requires that unaligned access support be enabled! */ | ||
587 | register void *sbs = scatter_buffer; | ||
588 | register void *sbd0 = sb_dst[0]; | ||
589 | register void *sbd1 = sb_dst[1]; | ||
590 | asm volatile( | ||
591 | "add r0, %1, #32 \n" /* Prefetch at DMA-direct boundaries */ | ||
592 | "mcrr p15, 2, r0, r0, c12 \n" | ||
593 | "mcrr p15, 2, %2, %2, c12 \n" | ||
594 | "ldmia %0!, { r0-r3 } \n" /* Copy the 32-bytes to destination */ | ||
595 | "str r0, [%1], #4 \n" /* stmia doesn't work unaligned */ | ||
596 | "str r1, [%1], #4 \n" | ||
597 | "str r2, [%1], #4 \n" | ||
598 | "str r3, [%1], #4 \n" | ||
599 | "ldmia %0!, { r0-r3 } \n" | ||
600 | "str r0, [%1], #4 \n" | ||
601 | "str r1, [%1], #4 \n" | ||
602 | "str r2, [%1], #4 \n" | ||
603 | "str r3, [%1] \n" | ||
604 | "ldmia %0!, { r0-r3 } \n" /* Copy the 32-bytes to destination */ | ||
605 | "str r0, [%2], #4 \n" /* stmia doesn't work unaligned */ | ||
606 | "str r1, [%2], #4 \n" | ||
607 | "str r2, [%2], #4 \n" | ||
608 | "str r3, [%2], #4 \n" | ||
609 | "ldmia %0!, { r0-r3 } \n" | ||
610 | "str r0, [%2], #4 \n" | ||
611 | "str r1, [%2], #4 \n" | ||
612 | "str r2, [%2], #4 \n" | ||
613 | "str r3, [%2] \n" | ||
614 | : "+r"(sbs), "+r"(sbd0), "+r"(sbd1) | ||
615 | : | ||
616 | : "r0", "r1", "r2", "r3"); | ||
617 | } | ||
618 | |||
619 | return true; | ||
620 | } | ||
621 | #endif /* HAVE_ATA_DMA */ | ||
622 | |||
154 | void ata_device_init(void) | 623 | void ata_device_init(void) |
155 | { | 624 | { |
156 | /* Make sure we're not in reset mode */ | 625 | /* Make sure we're not in reset mode */ |
157 | ata_enable(true); | 626 | ata_enable(true); |
158 | 627 | ||
628 | if (!initialized) | ||
629 | { | ||
630 | ATA_INTERRUPT_ENABLE = 0; | ||
631 | ATA_INTERRUPT_CLEAR = ATA_INTERRUPT_PENDING; | ||
632 | } | ||
633 | |||
634 | ata_set_intrq(false); | ||
635 | |||
636 | if (initialized) | ||
637 | return; | ||
638 | |||
159 | /* All modes use same tOFF/tON */ | 639 | /* All modes use same tOFF/tON */ |
160 | ATA_TIME_OFF = 3; | 640 | ATA_TIME_OFF = 3; |
161 | ATA_TIME_ON = 3; | 641 | ATA_TIME_ON = 3; |
162 | 642 | ||
163 | /* mode may be switched later once identify info is ready in which | 643 | /* Setup mode 0 for all by default |
644 | * Mode may be switched later once identify info is ready in which | ||
164 | * case the main driver calls back */ | 645 | * case the main driver calls back */ |
165 | ata_set_pio_timings(pio_mode); | 646 | ata_set_pio_timings(0); |
647 | |||
648 | #ifdef HAVE_ATA_DMA | ||
649 | ata_set_mdma_timings(0); | ||
650 | ata_set_udma_timings(0); | ||
651 | |||
652 | ata_dma_selected = ATA_DMA_PIO; | ||
653 | |||
654 | /* Called for first time at startup */ | ||
655 | wakeup_init(&ata_dma_wakeup); | ||
656 | |||
657 | /* Read/write channels share buffer descriptors */ | ||
658 | ata_cd_rd.bd_count = ATA_BD_COUNT; | ||
659 | ata_cd_rd.callback = ata_dma_callback; | ||
660 | ata_cd_rd.shp_addr = SDMA_PER_ADDR_ATA_RX; | ||
661 | ata_cd_rd.wml = SDMA_ATA_WML; | ||
662 | ata_cd_rd.per_type = SDMA_PER_ATA; | ||
663 | ata_cd_rd.tran_type = SDMA_TRAN_PER_2_EMI; | ||
664 | ata_cd_rd.event_id1 = SDMA_REQ_ATA_TXFER_END; | ||
665 | ata_cd_rd.event_id2 = SDMA_REQ_ATA_RX; | ||
666 | |||
667 | ata_cd_wr.bd_count = ATA_BD_COUNT; | ||
668 | ata_cd_wr.callback = ata_dma_callback; | ||
669 | ata_cd_wr.shp_addr = SDMA_PER_ADDR_ATA_TX; | ||
670 | ata_cd_wr.wml = SDMA_ATA_WML; | ||
671 | ata_cd_wr.per_type = SDMA_PER_ATA; | ||
672 | ata_cd_wr.tran_type = SDMA_TRAN_EMI_2_PER; | ||
673 | ata_cd_wr.event_id1 = SDMA_REQ_ATA_TXFER_END; | ||
674 | ata_cd_wr.event_id2 = SDMA_REQ_ATA_TX; | ||
675 | |||
676 | if (!sdma_channel_init(ATA_DMA_CH_NUM_RD, &ata_cd_rd, ata_bda) || | ||
677 | !sdma_channel_init(ATA_DMA_CH_NUM_WR, &ata_cd_wr, ata_bda)) | ||
678 | { | ||
679 | /* Channel init error - disable DMA forever */ | ||
680 | ata_dma_selected = ATA_DMA_DISABLED; | ||
681 | } | ||
682 | #endif /* HAVE_ATA_DMA */ | ||
683 | |||
684 | initialized = true; | ||
166 | } | 685 | } |
diff --git a/firmware/target/arm/imx31/gigabeat-s/ata-target.h b/firmware/target/arm/imx31/gigabeat-s/ata-target.h index f9579a242d..8b308f28b5 100644 --- a/firmware/target/arm/imx31/gigabeat-s/ata-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/ata-target.h | |||
@@ -26,13 +26,14 @@ | |||
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | /* Plain C read & write loops */ | 28 | /* Plain C read & write loops */ |
29 | /* They likely won't be used anyway since DMA potentially works for any | ||
30 | * sector number and alignment. */ | ||
29 | #define PREFER_C_READING | 31 | #define PREFER_C_READING |
30 | #define PREFER_C_WRITING | 32 | #define PREFER_C_WRITING |
31 | #if 0 | 33 | |
32 | #if !defined(BOOTLOADER) | 34 | #ifdef HAVE_ATA_DMA |
33 | #define ATA_OPTIMIZED_WRITING | 35 | #define ATA_MAX_MWDMA 2 |
34 | void copy_write_sectors(const unsigned char* buf, int wordcount); | 36 | #define ATA_MAX_UDMA 4 |
35 | #endif | ||
36 | #endif | 37 | #endif |
37 | 38 | ||
38 | #define ATA_DATA ATA_DRIVE_DATA | 39 | #define ATA_DATA ATA_DRIVE_DATA |
diff --git a/firmware/target/arm/imx31/gigabeat-s/kernel-imx31.c b/firmware/target/arm/imx31/gigabeat-s/kernel-imx31.c index ff0c47abc2..a2f3d779eb 100644 --- a/firmware/target/arm/imx31/gigabeat-s/kernel-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/kernel-imx31.c | |||
@@ -65,9 +65,7 @@ void tick_start(unsigned int interval_in_ms) | |||
65 | 65 | ||
66 | void kernel_device_init(void) | 66 | void kernel_device_init(void) |
67 | { | 67 | { |
68 | #ifndef BOOTLOADER | ||
69 | sdma_init(); | 68 | sdma_init(); |
70 | #endif | ||
71 | spi_init(); | 69 | spi_init(); |
72 | mc13783_init(); | 70 | mc13783_init(); |
73 | } | 71 | } |
diff --git a/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c b/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c index 649186ab2e..deaa2a0dcd 100644 --- a/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/pcm-imx31.c | |||
@@ -29,6 +29,8 @@ | |||
29 | 29 | ||
30 | #define DMA_PLAY_CH_NUM 2 | 30 | #define DMA_PLAY_CH_NUM 2 |
31 | #define DMA_REC_CH_NUM 1 | 31 | #define DMA_REC_CH_NUM 1 |
32 | #define DMA_PLAY_CH_PRIORITY 6 | ||
33 | #define DMA_REC_CH_PRIORITY 6 | ||
32 | 34 | ||
33 | static struct buffer_descriptor dma_play_bd DEVBSS_ATTR; | 35 | static struct buffer_descriptor dma_play_bd DEVBSS_ATTR; |
34 | static struct channel_descriptor dma_play_cd DEVBSS_ATTR; | 36 | static struct channel_descriptor dma_play_cd DEVBSS_ATTR; |
@@ -126,6 +128,7 @@ void pcm_play_dma_init(void) | |||
126 | dma_play_cd.event_id1 = SDMA_REQ_SSI2_TX1; | 128 | dma_play_cd.event_id1 = SDMA_REQ_SSI2_TX1; |
127 | 129 | ||
128 | sdma_channel_init(DMA_PLAY_CH_NUM, &dma_play_cd, &dma_play_bd); | 130 | sdma_channel_init(DMA_PLAY_CH_NUM, &dma_play_cd, &dma_play_bd); |
131 | sdma_channel_set_priority(DMA_PLAY_CH_NUM, DMA_PLAY_CH_PRIORITY); | ||
129 | 132 | ||
130 | imx31_clkctl_module_clock_gating(CG_SSI1, CGM_ON_ALL); | 133 | imx31_clkctl_module_clock_gating(CG_SSI1, CGM_ON_ALL); |
131 | imx31_clkctl_module_clock_gating(CG_SSI2, CGM_ON_ALL); | 134 | imx31_clkctl_module_clock_gating(CG_SSI2, CGM_ON_ALL); |
@@ -518,6 +521,7 @@ void pcm_rec_dma_init(void) | |||
518 | dma_rec_cd.event_id1 = SDMA_REQ_SSI1_RX1; | 521 | dma_rec_cd.event_id1 = SDMA_REQ_SSI1_RX1; |
519 | 522 | ||
520 | sdma_channel_init(DMA_REC_CH_NUM, &dma_rec_cd, &dma_rec_bd); | 523 | sdma_channel_init(DMA_REC_CH_NUM, &dma_rec_cd, &dma_rec_bd); |
524 | sdma_channel_set_priority(DMA_REC_CH_NUM, DMA_REC_CH_PRIORITY); | ||
521 | } | 525 | } |
522 | 526 | ||
523 | const void * pcm_rec_dma_get_peak_buffer(int *count) | 527 | const void * pcm_rec_dma_get_peak_buffer(int *count) |
diff --git a/firmware/target/arm/imx31/sdma-imx31.c b/firmware/target/arm/imx31/sdma-imx31.c index d1611d6332..4c5674afb9 100644 --- a/firmware/target/arm/imx31/sdma-imx31.c +++ b/firmware/target/arm/imx31/sdma-imx31.c | |||
@@ -468,6 +468,8 @@ static bool setup_channel(struct channel_control_block *ccb_p) | |||
468 | CHANNEL_CONTEXT_ADDR(channel), | 468 | CHANNEL_CONTEXT_ADDR(channel), |
469 | sizeof (context_buffer)/4); | 469 | sizeof (context_buffer)/4); |
470 | 470 | ||
471 | ccb_p->status.error = 0; /* Clear channel-wide error flag */ | ||
472 | |||
471 | if (cd_p->is_setup != 0) | 473 | if (cd_p->is_setup != 0) |
472 | return true; /* No more to do */ | 474 | return true; /* No more to do */ |
473 | 475 | ||
@@ -759,6 +761,12 @@ void sdma_channel_close(unsigned int channel) | |||
759 | memset(ccb_p, 0x00, sizeof (struct channel_control_block)); | 761 | memset(ccb_p, 0x00, sizeof (struct channel_control_block)); |
760 | } | 762 | } |
761 | 763 | ||
764 | /* Check channel-wide error flag */ | ||
765 | bool sdma_channel_is_error(unsigned int channel) | ||
766 | { | ||
767 | return channel < CH_NUM && ccb_array[channel].status.error; | ||
768 | } | ||
769 | |||
762 | /* Write 32-bit words to SDMA core memory. Host endian->SDMA endian. */ | 770 | /* Write 32-bit words to SDMA core memory. Host endian->SDMA endian. */ |
763 | void sdma_write_words(const unsigned long *buf, unsigned long start, int count) | 771 | void sdma_write_words(const unsigned long *buf, unsigned long start, int count) |
764 | { | 772 | { |
diff --git a/firmware/target/arm/imx31/sdma-imx31.h b/firmware/target/arm/imx31/sdma-imx31.h index b7e0ab42a4..17c1b9e4f8 100644 --- a/firmware/target/arm/imx31/sdma-imx31.h +++ b/firmware/target/arm/imx31/sdma-imx31.h | |||
@@ -85,7 +85,7 @@ enum SDMA_REQUEST_TYPE | |||
85 | { | 85 | { |
86 | SDMA_REQ_EXT0 = 0, /* Extern DMA request from MCU1_0 */ | 86 | SDMA_REQ_EXT0 = 0, /* Extern DMA request from MCU1_0 */ |
87 | SDMA_REQ_CCM = 1, /* DVFS/DPTC event (ccm_dvfs_sdma_int) */ | 87 | SDMA_REQ_CCM = 1, /* DVFS/DPTC event (ccm_dvfs_sdma_int) */ |
88 | SDMA_REQ_ATA_TX_END = 2, /* ata_txfer_end_alarm (event_id) */ | 88 | SDMA_REQ_ATA_TXFER_END = 2, /* ata_txfer_end_alarm (event_id1) */ |
89 | SDMA_REQ_ATA_TX = 3, /* ata_tx_fifo_alarm (event_id2) */ | 89 | SDMA_REQ_ATA_TX = 3, /* ata_tx_fifo_alarm (event_id2) */ |
90 | SDMA_REQ_ATA_RX = 4, /* ata_rcv_fifo_alarm (event_id2) */ | 90 | SDMA_REQ_ATA_RX = 4, /* ata_rcv_fifo_alarm (event_id2) */ |
91 | SDMA_REQ_SIM = 5, /* */ | 91 | SDMA_REQ_SIM = 5, /* */ |
@@ -223,5 +223,6 @@ bool sdma_channel_init(unsigned int channel, | |||
223 | struct channel_descriptor *cd_p, | 223 | struct channel_descriptor *cd_p, |
224 | struct buffer_descriptor *base_bd_p); | 224 | struct buffer_descriptor *base_bd_p); |
225 | void sdma_channel_close(unsigned int channel); | 225 | void sdma_channel_close(unsigned int channel); |
226 | bool sdma_channel_is_error(unsigned int channel); | ||
226 | 227 | ||
227 | #endif /* SDMA_IMX31_H */ | 228 | #endif /* SDMA_IMX31_H */ |