From 4e5f4ee5e03072d8f470610f8751efcf17ad4f6a Mon Sep 17 00:00:00 2001 From: Tomasz Malesinski Date: Sat, 12 Aug 2006 21:03:23 +0000 Subject: Iriver iFP7xx sound support. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10552 a1c6a512-1295-4272-9138-f99709370657 --- firmware/app.lds | 8 +++ firmware/export/pnx0101.h | 14 ++++ firmware/pcm_playback.c | 173 ++++++++++++++++++++++++++++++++++++++++++++-- firmware/sound.c | 8 ++- 4 files changed, 197 insertions(+), 6 deletions(-) diff --git a/firmware/app.lds b/firmware/app.lds index 1caea68fa0..7a8ec11c3e 100644 --- a/firmware/app.lds +++ b/firmware/app.lds @@ -154,6 +154,9 @@ MEMORY { DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE +#if CONFIG_CPU==PNX0101 + IRAM0 : ORIGIN = 0x0, LENGTH = IRAMSIZE +#endif } SECTIONS @@ -221,7 +224,12 @@ SECTIONS _vectorsstart = .; *(.vectors); _vectorsend = .; +#if CONFIG_CPU==PNX0101 + *(.dmabuf) + } >IRAM0 AT> DRAM +#else } AT> DRAM +#endif _vectorscopy = LOADADDR(.vectors); #endif diff --git a/firmware/export/pnx0101.h b/firmware/export/pnx0101.h index 4408c0aa5b..4867c6b25d 100644 --- a/firmware/export/pnx0101.h +++ b/firmware/export/pnx0101.h @@ -64,4 +64,18 @@ #define ADCR24 (*(volatile unsigned long *)0x80002424) #define ADCR28 (*(volatile unsigned long *)0x80002428) +#define DMAINTSTAT (*(volatile unsigned long *)0x80104c04) +#define DMAINTEN (*(volatile unsigned long *)0x80104c08) + +#define DMASRC(n) (*(volatile unsigned long *)(0x80104800 + (n) * 0x20)) +#define DMADEST(n) (*(volatile unsigned long *)(0x80104804 + (n) * 0x20)) +#define DMALEN(n) (*(volatile unsigned long *)(0x80104808 + (n) * 0x20)) +#define DMAR0C(n) (*(volatile unsigned long *)(0x8010480c + (n) * 0x20)) +#define DMAR10(n) (*(volatile unsigned long *)(0x80104810 + (n) * 0x20)) +#define DMAR1C(n) (*(volatile unsigned long *)(0x8010481c + (n) * 0x20)) + +#define MMUBLOCK(n) (*(volatile unsigned long *)(0x80105018 + (n) * 4)) + +#define CODECVOL (*(volatile unsigned long *)0x80200398) + #endif diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 473c49f30d..16e8f5e3af 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c @@ -33,6 +33,8 @@ #include "tlv320.h" #elif defined(HAVE_WM8731) || defined(HAVE_WM8721) #include "wm8731l.h" +#elif CONFIG_CPU == PNX0101 +#include "pnx0101.h" #endif #include "system.h" #include "logf.h" @@ -55,9 +57,9 @@ static bool pcm_paused; /* the registered callback function to ask for more mp3 data */ static void (*callback_for_more)(unsigned char**, size_t*) IDATA_ATTR = NULL; -#if (CONFIG_CPU == PNX0101 || CONFIG_CPU == S3C2440) +#if (CONFIG_CPU == S3C2440) -/* TODO: Implement for iFP7xx +/* TODO: Implement for Gigabeat For now, just implement some dummy functions. */ @@ -526,6 +528,168 @@ void pcm_init(void) dma_stop(); } +#elif (CONFIG_CPU == PNX0101) + +#define DMA_BUF_SAMPLES 0x100 + +short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES]; +short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES]; + +static int pcm_freq = 44100; /* 44.1 is default */ + +unsigned short* p IBSS_ATTR; +size_t p_size IBSS_ATTR; + +static void dma_start(const void *addr, size_t size) +{ + p = (unsigned short*)addr; + p_size = size; + + pcm_playing = true; +} + +static void dma_stop(void) +{ + pcm_playing = false; +} + +static inline void fill_dma_buf(int offset) +{ + short *l, *r, *lend; + + l = dma_buf_left + offset; + lend = l + DMA_BUF_SAMPLES / 2; + r = dma_buf_right + offset; + + if (pcm_playing && !pcm_paused) + { + do + { + int count; + unsigned short *tmp_p; + count = MIN(p_size / 4, (size_t)(lend - l)); + tmp_p = p; + p_size -= count * 4; + + if ((int)l & 3) + { + *l++ = *tmp_p++; + *r++ = *tmp_p++; + count--; + } + while (count >= 4) + { + asm("ldmia %0!, {r0, r1, r2, r3}\n\t" + "and r4, r0, %3\n\t" + "orr r4, r4, r1, lsl #16\n\t" + "and r5, r2, %3\n\t" + "orr r5, r5, r3, lsl #16\n\t" + "stmia %1!, {r4, r5}\n\t" + "bic r4, r1, %3\n\t" + "orr r4, r4, r0, lsr #16\n\t" + "bic r5, r3, %3\n\t" + "orr r5, r5, r2, lsr #16\n\t" + "stmia %2!, {r4, r5}" + : "+r" (tmp_p), "+r" (l), "+r" (r) + : "r" (0xffff) + : "r0", "r1", "r2", "r3", "r4", "r5", "memory"); + count -= 4; + } + while (count > 0) + { + *l++ = *tmp_p++; + *r++ = *tmp_p++; + count--; + } + p = tmp_p; + if (l >= lend) + return; + else if (callback_for_more) + callback_for_more((unsigned char**)&p, + &p_size); + } + while (p_size); + pcm_playing = false; + } + + if (l < lend) + { + memset(l, 0, sizeof(short) * (lend - l)); + memset(r, 0, sizeof(short) * (lend - l)); + } +} + +static void audio_irq(void) +{ + unsigned long st = DMAINTSTAT & ~DMAINTEN; + int i; + for (i = 0; i < 2; i++) + if (st & (1 << i)) + { + fill_dma_buf((i == 1) ? 0 : DMA_BUF_SAMPLES / 2); + DMAINTSTAT = 1 << i; + } +} + +unsigned long physical_address(void *p) +{ + unsigned long adr = (unsigned long)p; + return (MMUBLOCK((adr >> 21) & 0xf) << 21) | (adr & ((1 << 21) - 1)); +} + +void pcm_init(void) +{ + int i; + callback_for_more = NULL; + pcm_playing = false; + pcm_paused = false; + + memset(dma_buf_left, 0, sizeof(dma_buf_left)); + memset(dma_buf_right, 0, sizeof(dma_buf_right)); + + for (i = 0; i < 8; i++) + { + DMASRC(i) = 0; + DMADEST(i) = 0; + DMALEN(i) = 0x1ffff; + DMAR0C(i) = 0; + DMAR10(i) = 0; + DMAR1C(i) = 0; + } + + DMAINTSTAT = 0xc000ffff; + DMAINTEN = 0xc000ffff; + + DMASRC(0) = physical_address(dma_buf_left); + DMADEST(0) = 0x80200280; + DMALEN(0) = 0xff; + DMAR1C(0) = 0; + DMAR0C(0) = 0x40408; + + DMASRC(1) = physical_address(dma_buf_right); + DMADEST(1) = 0x80200284; + DMALEN(1) = 0xff; + DMAR1C(1) = 0; + DMAR0C(1) = 0x40409; + + irq_set_int_handler(0x1b, audio_irq); + irq_enable_int(0x1b); + + DMAINTSTAT = 1; + DMAINTSTAT = 2; + DMAINTEN &= ~3; + DMAR10(0) |= 1; + DMAR10(1) |= 1; +} + +void pcm_set_frequency(unsigned int frequency) +{ + pcm_freq=frequency; +} +size_t pcm_get_bytes_waiting(void) +{ + return p_size; +} #endif void pcm_play_stop(void) @@ -699,7 +863,7 @@ bool pcm_is_paused(void) { void pcm_calculate_peaks(int *left, int *right) { -#if (CONFIG_CPU == PNX0101 || CONFIG_CPU == S3C2440) +#if (CONFIG_CPU == S3C2440) (void)left; (void)right; #else @@ -710,7 +874,8 @@ void pcm_calculate_peaks(int *left, int *right) size_t samples = (BCR0 & 0xffffff) / 4; addr = (short *) (SAR0 & ~3); #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ - || defined(HAVE_WM8731) || defined(HAVE_WM8721) + || defined(HAVE_WM8731) || defined(HAVE_WM8721) \ + || (CONFIG_CPU == PNX0101) size_t samples = p_size / 4; addr = p; #endif diff --git a/firmware/sound.c b/firmware/sound.c index 5e4cd5db48..a3a8eed806 100644 --- a/firmware/sound.c +++ b/firmware/sound.c @@ -34,6 +34,8 @@ #include "wm8731l.h" #elif defined(HAVE_TLV320) #include "tlv320.h" +#elif CONFIG_CPU == PNX0101 +#include "pnx0101.h" #endif #include "dac.h" #include "system.h" @@ -85,6 +87,8 @@ static const struct sound_settings_info sound_settings_table[] = { [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25, sound_set_volume}, [SOUND_BASS] = {"dB", 0, 1, -6, 9, 0, sound_set_bass}, [SOUND_TREBLE] = {"dB", 0, 1, -6, 9, 0, sound_set_treble}, +#elif (CONFIG_CPU == PNX0101) + [SOUND_VOLUME] = {"dB", 0, 1, -48, 15, 0, sound_set_volume}, #else /* MAS3507D */ [SOUND_VOLUME] = {"dB", 0, 1, -78, 18, -18, sound_set_volume}, [SOUND_BASS] = {"dB", 0, 1, -15, 15, 7, sound_set_bass}, @@ -599,8 +603,8 @@ void sound_set_volume(int value) current_volume = value * 10; /* tenth of dB */ set_prescaled_volume(); #elif CONFIG_CPU == PNX0101 - /* TODO: implement for iFP */ - (void)value; + int tmp = (60 - value * 4) & 0xff; + CODECVOL = tmp | (tmp << 8); #endif } -- cgit