Skip to content

Commit

Permalink
hal/sparcv8leon: implement hp timer
Browse files Browse the repository at this point in the history
JIRA: RTOS-969
  • Loading branch information
lukileczo committed Nov 15, 2024
1 parent 4c07551 commit 1dd3c26
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 34 deletions.
4 changes: 2 additions & 2 deletions hal/sparcv8leon/gaisler/irqmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {

Check failure on line 124 in hal/sparcv8leon/gaisler/irqmp.c

View workflow job for this annotation

GitHub Actions / call-ci / build (sparcv8leon-generic-qemu)

'TIMER0_2_IRQ' undeclared (first use in this function); did you mean 'TIMER_IRQ'?
for (i = 0; i < hal_cpuGetCount(); ++i) {
*(interrupts_common.int_ctrl + INT_MASK_0 + i) |= (1 << irqn);
}
Expand Down
106 changes: 75 additions & 31 deletions hal/sparcv8leon/gaisler/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Check failure on line 71 in hal/sparcv8leon/gaisler/timer.c

View workflow job for this annotation

GitHub Actions / call-ci / build (sparcv8leon-generic-qemu)

'TIMER0_1_IRQ' undeclared (first use in this function); did you mean 'TIMER_IRQ'?

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;
}

Expand All @@ -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;

Check failure on line 153 in hal/sparcv8leon/gaisler/timer.c

View workflow job for this annotation

GitHub Actions / call-ci / build (sparcv8leon-generic-qemu)

'TIMER0_2_IRQ' undeclared (first use in this function); did you mean 'TIMER_IRQ'?
h->data = data;

return hal_interruptsSetHandler(h);
Expand All @@ -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;

Check failure on line 190 in hal/sparcv8leon/gaisler/timer.c

View workflow job for this annotation

GitHub Actions / call-ci / build (sparcv8leon-generic-qemu)

'TIMER0_1_IRQ' undeclared (first use in this function); did you mean 'TIMER_IRQ'?
timer_common.timebaseHandler.data = NULL;
hal_interruptsSetHandler(&timer_common.timebaseHandler);

timer_common.wakeupHandler.f = _timer_irqHandler;
timer_common.wakeupHandler.n = TIMER0_2_IRQ;

Check failure on line 195 in hal/sparcv8leon/gaisler/timer.c

View workflow job for this annotation

GitHub Actions / call-ci / build (sparcv8leon-generic-qemu)

'TIMER0_2_IRQ' undeclared (first use in this function); did you mean 'TIMER_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;
}
2 changes: 1 addition & 1 deletion hal/sparcv8leon/hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,5 @@ void _hal_init(void)
_hal_platformInit();
_hal_cpuInit();
_hal_consoleInit();
_hal_timerInit(SYSTICK_INTERVAL);
_hal_timerInit(0xffffffffu);
}

0 comments on commit 1dd3c26

Please sign in to comment.