diff --git a/hal/sparcv8leon/gaisler/irqmp.c b/hal/sparcv8leon/gaisler/irqmp.c index bc6cab27..1291e7b6 100644 --- a/hal/sparcv8leon/gaisler/irqmp.c +++ b/hal/sparcv8leon/gaisler/irqmp.c @@ -120,8 +120,8 @@ static void interrupts_enableIRQ(unsigned int irqn) { int i; - /* TLB and Systick IRQ should fire on all cores */ - if ((irqn == TLB_IRQ) || (irqn == TIMER_IRQ)) { + /* TLB and Wakeup Timer IRQ should fire on all cores */ + if ((irqn == TLB_IRQ) || (irqn == TIMER0_2_IRQ)) { for (i = 0; i < hal_cpuGetCount(); ++i) { *(interrupts_common.int_ctrl + INT_MASK_0 + i) |= (1 << irqn); } diff --git a/hal/sparcv8leon/gaisler/timer.c b/hal/sparcv8leon/gaisler/timer.c index a3bcb79b..eefbf126 100644 --- a/hal/sparcv8leon/gaisler/timer.c +++ b/hal/sparcv8leon/gaisler/timer.c @@ -40,31 +40,49 @@ #define GPT_TCTRL(n) ((n * 4) + 2) /* Timer n control register : 0xn8 */ #define GPT_TLATCH(n) ((n * 4) + 3) /* Timer n latch register : 0xnC */ -#define TIMER_DEFAULT 1 +#define TIMER_TIMEBASE 1 +#define TIMER_WAKEUP 2 static struct { volatile u32 *timer0_base; - intr_handler_t handler; + intr_handler_t timebaseHandler; + intr_handler_t wakeupHandler; volatile time_t jiffies; spinlock_t sp; u32 ticksPerFreq; } timer_common; +static void timer_clearIrq(int timer) +{ + /* Clear irq status - set & clear to handle different GPTIMER core versions */ + *(timer_common.timer0_base + GPT_TCTRL(timer)) |= TIMER_INT_PENDING; + hal_cpuDataStoreBarrier(); + *(timer_common.timer0_base + GPT_TCTRL(timer)) &= ~TIMER_INT_PENDING; + hal_cpuDataStoreBarrier(); +} + + static int _timer_irqHandler(unsigned int irq, cpu_context_t *ctx, void *data) { - volatile u32 st = *(timer_common.timer0_base + GPT_TCTRL(TIMER_DEFAULT)) & TIMER_INT_PENDING; + volatile u32 st; + spinlock_ctx_t sc; + int timer = (irq == TIMER0_1_IRQ) ? TIMER_TIMEBASE : TIMER_WAKEUP; + + hal_spinlockSet(&timer_common.sp, &sc); + + st = *(timer_common.timer0_base + GPT_TCTRL(timer)) & TIMER_INT_PENDING; if (st != 0) { - ++timer_common.jiffies; - /* Clear irq status - set & clear to handle different GPTIMER core versions */ - *(timer_common.timer0_base + GPT_TCTRL(TIMER_DEFAULT)) |= TIMER_INT_PENDING; - hal_cpuDataStoreBarrier(); - *(timer_common.timer0_base + GPT_TCTRL(TIMER_DEFAULT)) &= ~TIMER_INT_PENDING; - hal_cpuDataStoreBarrier(); + if (timer == TIMER_TIMEBASE) { + ++timer_common.jiffies; + } + timer_clearIrq(timer); } + hal_spinlockClear(&timer_common.sp, &sc); + return 0; } @@ -75,40 +93,64 @@ static inline void timer_setReloadValue(int timer, u32 val) } -static void timer_setPrescaler(int timer, u32 freq) +static void timer_setPrescaler(int timer, u32 interval) { u32 prescaler = SYSCLK_FREQ / 1000000; /* 1 MHz */ - u32 ticks = (SYSCLK_FREQ / prescaler) / freq; - timer_setReloadValue(timer, ticks - 1); + timer_setReloadValue(timer, interval - 1); *(timer_common.timer0_base + GPT_SRELOAD) = prescaler - 1; - timer_common.ticksPerFreq = ticks; + timer_common.ticksPerFreq = interval; } time_t hal_timerGetUs(void) { + u32 regVal; time_t val; spinlock_ctx_t sc; hal_spinlockSet(&timer_common.sp, &sc); + + regVal = *(timer_common.timer0_base + GPT_TCNTVAL(TIMER_TIMEBASE)); + + /* Check if there's pending irq */ + if ((*(timer_common.timer0_base + GPT_TCTRL(TIMER_TIMEBASE)) & TIMER_INT_PENDING) != 0) { + ++timer_common.jiffies; + timer_clearIrq(TIMER_TIMEBASE); + /* Timer might've just wrapped-around, take counter value again */ + regVal = *(timer_common.timer0_base + GPT_TCNTVAL(TIMER_TIMEBASE)); + } val = timer_common.jiffies; + hal_spinlockClear(&timer_common.sp, &sc); - return val * 1000ULL; + return val * timer_common.ticksPerFreq + timer_common.ticksPerFreq - regVal; } void hal_timerSetWakeup(u32 waitUs) { + spinlock_ctx_t sc; + + hal_spinlockSet(&timer_common.sp, &sc); + + /* Disable timer */ + *(timer_common.timer0_base + GPT_TCTRL(TIMER_WAKEUP)) = 0; + timer_clearIrq(TIMER_WAKEUP); + + /* Configure one shot timer */ + timer_setReloadValue(TIMER_WAKEUP, waitUs); + *(timer_common.timer0_base + GPT_TCTRL(TIMER_WAKEUP)) = TIMER_ENABLE | TIMER_INT_ENABLE | TIMER_LOAD; + + hal_spinlockClear(&timer_common.sp, &sc); } int hal_timerRegister(int (*f)(unsigned int, cpu_context_t *, void *), void *data, intr_handler_t *h) { h->f = f; - h->n = TIMER_IRQ; + h->n = TIMER0_2_IRQ; h->data = data; return hal_interruptsSetHandler(h); @@ -132,27 +174,29 @@ void _hal_timerInit(u32 interval) timer_common.timer0_base = _pmap_halMapDevice(PAGE_ALIGN(GPTIMER0_BASE), PAGE_OFFS(GPTIMER0_BASE), SIZE_PAGE); /* Disable timer interrupts - bits cleared when written 1 */ - st = *(timer_common.timer0_base + GPT_TCTRL(TIMER_DEFAULT)) & (TIMER_INT_ENABLE | TIMER_INT_PENDING); - *(timer_common.timer0_base + GPT_TCTRL(TIMER_DEFAULT)) = st; - /* Disable timer */ - *(timer_common.timer0_base + GPT_TCTRL(TIMER_DEFAULT)) = 0; + st = *(timer_common.timer0_base + GPT_TCTRL(TIMER_TIMEBASE)) & (TIMER_INT_ENABLE | TIMER_INT_PENDING); + *(timer_common.timer0_base + GPT_TCTRL(TIMER_TIMEBASE)) = st; + /* Disable timers */ + *(timer_common.timer0_base + GPT_TCTRL(TIMER_TIMEBASE)) = 0; + *(timer_common.timer0_base + GPT_TCTRL(TIMER_WAKEUP)) = 0; /* Reset counter and reload value */ - *(timer_common.timer0_base + GPT_TCNTVAL(TIMER_DEFAULT)) = 0; - timer_setReloadValue(TIMER_DEFAULT, 0); - - timer_common.handler.f = NULL; - timer_common.handler.n = TIMER_IRQ; - timer_common.handler.data = NULL; + *(timer_common.timer0_base + GPT_TCNTVAL(TIMER_TIMEBASE)) = 0; + timer_setReloadValue(TIMER_TIMEBASE, 0); - timer_setPrescaler(TIMER_DEFAULT, interval); + timer_setPrescaler(TIMER_TIMEBASE, interval); hal_spinlockCreate(&timer_common.sp, "timer"); - timer_common.handler.f = _timer_irqHandler; - timer_common.handler.n = TIMER_IRQ; - timer_common.handler.data = NULL; - hal_interruptsSetHandler(&timer_common.handler); + timer_common.timebaseHandler.f = _timer_irqHandler; + timer_common.timebaseHandler.n = TIMER0_1_IRQ; + timer_common.timebaseHandler.data = NULL; + hal_interruptsSetHandler(&timer_common.timebaseHandler); + + timer_common.wakeupHandler.f = _timer_irqHandler; + timer_common.wakeupHandler.n = TIMER0_2_IRQ; + timer_common.wakeupHandler.data = NULL; + hal_interruptsSetHandler(&timer_common.wakeupHandler); /* Enable timer and interrupts */ /* Load reload value into counter register */ - *(timer_common.timer0_base + GPT_TCTRL(TIMER_DEFAULT)) |= TIMER_ENABLE | TIMER_INT_ENABLE | TIMER_LOAD | TIMER_PERIODIC; + *(timer_common.timer0_base + GPT_TCTRL(TIMER_TIMEBASE)) |= TIMER_ENABLE | TIMER_INT_ENABLE | TIMER_LOAD | TIMER_PERIODIC; } diff --git a/hal/sparcv8leon/hal.c b/hal/sparcv8leon/hal.c index ab9bc4db..98f54708 100644 --- a/hal/sparcv8leon/hal.c +++ b/hal/sparcv8leon/hal.c @@ -97,5 +97,5 @@ void _hal_init(void) _hal_platformInit(); _hal_cpuInit(); _hal_consoleInit(); - _hal_timerInit(SYSTICK_INTERVAL); + _hal_timerInit(0xffffffffu); }