zephyr/drivers/timer/riscv_machine_timer.c
Kumar Gala cc334c7273 Convert remaining code to using newly introduced integer sized types
Convert code to use u{8,16,32,64}_t and s{8,16,32,64}_t instead of C99
integer types.  This handles the remaining includes and kernel, plus
touching up various points that we skipped because of include
dependancies.  We also convert the PRI printf formatters in the arch
code over to normal formatters.

Jira: ZEP-2051

Change-Id: Iecbb12601a3ee4ea936fd7ddea37788a645b08b0
Signed-off-by: Kumar Gala <kumar.gala@linaro.org>
2017-04-21 11:38:23 -05:00

107 lines
2.6 KiB
C

/*
* Copyright (c) 2017 Jean-Paul Etienne <fractalclone@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <arch/cpu.h>
#include <device.h>
#include <system_timer.h>
#include <board.h>
typedef struct {
u32_t val_low;
u32_t val_high;
} riscv_machine_timer_t;
static volatile riscv_machine_timer_t *mtime =
(riscv_machine_timer_t *)RISCV_MTIME_BASE;
static volatile riscv_machine_timer_t *mtimecmp =
(riscv_machine_timer_t *)RISCV_MTIMECMP_BASE;
/*
* The RISCV machine-mode timer is a one shot timer that needs to be rearm upon
* every interrupt. Timer clock is a 64-bits ART.
* To arm timer, we need to read the RTC value and update the
* timer compare register by the RTC value + time interval we want timer
* to interrupt.
*/
static ALWAYS_INLINE void riscv_machine_rearm_timer(void)
{
u64_t rtc;
/*
* Disable timer interrupt while rearming the timer
* to avoid generation of interrupts while setting
* the mtimecmp->val_low register.
*/
irq_disable(RISCV_MACHINE_TIMER_IRQ);
/*
* Following machine-mode timer implementation in QEMU, the actual
* RTC read is performed when reading low timer value register.
* Reading high timer value just reads the most significant 32-bits
* of a cache value, obtained from a previous read to the low
* timer value register. Hence, always read timer->val_low first.
* This also works for other implementations.
*/
rtc = mtime->val_low;
rtc |= ((u64_t)mtime->val_high << 32);
/*
* Rearm timer to generate an interrupt after
* sys_clock_hw_cycles_per_tick
*/
rtc += sys_clock_hw_cycles_per_tick;
mtimecmp->val_low = (u32_t)(rtc & 0xffffffff);
mtimecmp->val_high = (u32_t)((rtc >> 32) & 0xffffffff);
/* Enable timer interrupt */
irq_enable(RISCV_MACHINE_TIMER_IRQ);
}
static void riscv_machine_timer_irq_handler(void *unused)
{
ARG_UNUSED(unused);
_sys_clock_tick_announce();
/* Rearm timer */
riscv_machine_rearm_timer();
}
#ifdef CONFIG_TICKLESS_IDLE
#error "Tickless idle not yet implemented for riscv-machine timer"
#endif
int _sys_clock_driver_init(struct device *device)
{
ARG_UNUSED(device);
IRQ_CONNECT(RISCV_MACHINE_TIMER_IRQ, 0,
riscv_machine_timer_irq_handler, NULL, 0);
/* Initialize timer, just call riscv_machine_rearm_timer */
riscv_machine_rearm_timer();
return 0;
}
/**
*
* @brief Read the platform's timer hardware
*
* This routine returns the current time in terms of timer hardware clock
* cycles.
*
* @return up counter of elapsed clock cycles
*/
u32_t _timer_cycle_get_32(void)
{
/* We just want a cycle count so just post what's in the low 32
* bits of the mtime real-time counter
*/
return mtime->val_low;
}