forked from len0rd/rockbox
FS#6096. Recording on PortalPlayer targets (H10, iPod Video, iPod 4g, iPod Color, iPod Nano).
* Fix failed compile of enc_config.c when HAVE_MPEG2_SAMPR is not defined. * Fix bug in AIFF encoder header creation on little endian targets. * Add recording screen keymaps for H10 and iPod. * Move pcm_playback PP specific code to target tree. * Add recording code to wmcodec drivers. * Add pcm_record code. Some problems still remain: * Playback doesn't work after recording until Rockbox is restarted. * Gain control not implemented. * Only 16-bit/44KHz for now. The hardware should be capable of up to 24-bit/96KHz. * Line-in recording not tested on H10. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11794 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
440353a9aa
commit
df0dc2262e
24 changed files with 961 additions and 369 deletions
|
|
@ -98,326 +98,6 @@ size_t pcm_get_bytes_waiting(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|
||||
|| defined(HAVE_WM8731) || defined(HAVE_WM8721) \
|
||||
|| defined(HAVE_PP5024_CODEC)
|
||||
|
||||
/* We need to unify this code with the uda1380 code as much as possible, but
|
||||
we will keep it separate during early development.
|
||||
*/
|
||||
|
||||
#if CONFIG_CPU == PP5020
|
||||
#define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x3f0000) >> 16)
|
||||
#elif CONFIG_CPU == PP5002
|
||||
#define FIFO_FREE_COUNT ((IISFIFO_CFG & 0x7800000) >> 23)
|
||||
#elif CONFIG_CPU == PP5024
|
||||
#define FIFO_FREE_COUNT 4 /* TODO: make this sensible */
|
||||
#endif
|
||||
|
||||
static int pcm_freq = HW_SAMPR_DEFAULT; /* 44.1 is default */
|
||||
|
||||
/* NOTE: The order of these two variables is important if you use the iPod
|
||||
assembler optimised fiq handler, so don't change it. */
|
||||
unsigned short* p IBSS_ATTR;
|
||||
size_t p_size IBSS_ATTR;
|
||||
|
||||
void pcm_play_dma_start(const void *addr, size_t size)
|
||||
{
|
||||
p=(unsigned short*)addr;
|
||||
p_size=size;
|
||||
|
||||
pcm_playing = true;
|
||||
|
||||
#if CONFIG_CPU == PP5020
|
||||
/* setup I2S interrupt for FIQ */
|
||||
outl(inl(0x6000402c) | I2S_MASK, 0x6000402c);
|
||||
outl(I2S_MASK, 0x60004024);
|
||||
#elif CONFIG_CPU == PP5024
|
||||
#else
|
||||
/* setup I2S interrupt for FIQ */
|
||||
outl(inl(0xcf00102c) | DMA_OUT_MASK, 0xcf00102c);
|
||||
outl(DMA_OUT_MASK, 0xcf001024);
|
||||
#endif
|
||||
|
||||
/* Clear the FIQ disable bit in cpsr_c */
|
||||
enable_fiq();
|
||||
|
||||
/* Enable playback FIFO */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x20000000;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISCONFIG |= 0x4;
|
||||
#endif
|
||||
|
||||
/* Fill the FIFO - we assume there are enough bytes in the pcm buffer to
|
||||
fill the 32-byte FIFO. */
|
||||
while (p_size > 0) {
|
||||
if (FIFO_FREE_COUNT < 2) {
|
||||
/* Enable interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x2;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISFIFO_CFG |= (1<<9);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
p_size-=4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Stops the DMA transfer and interrupt */
|
||||
void pcm_play_dma_stop(void)
|
||||
{
|
||||
pcm_playing = false;
|
||||
|
||||
#if CONFIG_CPU == PP5020
|
||||
|
||||
/* Disable playback FIFO */
|
||||
IISCONFIG &= ~0x20000000;
|
||||
|
||||
/* Disable the interrupt */
|
||||
IISCONFIG &= ~0x2;
|
||||
|
||||
#elif CONFIG_CPU == PP5002
|
||||
|
||||
/* Disable playback FIFO */
|
||||
IISCONFIG &= ~0x4;
|
||||
|
||||
/* Disable the interrupt */
|
||||
IISFIFO_CFG &= ~(1<<9);
|
||||
#endif
|
||||
|
||||
disable_fiq();
|
||||
}
|
||||
|
||||
void pcm_play_pause_pause(void)
|
||||
{
|
||||
#if CONFIG_CPU == PP5020
|
||||
/* Disable the interrupt */
|
||||
IISCONFIG &= ~0x2;
|
||||
/* Disable playback FIFO */
|
||||
IISCONFIG &= ~0x20000000;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
/* Disable the interrupt */
|
||||
IISFIFO_CFG &= ~(1<<9);
|
||||
/* Disable playback FIFO */
|
||||
IISCONFIG &= ~0x4;
|
||||
#endif
|
||||
disable_fiq();
|
||||
}
|
||||
|
||||
void pcm_play_pause_unpause(void)
|
||||
{
|
||||
/* Enable the FIFO and fill it */
|
||||
|
||||
enable_fiq();
|
||||
|
||||
/* Enable playback FIFO */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x20000000;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISCONFIG |= 0x4;
|
||||
#endif
|
||||
|
||||
/* Fill the FIFO - we assume there are enough bytes in the
|
||||
pcm buffer to fill the 32-byte FIFO. */
|
||||
while (p_size > 0) {
|
||||
if (FIFO_FREE_COUNT < 2) {
|
||||
/* Enable interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x2;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISFIFO_CFG |= (1<<9);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
p_size-=4;
|
||||
}
|
||||
}
|
||||
|
||||
void pcm_set_frequency(unsigned int frequency)
|
||||
{
|
||||
(void)frequency;
|
||||
pcm_freq = HW_SAMPR_DEFAULT;
|
||||
}
|
||||
|
||||
size_t pcm_get_bytes_waiting(void)
|
||||
{
|
||||
return p_size;
|
||||
}
|
||||
|
||||
/* ASM optimised FIQ handler. GCC fails to make use of the fact that FIQ mode
|
||||
has registers r8-r14 banked, and so does not need to be saved. This routine
|
||||
uses only these registers, and so will never touch the stack unless it
|
||||
actually needs to do so when calling pcm_callback_for_more. C version is
|
||||
still included below for reference.
|
||||
*/
|
||||
#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002
|
||||
void fiq(void) ICODE_ATTR __attribute__((naked));
|
||||
void fiq(void)
|
||||
{
|
||||
/* r12 contains IISCONFIG address (set in crt0.S to minimise code in actual
|
||||
* FIQ handler. r11 contains address of p (also set in crt0.S). Most other
|
||||
* addresses we need are generated by using offsets with these two.
|
||||
* r12 + 0x40 is IISFIFO_WR, and r12 + 0x0c is IISFIFO_CFG.
|
||||
* r8 and r9 contains local copies of p_size and p respectively.
|
||||
* r10 is a working register.
|
||||
*/
|
||||
asm volatile (
|
||||
#if CONFIG_CPU == PP5002
|
||||
"ldr r10, =0xcf001040 \n\t" /* Some magic from iPodLinux */
|
||||
"ldr r10, [r10] \n\t"
|
||||
"ldr r10, [r12, #0x1c]\n\t"
|
||||
"bic r10, r10, #0x200 \n\t" /* clear interrupt */
|
||||
"str r10, [r12, #0x1c]\n\t"
|
||||
#else
|
||||
"ldr r10, [r12] \n\t"
|
||||
"bic r10, r10, #0x2 \n\t" /* clear interrupt */
|
||||
"str r10, [r12] \n\t"
|
||||
#endif
|
||||
"ldr r8, [r11, #4] \n\t" /* r8 = p_size */
|
||||
"ldr r9, [r11] \n\t" /* r9 = p */
|
||||
".loop: \n\t"
|
||||
"cmp r8, #0 \n\t" /* is p_size 0? */
|
||||
"beq .more_data \n\t" /* if so, ask pcmbuf for more data */
|
||||
".fifo_loop: \n\t"
|
||||
#if CONFIG_CPU == PP5002
|
||||
"ldr r10, [r12, #0x1c]\n\t" /* read IISFIFO_CFG to check FIFO status */
|
||||
"and r10, r10, #0x7800000\n\t"
|
||||
"cmp r10, #0x800000 \n\t"
|
||||
#else
|
||||
"ldr r10, [r12, #0x0c]\n\t" /* read IISFIFO_CFG to check FIFO status */
|
||||
"and r10, r10, #0x3f0000\n\t"
|
||||
"cmp r10, #0x10000 \n\t"
|
||||
#endif
|
||||
"bls .fifo_full \n\t" /* FIFO full, exit */
|
||||
"ldr r10, [r9], #4 \n\t" /* load two samples */
|
||||
"mov r10, r10, ror #16\n\t" /* put left sample at the top bits */
|
||||
"str r10, [r12, #0x40]\n\t" /* write top sample, lower sample ignored */
|
||||
"mov r10, r10, lsl #16\n\t" /* shift lower sample up */
|
||||
"str r10, [r12, #0x40]\n\t" /* then write it */
|
||||
"subs r8, r8, #4 \n\t" /* check if we have more samples */
|
||||
"bne .fifo_loop \n\t" /* yes, continue */
|
||||
".more_data: \n\t"
|
||||
"stmdb sp!, { r0-r3, r12, lr}\n\t" /* stack scratch regs and lr */
|
||||
"mov r0, r11 \n\t" /* r0 = &p */
|
||||
"add r1, r11, #4 \n\t" /* r1 = &p_size */
|
||||
"str r9, [r0] \n\t" /* save internal copies of variables back */
|
||||
"str r8, [r1] \n\t"
|
||||
"ldr r2, =pcm_callback_for_more\n\t"
|
||||
"ldr r2, [r2] \n\t" /* get callback address */
|
||||
"cmp r2, #0 \n\t" /* check for null pointer */
|
||||
"movne lr, pc \n\t" /* call pcm_callback_for_more */
|
||||
"bxne r2 \n\t"
|
||||
"ldmia sp!, { r0-r3, r12, lr}\n\t"
|
||||
"ldr r8, [r11, #4] \n\t" /* reload p_size and p */
|
||||
"ldr r9, [r11] \n\t"
|
||||
"cmp r8, #0 \n\t" /* did we actually get more data? */
|
||||
"bne .loop \n\t" /* yes, continue to try feeding FIFO */
|
||||
".dma_stop: \n\t" /* no more data, do dma_stop() and exit */
|
||||
"ldr r10, =pcm_playing\n\t"
|
||||
"strb r8, [r10] \n\t" /* pcm_playing = false (r8=0, look above) */
|
||||
"ldr r10, [r12] \n\t"
|
||||
#if CONFIG_CPU == PP5002
|
||||
"bic r10, r10, #0x4\n\t" /* disable playback FIFO */
|
||||
"str r10, [r12] \n\t"
|
||||
"ldr r10, [r12, #0x1c] \n\t"
|
||||
"bic r10, r10, #0x200 \n\t" /* clear interrupt */
|
||||
"str r10, [r12, #0x1c] \n\t"
|
||||
#else
|
||||
"bic r10, r10, #0x20000002\n\t" /* disable playback FIFO and IRQ */
|
||||
"str r10, [r12] \n\t"
|
||||
#endif
|
||||
"mrs r10, cpsr \n\t"
|
||||
"orr r10, r10, #0x40 \n\t" /* disable FIQ */
|
||||
"msr cpsr_c, r10 \n\t"
|
||||
".exit: \n\t"
|
||||
"str r8, [r11, #4] \n\t"
|
||||
"str r9, [r11] \n\t"
|
||||
"subs pc, lr, #4 \n\t" /* FIQ specific return sequence */
|
||||
".fifo_full: \n\t" /* enable IRQ and exit */
|
||||
#if CONFIG_CPU == PP5002
|
||||
"ldr r10, [r12, #0x1c]\n\t"
|
||||
"orr r10, r10, #0x200 \n\t" /* set interrupt */
|
||||
"str r10, [r12, #0x1c]\n\t"
|
||||
#else
|
||||
"ldr r10, [r12] \n\t"
|
||||
"orr r10, r10, #0x2 \n\t" /* set interrupt */
|
||||
"str r10, [r12] \n\t"
|
||||
#endif
|
||||
"b .exit \n\t"
|
||||
);
|
||||
}
|
||||
#else /* !(CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002) */
|
||||
void fiq(void) ICODE_ATTR __attribute__ ((interrupt ("FIQ")));
|
||||
void fiq(void)
|
||||
{
|
||||
/* Clear interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG &= ~0x2;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
inl(0xcf001040);
|
||||
IISFIFO_CFG &= ~(1<<9);
|
||||
#endif
|
||||
|
||||
do {
|
||||
while (p_size) {
|
||||
if (FIFO_FREE_COUNT < 2) {
|
||||
/* Enable interrupt */
|
||||
#if CONFIG_CPU == PP5020
|
||||
IISCONFIG |= 0x2;
|
||||
#elif CONFIG_CPU == PP5002
|
||||
IISFIFO_CFG |= (1<<9);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
IISFIFO_WR = (*(p++))<<16;
|
||||
p_size-=4;
|
||||
}
|
||||
|
||||
/* p is empty, get some more data */
|
||||
if (pcm_callback_for_more) {
|
||||
pcm_callback_for_more((unsigned char**)&p,&p_size);
|
||||
}
|
||||
} while (p_size);
|
||||
|
||||
/* No more data, so disable the FIFO/FIQ */
|
||||
pcm_play_dma_stop();
|
||||
}
|
||||
#endif /* CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 */
|
||||
|
||||
#ifdef HAVE_PP5024_CODEC
|
||||
void pcm_init(void)
|
||||
{
|
||||
}
|
||||
#else
|
||||
void pcm_init(void)
|
||||
{
|
||||
pcm_playing = false;
|
||||
pcm_paused = false;
|
||||
pcm_callback_for_more = NULL;
|
||||
|
||||
/* Initialize default register values. */
|
||||
audiohw_init();
|
||||
|
||||
/* Power on */
|
||||
audiohw_enable_output(true);
|
||||
|
||||
/* Unmute the master channel (DAC should be at zero point now). */
|
||||
audiohw_mute(false);
|
||||
|
||||
/* Call pcm_play_dma_stop to initialize everything. */
|
||||
pcm_play_dma_stop();
|
||||
}
|
||||
#endif /* HAVE_PP5024_CODEC */
|
||||
#elif (CONFIG_CPU == PNX0101)
|
||||
|
||||
#define DMA_BUF_SAMPLES 0x100
|
||||
|
|
@ -608,7 +288,7 @@ void pcm_mute(bool mute)
|
|||
if (mute)
|
||||
sleep(HZ/16);
|
||||
}
|
||||
|
||||
#if !defined(CPU_PP)
|
||||
/*
|
||||
* 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
|
||||
|
|
@ -632,9 +312,7 @@ void pcm_calculate_peaks(int *left, int *right)
|
|||
short *addr;
|
||||
short *end;
|
||||
{
|
||||
#if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|
||||
|| defined(HAVE_WM8731) || defined(HAVE_WM8721) \
|
||||
|| (CONFIG_CPU == PNX0101) || defined(HAVE_PP5024_CODEC)
|
||||
#if CONFIG_CPU == PNX0101
|
||||
size_t samples = p_size / 4;
|
||||
addr = p;
|
||||
#endif
|
||||
|
|
@ -690,7 +368,7 @@ void pcm_calculate_peaks(int *left, int *right)
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* CPU_COLDFIRE */
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue