#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: oclock.c,v 1.21 2021/01/24 07:36:54 mrg Exp $");
#include "opt_sparc_arch.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <machine/promlib.h>
#include <machine/autoconf.h>
#include <sparc/sparc/timervar.h>
#include <dev/clock_subr.h>
#include <dev/ic/intersil7170reg.h>
#include <dev/ic/intersil7170var.h>
static int oclockmatch(device_t, cfdata_t, void *);
static void oclockattach(device_t, device_t, void *);
CFATTACH_DECL_NEW(oclock, sizeof(struct intersil7170_softc),
oclockmatch, oclockattach, NULL, NULL);
#if defined(SUN4)
static bus_space_tag_t i7_bt;
static bus_space_handle_t i7_bh;
#define intersil_disable() \
bus_space_write_1(i7_bt, i7_bh, INTERSIL_ICMD, \
INTERSIL_COMMAND(INTERSIL_CMD_RUN, INTERSIL_CMD_IDISABLE));
#define intersil_enable() \
bus_space_write_1(i7_bt, i7_bh, INTERSIL_ICMD, \
INTERSIL_COMMAND(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE));
#define intersil_clear() bus_space_read_1(i7_bt, i7_bh, INTERSIL_IINTR)
int oclockintr(void *);
static struct intrhand level10 = { oclockintr };
void oclock_init(void);
#endif
static int
oclockmatch(device_t parent, cfdata_t cf, void *aux)
{
union obio_attach_args *uoba = aux;
struct obio4_attach_args *oba;
if (uoba->uoba_isobio4 == 0)
return (0);
if (!CPU_ISSUN4 ||
(cpuinfo.cpu_type != CPUTYP_4_100 &&
cpuinfo.cpu_type != CPUTYP_4_200))
return (0);
oba = &uoba->uoba_oba4;
return (bus_space_probe(oba->oba_bustag, oba->oba_paddr,
1,
0,
0,
NULL, NULL));
}
static void
oclockattach(device_t parent, device_t self, void *aux)
{
#if defined(SUN4)
struct intersil7170_softc *sc = device_private(self);
union obio_attach_args *uoba = aux;
struct obio4_attach_args *oba = &uoba->uoba_oba4;
oldclk = 1;
sc->sc_dev = self;
sc->sc_bst = oba->oba_bustag;
if (bus_space_map(sc->sc_bst,
oba->oba_paddr,
sizeof(struct intersil7170),
BUS_SPACE_MAP_LINEAR,
&sc->sc_bsh) != 0) {
aprint_error(": can't map register\n");
return;
}
i7_bt = sc->sc_bst;
i7_bh = sc->sc_bsh;
ienab_bic(IE_L14 | IE_L10);
for (timerblurb = 1; ; timerblurb++) {
int ival;
bus_space_write_1(sc->sc_bst, sc->sc_bsh, INTERSIL_IINTR,
INTERSIL_INTER_CSECONDS);
intersil_enable();
while ((intersil_clear() & INTERSIL_INTER_PENDING) == 0)
;
while ((intersil_clear() & INTERSIL_INTER_PENDING) == 0)
;
delay(10000);
ival = intersil_clear();
intersil_disable();
if ((ival & INTERSIL_INTER_PENDING) != 0) {
aprint_normal(" delay constant %d%s\n", timerblurb,
(timerblurb == 1) ? " [TOO SMALL?]" : "");
break;
}
if (timerblurb > 10) {
aprint_normal("\n");
aprint_error_dev(self, "calibration failing; "
"clamped at %d\n", timerblurb);
break;
}
}
timer_init = oclock_init;
intr_establish(10, 0, &level10, NULL, false);
sc->sc_year0 = 1968;
intersil7170_attach(sc);
aprint_normal("\n");
#endif
}
#if defined(SUN4)
void
oclock_init(void)
{
profhz = hz = 100;
tick = 1000000 / hz;
bus_space_write_1(i7_bt, i7_bh, INTERSIL_IINTR,
INTERSIL_INTER_CSECONDS);
ienab_bic(IE_L14 | IE_L10);
intersil_disable();
(void)intersil_clear();
ienab_bis(IE_L10);
intersil_enable();
}
int
oclockintr(void *cap)
{
int s;
s = splhigh();
(void)intersil_clear();
ienab_bic(IE_L10);
ienab_bis(IE_L10);
splx(s);
hardclock((struct clockframe *)cap);
return (1);
}
#endif