Add timecounter(9) support for mvme68k.
Based on a patch from Garrett D'Amore and several tweaks by me. Compile tested only, but reviewed by joerg@ and no objection from scw@ on port-mvme68k.
This commit is contained in:
parent
7f4f83c80c
commit
2b341ae01b
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: clock_pcc.c,v 1.16 2005/12/11 12:18:17 christos Exp $ */
|
||||
/* $NetBSD: clock_pcc.c,v 1.17 2008/01/07 14:39:28 tsutsui Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996 The NetBSD Foundation, Inc.
|
||||
@ -42,12 +42,13 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: clock_pcc.c,v 1.16 2005/12/11 12:18:17 christos Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: clock_pcc.c,v 1.17 2008/01/07 14:39:28 tsutsui Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/timetc.h>
|
||||
|
||||
#include <machine/psl.h>
|
||||
#include <machine/bus.h>
|
||||
@ -64,6 +65,7 @@ struct clock_pcc_softc {
|
||||
struct device sc_dev;
|
||||
struct clock_attach_args sc_clock_args;
|
||||
u_char sc_clock_lvl;
|
||||
struct timecounter sc_tc;
|
||||
};
|
||||
|
||||
CFATTACH_DECL(clock_pcc, sizeof(struct clock_pcc_softc),
|
||||
@ -75,10 +77,12 @@ extern struct cfdriver clock_cd;
|
||||
static int clock_pcc_profintr __P((void *));
|
||||
static int clock_pcc_statintr __P((void *));
|
||||
static void clock_pcc_initclocks __P((void *, int, int));
|
||||
static long clock_pcc_microtime __P((void *));
|
||||
static u_int clock_pcc_getcount(struct timecounter *);
|
||||
static void clock_pcc_shutdown __P((void *));
|
||||
|
||||
static struct clock_pcc_softc *clock_pcc_sc;
|
||||
static uint32_t clock_pcc_count;
|
||||
static uint16_t clock_pcc_reload;
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
@ -122,7 +126,6 @@ clock_pcc_attach(parent, self, aux)
|
||||
clock_pcc_sc = sc;
|
||||
sc->sc_clock_args.ca_arg = sc;
|
||||
sc->sc_clock_args.ca_initfunc = clock_pcc_initclocks;
|
||||
sc->sc_clock_args.ca_microtime = clock_pcc_microtime;
|
||||
|
||||
/* Do common portions of clock config. */
|
||||
clock_config(self, &sc->sc_clock_args, pccintr_evcnt(pa->pa_ipl));
|
||||
@ -146,8 +149,8 @@ clock_pcc_initclocks(arg, prof_us, stat_us)
|
||||
{
|
||||
struct clock_pcc_softc *sc = arg;
|
||||
|
||||
pcc_reg_write16(sys_pcc, PCCREG_TMR1_PRELOAD,
|
||||
pcc_timer_us2lim(prof_us));
|
||||
clock_pcc_reload = pcc_timer_us2lim(prof_us);
|
||||
pcc_reg_write16(sys_pcc, PCCREG_TMR1_PRELOAD, clock_pcc_reload);
|
||||
pcc_reg_write(sys_pcc, PCCREG_TMR1_CONTROL, PCC_TIMERCLEAR);
|
||||
pcc_reg_write(sys_pcc, PCCREG_TMR1_CONTROL, PCC_TIMERSTART);
|
||||
pcc_reg_write(sys_pcc, PCCREG_TMR1_INTR_CTRL, sc->sc_clock_lvl);
|
||||
@ -157,20 +160,25 @@ clock_pcc_initclocks(arg, prof_us, stat_us)
|
||||
pcc_reg_write(sys_pcc, PCCREG_TMR2_CONTROL, PCC_TIMERCLEAR);
|
||||
pcc_reg_write(sys_pcc, PCCREG_TMR2_CONTROL, PCC_TIMERSTART);
|
||||
pcc_reg_write(sys_pcc, PCCREG_TMR2_INTR_CTRL, sc->sc_clock_lvl);
|
||||
|
||||
sc->sc_tc.tc_get_timecount = clock_pcc_getcount;
|
||||
sc->sc_tc.tc_name = "pcc_count";
|
||||
sc->sc_tc.tc_frequency = PCC_TIMERFREQ;
|
||||
sc->sc_tc.tc_quality = 100;
|
||||
sc->sc_tc.tc_counter_mask = ~0;
|
||||
tc_init(&sc->sc_tc);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
long
|
||||
clock_pcc_microtime(arg)
|
||||
void *arg;
|
||||
u_int
|
||||
clock_pcc_getcount(struct timecounter *tc)
|
||||
{
|
||||
static int ovfl_adj[] = {
|
||||
0, 10000, 20000, 30000,
|
||||
40000, 50000, 60000, 70000,
|
||||
80000, 90000, 100000, 110000,
|
||||
120000, 130000, 140000, 150000};
|
||||
u_int8_t cr;
|
||||
u_int16_t tc, tc2;
|
||||
u_int cnt;
|
||||
uint16_t tc1, tc2;
|
||||
uint8_t cr;
|
||||
int s;
|
||||
|
||||
s = splhigh();
|
||||
|
||||
/*
|
||||
* There's no way to latch the counter and overflow registers
|
||||
@ -178,16 +186,22 @@ clock_pcc_microtime(arg)
|
||||
* race by checking for counter wrap-around and re-reading the
|
||||
* overflow counter if necessary.
|
||||
*
|
||||
* Note: This only works because we're called at splhigh().
|
||||
* Note: This only works because we're at splhigh().
|
||||
*/
|
||||
tc = pcc_reg_read16(sys_pcc, PCCREG_TMR1_COUNT);
|
||||
tc1 = pcc_reg_read16(sys_pcc, PCCREG_TMR1_COUNT);
|
||||
cr = pcc_reg_read(sys_pcc, PCCREG_TMR1_CONTROL);
|
||||
if (tc > (tc2 = pcc_reg_read16(sys_pcc, PCCREG_TMR1_COUNT))) {
|
||||
tc2 = pcc_reg_read16(sys_pcc, PCCREG_TMR1_COUNT);
|
||||
if (tc1 > tc2) {
|
||||
cr = pcc_reg_read(sys_pcc, PCCREG_TMR1_CONTROL);
|
||||
tc = tc2;
|
||||
tc1 = tc2;
|
||||
}
|
||||
cnt = clock_pcc_count;
|
||||
splx(s);
|
||||
/* XXX assume HZ == 100 */
|
||||
cnt += (tc1 - clock_pcc_reload) +
|
||||
(PCC_TIMERFREQ / 100) * (cr >> PCC_TIMEROVFLSHIFT);
|
||||
|
||||
return ((long) pcc_timer_cnt2us(tc) + ovfl_adj[cr>>PCC_TIMEROVFLSHIFT]);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
int
|
||||
@ -208,8 +222,11 @@ clock_pcc_profintr(frame)
|
||||
clock_pcc_sc->sc_clock_lvl);
|
||||
splx(s);
|
||||
|
||||
for (cr >>= PCC_TIMEROVFLSHIFT; cr; cr--)
|
||||
for (cr >>= PCC_TIMEROVFLSHIFT; cr; cr--) {
|
||||
/* XXX assume HZ == 100 */
|
||||
clock_pcc_count += PCC_TIMERFREQ / 100;
|
||||
hardclock(frame);
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: pccreg.h,v 1.9 2001/08/12 18:33:13 scw Exp $ */
|
||||
/* $NetBSD: pccreg.h,v 1.10 2008/01/07 14:39:28 tsutsui Exp $ */
|
||||
|
||||
/*
|
||||
*
|
||||
@ -154,16 +154,15 @@
|
||||
*/
|
||||
|
||||
#define PCC_TIMERACK 0x80 /* ack intr */
|
||||
#define PCC_TIMER100HZ 63936 /* load value for 100Hz */
|
||||
#define PCC_TIMERCLEAR 0x0 /* reset and clear timer */
|
||||
#define PCC_TIMERENABLE 0x1 /* Enable clock */
|
||||
#define PCC_TIMERSTOP 0x3 /* stop clock, but don't clear it */
|
||||
#define PCC_TIMERSTART 0x7 /* start timer */
|
||||
#define PCC_TIMEROVFLSHIFT 4
|
||||
|
||||
#define pcc_timer_hz2lim(hz) (65536 - (160000/(hz)))
|
||||
#define pcc_timer_us2lim(us) (65536 - (160000/(1000000/(us))))
|
||||
#define pcc_timer_cnt2us(cnt) ((((cnt) - PCC_TIMER100HZ) * 25) / 4)
|
||||
#define PCC_TIMERFREQ 160000
|
||||
#define pcc_timer_hz2lim(hz) (0x10000 - (PCC_TIMERFREQ/(hz)))
|
||||
#define pcc_timer_us2lim(us) (0x10000 - (PCC_TIMERFREQ/(1000000/(us))))
|
||||
|
||||
/*
|
||||
* serial control
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: types.h,v 1.12 2007/10/17 19:55:47 garbled Exp $ */
|
||||
/* $NetBSD: types.h,v 1.13 2008/01/07 14:39:28 tsutsui Exp $ */
|
||||
|
||||
#ifndef _MACHINE_TYPES_H_
|
||||
#define _MACHINE_TYPES_H_
|
||||
@ -7,5 +7,6 @@
|
||||
|
||||
#define __HAVE_DEVICE_REGISTER
|
||||
#define __HAVE_GENERIC_TODR
|
||||
#define __HAVE_TIMECOUNTER
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: clock.c,v 1.24 2006/09/09 22:28:27 gdamore Exp $ */
|
||||
/* $NetBSD: clock.c,v 1.25 2008/01/07 14:39:28 tsutsui Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
@ -41,7 +41,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.24 2006/09/09 22:28:27 gdamore Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.25 2008/01/07 14:39:28 tsutsui Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -139,39 +139,3 @@ setstatclockrate(newhz)
|
||||
|
||||
/* XXX should we do something here? XXX */
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the best possible estimate of the time in the timeval
|
||||
* to which tvp points. We do this by returning the current time
|
||||
* plus the amount of time, in uSec, since the last clock interrupt
|
||||
* (clock_args->ca_microtime()) was handled.
|
||||
*
|
||||
* Check that this time is no less than any previously-reported time,
|
||||
* which could happen around the time of a clock adjustment. Just for fun,
|
||||
* we guarantee that the time will be greater than the value obtained by a
|
||||
* previous call.
|
||||
*/
|
||||
|
||||
void
|
||||
microtime(tvp)
|
||||
struct timeval *tvp;
|
||||
{
|
||||
int s = splhigh();
|
||||
static struct timeval lasttime;
|
||||
|
||||
*tvp = time;
|
||||
tvp->tv_usec += (*clock_args->ca_microtime)(clock_args->ca_arg);
|
||||
while (tvp->tv_usec >= 1000000) {
|
||||
tvp->tv_sec++;
|
||||
tvp->tv_usec -= 1000000;
|
||||
}
|
||||
if (tvp->tv_sec == lasttime.tv_sec &&
|
||||
tvp->tv_usec <= lasttime.tv_usec &&
|
||||
(tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
|
||||
tvp->tv_sec++;
|
||||
tvp->tv_usec -= 1000000;
|
||||
}
|
||||
lasttime = *tvp;
|
||||
splx(s);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: clock_pcctwo.c,v 1.11 2007/10/19 12:00:36 ad Exp $ */
|
||||
/* $NetBSD: clock_pcctwo.c,v 1.12 2008/01/07 14:39:28 tsutsui Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
|
||||
@ -43,12 +43,13 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: clock_pcctwo.c,v 1.11 2007/10/19 12:00:36 ad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: clock_pcctwo.c,v 1.12 2008/01/07 14:39:28 tsutsui Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/timetc.h>
|
||||
|
||||
#include <machine/psl.h>
|
||||
#include <sys/bus.h>
|
||||
@ -65,6 +66,7 @@ struct clock_pcctwo_softc {
|
||||
struct device sc_dev;
|
||||
struct clock_attach_args sc_clock_args;
|
||||
u_char sc_clock_lvl;
|
||||
struct timecounter sc_tc;
|
||||
};
|
||||
|
||||
CFATTACH_DECL(clock_pcctwo, sizeof(struct clock_pcctwo_softc),
|
||||
@ -75,10 +77,11 @@ extern struct cfdriver clock_cd;
|
||||
static int clock_pcctwo_profintr(void *);
|
||||
static int clock_pcctwo_statintr(void *);
|
||||
static void clock_pcctwo_initclocks(void *, int, int);
|
||||
static long clock_pcctwo_microtime(void *);
|
||||
static u_int clock_pcctwo_getcount(struct timecounter *);
|
||||
static void clock_pcctwo_shutdown(void *);
|
||||
|
||||
static struct clock_pcctwo_softc *clock_pcctwo_sc;
|
||||
static uint32_t clock_pcctwo_count;
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
@ -119,7 +122,6 @@ clock_pcctwo_attach(parent, self, aux)
|
||||
|
||||
sc->sc_clock_args.ca_arg = sc;
|
||||
sc->sc_clock_args.ca_initfunc = clock_pcctwo_initclocks;
|
||||
sc->sc_clock_args.ca_microtime = clock_pcctwo_microtime;
|
||||
|
||||
/* Do common portions of clock config. */
|
||||
clock_config(self, &sc->sc_clock_args, pcctwointr_evcnt(pa->pa_ipl));
|
||||
@ -162,20 +164,25 @@ clock_pcctwo_initclocks(arg, prof_us, stat_us)
|
||||
pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL,
|
||||
PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
|
||||
pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR, sc->sc_clock_lvl);
|
||||
|
||||
sc->sc_tc.tc_get_timecount = clock_pcctwo_getcount;
|
||||
sc->sc_tc.tc_name = "pcctwo_count";
|
||||
sc->sc_tc.tc_frequency = PCCTWO_TIMERFREQ;
|
||||
sc->sc_tc.tc_quality = 100;
|
||||
sc->sc_tc.tc_counter_mask = ~0;
|
||||
tc_init(&sc->sc_tc);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
long
|
||||
clock_pcctwo_microtime(arg)
|
||||
void *arg;
|
||||
u_int
|
||||
clock_pcctwo_getcount(struct timecounter *tc)
|
||||
{
|
||||
static int ovfl_adj[] = {
|
||||
0, 10000, 20000, 30000,
|
||||
40000, 50000, 60000, 70000,
|
||||
80000, 90000, 100000, 110000,
|
||||
120000, 130000, 140000, 150000};
|
||||
u_int8_t cr;
|
||||
u_int32_t tc, tc2;
|
||||
u_int cnt;
|
||||
uint32_t tc1, tc2;
|
||||
uint8_t cr;
|
||||
int s;
|
||||
|
||||
s = splhigh();
|
||||
|
||||
/*
|
||||
* There's no way to latch the counter and overflow registers
|
||||
@ -183,16 +190,21 @@ clock_pcctwo_microtime(arg)
|
||||
* race by checking for counter wrap-around and re-reading the
|
||||
* overflow counter if necessary.
|
||||
*
|
||||
* Note: This only works because we're called at splhigh().
|
||||
* Note: This only works because we're at splhigh().
|
||||
*/
|
||||
tc = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER);
|
||||
tc1 = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER);
|
||||
cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
|
||||
if (tc > (tc2 = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER))) {
|
||||
tc2 = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER);
|
||||
if (tc1 > tc2) {
|
||||
cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
|
||||
tc = tc2;
|
||||
tc1 = tc2;
|
||||
}
|
||||
cnt = clock_pcctwo_count;
|
||||
splx(s);
|
||||
/* XXX assume HZ == 100 */
|
||||
cnt += tc1 + (PCCTWO_TIMERFREQ / 100) * PCCTWO_TT_CTRL_OVF(cr);
|
||||
|
||||
return ((long) PCCTWO_LIM2US(tc) + ovfl_adj[PCCTWO_TT_CTRL_OVF(cr)]);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
int
|
||||
@ -214,8 +226,11 @@ clock_pcctwo_profintr(frame)
|
||||
clock_pcctwo_sc->sc_clock_lvl);
|
||||
splx(s);
|
||||
|
||||
for (cr = PCCTWO_TT_CTRL_OVF(cr); cr; cr--)
|
||||
for (cr = PCCTWO_TT_CTRL_OVF(cr); cr; cr--) {
|
||||
/* XXX assume HZ == 100 */
|
||||
clock_pcctwo_count += PCCTWO_TIMERFREQ / 100;
|
||||
hardclock(frame);
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: clockvar.h,v 1.6 2005/12/11 12:22:47 christos Exp $ */
|
||||
/* $NetBSD: clockvar.h,v 1.7 2008/01/07 14:39:28 tsutsui Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996, 2002 The NetBSD Foundation, Inc.
|
||||
@ -53,7 +53,6 @@ extern int clock_statmin;
|
||||
|
||||
struct clock_attach_args {
|
||||
void (*ca_initfunc)(void *, int, int);
|
||||
long (*ca_microtime)(void *);
|
||||
void *ca_arg;
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: pcctworeg.h,v 1.1 2002/02/12 20:38:49 scw Exp $ */
|
||||
/* $NetBSD: pcctworeg.h,v 1.2 2008/01/07 14:39:28 tsutsui Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
|
||||
@ -239,6 +239,7 @@
|
||||
* this is simple since the Tick Counters already have
|
||||
* a 1uS period. (PCC2REG_TIMER[12]_COMPARE)
|
||||
*/
|
||||
#define PCCTWO_TIMERFREQ 1000000
|
||||
#define PCCTWO_US2LIM(us) (us)
|
||||
#define PCCTWO_LIM2US(lim) (lim)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user