- fix am335x interrupt handling and disable watchdog
This commit is contained in:
parent
01ba49802c
commit
80308386e7
2 changed files with 72 additions and 16 deletions
|
|
@ -15,6 +15,8 @@
|
|||
#define INTC_PPTR 0xfff01000
|
||||
#define UART0_PPTR 0xfff02000
|
||||
#define DMTIMER0_PPTR 0xfff03000
|
||||
#define WDT1_PPTR 0xfff04000
|
||||
|
||||
|
||||
/* Other devices on the SoC. */
|
||||
#define INTC_PADDR 0x48200000
|
||||
|
|
@ -26,5 +28,7 @@
|
|||
#define DMTIMER5_PADDR 0x48046000
|
||||
#define DMTIMER6_PADDR 0x48048000
|
||||
#define DMTIMER7_PADDR 0x4804A000
|
||||
#define WDT1_PADDR 0x44e35000
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ const p_region_t BOOT_RODATA dev_p_regs[] = {
|
|||
{ /* .start = */ DMTIMER5_PADDR, /* .end = */ DMTIMER5_PADDR + (1 << PAGE_BITS) },
|
||||
{ /* .start = */ DMTIMER6_PADDR, /* .end = */ DMTIMER6_PADDR + (1 << PAGE_BITS) },
|
||||
{ /* .start = */ DMTIMER7_PADDR, /* .end = */ DMTIMER7_PADDR + (1 << PAGE_BITS) },
|
||||
{ /* .start = */ WDT1_PADDR, /* .end = */ WDT1_PADDR + (1 << PAGE_BITS) },
|
||||
/* Board devices. */
|
||||
/* TODO: This should ultimately be replaced with a more general solution. */
|
||||
};
|
||||
|
|
@ -93,6 +94,18 @@ map_kernel_devices(void)
|
|||
)
|
||||
);
|
||||
|
||||
/* map kernel device: WDT1 */
|
||||
map_kernel_frame(
|
||||
WDT1_PADDR,
|
||||
WDT1_PPTR,
|
||||
VMKernelOnly,
|
||||
vm_attributes_new(
|
||||
false, /* armExecuteNever */
|
||||
false, /* armParityEnabled */
|
||||
false /* armPageCacheable */
|
||||
)
|
||||
);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* map kernel device: UART */
|
||||
map_kernel_frame(
|
||||
|
|
@ -108,6 +121,12 @@ map_kernel_devices(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
#define INTCPS_SYSCONFIG_SOFTRESET BIT(1)
|
||||
#define INTCPS_SYSSTATUS_RESETDONE BIT(0)
|
||||
#define INTCPS_CONTROL_NEWIRQAGR BIT(0)
|
||||
#define INTCPS_SIR_IRQ_SPURIOUSIRQFLAG 0xffffff80
|
||||
|
||||
/*
|
||||
* The struct below is used to discourage the compiler from generating literals
|
||||
* for every single address we might access.
|
||||
|
|
@ -136,11 +155,11 @@ volatile struct INTC_map {
|
|||
uint32_t intcps_isr_clear;
|
||||
uint32_t intcps_pending_irq;
|
||||
uint32_t intcps_pending_fiq;
|
||||
} intcps_n[3];
|
||||
uint32_t padding5[8];
|
||||
uint32_t intcps_ilr[96];
|
||||
} intcps_n[4];
|
||||
uint32_t intcps_ilr[128];
|
||||
} *intc = (volatile void*)INTC_PPTR;
|
||||
|
||||
|
||||
/**
|
||||
DONT_TRANSLATE
|
||||
*/
|
||||
|
|
@ -148,23 +167,30 @@ volatile struct INTC_map {
|
|||
interrupt_t
|
||||
getActiveIRQ(void)
|
||||
{
|
||||
interrupt_t irq = intc->intcps_sir_irq;
|
||||
uint32_t intcps_sir_irq = intc->intcps_sir_irq;
|
||||
interrupt_t irq = (interrupt_t)(intcps_sir_irq & 0x7f);
|
||||
|
||||
/* Ignore spurious interrupts. */
|
||||
if ((irq & ~0b1111111) == 0) {
|
||||
assert(irq <= maxIRQ);
|
||||
if ((intcps_sir_irq & INTCPS_SIR_IRQ_SPURIOUSIRQFLAG) == 0) {
|
||||
assert((irq / 32) < (sizeof intc->intcps_n / sizeof intc->intcps_n[0]));
|
||||
if (intc->intcps_n[irq / 32].intcps_pending_irq & (1 << (irq & 31))) {
|
||||
return irq;
|
||||
} else {
|
||||
/* XXX happening a lot for irq=66! */
|
||||
}
|
||||
} else {
|
||||
/* XXX - should never happen? */
|
||||
printf("spurious irq %d / %x\n", irq, intcps_sir_irq);
|
||||
}
|
||||
|
||||
|
||||
/* No interrupt. */
|
||||
return 0xff;
|
||||
return irqInvalid;
|
||||
}
|
||||
|
||||
/* Check for pending IRQ */
|
||||
bool_t isIRQPending(void)
|
||||
{
|
||||
return getActiveIRQ() != 0xff;
|
||||
return getActiveIRQ() != irqInvalid;
|
||||
}
|
||||
|
||||
/* Enable or disable irq according to the 'disable' flag. */
|
||||
|
|
@ -174,6 +200,7 @@ bool_t isIRQPending(void)
|
|||
void
|
||||
maskInterrupt(bool_t disable, interrupt_t irq)
|
||||
{
|
||||
assert(irq <= maxIRQ);
|
||||
if (disable) {
|
||||
intc->intcps_n[irq / 32].intcps_mir_set = 1 << (irq & 31);
|
||||
} else {
|
||||
|
|
@ -185,22 +212,22 @@ maskInterrupt(bool_t disable, interrupt_t irq)
|
|||
bool_t
|
||||
isReservedIRQ(interrupt_t irq)
|
||||
{
|
||||
return false;
|
||||
return irq == KERNEL_TIMER_IRQ;
|
||||
}
|
||||
|
||||
/* Handle a platform-reserved IRQ. */
|
||||
void handleReservedIRQ(irq_t irq)
|
||||
{
|
||||
printf("Received reserved IRQ: %d\n", (int)irq);
|
||||
/* We shouldn't be receiving any reserved IRQs anyway. */
|
||||
maskInterrupt(true, irq);
|
||||
|
||||
return;
|
||||
//maskInterrupt(true, irq);
|
||||
//return;
|
||||
}
|
||||
|
||||
void
|
||||
ackInterrupt(irq_t irq)
|
||||
{
|
||||
intc->intcps_control = 1;
|
||||
intc->intcps_control = INTCPS_CONTROL_NEWIRQAGR;
|
||||
/* Ensure the ack has hit the interrupt controller before potentially
|
||||
* re-enabling interrupts. */
|
||||
dsb();
|
||||
|
|
@ -255,6 +282,25 @@ resetTimer(void)
|
|||
ackInterrupt(DMTIMER0_IRQ);
|
||||
}
|
||||
|
||||
#define WDT_REG(base, off) ((volatile uint32_t *)((base) + (off)))
|
||||
#define WDT_REG_WWPS 0x34
|
||||
#define WDT_REG_WSPR 0x48
|
||||
#define WDT_WWPS_PEND_WSPR BIT(4)
|
||||
|
||||
static BOOT_CODE void
|
||||
disableWatchdog(void)
|
||||
{
|
||||
uint32_t wdt = WDT1_PPTR;
|
||||
|
||||
// am335x ref man, sec 20.4.3.8
|
||||
*WDT_REG(wdt, WDT_REG_WSPR) = 0xaaaa;
|
||||
while((*WDT_REG(wdt, WDT_REG_WWPS) & WDT_WWPS_PEND_WSPR))
|
||||
continue;
|
||||
*WDT_REG(wdt, WDT_REG_WSPR) = 0x5555;
|
||||
while((*WDT_REG(wdt, WDT_REG_WWPS) & WDT_WWPS_PEND_WSPR))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Configure dmtimer0 as kernel preemption timer */
|
||||
/**
|
||||
DONT_TRANSLATE
|
||||
|
|
@ -264,11 +310,14 @@ initTimer(void)
|
|||
{
|
||||
int timeout;
|
||||
|
||||
disableWatchdog();
|
||||
|
||||
timer->cfg = TIOCP_CFG_SOFTRESET;
|
||||
|
||||
for (timeout = 10000; (timer->cfg & TIOCP_CFG_SOFTRESET) && timeout > 0; timeout--)
|
||||
;
|
||||
if (!timeout) {
|
||||
printf("init timer failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -293,12 +342,15 @@ initTimer(void)
|
|||
BOOT_CODE void
|
||||
initIRQController(void)
|
||||
{
|
||||
/* Do nothing */
|
||||
intc->intcps_sysconfig = INTCPS_SYSCONFIG_SOFTRESET;
|
||||
while (!(intc->intcps_sysstatus & INTCPS_SYSSTATUS_RESETDONE)) ;
|
||||
}
|
||||
|
||||
void
|
||||
handleSpuriousIRQ(void)
|
||||
{
|
||||
/* Do nothing */
|
||||
/* Reset and re-enable IRQs. */
|
||||
intc->intcps_control = INTCPS_CONTROL_NEWIRQAGR;
|
||||
dsb();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue