1
0
Fork 0
forked from len0rd/rockbox

iPod Classic: Fix remaining PCM issues and add DMA information to the HW debug screen

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28991 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sparmann 2011-01-07 15:16:17 +00:00
parent 67a85912c8
commit 46945eff06
3 changed files with 93 additions and 37 deletions

View file

@ -29,6 +29,7 @@
#include "storage.h" #include "storage.h"
#include "power.h" #include "power.h"
#include "pmu-target.h" #include "pmu-target.h"
#include "pcm-target.h"
/* Skeleton for adding target specific debug info to the debug menu /* Skeleton for adding target specific debug info to the debug menu
*/ */
@ -40,7 +41,7 @@ bool __dbg_hw_info(void)
int line; int line;
int i; int i;
unsigned int state = 0; unsigned int state = 0;
const unsigned int max_states=2; const unsigned int max_states=3;
lcd_clear_display(); lcd_clear_display();
lcd_setfont(FONT_SYSFIXED); lcd_setfont(FONT_SYSFIXED);
@ -81,6 +82,16 @@ bool __dbg_hw_info(void)
_DEBUG_PRINTF("backlight: %s", pmu_read(0x29) ? "on" : "off"); _DEBUG_PRINTF("backlight: %s", pmu_read(0x29) ? "on" : "off");
_DEBUG_PRINTF("brightness value: %d", pmu_read(0x28)); _DEBUG_PRINTF("brightness value: %d", pmu_read(0x28));
} }
else if(state==2)
{
_DEBUG_PRINTF("Audio DMA:");
_DEBUG_PRINTF(">%08X %08X %08X %08X %08X", DMAC0C0CONFIG, DMAC0C0SRCADDR,
DMAC0C0DESTADDR, DMAC0C0NEXTLLI, DMAC0C0CONTROL);
for(i = 0; i < PCM_LLICOUNT; i++)
_DEBUG_PRINTF("%08X: %08X %08X %08X %08X", &pcm_lli[i], pcm_lli[i].srcaddr,
pcm_lli[i].dstaddr, pcm_lli[i].nextlli, pcm_lli[i].control);
_DEBUG_PRINTF("chunk: %08X %08X", pcm_chunksize, pcm_remaining);
}
else else
{ {
state=0; state=0;

View file

@ -29,21 +29,17 @@
#include "pcm.h" #include "pcm.h"
#include "pcm_sampr.h" #include "pcm_sampr.h"
#include "mmu-arm.h" #include "mmu-arm.h"
#include "pcm-target.h"
/* S5L8702 PCM driver tunables: */
#define LLIMAX (2047) /* Maximum number of samples per LLI */
#define CHUNKSIZE (8700) /* Maximum number of samples to handle with one IRQ */
/* (bigger chunks will be segmented internally) */
#define WATERMARK (512) /* Number of remaining samples to schedule IRQ at */
static volatile int locked = 0; static volatile int locked = 0;
static const int zerosample = 0; static const int zerosample = 0;
static unsigned char dblbuf[WATERMARK * 4] IBSS_ATTR; static unsigned char dblbuf[2][PCM_WATERMARK * 4];
struct dma_lli lli[(CHUNKSIZE - WATERMARK + LLIMAX - 1) / LLIMAX + 1] static int active_dblbuf;
__attribute__((aligned(16))); struct dma_lli pcm_lli[PCM_LLICOUNT] __attribute__((aligned(16)));
struct dma_lli* lastlli; static struct dma_lli* lastlli;
static const unsigned char* dataptr; static const unsigned char* dataptr;
static size_t remaining; size_t pcm_remaining;
size_t pcm_chunksize;
/* Mask the DMA interrupt */ /* Mask the DMA interrupt */
void pcm_play_lock(void) void pcm_play_lock(void)
@ -66,54 +62,63 @@ void INT_DMAC0C0(void) ICODE_ATTR;
void INT_DMAC0C0(void) void INT_DMAC0C0(void)
{ {
DMAC0INTTCCLR = 1; DMAC0INTTCCLR = 1;
if (!remaining) pcm_play_get_more_callback((void**)&dataptr, &remaining); if (!pcm_remaining)
if (!remaining)
{ {
lli->nextlli = NULL; pcm_play_get_more_callback((void**)&dataptr, &pcm_remaining);
lli->control = 0x75249000; pcm_chunksize = pcm_remaining;
}
if (!pcm_remaining)
{
pcm_lli->nextlli = NULL;
pcm_lli->control = 0x75249000;
clean_dcache(); clean_dcache();
return; return;
} }
uint32_t lastsize = MIN(WATERMARK * 4, remaining); uint32_t lastsize = MIN(PCM_WATERMARK * 4, pcm_remaining / 2 + 1) & ~1;
remaining -= lastsize; pcm_remaining -= lastsize;
if (remaining) lastlli = &lli[ARRAYLEN(lli) - 1]; if (pcm_remaining) lastlli = &pcm_lli[ARRAYLEN(pcm_lli) - 1];
else lastlli = lli; else lastlli = pcm_lli;
uint32_t chunksize = MIN(CHUNKSIZE * 4 - lastsize, remaining); uint32_t chunksize = MIN(PCM_CHUNKSIZE * 4 - lastsize, pcm_remaining);
if (remaining > chunksize && chunksize > remaining - WATERMARK * 4) if (pcm_remaining > chunksize && chunksize > pcm_remaining - PCM_WATERMARK * 8)
chunksize = remaining - WATERMARK * 4; chunksize = pcm_remaining - PCM_WATERMARK * 8;
remaining -= chunksize; pcm_remaining -= chunksize;
bool last = !chunksize; bool last = !chunksize;
int i = 0; int i = 0;
while (chunksize) while (chunksize)
{ {
uint32_t thislli = MIN(LLIMAX * 4, chunksize); uint32_t thislli = MIN(PCM_LLIMAX * 4, chunksize);
chunksize -= thislli; chunksize -= thislli;
lli[i].srcaddr = (void*)dataptr; pcm_lli[i].srcaddr = (void*)dataptr;
lli[i].dstaddr = (void*)((int)&I2STXDB0); pcm_lli[i].dstaddr = (void*)((int)&I2STXDB0);
lli[i].nextlli = chunksize ? &lli[i + 1] : lastlli; pcm_lli[i].nextlli = chunksize ? &pcm_lli[i + 1] : lastlli;
lli[i].control = (chunksize ? 0x75249000 : 0xf5249000) | (thislli / 2); pcm_lli[i].control = (chunksize ? 0x75249000 : 0xf5249000) | (thislli / 2);
dataptr += thislli; dataptr += thislli;
i++; i++;
} }
if (!remaining) memcpy(dblbuf, dataptr, lastsize); if (!pcm_remaining)
lastlli->srcaddr = remaining ? dataptr : dblbuf; {
memcpy(dblbuf[active_dblbuf], dataptr, lastsize);
lastlli->srcaddr = dblbuf[active_dblbuf];
active_dblbuf ^= 1;
}
else lastlli->srcaddr = dataptr;
lastlli->dstaddr = (void*)((int)&I2STXDB0); lastlli->dstaddr = (void*)((int)&I2STXDB0);
lastlli->nextlli = last ? NULL : lli; lastlli->nextlli = last ? NULL : pcm_lli;
lastlli->control = (last ? 0xf5249000 : 0x75249000) | (lastsize / 2); lastlli->control = (last ? 0xf5249000 : 0x75249000) | (lastsize / 2);
dataptr += lastsize; dataptr += lastsize;
clean_dcache(); clean_dcache();
if (!(DMAC0C0CONFIG & 1) && (lli[0].control & 0xfff)) if (!(DMAC0C0CONFIG & 1) && (pcm_lli[0].control & 0xfff))
{ {
DMAC0C0LLI = lli[0]; DMAC0C0LLI = pcm_lli[0];
DMAC0C0CONFIG = 0x8a81; DMAC0C0CONFIG = 0x8a81;
} }
else DMAC0C0NEXTLLI = lli; else DMAC0C0NEXTLLI = pcm_lli;
} }
void pcm_play_dma_start(const void* addr, size_t size) void pcm_play_dma_start(const void* addr, size_t size)
{ {
dataptr = (const unsigned char*)addr; dataptr = (const unsigned char*)addr;
remaining = size; pcm_remaining = size;
I2STXCOM = 0xe; I2STXCOM = 0xe;
DMAC0CONFIG |= 4; DMAC0CONFIG |= 4;
INT_DMAC0C0(); INT_DMAC0C0();
@ -155,7 +160,7 @@ void pcm_dma_apply_settings(void)
size_t pcm_get_bytes_waiting(void) size_t pcm_get_bytes_waiting(void)
{ {
int bytes = remaining; int bytes = pcm_remaining;
const struct dma_lli* lli = (const struct dma_lli*)((int)&DMAC0C0LLI); const struct dma_lli* lli = (const struct dma_lli*)((int)&DMAC0C0LLI);
while (lli) while (lli)
{ {

View file

@ -0,0 +1,40 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id: system-target.h 28791 2010-12-11 09:39:33Z Buschel $
*
* Copyright (C) 2010 by Michael Sparmann
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef __PCM_TARGET_H__
#define __PCM_TARGET_H__
/* S5L8702 PCM driver tunables: */
#define PCM_LLIMAX (2047) /* Maximum number of samples per LLI */
#define PCM_CHUNKSIZE (10747) /* Maximum number of samples to handle with one IRQ */
/* (bigger chunks will be segmented internally) */
#define PCM_WATERMARK (512) /* Number of remaining samples to schedule IRQ at */
#define PCM_LLICOUNT ((PCM_CHUNKSIZE - PCM_WATERMARK + PCM_LLIMAX - 1) / PCM_LLIMAX + 1)
extern struct dma_lli pcm_lli[PCM_LLICOUNT];
extern size_t pcm_remaining;
extern size_t pcm_chunksize;
#endif /* __PCM_TARGET_H__ */