#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.11 2020/05/29 12:30:40 rin Exp $");
#include "opt_multiprocessor.h"
#include <sys/param.h>
#include <sys/cpu.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/timetc.h>
#include <mips/ingenic/ingenic_var.h>
#include <mips/ingenic/ingenic_regs.h>
#include "opt_ingenic.h"
extern void ingenic_puts(const char *);
void ingenic_clockintr(struct clockframe *);
static u_int
ingenic_count_read(struct timecounter *tc)
{
return readreg(JZ_OST_CNT_LO);
}
void
cpu_initclocks(void)
{
struct cpu_info * const ci = curcpu();
uint32_t cnt;
static struct timecounter tc = {
.tc_get_timecount = ingenic_count_read,
.tc_counter_mask = ~0u,
.tc_frequency = 12000000,
.tc_name = "Ingenic OS timer",
.tc_quality = 100,
};
curcpu()->ci_cctr_freq = tc.tc_frequency;
tc_init(&tc);
printf("starting timer interrupt...\n");
cnt = readreg(JZ_OST_CNT_LO);
ci->ci_next_cp0_clk_intr = cnt + ci->ci_cycles_per_hz;
writereg(JZ_TC_TFCR, TFR_OSTFLAG);
writereg(JZ_OST_DATA, ci->ci_next_cp0_clk_intr);
#ifdef USE_OST
writereg(JZ_TC_TMCR, TFR_OSTFLAG);
#else
writereg(JZ_TC_TECR, TESR_TCST5);
writereg(JZ_TC_TCNT(5), 0);
writereg(JZ_TC_TDFR(5), 30000);
writereg(JZ_TC_TDHR(5), 60000);
writereg(JZ_TC_TCSR(5), TCSR_EXT_EN| TCSR_DIV_16);
writereg(JZ_TC_TMCR, TFR_FFLAG5);
writereg(JZ_TC_TFCR, TFR_FFLAG5);
writereg(JZ_TC_TESR, TESR_TCST5);
#endif
#ifdef INGENIC_CLOCK_DEBUG
printf("INTC %08x %08x\n", readreg(JZ_ICSR0), readreg(JZ_ICSR1));
printf("ICMR0 %08x\n", readreg(JZ_ICMR0));
#endif
writereg(JZ_ICMCR0, 0x0c000000);
spl0();
#ifdef INGENIC_CLOCK_DEBUG
printf("TFR: %08x\n", readreg(JZ_TC_TFR));
printf("TMR: %08x\n", readreg(JZ_TC_TMR));
printf("cnt5: %08x\n", readreg(JZ_TC_TCNT(5)));
printf("CR: %08x\n", MFC0(MIPS_COP_0_CAUSE, 0));
printf("SR: %08x\n", MFC0(MIPS_COP_0_STATUS, 0));
delay(100000);
printf("TFR: %08x\n", readreg(JZ_TC_TFR));
printf("TMR: %08x\n", readreg(JZ_TC_TMR));
printf("cnt5: %08x\n", readreg(JZ_TC_TCNT(5)));
printf("CR: %08x\n", MFC0(MIPS_COP_0_CAUSE, 0));
printf("SR: %08x\n", MFC0(MIPS_COP_0_STATUS, 0));
printf("TFR: %08x\n", readreg(JZ_TC_TFR));
printf("TMR: %08x\n", readreg(JZ_TC_TMR));
printf("cnt5: %08x\n", readreg(JZ_TC_TCNT(5)));
printf("CR: %08x\n", MFC0(MIPS_COP_0_CAUSE, 0));
printf("SR: %08x\n", MFC0(MIPS_COP_0_STATUS, 0));
printf("INTC %08x %08x\n", readreg(JZ_ICSR0), readreg(JZ_ICSR1));
delay(3000000);
printf("%s %d\n", __func__, MFC0(12, 3));
printf("%s %08x\n", __func__, MFC0(12, 4));
#endif
}
void
delay(int n)
{
u_long divisor_delay;
uint32_t cur, last, delta, usecs;
last = readreg(JZ_OST_CNT_LO);
delta = usecs = 0;
divisor_delay = curcpu()->ci_divisor_delay;
if (divisor_delay == 0) {
#define FAST_FREQ (300 * 1000 * 1000)
divisor_delay = FAST_FREQ / (1000 * 1000);
}
while (n > usecs) {
cur = readreg(JZ_OST_CNT_LO);
delta += (cur - last);
last = cur;
while (delta >= divisor_delay) {
usecs++;
delta -= divisor_delay;
}
}
}
void
setstatclockrate(int r)
{
}
#ifdef INGENIC_CLOCK_DEBUG
int cnt = 99;
#endif
void
ingenic_clockintr(struct clockframe *cf)
{
int s = splsched();
struct cpu_info * const ci = curcpu();
#ifdef USE_OST
uint32_t new_cnt;
#endif
writereg(JZ_TC_TFCR, TFR_OSTFLAG);
ci->ci_next_cp0_clk_intr += (uint32_t)(ci->ci_cycles_per_hz & 0xffffffff);
#ifdef USE_OST
writereg(JZ_OST_DATA, ci->ci_next_cp0_clk_intr);
new_cnt = readreg(JZ_OST_CNT_LO);
if ((ci->ci_next_cp0_clk_intr - new_cnt) & 0x80000000) {
ci->ci_next_cp0_clk_intr = new_cnt + curcpu()->ci_cycles_per_hz;
writereg(JZ_OST_DATA, ci->ci_next_cp0_clk_intr);
curcpu()->ci_ev_count_compare_missed.ev_count++;
}
writereg(JZ_TC_TFCR, TFR_OSTFLAG);
#else
writereg(JZ_TC_TFCR, TFR_FFLAG5);
#endif
#ifdef INGENIC_CLOCK_DEBUG
cnt++;
if (cnt == 100) {
cnt = 0;
ingenic_puts("+");
}
#endif
#ifdef MULTIPROCESSOR
mips_cp0_corembox_write(1, 1 << IPI_CLOCK);
#endif
hardclock(cf);
splx(s);
}