#include <sys/cdefs.h>
__RCSID("$NetBSD: clock_machdep.c,v 1.10 2025/11/08 16:20:17 skrll Exp $");
#include <sys/param.h>
#include <sys/cpu.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/timetc.h>
#include <machine/machdep.h>
#include <machine/sbi.h>
#include <machine/sysreg.h>
static void (*_riscv_timer_init)(void) = riscv_timer_init;
static uint32_t timer_frequency;
static uint32_t timer_ticks_per_hz;
static uint32_t timer_ticks_per_usec;
static u_int
timer_get_timecount(struct timecounter *tc)
{
return csr_time_read();
}
static struct timecounter tc = {
.tc_get_timecount = timer_get_timecount,
.tc_counter_mask = ~0u,
.tc_name = "riscv",
.tc_quality = 100,
};
void
riscv_timer_frequency_set(uint32_t freq)
{
timer_frequency = freq;
timer_ticks_per_hz = freq / hz;
timer_ticks_per_usec = freq / 1000000;
}
uint32_t
riscv_timer_frequency_get(void)
{
return timer_frequency;
}
void
riscv_timer_register(void (*timerfn)(void))
{
if (_riscv_timer_init != NULL) {
#ifdef DIAGNOSTIC
aprint_verbose("%s: timer already registered\n", __func__);
#endif
}
_riscv_timer_init = timerfn;
}
void
riscv_timer_init(void)
{
struct cpu_info * const ci = curcpu();
evcnt_attach_dynamic(&ci->ci_ev_timer, EVCNT_TYPE_INTR,
NULL, device_xname(ci->ci_dev), "timer");
evcnt_attach_dynamic(&ci->ci_ev_timer_missed, EVCNT_TYPE_MISC,
NULL, device_xname(ci->ci_dev), "timer missed");
ci->ci_lastintr = csr_time_read();
uint64_t next = ci->ci_lastintr + timer_ticks_per_hz;
ci->ci_lastintr_scheduled = next;
sbi_set_timer(next);
csr_sie_set(SIE_STIE);
if (cpu_index(ci) == 0) {
tc.tc_frequency = timer_frequency;
tc_init(&tc);
}
}
int
riscv_timer_intr(void *arg)
{
struct cpu_info * const ci = curcpu();
struct clockframe * const cf = arg;
csr_sip_clear(SIP_STIP);
const uint64_t now = csr_time_read();
ci->ci_lastintr = now;
ci->ci_ev_timer.ev_count++;
do {
ci->ci_lastintr_scheduled += timer_ticks_per_hz;
if (__predict_true(ci->ci_lastintr_scheduled > now))
break;
ci->ci_ev_timer_missed.ev_count++;
} while (true);
sbi_set_timer(ci->ci_lastintr_scheduled);
hardclock(cf);
return 1;
}
void
cpu_initclocks(void)
{
if (_riscv_timer_init == NULL)
panic("cpu_initclocks: no timer registered");
_riscv_timer_init();
}
void
setstatclockrate(int newhz)
{
}
void
delay(unsigned long us)
{
const uint64_t ticks = (uint64_t)us * timer_ticks_per_usec;
const uint64_t finish = csr_time_read() + ticks;
while (csr_time_read() < finish) {
}
}