From 80308386e78d32f46ffe5c36db4cd330a73ee092 Mon Sep 17 00:00:00 2001 From: Tim Newsham Date: Sun, 15 Feb 2015 20:52:53 -1000 Subject: [PATCH] - fix am335x interrupt handling and disable watchdog --- include/plat/am335x/plat/machine/devices.h | 4 ++ src/plat/am335x/machine/hardware.c | 84 +++++++++++++++++----- 2 files changed, 72 insertions(+), 16 deletions(-) diff --git a/include/plat/am335x/plat/machine/devices.h b/include/plat/am335x/plat/machine/devices.h index 58f2928dd..adbe8758b 100644 --- a/include/plat/am335x/plat/machine/devices.h +++ b/include/plat/am335x/plat/machine/devices.h @@ -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 diff --git a/src/plat/am335x/machine/hardware.c b/src/plat/am335x/machine/hardware.c index 199baf03c..6a5771256 100644 --- a/src/plat/am335x/machine/hardware.c +++ b/src/plat/am335x/machine/hardware.c @@ -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(); }