mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-09 21:25:19 -05:00
i.MX31: Remove long udelay from DVFS interrupt handler
Split the ISR into two parts and alllow quick return from first half. Introduces a uevent() API to have a callback happen in a specified number of microseconds. Right now only one event is supported. Change-Id: Ib1666165be2f6082e5275d64961f083cab104f9f
This commit is contained in:
parent
4877f618d6
commit
0a7d941fb9
6 changed files with 140 additions and 88 deletions
|
|
@ -56,7 +56,7 @@ void INIT_ATTR tick_start(unsigned int interval_in_ms)
|
|||
EPITCR1 = EPITCR_CLKSRC_IPG_CLK | EPITCR_WAITEN | EPITCR_IOVW |
|
||||
((2640-1) << EPITCR_PRESCALER_POS) | EPITCR_RLD |
|
||||
EPITCR_OCIEN | EPITCR_ENMOD;
|
||||
|
||||
|
||||
EPITLR1 = interval_in_ms*25; /* Count down from interval */
|
||||
EPITCMPR1 = 0; /* Event when counter reaches 0 */
|
||||
EPITSR1 = EPITSR_OCIF; /* Clear any pending interrupt */
|
||||
|
|
@ -86,9 +86,3 @@ void tick_stop(void)
|
|||
EPITSR1 = EPITSR_OCIF; /* Clear pending */
|
||||
ccm_module_clock_gating(CG_EPIT1, CGM_OFF); /* Turn off module clock */
|
||||
}
|
||||
|
||||
|
||||
void kernel_audio_locking(bool locking)
|
||||
{
|
||||
dvfs_int_mask(locking);
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ static void play_dma_callback(void)
|
|||
PCM_DMAST_ERR_DMA : PCM_DMAST_OK;
|
||||
const void *addr;
|
||||
size_t size;
|
||||
|
||||
|
||||
if (pcm_play_dma_complete_callback(status, &addr, &size))
|
||||
{
|
||||
play_start_dma(addr, size);
|
||||
|
|
@ -114,33 +114,20 @@ static void play_dma_callback(void)
|
|||
|
||||
void pcm_play_lock(void)
|
||||
{
|
||||
/* Need to prevent DVFS from causing interrupt priority inversion if audio
|
||||
* is locked and a DVFS interrupt fires, blocking reenabling of audio by a
|
||||
* low-priority mode for at least the duration of the lengthy DVFS routine.
|
||||
* Not really an issue with state changes but lockout when playing.
|
||||
*
|
||||
* Keep direct use of DVFS code away from here though. This could provide
|
||||
* more services in the future anyway. */
|
||||
kernel_audio_locking(true);
|
||||
++dma_play_data.locked;
|
||||
}
|
||||
|
||||
void pcm_play_unlock(void)
|
||||
{
|
||||
if (--dma_play_data.locked == 0)
|
||||
if (--dma_play_data.locked == 0 && dma_play_data.state != 0)
|
||||
{
|
||||
if (dma_play_data.state != 0)
|
||||
{
|
||||
int oldstatus = disable_irq_save();
|
||||
int pending = dma_play_data.callback_pending;
|
||||
dma_play_data.callback_pending = 0;
|
||||
restore_irq(oldstatus);
|
||||
int oldstatus = disable_irq_save();
|
||||
int pending = dma_play_data.callback_pending;
|
||||
dma_play_data.callback_pending = 0;
|
||||
restore_irq(oldstatus);
|
||||
|
||||
if (pending != 0)
|
||||
play_dma_callback();
|
||||
}
|
||||
|
||||
kernel_audio_locking(false);
|
||||
if (pending != 0)
|
||||
play_dma_callback();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -368,26 +355,20 @@ static void rec_dma_callback(void)
|
|||
|
||||
void pcm_rec_lock(void)
|
||||
{
|
||||
kernel_audio_locking(true);
|
||||
++dma_rec_data.locked;
|
||||
}
|
||||
|
||||
void pcm_rec_unlock(void)
|
||||
{
|
||||
if (--dma_rec_data.locked == 0)
|
||||
if (--dma_rec_data.locked == 0 && dma_rec_data.state != 0)
|
||||
{
|
||||
if (dma_rec_data.state != 0)
|
||||
{
|
||||
int oldstatus = disable_irq_save();
|
||||
int pending = dma_rec_data.callback_pending;
|
||||
dma_rec_data.callback_pending = 0;
|
||||
restore_irq(oldstatus);
|
||||
int oldstatus = disable_irq_save();
|
||||
int pending = dma_rec_data.callback_pending;
|
||||
dma_rec_data.callback_pending = 0;
|
||||
restore_irq(oldstatus);
|
||||
|
||||
if (pending != 0)
|
||||
rec_dma_callback();
|
||||
}
|
||||
|
||||
kernel_audio_locking(false);
|
||||
if (pending != 0)
|
||||
rec_dma_callback();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,62 @@ void watchdog_service(void)
|
|||
WDOG_WSR = 0xaaaa;
|
||||
}
|
||||
|
||||
/** GPT timer routines - basis for udelay **/
|
||||
|
||||
/** uevent APIs **/
|
||||
|
||||
static void (*ucallback)(void) = NULL; /* uevent callback */
|
||||
|
||||
static void cancel_uevent(void)
|
||||
{
|
||||
GPTSR = GPTSR_OF1;
|
||||
GPTIR &= ~GPTIR_OF1IE;
|
||||
ucallback = NULL;
|
||||
}
|
||||
|
||||
static void __attribute__((interrupt("IRQ"))) GPT_HANDLER(void)
|
||||
{
|
||||
uevent_cb_type cb = ucallback;
|
||||
cancel_uevent();
|
||||
cb();
|
||||
}
|
||||
|
||||
void uevent(unsigned long usecs, uevent_cb_type callback)
|
||||
{
|
||||
if (!callback || ucallback)
|
||||
return; /* Is busy */
|
||||
|
||||
unsigned long status = disable_interrupt_save(IRQ_FIQ_STATUS);
|
||||
|
||||
ucallback = callback;
|
||||
|
||||
for (int i = 0; i < 1; i++)
|
||||
{
|
||||
unsigned long utime = GPTCNT;
|
||||
unsigned long time = utime + usecs + 1;
|
||||
|
||||
GPTOCR1 = time;
|
||||
GPTSR = GPTSR_OF1;
|
||||
GPTIR |= GPTIR_OF1IE;
|
||||
|
||||
if (TIME_BEFORE(GPTCNT, time))
|
||||
break; /* Didn't miss it */
|
||||
}
|
||||
|
||||
restore_interrupt(status);
|
||||
}
|
||||
|
||||
void uevent_cancel(void)
|
||||
{
|
||||
unsigned long status = disable_interrupt_save(IRQ_FIQ_STATUS);
|
||||
|
||||
if (ucallback)
|
||||
cancel_uevent();
|
||||
|
||||
restore_interrupt(status);
|
||||
}
|
||||
|
||||
|
||||
/** GPT timer routines - basis for udelay/uevent **/
|
||||
|
||||
/* Start the general-purpose timer (1MHz) */
|
||||
void gpt_start(void)
|
||||
|
|
@ -102,13 +157,20 @@ void gpt_start(void)
|
|||
*/
|
||||
GPTCR = GPTCR_FRR | GPTCR_WAITEN | GPTCR_CLKSRC_IPG_CLK;
|
||||
GPTPR = ipg_mhz - 1;
|
||||
GPTSR = GPTSR_OF1;
|
||||
GPTCR |= GPTCR_EN;
|
||||
|
||||
avic_enable_int(INT_GPT, INT_TYPE_IRQ, INT_PRIO_GPT, GPT_HANDLER);
|
||||
}
|
||||
|
||||
/* Stop the general-purpose timer */
|
||||
void gpt_stop(void)
|
||||
{
|
||||
unsigned long status = disable_interrupt_save(IRQ_FIQ_STATUS);
|
||||
avic_disable_int(INT_GPT);
|
||||
cancel_uevent();
|
||||
GPTCR &= ~GPTCR_EN;
|
||||
restore_interrupt(status);
|
||||
}
|
||||
|
||||
int system_memory_guard(int newmode)
|
||||
|
|
@ -258,7 +320,7 @@ void dumpregs(void)
|
|||
"mov %3,r12":
|
||||
"=r"(regs.r8),"=r"(regs.r9),
|
||||
"=r"(regs.r10),"=r"(regs.r11):);
|
||||
|
||||
|
||||
asm volatile ("mov %0,r12\n\t"
|
||||
"mov %1,sp\n\t"
|
||||
"mov %2,lr\n\t"
|
||||
|
|
@ -280,7 +342,7 @@ void dumpregs(void)
|
|||
DEBUGF("R8=0x%x\tR9=0x%x\tR10=0x%x\tR11=0x%x\n",regs.r8,regs.r9,regs.r10,regs.r11);
|
||||
DEBUGF("R12=0x%x\tSP=0x%x\tLR=0x%x\tPC=0x%x\n",regs.r12,regs.sp,regs.lr,regs.pc);
|
||||
//DEBUGF("CPSR=0x%x\t\n",regs.cpsr);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@ static inline unsigned long usec_timer(void)
|
|||
return GPTCNT;
|
||||
}
|
||||
|
||||
/* Fire an event usecs microseconds from now */
|
||||
typedef void (* uevent_cb_type)(void);
|
||||
void uevent(unsigned long usecs, uevent_cb_type callback);
|
||||
void uevent_cancel(void);
|
||||
|
||||
void watchdog_init(unsigned int half_seconds);
|
||||
void watchdog_service(void);
|
||||
|
||||
|
|
@ -58,9 +63,6 @@ void tick_stop(void);
|
|||
void kernel_device_init(void);
|
||||
void system_halt(void);
|
||||
|
||||
/* Handle some audio lockout related tasks */
|
||||
void kernel_audio_locking(bool locking);
|
||||
|
||||
#define KDEV_INIT
|
||||
|
||||
struct ARM_REGS {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue