AS3525: Implement a true audio pause and full-resolution audio tick. Take care of a few atomic hotspots.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29088 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
77075be279
commit
c04f1a23c7
3 changed files with 85 additions and 30 deletions
|
@ -33,7 +33,7 @@ void dma_retain(void)
|
|||
if(++dma_used == 1)
|
||||
{
|
||||
bitset32(&CGU_PERI, CGU_DMA_CLOCK_ENABLE);
|
||||
DMAC_CONFIGURATION |= (1<<0);
|
||||
bitset32(&DMAC_CONFIGURATION, 1<<0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ void dma_release(void)
|
|||
{
|
||||
if(--dma_used == 0)
|
||||
{
|
||||
DMAC_CONFIGURATION &= ~(1<<0);
|
||||
bitclr32(&DMAC_CONFIGURATION, 1<<0);
|
||||
bitclr32(&CGU_PERI, CGU_DMA_CLOCK_ENABLE);
|
||||
}
|
||||
if (dma_used < 0)
|
||||
|
@ -56,11 +56,33 @@ void dma_init(void)
|
|||
VIC_INT_ENABLE = INTERRUPT_DMAC;
|
||||
}
|
||||
|
||||
void dma_disable_channel(int channel)
|
||||
void dma_pause_channel(int channel)
|
||||
{
|
||||
DMAC_CH_CONFIGURATION(channel) &= ~(1<<0);
|
||||
/* Disable the channel - clears the FIFO after sending last word */
|
||||
bitclr32(&DMAC_CH_CONFIGURATION(channel), 1<<0);
|
||||
/* Wait for it to go inactive */
|
||||
while (DMAC_CH_CONFIGURATION(channel) & (1<<17));
|
||||
}
|
||||
|
||||
void dma_resume_channel(int channel)
|
||||
{
|
||||
/* Resume - must reinit to where it left off (so the docs say) */
|
||||
unsigned long control = DMAC_CH_CONTROL(channel);
|
||||
if ((control & 0x7ff) == 0)
|
||||
return; /* empty */
|
||||
|
||||
DMAC_INT_TC_CLEAR = (1<<channel);
|
||||
DMAC_INT_ERR_CLEAR = (1<<channel);
|
||||
DMAC_CH_SRC_ADDR(channel) = DMAC_CH_SRC_ADDR(channel);
|
||||
DMAC_CH_DST_ADDR(channel) = DMAC_CH_DST_ADDR(channel);
|
||||
DMAC_CH_LLI(channel) = DMAC_CH_LLI(channel);
|
||||
DMAC_CH_CONTROL(channel) = control;
|
||||
bitset32(&DMAC_CH_CONFIGURATION(channel), (1<<0));
|
||||
}
|
||||
|
||||
void dma_disable_channel(int channel) \
|
||||
__attribute__((alias("dma_pause_channel")));
|
||||
|
||||
void dma_enable_channel(int channel, void *src, void *dst, int peri,
|
||||
int flow_controller, bool src_inc, bool dst_inc,
|
||||
size_t size, int nwords, void (*callback)(void))
|
||||
|
|
|
@ -38,6 +38,8 @@ void dma_enable_channel(int channel, void *src, void *dst, int peri,
|
|||
int flow_controller, bool src_inc, bool dst_inc,
|
||||
size_t size, int nwords, void (*callback)(void));
|
||||
void dma_disable_channel(int channel);
|
||||
void dma_pause_channel(int channel);
|
||||
void dma_resume_channel(int channel);
|
||||
|
||||
void dma_retain(void);
|
||||
void dma_release(void);
|
||||
|
|
|
@ -35,9 +35,11 @@
|
|||
* and the number of 32bits words has to
|
||||
* fit in 11 bits of DMA register */
|
||||
|
||||
static void *dma_start_addr;
|
||||
static size_t dma_size; /* in 4*32 bits */
|
||||
static size_t play_sub_size; /* size of subtransfer */
|
||||
static void *dma_start_addr; /* Pointer to callback buffer */
|
||||
static size_t dma_start_size; /* Size of callback buffer */
|
||||
static void *dma_sub_addr; /* Pointer to sub buffer */
|
||||
static size_t dma_rem_size; /* Remaining size - in 4*32 bits */
|
||||
static size_t play_sub_size; /* size of current subtransfer */
|
||||
static void dma_callback(void);
|
||||
static int locked = 0;
|
||||
static bool is_playing = false;
|
||||
|
@ -66,23 +68,22 @@ void pcm_play_unlock(void)
|
|||
|
||||
static void play_start_pcm(void)
|
||||
{
|
||||
const unsigned char* addr = dma_start_addr;
|
||||
size_t size = dma_size;
|
||||
const void *addr = dma_sub_addr;
|
||||
size_t size = dma_rem_size;
|
||||
if(size > MAX_TRANSFER)
|
||||
size = MAX_TRANSFER;
|
||||
|
||||
play_sub_size = size;
|
||||
|
||||
clean_dcache_range((void*)addr, size); /* force write back */
|
||||
dma_enable_channel(1, (void*)addr, (void*)I2SOUT_DATA, DMA_PERI_I2SOUT,
|
||||
DMAC_FLOWCTRL_DMAC_MEM_TO_PERI, true, false, size >> 2, DMA_S1,
|
||||
dma_callback);
|
||||
DMAC_FLOWCTRL_DMAC_MEM_TO_PERI, true, false, size >> 2,
|
||||
DMA_S1, dma_callback);
|
||||
}
|
||||
|
||||
static void dma_callback(void)
|
||||
{
|
||||
dma_size -= play_sub_size;
|
||||
dma_start_addr += play_sub_size;
|
||||
dma_sub_addr += play_sub_size;
|
||||
dma_rem_size -= play_sub_size;
|
||||
play_sub_size = 0; /* Might get called again if locked */
|
||||
|
||||
if(locked)
|
||||
|
@ -91,12 +92,18 @@ static void dma_callback(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if(!dma_size)
|
||||
if(!dma_rem_size)
|
||||
{
|
||||
pcm_play_get_more_callback(&dma_start_addr, &dma_size);
|
||||
pcm_play_get_more_callback(&dma_start_addr, &dma_start_size);
|
||||
|
||||
if (!dma_size)
|
||||
if (!dma_start_size)
|
||||
return;
|
||||
|
||||
dma_sub_addr = dma_start_addr;
|
||||
dma_rem_size = dma_start_size;
|
||||
|
||||
/* force writeback */
|
||||
clean_dcache_range(dma_start_addr, dma_start_size);
|
||||
}
|
||||
|
||||
play_start_pcm();
|
||||
|
@ -104,8 +111,10 @@ static void dma_callback(void)
|
|||
|
||||
void pcm_play_dma_start(const void *addr, size_t size)
|
||||
{
|
||||
dma_size = size;
|
||||
dma_start_addr = (unsigned char*)addr;
|
||||
dma_start_addr = (void*)addr;
|
||||
dma_start_size = size;
|
||||
dma_sub_addr = dma_start_addr;
|
||||
dma_rem_size = size;
|
||||
|
||||
bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE);
|
||||
CGU_AUDIO |= (1<<11);
|
||||
|
@ -114,6 +123,8 @@ void pcm_play_dma_start(const void *addr, size_t size)
|
|||
|
||||
is_playing = true;
|
||||
|
||||
/* force writeback */
|
||||
clean_dcache_range(dma_start_addr, dma_start_size);
|
||||
play_start_pcm();
|
||||
}
|
||||
|
||||
|
@ -121,7 +132,12 @@ void pcm_play_dma_stop(void)
|
|||
{
|
||||
is_playing = false;
|
||||
dma_disable_channel(1);
|
||||
dma_size = 0;
|
||||
|
||||
/* Ensure byte counts read back 0 */
|
||||
DMAC_CH_SRC_ADDR(1) = 0;
|
||||
dma_start_addr = NULL;
|
||||
dma_start_size = 0;
|
||||
dma_rem_size = 0;
|
||||
|
||||
dma_release();
|
||||
|
||||
|
@ -133,15 +149,21 @@ void pcm_play_dma_stop(void)
|
|||
|
||||
void pcm_play_dma_pause(bool pause)
|
||||
{
|
||||
is_playing = !pause;
|
||||
|
||||
if(pause)
|
||||
{
|
||||
is_playing = false;
|
||||
dma_disable_channel(1);
|
||||
dma_pause_channel(1);
|
||||
|
||||
/* if producer's buffer finished, upper layer starts anew */
|
||||
if (dma_rem_size == 0)
|
||||
play_callback_pending = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
play_start_pcm();
|
||||
if (play_sub_size != 0)
|
||||
dma_resume_channel(1);
|
||||
/* else unlock calls the callback if sub buffers remain */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,16 +216,25 @@ void pcm_dma_apply_settings(void)
|
|||
|
||||
size_t pcm_get_bytes_waiting(void)
|
||||
{
|
||||
return dma_size;
|
||||
int oldstatus = disable_irq_save();
|
||||
size_t addr = DMAC_CH_SRC_ADDR(1);
|
||||
size_t start_addr = (size_t)dma_start_addr;
|
||||
size_t start_size = dma_start_size;
|
||||
restore_interrupt(oldstatus);
|
||||
|
||||
return start_size - addr + start_addr;
|
||||
}
|
||||
|
||||
const void * pcm_play_dma_get_peak_buffer(int *count)
|
||||
{
|
||||
pcm_play_lock();
|
||||
void *addr = (void*)DMAC_CH_SRC_ADDR(1);
|
||||
*count = (dma_size - (addr - dma_start_addr)) >> 2;
|
||||
pcm_play_unlock();
|
||||
return AS3525_UNCACHED_ADDR(addr);
|
||||
int oldstatus = disable_irq_save();
|
||||
size_t addr = DMAC_CH_SRC_ADDR(1);
|
||||
size_t start_addr = (size_t)dma_start_addr;
|
||||
size_t start_size = dma_start_size;
|
||||
restore_interrupt(oldstatus);
|
||||
|
||||
*count = (start_size - addr + start_addr) >> 2;
|
||||
return (void*)AS3525_UNCACHED_ADDR(addr);
|
||||
}
|
||||
|
||||
#ifdef HAVE_PCM_DMA_ADDRESS
|
||||
|
|
Loading…
Reference in a new issue