Index: firmware/pcm_playback.c =================================================================== RCS file: /cvsroot/rockbox/firmware/pcm_playback.c,v retrieving revision 1.105 diff -u -r1.105 pcm_playback.c --- firmware/pcm_playback.c 10 Mar 2006 13:47:12 -0000 1.105 +++ firmware/pcm_playback.c 10 Apr 2006 18:11:55 -0000 @@ -33,6 +33,8 @@ #include "tlv320.h" #elif defined(HAVE_WM8731) #include "wm8731l.h" +#elif CONFIG_CPU == PNX0101 +#include "pnx0101.h" #endif #include "system.h" #include "logf.h" @@ -682,13 +684,146 @@ #elif (CONFIG_CPU == PNX0101) -/* TODO: Implement for iFP7xx - For now, just implement some dummy functions. -*/ +static struct { + unsigned short* p; + long p_size; + bool pcm_playing; + bool pcm_paused; + void (*callback_for_more)(unsigned char**, size_t*); +} pcm_state; + + +#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 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_state.pcm_playing && !pcm_state.pcm_paused) + { + do + { + int count; + unsigned short *tmp_p; + count = MIN(pcm_state.p_size / 4, lend - l); + tmp_p = pcm_state.p; + pcm_state.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--; + } + pcm_state.p = tmp_p; + if (l >= lend) + return; + else if (pcm_state.callback_for_more) + pcm_state.callback_for_more((unsigned char**)&pcm_state.p, + &pcm_state.p_size); + } + while (pcm_state.p_size); + pcm_state.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; + pcm_state.callback_for_more = NULL; + pcm_state.pcm_playing = false; + pcm_state.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) @@ -699,13 +834,15 @@ void pcm_play_data(void (*get_more)(unsigned char** start, size_t* size), unsigned char* start, size_t size) { - (void)get_more; - (void)start; - (void)size; + pcm_state.callback_for_more = get_more; + pcm_state.p = (unsigned short *)start; + pcm_state.p_size = size; + pcm_state.pcm_playing = true; } void pcm_play_stop(void) { + pcm_state.pcm_playing = false; } void pcm_mute(bool mute) @@ -715,33 +852,28 @@ void pcm_play_pause(bool play) { - (void)play; + if (!pcm_state.pcm_playing) + return; + pcm_state.pcm_paused = !play; } bool pcm_is_paused(void) { - return false; + return pcm_state.pcm_paused; } bool pcm_is_playing(void) { - return false; -} - -void pcm_calculate_peaks(int *left, int *right) -{ - (void)left; - (void)right; + return pcm_state.pcm_playing; } size_t pcm_get_bytes_waiting(void) { - return 0; + return pcm_state.p_size; } #endif -#if (CONFIG_CPU != PNX0101) /* * This function goes directly into the DMA buffer to calculate the left and * right peak values. To avoid missing peaks it tries to look forward two full @@ -771,6 +903,9 @@ #elif defined(HAVE_TLV320) size_t samples = 4; /* TODO X5 */ addr = NULL; +#elif CONFIG_CPU == PNX0101 + size_t samples = pcm_state.p_size / 4; + addr = pcm_state.p; #endif if (samples > PEAK_SAMPLES) @@ -823,5 +958,3 @@ *right = peak_value; } } - -#endif Index: firmware/sound.c =================================================================== RCS file: /cvsroot/rockbox/firmware/sound.c,v retrieving revision 1.29 diff -u -r1.29 sound.c --- firmware/sound.c 28 Feb 2006 00:58:17 -0000 1.29 +++ firmware/sound.c 10 Apr 2006 18:11:55 -0000 @@ -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" @@ -557,8 +559,10 @@ current_volume = value * 10; /* tenth of dB */ set_prescaled_volume(); #elif CONFIG_CPU == PNX0101 - /* TODO: implement for iFP */ - (void)value; + int tmp = 0xff - (value + 78); + if (tmp < 0x10) tmp = 0x10; + if (tmp > 0xfc) tmp = 0xfc; + CODECVOL = tmp | (tmp << 8); #endif } Index: firmware/export/pnx0101.h =================================================================== RCS file: /cvsroot/rockbox/firmware/export/pnx0101.h,v retrieving revision 1.1 diff -u -r1.1 pnx0101.h --- firmware/export/pnx0101.h 12 Jan 2006 00:35:50 -0000 1.1 +++ firmware/export/pnx0101.h 10 Apr 2006 18:11:56 -0000 @@ -64,3 +64,16 @@ #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)