#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: arm11_pmc.c,v 1.9 2025/12/19 13:03:51 nia Exp $");
#include <sys/param.h>
#include <sys/types.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/timetc.h>
#include <dev/clock_subr.h>
#include <arm/armreg.h>
#include <arm/cpufunc.h>
#ifndef ARM11_PMC_CCNT_HZ
# define ARM11_PMC_CCNT_HZ 400000000
#endif
void arm11_pmc_ccnt_init(void);
#define COUNTS_PER_USEC (ARM11_PMC_CCNT_HZ / 1000000)
static uint32_t counts_per_wrap = ~0UL;
static inline uint32_t
arm11_pmc_ctrl_read(void)
{
uint32_t val;
__asm volatile ("mrc p15, 0, %0, c15, c12, 0" : "=r" (val));
return val;
}
static inline void
arm11_pmc_ctrl_write(uint32_t val)
{
__asm volatile ("mcr p15, 0, %0, c15, c12, 0" :: "r" (val));
}
static inline uint32_t
arm11_pmc_ccnt_read(void)
{
uint32_t val;
__asm volatile ("mrc p15, 0, %0, c15, c12, 1" : "=r" (val));
return val;
}
__unused static inline void
arm11_pmc_ccnt_write(uint32_t val)
{
__asm volatile ("mcr p15, 0, %0, c15, c12, 1;" :: "r" (val));
}
void
arm11_pmc_ccnt_init(void)
{
uint32_t val;
val = ARM11_PMCCTL_E | ARM11_PMCCTL_P | ARM11_PMCCTL_C;
arm11_pmc_ctrl_write(val);
}
#define DELAY_ARG_LIMIT (((uint32_t)~0) / COUNTS_PER_USEC)
void
delay(u_int arg)
{
uint32_t ctrl;
uint32_t cur;
uint32_t last;
uint32_t delta = 0;
uint32_t usecs = 0;
if (arg > DELAY_ARG_LIMIT)
panic("delay: arg %u overflow, limit is %d usec\n", arg, DELAY_ARG_LIMIT);
last = arm11_pmc_ccnt_read();
delta = usecs = 0;
while (arg > usecs) {
cur = arm11_pmc_ccnt_read();
ctrl = arm11_pmc_ctrl_read();
if (ctrl & ARM11_PMCCTL_CCR) {
ctrl &= ~(ARM11_PMCCTL_CR0|ARM11_PMCCTL_CR1);
arm11_pmc_ctrl_write(ctrl);
delta += (last + (counts_per_wrap - cur));
} else {
delta += (cur - last);
}
last = cur;
if (delta >= COUNTS_PER_USEC) {
usecs += delta / COUNTS_PER_USEC;
delta %= COUNTS_PER_USEC;
}
}
}