summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/pcmbuf.c4
-rw-r--r--firmware/export/pp5020.h95
-rw-r--r--firmware/target/arm/i2s-pp.c4
-rw-r--r--firmware/target/arm/pcm-pp.c245
-rw-r--r--firmware/target/arm/system-pp502x.c6
-rw-r--r--firmware/target/arm/usb-drv-arc.c2
6 files changed, 304 insertions, 52 deletions
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index 7d2c579e42..9143e32660 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -18,10 +18,9 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21
22#include <stdbool.h>
23#include <stdio.h> 21#include <stdio.h>
24#include "config.h" 22#include "config.h"
23#include "system.h"
25#include "debug.h" 24#include "debug.h"
26#include "panic.h" 25#include "panic.h"
27#include <kernel.h> 26#include <kernel.h>
@@ -31,7 +30,6 @@
31#ifndef SIMULATOR 30#ifndef SIMULATOR
32#include "cpu.h" 31#include "cpu.h"
33#endif 32#endif
34#include "system.h"
35#include <string.h> 33#include <string.h>
36#include "buffer.h" 34#include "buffer.h"
37#include "settings.h" 35#include "settings.h"
diff --git a/firmware/export/pp5020.h b/firmware/export/pp5020.h
index 36c88e00df..26d5bbaa51 100644
--- a/firmware/export/pp5020.h
+++ b/firmware/export/pp5020.h
@@ -23,6 +23,9 @@
23 23
24/* All info gleaned and/or copied from the iPodLinux project. */ 24/* All info gleaned and/or copied from the iPodLinux project. */
25 25
26/* PCM addresses for obtaining buffers will be what DMA is using (physical) */
27#define HAVE_PCM_DMA_ADDRESS
28
26/* USBOTG */ 29/* USBOTG */
27#define USB_NUM_ENDPOINTS 3 30#define USB_NUM_ENDPOINTS 3
28/* This needs to be 2048 byte aligned, but USB_QHARRAY_ATTR should take care 31/* This needs to be 2048 byte aligned, but USB_QHARRAY_ATTR should take care
@@ -104,6 +107,10 @@
104#define USB_IRQ 20 107#define USB_IRQ 20
105#define IDE_IRQ 23 108#define IDE_IRQ 23
106#define FIREWIRE_IRQ 25 109#define FIREWIRE_IRQ 25
110#define DMA0_IRQ 26
111#define DMA1_IRQ 27 /* guess */
112#define DMA2_IRQ 28 /* guess */
113#define DMA3_IRQ 29 /* guess */
107#define HI_IRQ 30 114#define HI_IRQ 30
108#define GPIO0_IRQ (32+0) /* Ports A..D */ 115#define GPIO0_IRQ (32+0) /* Ports A..D */
109#define GPIO1_IRQ (32+1) /* Ports E..H */ 116#define GPIO1_IRQ (32+1) /* Ports E..H */
@@ -119,6 +126,10 @@
119#define IDE_MASK (1 << IDE_IRQ) 126#define IDE_MASK (1 << IDE_IRQ)
120#define USB_MASK (1 << USB_IRQ) 127#define USB_MASK (1 << USB_IRQ)
121#define FIREWIRE_MASK (1 << FIREWIRE_IRQ) 128#define FIREWIRE_MASK (1 << FIREWIRE_IRQ)
129#define DMA0_MASK (1 << DMA0_IRQ)
130#define DMA1_MASK (1 << DMA1_IRQ)
131#define DMA2_MASK (1 << DMA2_IRQ)
132#define DMA3_MASK (1 << DMA3_IRQ)
122#define HI_MASK (1 << HI_IRQ) 133#define HI_MASK (1 << HI_IRQ)
123#define GPIO0_MASK (1 << (GPIO0_IRQ-32)) 134#define GPIO0_MASK (1 << (GPIO0_IRQ-32))
124#define GPIO1_MASK (1 << (GPIO1_IRQ-32)) 135#define GPIO1_MASK (1 << (GPIO1_IRQ-32))
@@ -601,4 +612,88 @@
601#define MMAP7_LOGICAL (*(volatile unsigned long*)(0xf000f038)) 612#define MMAP7_LOGICAL (*(volatile unsigned long*)(0xf000f038))
602#define MMAP7_PHYSICAL (*(volatile unsigned long*)(0xf000f03c)) 613#define MMAP7_PHYSICAL (*(volatile unsigned long*)(0xf000f03c))
603 614
615/** DMA engine **/
616#define DMA0_BASE_ADDR 0x6000b000
617#define DMA1_BASE_ADDR 0x6000b020
618#define DMA2_BASE_ADDR 0x6000b040
619#define DMA3_BASE_ADDR 0x6000b060
620
621/* DMA request IDs */
622#define DMA_REQ_IIS 2
623#define DMA_REQ_SDHC 13
624
625#define DMA_MASTER_CONTROL (*(volatile unsigned long*)(0x6000a000))
626#define DMA_MASTER_STATUS (*(volatile unsigned long*)(0x6000a004))
627 /* 1ul << DMA_REQ_xxx to set bit */
628#define DMA_REQ_STATUS (*(volatile unsigned long*)(0x6000a008))
629
630#define DMA_MASTER_CONTROL_EN (1 << 31)
631
632#define DMA_MASTER_STATUS_CH0 (0x1 << 24)
633#define DMA_MASTER_STATUS_CH1 (0x1 << 25)
634#define DMA_MASTER_STATUS_CH2 (0x1 << 26)
635#define DMA_MASTER_STATUS_CH3 (0x1 << 27)
636
637#define DMA0_CMD (*(volatile unsigned long*)(DMA0_BASE_ADDR+0x00))
638#define DMA0_STATUS (*(volatile unsigned long*)(DMA0_BASE_ADDR+0x04))
639#define DMA0_RAM_ADDR (*(volatile unsigned long*)(DMA0_BASE_ADDR+0x10))
640#define DMA0_FLAGS (*(volatile unsigned long*)(DMA0_BASE_ADDR+0x14))
641#define DMA0_PER_ADDR (*(volatile unsigned long*)(DMA0_BASE_ADDR+0x18))
642#define DMA0_INCR (*(volatile unsigned long*)(DMA0_BASE_ADDR+0x1c))
643
644#define DMA1_CMD (*(volatile unsigned long*)(DMA1_BASE_ADDR+0x00))
645#define DMA1_STATUS (*(volatile unsigned long*)(DMA1_BASE_ADDR+0x04))
646#define DMA1_RAM_ADDR (*(volatile unsigned long*)(DMA1_BASE_ADDR+0x10))
647#define DMA1_FLAGS (*(volatile unsigned long*)(DMA1_BASE_ADDR+0x14))
648#define DMA1_PER_ADDR (*(volatile unsigned long*)(DMA1_BASE_ADDR+0x18))
649#define DMA1_INCR (*(volatile unsigned long*)(DMA1_BASE_ADDR+0x1c))
650
651#define DMA2_CMD (*(volatile unsigned long*)(DMA2_BASE_ADDR+0x00))
652#define DMA2_STATUS (*(volatile unsigned long*)(DMA2_BASE_ADDR+0x04))
653#define DMA2_RAM_ADDR (*(volatile unsigned long*)(DMA2_BASE_ADDR+0x10))
654#define DMA2_FLAGS (*(volatile unsigned long*)(DMA2_BASE_ADDR+0x14))
655#define DMA2_PER_ADDR (*(volatile unsigned long*)(DMA2_BASE_ADDR+0x18))
656#define DMA2_INCR (*(volatile unsigned long*)(DMA2_BASE_ADDR+0x1c))
657
658#define DMA3_CMD (*(volatile unsigned long*)(DMA3_BASE_ADDR+0x00))
659#define DMA3_STATUS (*(volatile unsigned long*)(DMA3_BASE_ADDR+0x04))
660#define DMA3_RAM_ADDR (*(volatile unsigned long*)(DMA3_BASE_ADDR+0x10))
661#define DMA3_FLAGS (*(volatile unsigned long*)(DMA3_BASE_ADDR+0x14))
662#define DMA3_PER_ADDR (*(volatile unsigned long*)(DMA3_BASE_ADDR+0x18))
663#define DMA3_INCR (*(volatile unsigned long*)(DMA3_BASE_ADDR+0x1c))
664
665#define DMA_CMD_SIZE (0xffff)
666#define DMA_CMD_REQ_ID (0xf << 16)
667 #define DMA_CMD_REQ_ID_POS 16
668#define DMA_CMD_WAIT_REQ (0x1 << 24)
669#define DMA_CMD_UNK25 (0x1 << 25)
670#define DMA_CMD_SINGLE (0x1 << 26) /* stop on complete, no auto reload */
671#define DMA_CMD_RAM_TO_PER (0x1 << 27) /* otherwise per to ram */
672#define DMA_CMD_SLEEP_WAIT (0x1 << 28)
673#define DMA_CMD_INTR (0x1 << 30)
674#define DMA_CMD_START (0x1 << 31)
675
676#define DMA_STATUS_SIZE_REMAIN (0xffff)
677#define DMA_STATUS_INTR (0x1 << 30)
678#define DMA_STATUS_BUSY (0x1 << 31)
679
680#define DMA_FLAGS_ALIGNED (0x1 << 24)
681#define DMA_FLAGS_UNK26 (0x1 << 26)
682
683#define DMA_INCR_RANGE (0x7 << 16)
684#define DMA_INCR_RANGE_UNL (0x0 << 16)
685#define DMA_INCR_RANGE_FIXED (0x1 << 16)
686#define DMA_INCR_RANGE_ALTR (0x2 << 16)
687#define DMA_INCR_RANGE_4 (0x3 << 16)
688#define DMA_INCR_RANGE_8 (0x4 << 16)
689#define DMA_INCR_RANGE_16 (0x5 << 16)
690#define DMA_INCR_RANGE_32 (0x6 << 16)
691#define DMA_INCR_RANGE_64 (0x7 << 16)
692
693#define DMA_INCR_WIDTH (0x7 << 28)
694#define DMA_INCR_WIDTH_8BIT (0x0 << 28)
695#define DMA_INCR_WIDTH_16BIT (0x1 << 28)
696#define DMA_INCR_WIDTH_32BIT (0x2 << 28)
697/* All other values reserved? */
698
604#endif /* __PP5020_H__ */ 699#endif /* __PP5020_H__ */
diff --git a/firmware/target/arm/i2s-pp.c b/firmware/target/arm/i2s-pp.c
index 81c1fa1265..e4b9f8e1df 100644
--- a/firmware/target/arm/i2s-pp.c
+++ b/firmware/target/arm/i2s-pp.c
@@ -71,8 +71,8 @@ void i2s_reset(void)
71 IISCONFIG = ((IISCONFIG & ~IIS_FIFO_FORMAT_MASK) | IIS_FIFO_FORMAT_LE16_2); 71 IISCONFIG = ((IISCONFIG & ~IIS_FIFO_FORMAT_MASK) | IIS_FIFO_FORMAT_LE16_2);
72 72
73 /* RX_ATN_LVL = when 12 slots full */ 73 /* RX_ATN_LVL = when 12 slots full */
74 /* TX_ATN_LVL = when 12 slots empty */ 74 /* TX_ATN_LVL = DMA request when 4 slots empty */
75 IISFIFO_CFG |= IIS_RX_FULL_LVL_12 | IIS_TX_EMPTY_LVL_12; 75 IISFIFO_CFG |= IIS_RX_FULL_LVL_12 | IIS_TX_EMPTY_LVL_4;
76 76
77 /* Rx.CLR = 1, TX.CLR = 1 */ 77 /* Rx.CLR = 1, TX.CLR = 1 */
78 IISFIFO_CFG |= IIS_RXCLR | IIS_TXCLR; 78 IISFIFO_CFG |= IIS_RXCLR | IIS_TXCLR;
diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c
index 0f87a74d1c..f441bb82ce 100644
--- a/firmware/target/arm/pcm-pp.c
+++ b/firmware/target/arm/pcm-pp.c
@@ -32,6 +32,18 @@
32#ifdef CPU_PP502x 32#ifdef CPU_PP502x
33/* 16-bit, L-R packed into 32 bits with left in the least significant halfword */ 33/* 16-bit, L-R packed into 32 bits with left in the least significant halfword */
34#define SAMPLE_SIZE 16 34#define SAMPLE_SIZE 16
35/* DMA Requests from IIS, Memory to peripheral, single transfer,
36 wait for DMA request, interrupt on complete */
37#define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \
38 DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \
39 DMA_CMD_WAIT_REQ | DMA_CMD_INTR)
40/* DMA status cannot be viewed from outside code in control because that can
41 * clear the interrupt from outside the handler and prevent the handler from
42 * from being called. Split up transfers to a reasonable size that is good as
43 * a timer, obtaining a keyclick position and peaking yet still keeps the
44 * FIQ count low.
45 */
46#define MAX_DMA_CHUNK_SIZE (pcm_curr_sampr >> 6) /* ~1/256 seconds */
35#else 47#else
36/* 32-bit, one left 32-bit sample followed by one right 32-bit sample */ 48/* 32-bit, one left 32-bit sample followed by one right 32-bit sample */
37#define SAMPLE_SIZE 32 49#define SAMPLE_SIZE 32
@@ -41,11 +53,12 @@ struct dma_data
41{ 53{
42/* NOTE: The order of size and p is important if you use assembler 54/* NOTE: The order of size and p is important if you use assembler
43 optimised fiq handler, so don't change it. */ 55 optimised fiq handler, so don't change it. */
44#if SAMPLE_SIZE == 16 56 union
45 uint32_t *p; 57 {
46#elif SAMPLE_SIZE == 32 58 unsigned long addr;
47 uint16_t *p; 59 uint32_t *p16; /* For packed 16-16 stereo pairs */
48#endif 60 uint16_t *p32; /* For individual samples converted to 32-bit */
61 };
49 size_t size; 62 size_t size;
50#if NUM_CORES > 1 63#if NUM_CORES > 1
51 unsigned core; 64 unsigned core;
@@ -67,15 +80,24 @@ void fiq_handler(void)
67 ); 80 );
68} 81}
69 82
83#ifdef HAVE_PCM_DMA_ADDRESS
84void * pcm_dma_addr(void *addr)
85{
86 if (addr != NULL && (unsigned long)addr < UNCACHED_BASE_ADDR)
87 addr = UNCACHED_ADDR(addr);
88 return addr;
89}
90#endif
91
70/* TODO: Get simultaneous recording and playback to work. Just needs some tweaking */ 92/* TODO: Get simultaneous recording and playback to work. Just needs some tweaking */
71 93
72/**************************************************************************** 94/****************************************************************************
73 ** Playback DMA transfer 95 ** Playback DMA transfer
74 **/ 96 **/
75static struct dma_data dma_play_data SHAREDBSS_ATTR = 97static struct dma_data dma_play_data IBSS_ATTR =
76{ 98{
77 /* Initialize to a locked, stopped state */ 99 /* Initialize to a locked, stopped state */
78 .p = NULL, 100 { .addr = 0 },
79 .size = 0, 101 .size = 0,
80#if NUM_CORES > 1 102#if NUM_CORES > 1
81 .core = 0x00, 103 .core = 0x00,
@@ -89,6 +111,59 @@ void pcm_dma_apply_settings(void)
89 audiohw_set_frequency(pcm_fsel); 111 audiohw_set_frequency(pcm_fsel);
90} 112}
91 113
114#if defined(CPU_PP502x)
115/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
116void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
117{
118 register pcm_more_callback_type get_more;
119 register size_t size;
120
121 DMA0_STATUS; /* Clear any pending interrupt */
122
123 size = (DMA0_CMD & 0xffff) + 4; /* Get size of trasfer that caused this
124 interrupt */
125 dma_play_data.addr += size;
126 dma_play_data.size -= size;
127
128 while (1)
129 {
130 if (dma_play_data.size > 0) {
131 size = MAX_DMA_CHUNK_SIZE;
132 /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less
133 * than a FIFO's worth of data after this transfer? */
134 if (size + 16*4 > dma_play_data.size)
135 size = dma_play_data.size;
136
137 /* Set the new DMA values and activate channel */
138 DMA0_RAM_ADDR = dma_play_data.addr;
139 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
140 return;
141 }
142
143 /* Buffer empty. Try to get more. */
144 get_more = pcm_callback_for_more;
145 if (get_more) {
146 get_more((unsigned char **)&dma_play_data.addr, &dma_play_data.size);
147 dma_play_data.addr = (dma_play_data.addr + 3) & ~3;
148 dma_play_data.size &= 0xfffc;
149 }
150
151 if (dma_play_data.size <= 0) {
152 break;
153 }
154
155 if (dma_play_data.addr < UNCACHED_BASE_ADDR) {
156 /* Flush any pending cache writes */
157 dma_play_data.addr = UNCACHED_ADDR(dma_play_data.addr);
158 cpucache_flush();
159 }
160 }
161
162 /* Callback missing or no more DMA to do */
163 pcm_play_dma_stop();
164 pcm_play_dma_stopped_callback();
165}
166#else
92/* ASM optimised FIQ handler. Checks for the minimum allowed loop cycles by 167/* ASM optimised FIQ handler. Checks for the minimum allowed loop cycles by
93 * evalutation of free IISFIFO-slots against available source buffer words. 168 * evalutation of free IISFIFO-slots against available source buffer words.
94 * Through this it is possible to move the check for IIS_TX_FREE_COUNT outside 169 * Through this it is possible to move the check for IIS_TX_FREE_COUNT outside
@@ -221,10 +296,10 @@ void fiq_playback(void)
221 return; 296 return;
222 } 297 }
223#if SAMPLE_SIZE == 16 298#if SAMPLE_SIZE == 16
224 IISFIFO_WR = *dma_play_data.p++; 299 IISFIFO_WR = *dma_play_data.p16++;
225#elif SAMPLE_SIZE == 32 300#elif SAMPLE_SIZE == 32
226 IISFIFO_WR = *dma_play_data.p++ << 16; 301 IISFIFO_WR = *dma_play_data.p32++ << 16;
227 IISFIFO_WR = *dma_play_data.p++ << 16; 302 IISFIFO_WR = *dma_play_data.p32++ << 16;
228#endif 303#endif
229 dma_play_data.size -= 4; 304 dma_play_data.size -= 4;
230 } 305 }
@@ -232,7 +307,7 @@ void fiq_playback(void)
232 /* p is empty, get some more data */ 307 /* p is empty, get some more data */
233 get_more = pcm_callback_for_more; 308 get_more = pcm_callback_for_more;
234 if (get_more) { 309 if (get_more) {
235 get_more((unsigned char**)&dma_play_data.p, 310 get_more((unsigned char**)&dma_play_data.addr,
236 &dma_play_data.size); 311 &dma_play_data.size);
237 } 312 }
238 } while (dma_play_data.size); 313 } while (dma_play_data.size);
@@ -242,6 +317,7 @@ void fiq_playback(void)
242 pcm_play_dma_stopped_callback(); 317 pcm_play_dma_stopped_callback();
243} 318}
244#endif /* ASM / C selection */ 319#endif /* ASM / C selection */
320#endif /* CPU_PP502x */
245 321
246/* For the locks, FIQ must be disabled because the handler manipulates 322/* For the locks, FIQ must be disabled because the handler manipulates
247 IISCONFIG and the operation is not atomic - dual core support 323 IISCONFIG and the operation is not atomic - dual core support
@@ -251,7 +327,11 @@ void pcm_play_lock(void)
251 int status = disable_fiq_save(); 327 int status = disable_fiq_save();
252 328
253 if (++dma_play_data.locked == 1) { 329 if (++dma_play_data.locked == 1) {
330#ifdef CPU_PP502x
331 CPU_INT_DIS = DMA0_MASK;
332#else
254 IIS_IRQTX_REG &= ~IIS_IRQTX; 333 IIS_IRQTX_REG &= ~IIS_IRQTX;
334#endif
255 } 335 }
256 336
257 restore_fiq(status); 337 restore_fiq(status);
@@ -262,7 +342,11 @@ void pcm_play_unlock(void)
262 int status = disable_fiq_save(); 342 int status = disable_fiq_save();
263 343
264 if (--dma_play_data.locked == 0 && dma_play_data.state != 0) { 344 if (--dma_play_data.locked == 0 && dma_play_data.state != 0) {
345#ifdef CPU_PP502x
346 CPU_INT_EN = DMA0_MASK;
347#else
265 IIS_IRQTX_REG |= IIS_IRQTX; 348 IIS_IRQTX_REG |= IIS_IRQTX;
349#endif
266 } 350 }
267 351
268 restore_fiq(status); 352 restore_fiq(status);
@@ -272,30 +356,71 @@ static void play_start_pcm(void)
272{ 356{
273 fiq_function = fiq_playback; 357 fiq_function = fiq_playback;
274 358
275 IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */ 359#ifdef CPU_PP502x
360 /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less than a
361 * FIFO's worth of data after this transfer? */
362 size_t size = MAX_DMA_CHUNK_SIZE;
363 if (dma_play_data.size + 16*4 < size)
364 size = dma_play_data.size;
365
366 DMA0_RAM_ADDR = dma_play_data.addr;
367 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
276 dma_play_data.state = 1; 368 dma_play_data.state = 1;
369#else
370 IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */
277 371
278 /* Fill the FIFO or start when data is used up */ 372 /* Fill the FIFO or start when data is used up */
279 while (1) { 373 while (1) {
280 if (IIS_TX_FREE_COUNT < 2 || dma_play_data.size == 0) { 374 if (IIS_TX_FREE_COUNT < 2 || dma_play_data.size == 0) {
281 IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */ 375 IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */
376 dma_play_data.state = 1;
282 return; 377 return;
283 } 378 }
284 379
285#if SAMPLE_SIZE == 16 380#if SAMPLE_SIZE == 16
286 IISFIFO_WR = *dma_play_data.p++; 381 IISFIFO_WR = *dma_play_data.p16++;
287#elif SAMPLE_SIZE == 32 382#elif SAMPLE_SIZE == 32
288 IISFIFO_WR = *dma_play_data.p++ << 16; 383 IISFIFO_WR = *dma_play_data.p32++ << 16;
289 IISFIFO_WR = *dma_play_data.p++ << 16; 384 IISFIFO_WR = *dma_play_data.p32++ << 16;
290#endif 385#endif
291 dma_play_data.size -= 4; 386 dma_play_data.size -= 4;
292 } 387 }
388#endif
293} 389}
294 390
295static void play_stop_pcm(void) 391static void play_stop_pcm(void)
296{ 392{
393#ifdef CPU_PP502x
394 size_t status = DMA0_STATUS;
395 size_t size;
396
397 /* Stop transfer */
398 DMA0_CMD &= ~(DMA_CMD_START | DMA_CMD_INTR);
399
400 /* Wait for not busy + clear int */
401 while (DMA0_STATUS & (DMA_STATUS_BUSY | DMA_STATUS_INTR));
402
403 size = (status & 0xfffc) + 4;
404
405 if (status & DMA_STATUS_BUSY)
406 {
407 /* Transfer was interrupted - leave what's left */
408 dma_play_data.addr += dma_play_data.size - size;
409 dma_play_data.size = size;
410 }
411 else if (status & DMA_STATUS_INTR)
412 {
413 /* Tranfer was finished - DMA0_STATUS will have been reloaded
414 * automatically with size in DMA0_CMD. */
415 dma_play_data.addr += size;
416 dma_play_data.size -= size;
417 if (dma_play_data.size <= 0)
418 dma_play_data.addr = 0; /* Entire buffer has completed */
419 }
420#else
297 /* Disable TX interrupt */ 421 /* Disable TX interrupt */
298 IIS_IRQTX_REG &= ~IIS_IRQTX; 422 IIS_IRQTX_REG &= ~IIS_IRQTX;
423#endif
299 424
300 /* Wait for FIFO to empty */ 425 /* Wait for FIFO to empty */
301 while (!IIS_TX_IS_EMPTY); 426 while (!IIS_TX_IS_EMPTY);
@@ -305,16 +430,32 @@ static void play_stop_pcm(void)
305 430
306void pcm_play_dma_start(const void *addr, size_t size) 431void pcm_play_dma_start(const void *addr, size_t size)
307{ 432{
308 dma_play_data.p = (void *)(((uintptr_t)addr + 2) & ~3); 433 addr = (void *)(((long)addr + 2) & ~3);
309 dma_play_data.size = (size & ~3); 434 size &= 0xfffc;
310 435
311#if NUM_CORES > 1 436#if NUM_CORES > 1
312 /* This will become more important later - and different ! */ 437 /* This will become more important later - and different ! */
313 dma_play_data.core = processor_id(); /* save initiating core */ 438 dma_play_data.core = processor_id(); /* save initiating core */
314#endif 439#endif
315 440
316 CPU_INT_PRIORITY |= IIS_MASK; /* FIQ priority for I2S */ 441 pcm_play_dma_stop();
317 CPU_INT_EN = IIS_MASK; 442
443 if (size <= 0)
444 return;
445
446#ifdef CPU_PP502x
447 if ((unsigned long)addr < UNCACHED_BASE_ADDR) {
448 /* Flush any pending cache writes */
449 addr = UNCACHED_ADDR(addr);
450 cpucache_flush();
451 }
452
453 dma_play_data.addr = (unsigned long)addr;
454 dma_play_data.size = size;
455 DMA0_PER_ADDR = (unsigned long)&IISFIFO_WR;
456 DMA0_FLAGS = DMA_FLAGS_UNK26;
457 DMA0_INCR = DMA_INCR_RANGE_FIXED | DMA_INCR_WIDTH_32BIT;
458#endif
318 459
319 play_start_pcm(); 460 play_start_pcm();
320} 461}
@@ -323,6 +464,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
323void pcm_play_dma_stop(void) 464void pcm_play_dma_stop(void)
324{ 465{
325 play_stop_pcm(); 466 play_stop_pcm();
467 dma_play_data.addr = 0;
326 dma_play_data.size = 0; 468 dma_play_data.size = 0;
327#if NUM_CORES > 1 469#if NUM_CORES > 1
328 dma_play_data.core = 0; /* no core in control */ 470 dma_play_data.core = 0; /* no core in control */
@@ -345,6 +487,20 @@ size_t pcm_get_bytes_waiting(void)
345 487
346void pcm_play_dma_init(void) 488void pcm_play_dma_init(void)
347{ 489{
490 /* Initialize default register values. */
491 audiohw_init();
492
493#ifdef CPU_PP502x
494 /* Enable DMA controller */
495 DMA_MASTER_CONTROL |= DMA_MASTER_CONTROL_EN;
496 /* FIQ priority for DMA0 */
497 CPU_INT_PRIORITY |= DMA0_MASK;
498 /* Enable request?? Not setting or clearing everything doesn't seem to
499 * prevent it operating. Perhaps important for reliability (how requests
500 * are handled). */
501 DMA_REQ_STATUS |= 1ul << DMA_REQ_IIS;
502 DMA0_STATUS;
503#else
348 /* Set up banked registers for FIQ mode */ 504 /* Set up banked registers for FIQ mode */
349 505
350 /* Use non-banked registers for scratch. */ 506 /* Use non-banked registers for scratch. */
@@ -363,12 +519,9 @@ void pcm_play_dma_init(void)
363 : [iiscfg]"r"(iiscfg), [dmapd]"r"(dmapd) 519 : [iiscfg]"r"(iiscfg), [dmapd]"r"(dmapd)
364 : "r2"); 520 : "r2");
365 521
366 /* Initialize default register values. */ 522 /* FIQ priority for I2S */
367 audiohw_init(); 523 CPU_INT_PRIORITY |= IIS_MASK;
368 524 CPU_INT_EN = IIS_MASK;
369 dma_play_data.size = 0;
370#if NUM_CORES > 1
371 dma_play_data.core = 0; /* no core in control */
372#endif 525#endif
373 526
374 IISCONFIG |= IIS_TXFIFOEN; 527 IISCONFIG |= IIS_TXFIFOEN;
@@ -381,9 +534,14 @@ void pcm_postinit(void)
381 534
382const void * pcm_play_dma_get_peak_buffer(int *count) 535const void * pcm_play_dma_get_peak_buffer(int *count)
383{ 536{
384 unsigned long addr = (unsigned long)dma_play_data.p; 537 unsigned long addr, size;
385 size_t cnt = dma_play_data.size; 538
386 *count = cnt >> 2; 539 int status = disable_fiq_save();
540 addr = dma_play_data.addr;
541 size = dma_play_data.size;
542 restore_fiq(status);
543
544 *count = size >> 2;
387 return (void *)((addr + 2) & ~3); 545 return (void *)((addr + 2) & ~3);
388} 546}
389 547
@@ -392,10 +550,10 @@ const void * pcm_play_dma_get_peak_buffer(int *count)
392 **/ 550 **/
393#ifdef HAVE_RECORDING 551#ifdef HAVE_RECORDING
394/* PCM recording interrupt routine lockout */ 552/* PCM recording interrupt routine lockout */
395static struct dma_data dma_rec_data SHAREDBSS_ATTR = 553static struct dma_data dma_rec_data IBSS_ATTR =
396{ 554{
397 /* Initialize to a locked, stopped state */ 555 /* Initialize to a locked, stopped state */
398 .p = NULL, 556 { .addr = 0 },
399 .size = 0, 557 .size = 0,
400#if NUM_CORES > 1 558#if NUM_CORES > 1
401 .core = 0x00, 559 .core = 0x00,
@@ -447,7 +605,7 @@ void fiq_record(void)
447 value = IISFIFO_RD; 605 value = IISFIFO_RD;
448 IISFIFO_RD; 606 IISFIFO_RD;
449 607
450 *dma_rec_data.p++ = value; 608 *dma_rec_data.p16++ = value;
451 dma_rec_data.size -= 4; 609 dma_rec_data.size -= 4;
452 610
453 /* TODO: Figure out how to do IIS loopback */ 611 /* TODO: Figure out how to do IIS loopback */
@@ -475,7 +633,7 @@ void fiq_record(void)
475 633
476 value = (uint16_t)value | (value << 16); 634 value = (uint16_t)value | (value << 16);
477 635
478 *dma_rec_data.p++ = value; 636 *dma_rec_data.p16++ = value;
479 dma_rec_data.size -= 4; 637 dma_rec_data.size -= 4;
480 638
481 if (audio_output_source != AUDIO_SRC_PLAYBACK) { 639 if (audio_output_source != AUDIO_SRC_PLAYBACK) {
@@ -485,7 +643,7 @@ void fiq_record(void)
485 IISFIFO_WR = 0; 643 IISFIFO_WR = 0;
486 } 644 }
487 645
488 value = *((int32_t *)dma_rec_data.p - 1); 646 value = *((int32_t *)dma_rec_data.p16 - 1);
489 IISFIFO_WR = value; 647 IISFIFO_WR = value;
490 IISFIFO_WR = value; 648 IISFIFO_WR = value;
491 } 649 }
@@ -512,10 +670,10 @@ void fiq_record(void)
512 } 670 }
513 671
514#if SAMPLE_SIZE == 16 672#if SAMPLE_SIZE == 16
515 *dma_rec_data.p++ = IISFIFO_RD; 673 *dma_rec_data.p16++ = IISFIFO_RD;
516#elif SAMPLE_SIZE == 32 674#elif SAMPLE_SIZE == 32
517 *dma_rec_data.p++ = IISFIFO_RD >> 16; 675 *dma_rec_data.p32++ = IISFIFO_RD >> 16;
518 *dma_rec_data.p++ = IISFIFO_RD >> 16; 676 *dma_rec_data.p32++ = IISFIFO_RD >> 16;
519#endif 677#endif
520 dma_rec_data.size -= 4; 678 dma_rec_data.size -= 4;
521 } 679 }
@@ -535,8 +693,8 @@ void fiq_record(void)
535void pcm_record_more(void *start, size_t size) 693void pcm_record_more(void *start, size_t size)
536{ 694{
537 pcm_rec_peak_addr = start; /* Start peaking at dest */ 695 pcm_rec_peak_addr = start; /* Start peaking at dest */
538 dma_rec_data.p = start; /* Start of RX buffer */ 696 dma_rec_data.addr = (unsigned long)start; /* Start of RX buffer */
539 dma_rec_data.size = size; /* Bytes to transfer */ 697 dma_rec_data.size = size; /* Bytes to transfer */
540} 698}
541 699
542void pcm_rec_dma_stop(void) 700void pcm_rec_dma_stop(void)
@@ -560,7 +718,7 @@ void pcm_rec_dma_start(void *addr, size_t size)
560 pcm_rec_dma_stop(); 718 pcm_rec_dma_stop();
561 719
562 pcm_rec_peak_addr = addr; 720 pcm_rec_peak_addr = addr;
563 dma_rec_data.p = addr; 721 dma_rec_data.addr = (unsigned long)addr;
564 dma_rec_data.size = size; 722 dma_rec_data.size = size;
565#if NUM_CORES > 1 723#if NUM_CORES > 1
566 /* This will become more important later - and different ! */ 724 /* This will become more important later - and different ! */
@@ -592,8 +750,13 @@ void pcm_rec_dma_init(void)
592 750
593const void * pcm_rec_dma_get_peak_buffer(int *count) 751const void * pcm_rec_dma_get_peak_buffer(int *count)
594{ 752{
595 unsigned long addr = (unsigned long)pcm_rec_peak_addr; 753 unsigned long addr, end;
596 unsigned long end = (unsigned long)dma_rec_data.p; 754
755 int status = disable_fiq_save();
756 addr = (unsigned long)pcm_rec_peak_addr;
757 end = dma_rec_data.addr;
758 restore_fiq(status);
759
597 *count = (end >> 2) - (addr >> 2); 760 *count = (end >> 2) - (addr >> 2);
598 return (void *)(addr & ~3); 761 return (void *)(addr & ~3);
599} /* pcm_rec_dma_get_peak_buffer */ 762} /* pcm_rec_dma_get_peak_buffer */
diff --git a/firmware/target/arm/system-pp502x.c b/firmware/target/arm/system-pp502x.c
index 10a7651f7b..2b6bd3f717 100644
--- a/firmware/target/arm/system-pp502x.c
+++ b/firmware/target/arm/system-pp502x.c
@@ -169,6 +169,7 @@ void ICODE_ATTR cpucache_flush(void)
169 { 169 {
170 CACHE_OPERATION |= CACHE_OP_FLUSH; 170 CACHE_OPERATION |= CACHE_OP_FLUSH;
171 while ((CACHE_CTL & CACHE_CTL_BUSY) != 0); 171 while ((CACHE_CTL & CACHE_CTL_BUSY) != 0);
172 nop; nop; nop; nop;
172 } 173 }
173} 174}
174 175
@@ -470,11 +471,6 @@ void system_init(void)
470 GPIOK_INT_EN = 0; 471 GPIOK_INT_EN = 0;
471 GPIOL_INT_EN = 0; 472 GPIOL_INT_EN = 0;
472 473
473#if defined(SANSA_E200) || defined(SANSA_C200) || defined(PHILIPS_SA9200)
474 /* outl(0x00000000, 0x6000b000); */
475 outl(inl(0x6000a000) | 0x80000000, 0x6000a000); /* Init DMA controller? */
476#endif
477
478#ifdef HAVE_ADJUSTABLE_CPU_FREQ 474#ifdef HAVE_ADJUSTABLE_CPU_FREQ
479#if NUM_CORES > 1 475#if NUM_CORES > 1
480 corelock_init(&cpufreq_cl); 476 corelock_init(&cpufreq_cl);
diff --git a/firmware/target/arm/usb-drv-arc.c b/firmware/target/arm/usb-drv-arc.c
index af97e3e174..6d519469a2 100644
--- a/firmware/target/arm/usb-drv-arc.c
+++ b/firmware/target/arm/usb-drv-arc.c
@@ -389,7 +389,7 @@ void usb_drv_reset(void)
389 REG_USBCMD |= USBCMD_CTRL_RESET; 389 REG_USBCMD |= USBCMD_CTRL_RESET;
390 while (REG_USBCMD & USBCMD_CTRL_RESET); 390 while (REG_USBCMD & USBCMD_CTRL_RESET);
391 391
392#if CONFIG_CPU == PP5022 || CONFIG_CPU == PP5024 392#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5022 || CONFIG_CPU == PP5024
393 /* On a CPU which identifies as a PP5022, this 393 /* On a CPU which identifies as a PP5022, this
394 initialization must be done after USB is reset. 394 initialization must be done after USB is reset.
395 */ 395 */