summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCástor Muñoz <cmvidal@gmail.com>2014-12-06 18:37:09 +0100
committerCástor Muñoz <cmvidal@gmail.com>2015-10-07 06:15:03 +0200
commit67b4e7f958f4b6569dce8c50c117b22c9f1f9ca7 (patch)
tree638f9a6141122065f0120cba51bafd7c8ea6f22e
parentd6ee2c9eafbf5381695d1c7eb01801855c85222b (diff)
downloadrockbox-67b4e7f958f4b6569dce8c50c117b22c9f1f9ca7.tar.gz
rockbox-67b4e7f958f4b6569dce8c50c117b22c9f1f9ca7.zip
iPod Classic: use new PL080 DMA driver
This patch uses the new pl080 DMA driver for I2S playback and LCD update. I have tried to be as fiel as possible to the current behaviour, algorithms and configurations are the same, but using the new driver. Other modifications: Playback: - CHUNK_SIZE is decreased from 42988 to 8188 bytes, it does not affect normal playback (block size 1024), was tested using metronome (block size 46080). This change is needed because the new code commits d-cache range instead of commiting the whole d-cache, maximum time spent commiting the range should be limited, CHUNK_SIZE can be decreased even more if necessary. - pcm_play_dma_start() calls pcm_play_dma_stop() to stop the channel when it is running (metronome replays the tick sound without stopping the channel). - pcm_play_dma_get_peak_buffer(): same as actual SVN function but returns samples count instead of bytes count. TODO: AFAIK, actually this function is not used in RB. Not tested, but probably this function will fail because it returns pointers to the internal double buffer. LCD update: - suppresses lcd_wakeup semaphore and uses yield() Change-Id: I79b8aa47a941e0dd91847150618f3f7f676c26ef
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/export/s5l8702.h174
-rw-r--r--firmware/target/arm/s5l8702/debug-s5l8702.c12
-rw-r--r--firmware/target/arm/s5l8702/dma-s5l8702.c68
-rw-r--r--firmware/target/arm/s5l8702/dma-s5l8702.h107
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c78
-rw-r--r--firmware/target/arm/s5l8702/pcm-s5l8702.c180
-rw-r--r--firmware/target/arm/s5l8702/pcm-target.h11
-rw-r--r--firmware/target/arm/s5l8702/system-s5l8702.c48
9 files changed, 336 insertions, 343 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 17f6ad7e0a..adfedcb212 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -1599,6 +1599,7 @@ target/arm/s5l8702/kernel-s5l8702.c
1599target/arm/s5l8702/system-s5l8702.c 1599target/arm/s5l8702/system-s5l8702.c
1600target/arm/s5l8702/gpio-s5l8702.c 1600target/arm/s5l8702/gpio-s5l8702.c
1601target/arm/s5l8702/pl080.c 1601target/arm/s5l8702/pl080.c
1602target/arm/s5l8702/dma-s5l8702.c
1602target/arm/s5l8702/ipod6g/lcd-ipod6g.c 1603target/arm/s5l8702/ipod6g/lcd-ipod6g.c
1603target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S 1604target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S
1604#if 0 //TODO 1605#if 0 //TODO
diff --git a/firmware/export/s5l8702.h b/firmware/export/s5l8702.h
index 701dcabeb4..34b6da874b 100644
--- a/firmware/export/s5l8702.h
+++ b/firmware/export/s5l8702.h
@@ -419,178 +419,6 @@
419#define SHA1DATAIN ((uint32_t volatile*)(0x38000040)) 419#define SHA1DATAIN ((uint32_t volatile*)(0x38000040))
420 420
421 421
422/////DMA/////
423#ifndef ASM
424struct dma_lli
425{
426 const void* srcaddr;
427 void* dstaddr;
428 const struct dma_lli* nextlli;
429 uint32_t control;
430};
431#endif
432/* currently these definitions are not used, temporarily
433 removed to avoid conflicts with pl080.h */
434#if 0
435#define DMACINTSTS(d) (*((uint32_t volatile*)(0x38200000 + 0x1700000 * (d))))
436#define DMACINTTCSTS(d) (*((uint32_t volatile*)(0x38200004 + 0x1700000 * (d))))
437#define DMACINTTCCLR(d) (*((uint32_t volatile*)(0x38200008 + 0x1700000 * (d))))
438#define DMACINTERRSTS(d) (*((uint32_t volatile*)(0x3820000c + 0x1700000 * (d))))
439#define DMACINTERRCLR(d) (*((uint32_t volatile*)(0x38200010 + 0x1700000 * (d))))
440#define DMACRAWINTTCSTS(d) (*((uint32_t volatile*)(0x38200014 + 0x1700000 * (d))))
441#define DMACRAWINTERRSTS(d) (*((uint32_t volatile*)(0x38200018 + 0x1700000 * (d))))
442#define DMACENABLEDCHANS(d) (*((uint32_t volatile*)(0x3820001c + 0x1700000 * (d))))
443#define DMACSOFTBREQ(d) (*((uint32_t volatile*)(0x38200020 + 0x1700000 * (d))))
444#define DMACSOFTSREQ(d) (*((uint32_t volatile*)(0x38200024 + 0x1700000 * (d))))
445#define DMACSOFTLBREQ(d) (*((uint32_t volatile*)(0x38200028 + 0x1700000 * (d))))
446#define DMACSOFTLSREQ(d) (*((uint32_t volatile*)(0x3820002c + 0x1700000 * (d))))
447#define DMACCONFIG(d) (*((uint32_t volatile*)(0x38200030 + 0x1700000 * (d))))
448#define DMACSYNC(d) (*((uint32_t volatile*)(0x38200034 + 0x1700000 * (d))))
449#endif
450#define DMACCLLI(d, c) (*((struct dma_lli volatile*)(0x38200100 + 0x1700000 * (d) + 0x20 * (c))))
451#define DMACCSRCADDR(d, c) (*((const void* volatile*)(0x38200100 + 0x1700000 * (d) + 0x20 * (c))))
452#define DMACCDESTADDR(d, c) (*((void* volatile*)(0x38200104 + 0x1700000 * (d) + 0x20 * (c))))
453#define DMACCNEXTLLI(d, c) (*((const void* volatile*)(0x38200108 + 0x1700000 * (d) + 0x20 * (c))))
454#define DMACCCONTROL(d, c) (*((uint32_t volatile*)(0x3820010c + 0x1700000 * (d) + 0x20 * (c))))
455#define DMACCCONFIG(d, c) (*((uint32_t volatile*)(0x38200110 + 0x1700000 * (d) + 0x20 * (c))))
456#define DMAC0INTSTS (*((uint32_t volatile*)(0x38200000)))
457#define DMAC0INTTCSTS (*((uint32_t volatile*)(0x38200004)))
458#define DMAC0INTTCCLR (*((uint32_t volatile*)(0x38200008)))
459#define DMAC0INTERRSTS (*((uint32_t volatile*)(0x3820000c)))
460#define DMAC0INTERRCLR (*((uint32_t volatile*)(0x38200010)))
461#define DMAC0RAWINTTCSTS (*((uint32_t volatile*)(0x38200014)))
462#define DMAC0RAWINTERRSTS (*((uint32_t volatile*)(0x38200018)))
463#define DMAC0ENABLEDCHANS (*((uint32_t volatile*)(0x3820001c)))
464#define DMAC0SOFTBREQ (*((uint32_t volatile*)(0x38200020)))
465#define DMAC0SOFTSREQ (*((uint32_t volatile*)(0x38200024)))
466#define DMAC0SOFTLBREQ (*((uint32_t volatile*)(0x38200028)))
467#define DMAC0SOFTLSREQ (*((uint32_t volatile*)(0x3820002c)))
468#define DMAC0CONFIG (*((uint32_t volatile*)(0x38200030)))
469#define DMAC0SYNC (*((uint32_t volatile*)(0x38200034)))
470#define DMAC0CLLI(c) (*((struct dma_lli volatile*)(0x38200100 + 0x20 * (c))))
471#define DMAC0CSRCADDR(c) (*((const void* volatile*)(0x38200100 + 0x20 * (c))))
472#define DMAC0CDESTADDR(c) (*((void* volatile*)(0x38200104 + 0x20 * (c))))
473#define DMAC0CNEXTLLI(c) (*((const void* volatile*)(0x38200108 + 0x20 * (c))))
474#define DMAC0CCONTROL(c) (*((uint32_t volatile*)(0x3820010c + 0x20 * (c))))
475#define DMAC0CCONFIG(c) (*((uint32_t volatile*)(0x38200110 + 0x20 * (c))))
476#define DMAC0C0LLI (*((struct dma_lli volatile*)(0x38200100)))
477#define DMAC0C0SRCADDR (*((const void* volatile*)(0x38200100)))
478#define DMAC0C0DESTADDR (*((void* volatile*)(0x38200104)))
479#define DMAC0C0NEXTLLI (*((const struct dma_lli* volatile*)(0x38200108)))
480#define DMAC0C0CONTROL (*((uint32_t volatile*)(0x3820010c)))
481#define DMAC0C0CONFIG (*((uint32_t volatile*)(0x38200110)))
482#define DMAC0C1LLI (*((struct dma_lli volatile*)(0x38200120)))
483#define DMAC0C1SRCADDR (*((const void* volatile*)(0x38200120)))
484#define DMAC0C1DESTADDR (*((void* volatile*)(0x38200124)))
485#define DMAC0C1NEXTLLI (*((const struct dma_lli* volatile*)(0x38200128)))
486#define DMAC0C1CONTROL (*((uint32_t volatile*)(0x3820012c)))
487#define DMAC0C1CONFIG (*((uint32_t volatile*)(0x38200130)))
488#define DMAC0C2LLI (*((struct dma_lli volatile*)(0x38200140)))
489#define DMAC0C2SRCADDR (*((const void* volatile*)(0x38200140)))
490#define DMAC0C2DESTADDR (*((void* volatile*)(0x38200144)))
491#define DMAC0C2NEXTLLI (*((const struct dma_lli* volatile*)(0x38200148)))
492#define DMAC0C2CONTROL (*((uint32_t volatile*)(0x3820014c)))
493#define DMAC0C2CONFIG (*((uint32_t volatile*)(0x38200150)))
494#define DMAC0C3LLI (*((struct dma_lli volatile*)(0x38200160)))
495#define DMAC0C3SRCADDR (*((const void* volatile*)(0x38200160)))
496#define DMAC0C3DESTADDR (*((void* volatile*)(0x38200164)))
497#define DMAC0C3NEXTLLI (*((const struct dma_lli* volatile*)(0x38200168)))
498#define DMAC0C3CONTROL (*((uint32_t volatile*)(0x3820016c)))
499#define DMAC0C3CONFIG (*((uint32_t volatile*)(0x38200170)))
500#define DMAC0C4LLI (*((struct dma_lli volatile*)(0x38200180)))
501#define DMAC0C4SRCADDR (*((const void* volatile*)(0x38200180)))
502#define DMAC0C4DESTADDR (*((void* volatile*)(0x38200184)))
503#define DMAC0C4NEXTLLI (*((const struct dma_lli* volatile*)(0x38200188)))
504#define DMAC0C4CONTROL (*((uint32_t volatile*)(0x3820018c)))
505#define DMAC0C4CONFIG (*((uint32_t volatile*)(0x38200190)))
506#define DMAC0C5LLI (*((struct dma_lli volatile*)(0x382001a0)))
507#define DMAC0C5SRCADDR (*((const void* volatile*)(0x382001a0)))
508#define DMAC0C5DESTADDR (*((void* volatile*)(0x382001a4)))
509#define DMAC0C5NEXTLLI (*((const struct dma_lli* volatile*)(0x382001a8)))
510#define DMAC0C5CONTROL (*((uint32_t volatile*)(0x382001ac)))
511#define DMAC0C5CONFIG (*((uint32_t volatile*)(0x382001b0)))
512#define DMAC0C6LLI (*((struct dma_lli volatile*)(0x382001c0)))
513#define DMAC0C6SRCADDR (*((const void* volatile*)(0x382001c0)))
514#define DMAC0C6DESTADDR (*((void* volatile*)(0x382001c4)))
515#define DMAC0C6NEXTLLI (*((const struct dma_lli* volatile*)(0x382001c8)))
516#define DMAC0C6CONTROL (*((uint32_t volatile*)(0x382001cc)))
517#define DMAC0C6CONFIG (*((uint32_t volatile*)(0x382001d0)))
518#define DMAC0C7LLI (*((struct dma_lli volatile*)(0x382001e0)))
519#define DMAC0C7SRCADDR (*((const void* volatile*)(0x382001e0)))
520#define DMAC0C7DESTADDR (*((void* volatile*)(0x382001e4)))
521#define DMAC0C7NEXTLLI (*((const struct dma_lli* volatile*)(0x382001e8)))
522#define DMAC0C7CONTROL (*((uint32_t volatile*)(0x382001ec)))
523#define DMAC0C7CONFIG (*((uint32_t volatile*)(0x382001f0)))
524#define DMAC1INTSTS (*((uint32_t volatile*)(0x39900000)))
525#define DMAC1INTTCSTS (*((uint32_t volatile*)(0x39900004)))
526#define DMAC1INTTCCLR (*((uint32_t volatile*)(0x39900008)))
527#define DMAC1INTERRSTS (*((uint32_t volatile*)(0x3990000c)))
528#define DMAC1INTERRCLR (*((uint32_t volatile*)(0x39900010)))
529#define DMAC1RAWINTTCSTS (*((uint32_t volatile*)(0x39900014)))
530#define DMAC1RAWINTERRSTS (*((uint32_t volatile*)(0x39900018)))
531#define DMAC1ENABLEDCHANS (*((uint32_t volatile*)(0x3990001c)))
532#define DMAC1SOFTBREQ (*((uint32_t volatile*)(0x39900020)))
533#define DMAC1SOFTSREQ (*((uint32_t volatile*)(0x39900024)))
534#define DMAC1SOFTLBREQ (*((uint32_t volatile*)(0x39900028)))
535#define DMAC1SOFTLSREQ (*((uint32_t volatile*)(0x3990002c)))
536#define DMAC1CONFIG (*((uint32_t volatile*)(0x39900030)))
537#define DMAC1SYNC (*((uint32_t volatile*)(0x39900034)))
538#define DMAC1CLLI(c) (*((struct dma_lli volatile*)(0x39900100 + 0x20 * (c))))
539#define DMAC1CSRCADDR(c) (*((const void* volatile*)(0x39900100 + 0x20 * (c))))
540#define DMAC1CDESTADDR(c) (*((void* volatile*)(0x39900104 + 0x20 * (c))))
541#define DMAC1CNEXTLLI(c) (*((const void* volatile*)(0x39900108 + 0x20 * (c))))
542#define DMAC1CCONTROL(c) (*((uint32_t volatile*)(0x3990010c + 0x20 * (c))))
543#define DMAC1CCONFIG(c) (*((uint32_t volatile*)(0x39900110 + 0x20 * (c))))
544#define DMAC1C0LLI (*((struct dma_lli volatile*)(0x39900100)))
545#define DMAC1C0SRCADDR (*((const void* volatile*)(0x39900100)))
546#define DMAC1C0DESTADDR (*((void* volatile*)(0x39900104)))
547#define DMAC1C0NEXTLLI (*((const struct dma_lli* volatile*)(0x39900108)))
548#define DMAC1C0CONTROL (*((uint32_t volatile*)(0x3990010c)))
549#define DMAC1C0CONFIG (*((uint32_t volatile*)(0x39900110)))
550#define DMAC1C1LLI (*((struct dma_lli volatile*)(0x39900120)))
551#define DMAC1C1SRCADDR (*((const void* volatile*)(0x39900120)))
552#define DMAC1C1DESTADDR (*((void* volatile*)(0x39900124)))
553#define DMAC1C1NEXTLLI (*((const struct dma_lli* volatile*)(0x39900128)))
554#define DMAC1C1CONTROL (*((uint32_t volatile*)(0x3990012c)))
555#define DMAC1C1CONFIG (*((uint32_t volatile*)(0x39900130)))
556#define DMAC1C2LLI (*((struct dma_lli volatile*)(0x39900140)))
557#define DMAC1C2SRCADDR (*((const void* volatile*)(0x39900140)))
558#define DMAC1C2DESTADDR (*((void* volatile*)(0x39900144)))
559#define DMAC1C2NEXTLLI (*((const struct dma_lli* volatile*)(0x39900148)))
560#define DMAC1C2CONTROL (*((uint32_t volatile*)(0x3990014c)))
561#define DMAC1C2CONFIG (*((uint32_t volatile*)(0x39900150)))
562#define DMAC1C3LLI (*((struct dma_lli volatile*)(0x39900160)))
563#define DMAC1C3SRCADDR (*((const void* volatile*)(0x39900160)))
564#define DMAC1C3DESTADDR (*((void* volatile*)(0x39900164)))
565#define DMAC1C3NEXTLLI (*((volatile void**)(0x39900168)))
566#define DMAC1C3CONTROL (*((uint32_t volatile*)(0x3990016c)))
567#define DMAC1C3CONFIG (*((uint32_t volatile*)(0x39900170)))
568#define DMAC1C4LLI (*((struct dma_lli volatile*)(0x39900180)))
569#define DMAC1C4SRCADDR (*((const void* volatile*)(0x39900180)))
570#define DMAC1C4DESTADDR (*((void* volatile*)(0x39900184)))
571#define DMAC1C4NEXTLLI (*((const struct dma_lli* volatile*)(0x39900188)))
572#define DMAC1C4CONTROL (*((uint32_t volatile*)(0x3990018c)))
573#define DMAC1C4CONFIG (*((uint32_t volatile*)(0x39900190)))
574#define DMAC1C5LLI (*((struct dma_lli volatile*)(0x399001a0)))
575#define DMAC1C5SRCADDR (*((const void* volatile*)(0x399001a0)))
576#define DMAC1C5DESTADDR (*((void* volatile*)(0x399001a4)))
577#define DMAC1C5NEXTLLI (*((const struct dma_lli* volatile*)(0x399001a8)))
578#define DMAC1C5CONTROL (*((uint32_t volatile*)(0x399001ac)))
579#define DMAC1C5CONFIG (*((uint32_t volatile*)(0x399001b0)))
580#define DMAC1C6LLI (*((struct dma_lli volatile*)(0x399001c0)))
581#define DMAC1C6SRCADDR (*((const void* volatile*)(0x399001c0)))
582#define DMAC1C6DESTADDR (*((void* volatile*)(0x399001c4)))
583#define DMAC1C6NEXTLLI (*((const struct dma_lli* volatile*)(0x399001c8)))
584#define DMAC1C6CONTROL (*((uint32_t volatile*)(0x399001cc)))
585#define DMAC1C6CONFIG (*((uint32_t volatile*)(0x399001d0)))
586#define DMAC1C7LLI (*((struct dma_lli volatile*)(0x399001e0)))
587#define DMAC1C7SRCADDR (*((const void* volatile*)(0x399001e0)))
588#define DMAC1C7DESTADDR (*((void* volatile*)(0x399001e4)))
589#define DMAC1C7NEXTLLI (*((const struct dma_lli* volatile*)(0x399001e8)))
590#define DMAC1C7CONTROL (*((uint32_t volatile*)(0x399001ec)))
591#define DMAC1C7CONFIG (*((uint32_t volatile*)(0x399001f0)))
592
593
594/////LCD///// 422/////LCD/////
595#define LCD_BASE (0x38300000) 423#define LCD_BASE (0x38300000)
596#define LCD_CONFIG (*((uint32_t volatile*)(0x38300000))) 424#define LCD_CONFIG (*((uint32_t volatile*)(0x38300000)))
@@ -844,6 +672,8 @@ struct dma_lli
844/////CLOCK GATES///// 672/////CLOCK GATES/////
845#define CLOCKGATE_USB_1 2 673#define CLOCKGATE_USB_1 2
846#define CLOCKGATE_USB_2 35 674#define CLOCKGATE_USB_2 35
675#define CLOCKGATE_DMAC0 25
676#define CLOCKGATE_DMAC1 26
847 677
848 678
849/////INTERRUPTS///// 679/////INTERRUPTS/////
diff --git a/firmware/target/arm/s5l8702/debug-s5l8702.c b/firmware/target/arm/s5l8702/debug-s5l8702.c
index 66bfa36a93..74f765e447 100644
--- a/firmware/target/arm/s5l8702/debug-s5l8702.c
+++ b/firmware/target/arm/s5l8702/debug-s5l8702.c
@@ -44,7 +44,7 @@ bool dbg_hw_info(void)
44 int line; 44 int line;
45 int i; 45 int i;
46 unsigned int state = 0; 46 unsigned int state = 0;
47 const unsigned int max_states=3; 47 const unsigned int max_states=2;
48 48
49 lcd_clear_display(); 49 lcd_clear_display();
50 lcd_setfont(FONT_SYSFIXED); 50 lcd_setfont(FONT_SYSFIXED);
@@ -95,16 +95,6 @@ bool dbg_hw_info(void)
95 _DEBUG_PRINTF("backlight: %s", pmu_read(0x29) ? "on" : "off"); 95 _DEBUG_PRINTF("backlight: %s", pmu_read(0x29) ? "on" : "off");
96 _DEBUG_PRINTF("brightness value: %d", pmu_read(0x28)); 96 _DEBUG_PRINTF("brightness value: %d", pmu_read(0x28));
97 } 97 }
98 else if(state==2)
99 {
100 _DEBUG_PRINTF("Audio DMA:");
101 _DEBUG_PRINTF(">%08X %08X %08X %08X %08X", DMAC0C0CONFIG, DMAC0C0SRCADDR,
102 DMAC0C0DESTADDR, DMAC0C0NEXTLLI, DMAC0C0CONTROL);
103 for(i = 0; i < PCM_LLICOUNT; i++)
104 _DEBUG_PRINTF("%08X: %08X %08X %08X %08X", &pcm_lli[i], pcm_lli[i].srcaddr,
105 pcm_lli[i].dstaddr, pcm_lli[i].nextlli, pcm_lli[i].control);
106 _DEBUG_PRINTF("chunk: %08X %08X", pcm_chunksize, pcm_remaining);
107 }
108 else 98 else
109 { 99 {
110 state=0; 100 state=0;
diff --git a/firmware/target/arm/s5l8702/dma-s5l8702.c b/firmware/target/arm/s5l8702/dma-s5l8702.c
new file mode 100644
index 0000000000..6fe25f712a
--- /dev/null
+++ b/firmware/target/arm/s5l8702/dma-s5l8702.c
@@ -0,0 +1,68 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2014 by Cástor Muñoz
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <config.h>
23
24#include "s5l8702.h"
25#include "pl080.h"
26#include "dma-s5l8702.h"
27
28/* s5l8702 PL080 controllers configuration */
29struct dmac s5l8702_dmac0 = {
30 .baddr = S5L8702_DMAC0_BASE,
31 .m1 = DMACCONFIG_M_LITTLE_ENDIAN,
32 .m2 = DMACCONFIG_M_LITTLE_ENDIAN,
33};
34
35struct dmac s5l8702_dmac1 = {
36 .baddr = S5L8702_DMAC1_BASE,
37 .m1 = DMACCONFIG_M_LITTLE_ENDIAN,
38 .m2 = DMACCONFIG_M_LITTLE_ENDIAN,
39};
40
41void ICODE_ATTR INT_DMAC0(void)
42{
43 dmac_callback(&s5l8702_dmac0);
44}
45
46void ICODE_ATTR INT_DMAC1(void)
47{
48 dmac_callback(&s5l8702_dmac1);
49}
50
51void dma_init_ctrl(struct dmac* dmac, int irq, int clockgate, int onoff)
52{
53 /* init DMAC */
54 VIC0INTENCLEAR = (1 << irq); /* disable interrupts */
55 PWRCON(0) &= ~(1 << clockgate); /* unmask clock gate */
56 dmac_open(dmac); /* init/reset controller */
57
58 if (onoff)
59 VIC0INTENABLE = (1 << irq); /* enable interrupts */
60 else
61 PWRCON(0) |= (1 << clockgate); /* mask clockgate */
62}
63
64void dma_init(void)
65{
66 dma_init_ctrl(&s5l8702_dmac0, IRQ_DMAC0, CLOCKGATE_DMAC0, 1);
67 dma_init_ctrl(&s5l8702_dmac1, IRQ_DMAC1, CLOCKGATE_DMAC1, 0);
68}
diff --git a/firmware/target/arm/s5l8702/dma-s5l8702.h b/firmware/target/arm/s5l8702/dma-s5l8702.h
new file mode 100644
index 0000000000..5f338578f7
--- /dev/null
+++ b/firmware/target/arm/s5l8702/dma-s5l8702.h
@@ -0,0 +1,107 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2014 by Cástor Muñoz
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef _DMA_S5l8702_H
23#define _DMA_S5l8702_H
24
25#include "pl080.h"
26
27/*
28 * s5l8702 PL080 controllers configuration
29 */
30
31extern struct dmac s5l8702_dmac0;
32extern struct dmac s5l8702_dmac1;
33
34#define S5L8702_DMAC_COUNT 2 /* N PL080 controllers */
35#define S5L8702_DMAC0_BASE 0x38200000
36#define S5L8702_DMAC1_BASE 0x39900000
37
38/* S5L7802 DMAC0 peripherals */
39#define S5L8702_DMAC0_PERI_IIS2_TX 0x0
40#define S5L8702_DMAC0_PERI_IIS2_RX 0x1
41#define S5L8702_DMAC0_PERI_UNKNOWN 0x2
42#define S5L8702_DMAC0_PERI_LCD_WR 0x3
43#define S5L8702_DMAC0_PERI_SPI0_TX 0x4
44#define S5L8702_DMAC0_PERI_SPI0_RX 0x5
45#define S5L8702_DMAC0_PERI_UART0_TX 0x6
46#define S5L8702_DMAC0_PERI_UART0_RX 0x7
47#define S5L8702_DMAC0_PERI_UART1_TX 0x8
48#define S5L8702_DMAC0_PERI_UART1_RX 0x9
49#define S5L8702_DMAC0_PERI_IIS0_TX 0xA
50#define S5L8702_DMAC0_PERI_IIS0_RX 0xB
51#define S5L8702_DMAC0_PERI_SPI2_TX 0xC
52#define S5L8702_DMAC0_PERI_SPI2_RX 0xD
53#define S5L8702_DMAC0_PERI_SPI1_TX 0xE
54#define S5L8702_DMAC0_PERI_SPI1_RX 0xF
55
56/* S5L7802 DMAC1 peripherals */
57#define S5L8702_DMAC1_PERI_CEATA_WR 0x0
58#define S5L8702_DMAC1_PERI_CEATA_RD 0x1
59#define S5L8702_DMAC1_PERI_IIS1_TX 0x2
60#define S5L8702_DMAC1_PERI_IIS1_RX 0x3
61#define S5L8702_DMAC1_PERI_IIS2_TX 0x4
62#define S5L8702_DMAC1_PERI_IIS2_RX 0x5
63#define S5L8702_DMAC1_PERI_SPI1_TX 0x6
64#define S5L8702_DMAC1_PERI_SPI1_RX 0x7
65#define S5L8702_DMAC1_PERI_UART2_TX 0x8
66#define S5L8702_DMAC1_PERI_UART2_RX 0x9
67#define S5L8702_DMAC1_PERI_SPI0_TX 0xA
68#define S5L8702_DMAC1_PERI_SPI0_RX 0xB
69#define S5L8702_DMAC1_PERI_UART3_TX 0xC
70#define S5L8702_DMAC1_PERI_UART3_RX 0xD
71#define S5L8702_DMAC1_PERI_SPI2_TX 0xE
72#define S5L8702_DMAC1_PERI_SPI2_RX 0xF
73
74/* used when src and/or dst peripheral is memory */
75#define S5L8702_DMAC0_PERI_MEM DMAC_PERI_NONE
76#define S5L8702_DMAC1_PERI_MEM DMAC_PERI_NONE
77
78/* s5l8702 peripheral DMA R/W addesses */
79#define S5L8702_DADDR_PERI_LCD_WR 0x38300040
80#define S5L8702_DADDR_PERI_UNKNOWN 0x3CB00010 /* SPDIF ??? */
81#define S5L8702_DADDR_PERI_UART0_TX 0x3CC00020
82#define S5L8702_DADDR_PERI_UART0_RX 0x3CC00024
83#define S5L8702_DADDR_PERI_UART1_TX 0x3CC04020
84#define S5L8702_DADDR_PERI_UART1_RX 0x3CC04024
85#define S5L8702_DADDR_PERI_UART2_TX 0x3CC08020
86#define S5L8702_DADDR_PERI_UART2_RX 0x3CC08024
87#define S5L8702_DADDR_PERI_UART3_TX 0x3CC0C020
88#define S5L8702_DADDR_PERI_UART3_RX 0x3CC0C024
89#define S5L8702_DADDR_PERI_IIS0_TX 0x3CA00010
90#define S5L8702_DADDR_PERI_IIS0_RX 0x3CA00038
91#define S5L8702_DADDR_PERI_IIS1_TX 0x3CD00010
92#define S5L8702_DADDR_PERI_IIS1_RX 0x3CD00038
93#define S5L8702_DADDR_PERI_IIS2_TX 0x3D400010
94#define S5L8702_DADDR_PERI_IIS2_RX 0x3D400038
95#define S5L8702_DADDR_PERI_CEATA_WR 0x38A00080
96#define S5L8702_DADDR_PERI_CEATA_RD 0x38A04080
97#define S5L8702_DADDR_PERI_SPI0_TX 0x3C300010
98#define S5L8702_DADDR_PERI_SPI0_RX 0x3C300020
99#define S5L8702_DADDR_PERI_SPI1_TX 0x3CE00010
100#define S5L8702_DADDR_PERI_SPI1_RX 0x3CE00020
101#define S5L8702_DADDR_PERI_SPI2_TX 0x3D200010
102#define S5L8702_DADDR_PERI_SPI2_RX 0x3D200020
103
104/* proto */
105void dma_init(void);
106
107#endif /* _DMA_S5l8702_H */
diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c
index f9dbab6180..bf6c1a1402 100644
--- a/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c
+++ b/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c
@@ -28,6 +28,7 @@
28#include "pmu-target.h" 28#include "pmu-target.h"
29#include "power.h" 29#include "power.h"
30#include "string.h" 30#include "string.h"
31#include "dma-s5l8702.h"
31 32
32 33
33#define R_HORIZ_GRAM_ADDR_SET 0x200 34#define R_HORIZ_GRAM_ADDR_SET 0x200
@@ -49,10 +50,8 @@
49/** globals **/ 50/** globals **/
50 51
51int lcd_type; /* also needed in debug-s5l8702.c */ 52int lcd_type; /* also needed in debug-s5l8702.c */
52static struct dma_lli lcd_lli[(LCD_WIDTH * LCD_HEIGHT - 1) / 0xfff] CACHEALIGN_ATTR;
53static struct semaphore lcd_wakeup;
54static struct mutex lcd_mutex; 53static struct mutex lcd_mutex;
55static uint16_t lcd_dblbuf[LCD_HEIGHT][LCD_WIDTH]; 54static uint16_t lcd_dblbuf[LCD_HEIGHT][LCD_WIDTH] CACHEALIGN_ATTR;
56static bool lcd_ispowered; 55static bool lcd_ispowered;
57 56
58#define SLEEP 0 57#define SLEEP 0
@@ -197,6 +196,48 @@ static const unsigned short lcd_init_sequence_23[] =
197}; 196};
198#endif 197#endif
199 198
199/* DMA configuration */
200
201/* one single transfer at once, needed LLIs:
202 * screen_size / (DMAC_LLI_MAX_COUNT << swidth) =
203 * (320*240*2) / (4095*2) = 19
204 */
205#define LCD_DMA_TSKBUF_SZ 1 /* N tasks, MUST be pow2 */
206#define LCD_DMA_LLIBUF_SZ 32 /* N LLIs, MUST be pow2 */
207
208static struct dmac_tsk lcd_dma_tskbuf[LCD_DMA_TSKBUF_SZ];
209static struct dmac_lli volatile \
210 lcd_dma_llibuf[LCD_DMA_LLIBUF_SZ] CACHEALIGN_ATTR;
211
212static struct dmac_ch lcd_dma_ch = {
213 .dmac = &s5l8702_dmac0,
214 .prio = DMAC_CH_PRIO(4),
215 .cb_fn = NULL,
216
217 .tskbuf = lcd_dma_tskbuf,
218 .tskbuf_mask = LCD_DMA_TSKBUF_SZ - 1,
219 .queue_mode = QUEUE_NORMAL,
220
221 .llibuf = lcd_dma_llibuf,
222 .llibuf_mask = LCD_DMA_LLIBUF_SZ - 1,
223 .llibuf_bus = DMAC_MASTER_AHB1,
224};
225
226static struct dmac_ch_cfg lcd_dma_ch_cfg = {
227 .srcperi = S5L8702_DMAC0_PERI_MEM,
228 .dstperi = S5L8702_DMAC0_PERI_LCD_WR,
229 .sbsize = DMACCxCONTROL_BSIZE_1,
230 .dbsize = DMACCxCONTROL_BSIZE_1,
231 .swidth = DMACCxCONTROL_WIDTH_16,
232 .dwidth = DMACCxCONTROL_WIDTH_16,
233 .sbus = DMAC_MASTER_AHB1,
234 .dbus = DMAC_MASTER_AHB1,
235 .sinc = DMACCxCONTROL_INC_ENABLE,
236 .dinc = DMACCxCONTROL_INC_DISABLE,
237 .prot = DMAC_PROT_CACH | DMAC_PROT_BUFF | DMAC_PROT_PRIV,
238 .lli_xfer_max_count = DMAC_LLI_MAX_COUNT,
239};
240
200static inline void s5l_lcd_write_reg(int cmd, unsigned int data) 241static inline void s5l_lcd_write_reg(int cmd, unsigned int data)
201{ 242{
202 while (LCD_STATUS & 0x10); 243 while (LCD_STATUS & 0x10);
@@ -328,12 +369,14 @@ void lcd_awake(void)
328void lcd_init_device(void) 369void lcd_init_device(void)
329{ 370{
330 /* Detect lcd type */ 371 /* Detect lcd type */
331 semaphore_init(&lcd_wakeup, 1, 0);
332 mutex_init(&lcd_mutex); 372 mutex_init(&lcd_mutex);
333 lcd_type = (PDAT6 & 0x30) >> 4; 373 lcd_type = (PDAT6 & 0x30) >> 4;
334 while (!(LCD_STATUS & 0x2)); 374 while (!(LCD_STATUS & 0x2));
335 LCD_CONFIG = 0x80100db0; 375 LCD_CONFIG = 0x80100db0;
336 376
377 /* Configure DMA channel */
378 dmac_ch_init(&lcd_dma_ch, &lcd_dma_ch_cfg);
379
337 lcd_ispowered = true; 380 lcd_ispowered = true;
338} 381}
339 382
@@ -362,8 +405,10 @@ extern void lcd_write_line(const fb_data *addr,
362static void displaylcd_setup(int x, int y, int width, int height) ICODE_ATTR; 405static void displaylcd_setup(int x, int y, int width, int height) ICODE_ATTR;
363static void displaylcd_setup(int x, int y, int width, int height) 406static void displaylcd_setup(int x, int y, int width, int height)
364{ 407{
408 /* TODO: ISR()->panicf()->lcd_update() blocks forever */
365 mutex_lock(&lcd_mutex); 409 mutex_lock(&lcd_mutex);
366 while (DMAC0C4CONFIG & 1) semaphore_wait(&lcd_wakeup, HZ / 10); 410 while (dmac_ch_running(&lcd_dma_ch))
411 yield();
367 412
368 int xe = (x + width) - 1; /* max horiz */ 413 int xe = (x + width) - 1; /* max horiz */
369 int ye = (y + height) - 1; /* max vert */ 414 int ye = (y + height) - 1; /* max vert */
@@ -398,31 +443,12 @@ static void displaylcd_setup(int x, int y, int width, int height)
398static void displaylcd_dma(int pixels) ICODE_ATTR; 443static void displaylcd_dma(int pixels) ICODE_ATTR;
399static void displaylcd_dma(int pixels) 444static void displaylcd_dma(int pixels)
400{ 445{
401 int i;
402 void* data = lcd_dblbuf;
403 for (i = -1; i < (int)ARRAYLEN(lcd_lli) && pixels > 0; i++, pixels -= 0xfff)
404 {
405 bool last = i + 1 >= (int)ARRAYLEN(lcd_lli) || pixels <= 0xfff;
406 struct dma_lli* lli = i < 0 ? (struct dma_lli*)((int)&DMAC0C4LLI) : &lcd_lli[i];
407 lli->srcaddr = data;
408 lli->dstaddr = (void*)((int)&LCD_WDATA);
409 lli->nextlli = last ? NULL : &lcd_lli[i + 1];
410 lli->control = 0x70240000 | (last ? pixels : 0xfff)
411 | (last ? 0x80000000 : 0) | 0x4000000;
412 data += 0x1ffe;
413 }
414 commit_dcache(); 446 commit_dcache();
415 DMAC0C4CONFIG = 0x88c1; 447 dmac_ch_queue(&lcd_dma_ch, lcd_dblbuf,
448 (void*)S5L8702_DADDR_PERI_LCD_WR, pixels*2, NULL);
416 mutex_unlock(&lcd_mutex); 449 mutex_unlock(&lcd_mutex);
417} 450}
418 451
419void INT_DMAC0C4(void) ICODE_ATTR;
420void INT_DMAC0C4(void)
421{
422 DMAC0INTTCCLR = 0x10;
423 semaphore_release(&lcd_wakeup);
424}
425
426/* Update a fraction of the display. */ 452/* Update a fraction of the display. */
427void lcd_update_rect(int, int, int, int) ICODE_ATTR; 453void lcd_update_rect(int, int, int, int) ICODE_ATTR;
428void lcd_update_rect(int x, int y, int width, int height) 454void lcd_update_rect(int x, int y, int width, int height)
diff --git a/firmware/target/arm/s5l8702/pcm-s5l8702.c b/firmware/target/arm/s5l8702/pcm-s5l8702.c
index 1048354ec5..a4ea56edce 100644
--- a/firmware/target/arm/s5l8702/pcm-s5l8702.c
+++ b/firmware/target/arm/s5l8702/pcm-s5l8702.c
@@ -31,104 +31,129 @@
31#include "pcm_sampr.h" 31#include "pcm_sampr.h"
32#include "mmu-arm.h" 32#include "mmu-arm.h"
33#include "pcm-target.h" 33#include "pcm-target.h"
34#include "dma-s5l8702.h"
35
36/* DMA configuration */
37
38/* 3 DMA tasks needed, one chunk task and two dblbuf tasks */
39#define DMA_PLAY_TSKBUF_SZ 4 /* N tasks, MUST be pow2 */
40#define DMA_PLAY_LLIBUF_SZ 4 /* N LLIs, MUST be pow2 */
41
42static struct dmac_tsk dma_play_tskbuf[DMA_PLAY_TSKBUF_SZ];
43static struct dmac_lli volatile \
44 dma_play_llibuf[DMA_PLAY_LLIBUF_SZ] CACHEALIGN_ATTR;
45
46static void dma_play_callback(void *data) ICODE_ATTR;
47
48static struct dmac_ch dma_play_ch = {
49 .dmac = &s5l8702_dmac0,
50 .prio = DMAC_CH_PRIO(2),
51 .cb_fn = dma_play_callback,
52
53 .tskbuf = dma_play_tskbuf,
54 .tskbuf_mask = DMA_PLAY_TSKBUF_SZ - 1,
55 .queue_mode = QUEUE_LINK,
56
57 .llibuf = dma_play_llibuf,
58 .llibuf_mask = DMA_PLAY_LLIBUF_SZ - 1,
59 .llibuf_bus = DMAC_MASTER_AHB1,
60};
61
62static struct dmac_ch_cfg dma_play_ch_cfg = {
63 .srcperi = S5L8702_DMAC0_PERI_MEM,
64 .dstperi = S5L8702_DMAC0_PERI_IIS0_TX,
65 .sbsize = DMACCxCONTROL_BSIZE_8,
66 .dbsize = DMACCxCONTROL_BSIZE_4,
67 .swidth = DMACCxCONTROL_WIDTH_16,
68 .dwidth = DMACCxCONTROL_WIDTH_16,
69 .sbus = DMAC_MASTER_AHB1,
70 .dbus = DMAC_MASTER_AHB1,
71 .sinc = DMACCxCONTROL_INC_ENABLE,
72 .dinc = DMACCxCONTROL_INC_DISABLE,
73 .prot = DMAC_PROT_CACH | DMAC_PROT_BUFF | DMAC_PROT_PRIV,
74 /* align LLI transfers to L-R pairs (samples) */
75 .lli_xfer_max_count = DMAC_LLI_MAX_COUNT & ~1,
76};
77#define LLI_MAX_BYTES 8188 /* lli_xfer_max_count << swidth */
78
79/* Use all available LLIs for chunk */
80/*#define CHUNK_MAX_BYTES (LLI_MAX_BYTES * (DMA_PLAY_LLIBUF_SZ - 2))*/
81#define CHUNK_MAX_BYTES (LLI_MAX_BYTES * 1)
82#define WATERMARK_BYTES (PCM_WATERMARK * 4)
34 83
35static volatile int locked = 0; 84static volatile int locked = 0;
36static const int zerosample = 0; 85static unsigned char dblbuf[2][WATERMARK_BYTES] CACHEALIGN_ATTR;
37static unsigned char dblbuf[2][PCM_WATERMARK * 4];
38static int active_dblbuf; 86static int active_dblbuf;
39struct dma_lli pcm_lli[PCM_LLICOUNT] __attribute__((aligned(16)));
40static struct dma_lli* lastlli;
41static const void* dataptr;
42size_t pcm_remaining; 87size_t pcm_remaining;
43size_t pcm_chunksize;
44 88
45/* Mask the DMA interrupt */ 89/* Mask the DMA interrupt */
46void pcm_play_lock(void) 90void pcm_play_lock(void)
47{ 91{
48 if (locked++ == 0) { 92 if (locked++ == 0)
49 //TODO: Urgh, I don't like that at all... 93 dmac_ch_lock_int(&dma_play_ch);
50 VIC0INTENCLEAR = 1 << IRQ_DMAC0;
51 }
52} 94}
53 95
54/* Unmask the DMA interrupt if enabled */ 96/* Unmask the DMA interrupt if enabled */
55void pcm_play_unlock(void) 97void pcm_play_unlock(void)
56{ 98{
57 if (--locked == 0) { 99 if (--locked == 0)
58 VIC0INTENABLE = 1 << IRQ_DMAC0; 100 dmac_ch_unlock_int(&dma_play_ch);
59 }
60} 101}
61 102
62void INT_DMAC0C0(void) ICODE_ATTR; 103static inline void play_queue_dma(void *addr, size_t size, void *cb_data)
63void INT_DMAC0C0(void)
64{ 104{
65 DMAC0INTTCCLR = 1; 105 commit_dcache_range(addr, size);
66 if (!pcm_remaining) 106 dmac_ch_queue(&dma_play_ch, addr,
67 { 107 (void*)S5L8702_DADDR_PERI_IIS0_TX, size, cb_data);
68 pcm_play_dma_complete_callback(PCM_DMAST_OK, &dataptr, &pcm_remaining); 108}
69 pcm_chunksize = pcm_remaining; 109
70 } 110static void dma_play_callback(void *cb_data)
111{
112 if (!cb_data)
113 return; /* dblbuf callback entered, nothing to do */
114
115 const void *dataptr = cb_data;
116
71 if (!pcm_remaining) 117 if (!pcm_remaining)
72 { 118 if (!pcm_play_dma_complete_callback(
73 pcm_lli->nextlli = NULL; 119 PCM_DMAST_OK, &dataptr, &pcm_remaining))
74 pcm_lli->control = 0x7524a000; 120 return;
75 commit_dcache(); 121
76 return; 122 uint32_t lastsize = MIN(WATERMARK_BYTES, pcm_remaining >> 1);
77 }
78 uint32_t lastsize = MIN(PCM_WATERMARK * 4, pcm_remaining / 2 + 1) & ~1;
79 pcm_remaining -= lastsize; 123 pcm_remaining -= lastsize;
80 if (pcm_remaining) lastlli = &pcm_lli[ARRAYLEN(pcm_lli) - 1]; 124 uint32_t chunksize = MIN(CHUNK_MAX_BYTES, pcm_remaining);
81 else lastlli = pcm_lli; 125
82 uint32_t chunksize = MIN(PCM_CHUNKSIZE * 4 - lastsize, pcm_remaining); 126 /* last chunk should be at least 2*WATERMARK_BYTES in size */
83 if (pcm_remaining > chunksize && chunksize > pcm_remaining - PCM_WATERMARK * 8) 127 if ((pcm_remaining > chunksize) &&
84 chunksize = pcm_remaining - PCM_WATERMARK * 8; 128 (pcm_remaining < chunksize + WATERMARK_BYTES * 2))
129 chunksize = pcm_remaining - WATERMARK_BYTES * 2;
130
85 pcm_remaining -= chunksize; 131 pcm_remaining -= chunksize;
86 bool last = !chunksize; 132
87 int i = 0; 133 /* first part */
88 while (chunksize) 134 play_queue_dma((void*)dataptr, chunksize,
89 { 135 (void*)dataptr + chunksize + lastsize); /* cb_data */
90 uint32_t thislli = MIN(PCM_LLIMAX * 4, chunksize); 136
91 chunksize -= thislli; 137 /* second part */
92 pcm_lli[i].srcaddr = (void*)dataptr; 138 memcpy(dblbuf[active_dblbuf], dataptr + chunksize, lastsize);
93 pcm_lli[i].dstaddr = (void*)((int)&I2STXDB0); 139 play_queue_dma(dblbuf[active_dblbuf], lastsize, NULL);
94 pcm_lli[i].nextlli = chunksize ? &pcm_lli[i + 1] : lastlli; 140 active_dblbuf ^= 1;
95 pcm_lli[i].control = (chunksize ? 0x7524a000 : 0xf524a000) | (thislli / 2);
96 dataptr += thislli;
97 i++;
98 }
99 if (!pcm_remaining)
100 {
101 memcpy(dblbuf[active_dblbuf], dataptr, lastsize);
102 lastlli->srcaddr = dblbuf[active_dblbuf];
103 active_dblbuf ^= 1;
104 }
105 else lastlli->srcaddr = dataptr;
106 lastlli->dstaddr = (void*)((int)&I2STXDB0);
107 lastlli->nextlli = last ? NULL : pcm_lli;
108 lastlli->control = (last ? 0xf524a000 : 0x7524a000) | (lastsize / 2);
109 dataptr += lastsize;
110 commit_dcache();
111 if (!(DMAC0C0CONFIG & 1) && (pcm_lli[0].control & 0xfff))
112 {
113 DMAC0C0LLI = pcm_lli[0];
114 DMAC0C0CONFIG = 0x8a81;
115 }
116 else DMAC0C0NEXTLLI = pcm_lli;
117 141
118 pcm_play_dma_status_callback(PCM_DMAST_STARTED); 142 pcm_play_dma_status_callback(PCM_DMAST_STARTED);
119} 143}
120 144
121void pcm_play_dma_start(const void* addr, size_t size) 145void pcm_play_dma_start(const void* addr, size_t size)
122{ 146{
123 dataptr = addr; 147 pcm_play_dma_stop();
148
124 pcm_remaining = size; 149 pcm_remaining = size;
125 I2STXCOM = 0xe; 150 I2STXCOM = 0xe;
126 INT_DMAC0C0(); 151 dma_play_callback((void*)addr);
127} 152}
128 153
129void pcm_play_dma_stop(void) 154void pcm_play_dma_stop(void)
130{ 155{
131 DMAC0C0CONFIG = 0x8a80; 156 dmac_ch_stop(&dma_play_ch);
132 I2STXCOM = 0xa; 157 I2STXCOM = 0xa;
133} 158}
134 159
@@ -184,9 +209,11 @@ void pcm_play_dma_init(void)
184{ 209{
185 PWRCON(0) &= ~(1 << 4); 210 PWRCON(0) &= ~(1 << 4);
186 PWRCON(1) &= ~(1 << 7); 211 PWRCON(1) &= ~(1 << 7);
212
213 dmac_ch_init(&dma_play_ch, &dma_play_ch_cfg);
214
187 I2STXCON = 0xb100019; 215 I2STXCON = 0xb100019;
188 I2SCLKCON = 1; 216 I2SCLKCON = 1;
189 VIC0INTENABLE = 1 << IRQ_DMAC0;
190 217
191 audiohw_preinit(); 218 audiohw_preinit();
192 pcm_dma_apply_settings(); 219 pcm_dma_apply_settings();
@@ -199,21 +226,16 @@ void pcm_play_dma_postinit(void)
199 226
200size_t pcm_get_bytes_waiting(void) 227size_t pcm_get_bytes_waiting(void)
201{ 228{
202 int bytes = pcm_remaining; 229 size_t total_bytes;
203 const struct dma_lli* lli = (const struct dma_lli*)((int)&DMAC0C0LLI); 230 dmac_ch_get_info(&dma_play_ch, NULL, &total_bytes);
204 while (lli) 231 return total_bytes;
205 {
206 bytes += (lli->control & 0xfff) * 2;
207 if (lli == lastlli) break;
208 lli = lli->nextlli;
209 }
210 return bytes;
211} 232}
212 233
213const void* pcm_play_dma_get_peak_buffer(int *count) 234const void* pcm_play_dma_get_peak_buffer(int *count)
214{ 235{
215 *count = (DMAC0C0LLI.control & 0xfff) * 2; 236 void *addr = dmac_ch_get_info(&dma_play_ch, count, NULL);
216 return (void*)(((uint32_t)DMAC0C0LLI.srcaddr) & ~3); 237 *count >>= 2; /* bytes to samples */
238 return addr; /* aligned to dest burst */
217} 239}
218 240
219#ifdef HAVE_PCM_DMA_ADDRESS 241#ifdef HAVE_PCM_DMA_ADDRESS
diff --git a/firmware/target/arm/s5l8702/pcm-target.h b/firmware/target/arm/s5l8702/pcm-target.h
index aefb64e328..b858581c4e 100644
--- a/firmware/target/arm/s5l8702/pcm-target.h
+++ b/firmware/target/arm/s5l8702/pcm-target.h
@@ -23,18 +23,7 @@
23 23
24 24
25/* S5L8702 PCM driver tunables: */ 25/* S5L8702 PCM driver tunables: */
26#define PCM_LLIMAX (2047) /* Maximum number of samples per LLI */
27#define PCM_CHUNKSIZE (10747) /* Maximum number of samples to handle with one IRQ */
28 /* (bigger chunks will be segmented internally) */
29#define PCM_WATERMARK (512) /* Number of remaining samples to schedule IRQ at */ 26#define PCM_WATERMARK (512) /* Number of remaining samples to schedule IRQ at */
30 27
31 28
32#define PCM_LLICOUNT ((PCM_CHUNKSIZE - PCM_WATERMARK + PCM_LLIMAX - 1) / PCM_LLIMAX + 1)
33
34
35extern struct dma_lli pcm_lli[PCM_LLICOUNT];
36extern size_t pcm_remaining;
37extern size_t pcm_chunksize;
38
39
40#endif /* __PCM_TARGET_H__ */ 29#endif /* __PCM_TARGET_H__ */
diff --git a/firmware/target/arm/s5l8702/system-s5l8702.c b/firmware/target/arm/s5l8702/system-s5l8702.c
index f93a6a70ec..6a06c29694 100644
--- a/firmware/target/arm/s5l8702/system-s5l8702.c
+++ b/firmware/target/arm/s5l8702/system-s5l8702.c
@@ -25,6 +25,7 @@
25#include "system-target.h" 25#include "system-target.h"
26#include "pmu-target.h" 26#include "pmu-target.h"
27#include "gpio-s5l8702.h" 27#include "gpio-s5l8702.h"
28#include "dma-s5l8702.h"
28 29
29#define default_interrupt(name) \ 30#define default_interrupt(name) \
30 extern __attribute__((weak,alias("UIRQ"))) void name (void) 31 extern __attribute__((weak,alias("UIRQ"))) void name (void)
@@ -55,22 +56,8 @@ default_interrupt(INT_IRQ12);
55default_interrupt(INT_IRQ13); 56default_interrupt(INT_IRQ13);
56default_interrupt(INT_IRQ14); 57default_interrupt(INT_IRQ14);
57default_interrupt(INT_IRQ15); 58default_interrupt(INT_IRQ15);
58default_interrupt(INT_DMAC0C0); 59default_interrupt(INT_DMAC0);
59default_interrupt(INT_DMAC0C1); 60default_interrupt(INT_DMAC1);
60default_interrupt(INT_DMAC0C2);
61default_interrupt(INT_DMAC0C3);
62default_interrupt(INT_DMAC0C4);
63default_interrupt(INT_DMAC0C5);
64default_interrupt(INT_DMAC0C6);
65default_interrupt(INT_DMAC0C7);
66default_interrupt(INT_DMAC1C0);
67default_interrupt(INT_DMAC1C1);
68default_interrupt(INT_DMAC1C2);
69default_interrupt(INT_DMAC1C3);
70default_interrupt(INT_DMAC1C4);
71default_interrupt(INT_DMAC1C5);
72default_interrupt(INT_DMAC1C6);
73default_interrupt(INT_DMAC1C7);
74default_interrupt(INT_IRQ18); 61default_interrupt(INT_IRQ18);
75default_interrupt(INT_USB_FUNC); 62default_interrupt(INT_USB_FUNC);
76default_interrupt(INT_IRQ20); 63default_interrupt(INT_IRQ20);
@@ -141,34 +128,6 @@ void INT_TIMER32()
141 if ((THCON >> 12) & 0x7 & tstat) INT_TIMERH(); 128 if ((THCON >> 12) & 0x7 & tstat) INT_TIMERH();
142} 129}
143 130
144void INT_DMAC0(void) ICODE_ATTR;
145void INT_DMAC0()
146{
147 uint32_t intsts = DMAC0INTSTS;
148 if (intsts & 1) INT_DMAC0C0();
149 if (intsts & 2) INT_DMAC0C1();
150 if (intsts & 4) INT_DMAC0C2();
151 if (intsts & 8) INT_DMAC0C3();
152 if (intsts & 0x10) INT_DMAC0C4();
153 if (intsts & 0x20) INT_DMAC0C5();
154 if (intsts & 0x40) INT_DMAC0C6();
155 if (intsts & 0x80) INT_DMAC0C7();
156}
157
158void INT_DMAC1(void) ICODE_ATTR;
159void INT_DMAC1()
160{
161 uint32_t intsts = DMAC1INTSTS;
162 if (intsts & 1) INT_DMAC1C0();
163 if (intsts & 2) INT_DMAC1C1();
164 if (intsts & 4) INT_DMAC1C2();
165 if (intsts & 8) INT_DMAC1C3();
166 if (intsts & 0x10) INT_DMAC1C4();
167 if (intsts & 0x20) INT_DMAC1C5();
168 if (intsts & 0x40) INT_DMAC1C6();
169 if (intsts & 0x80) INT_DMAC1C7();
170}
171
172static void (* const irqvector[])(void) = 131static void (* const irqvector[])(void) =
173{ 132{
174 INT_EXT0,INT_EXT1,INT_EXT2,INT_EXT3,INT_IRQ4,INT_IRQ5,INT_IRQ6,INT_TIMER32, 133 INT_EXT0,INT_EXT1,INT_EXT2,INT_EXT3,INT_IRQ4,INT_IRQ5,INT_IRQ6,INT_TIMER32,
@@ -225,6 +184,7 @@ void system_init(void)
225{ 184{
226 /*gpio_init();*/ 185 /*gpio_init();*/
227 pmu_init(); 186 pmu_init();
187 dma_init();
228 VIC0INTENABLE = 1 << IRQ_WHEEL; 188 VIC0INTENABLE = 1 << IRQ_WHEEL;
229 VIC0INTENABLE = 1 << IRQ_ATA; 189 VIC0INTENABLE = 1 << IRQ_ATA;
230 VIC1INTENABLE = 1 << (IRQ_MMC - 32); 190 VIC1INTENABLE = 1 << (IRQ_MMC - 32);