Convert netwinder and cats (and any other footbridge based system in the
future) to timecounters, using the dc21285_fclk. ok nick@, chris@.
This commit is contained in:
parent
196b83c3f8
commit
6cfcc60e81
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: footbridge_clock.c,v 1.22 2006/09/11 06:02:30 gdamore Exp $ */
|
||||
/* $NetBSD: footbridge_clock.c,v 1.23 2006/09/11 15:18:23 gdamore Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997 Mark Brinicombe.
|
||||
@ -35,7 +35,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: footbridge_clock.c,v 1.22 2006/09/11 06:02:30 gdamore Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: footbridge_clock.c,v 1.23 2006/09/11 15:18:23 gdamore Exp $");
|
||||
|
||||
/* Include header files */
|
||||
|
||||
@ -44,6 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: footbridge_clock.c,v 1.22 2006/09/11 06:02:30 gdamor
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/timetc.h>
|
||||
#include <sys/device.h>
|
||||
|
||||
#include <machine/intr.h>
|
||||
@ -74,6 +75,8 @@ int statmin; /* minimum stat clock count in ticks */
|
||||
int statcountperusec; /* number of ticks per usec at current stathz */
|
||||
int statprev; /* last value of we set statclock to */
|
||||
|
||||
void footbridge_tc_init(void);
|
||||
|
||||
#if 0
|
||||
static int clockmatch(struct device *parent, struct cfdata *cf, void *aux);
|
||||
static void clockattach(struct device *parent, struct device *self, void *aux);
|
||||
@ -300,61 +303,29 @@ cpu_initclocks(void)
|
||||
panic("%s: Cannot install timer 2 interrupt handler",
|
||||
clock_sc->sc_dev.dv_xname);
|
||||
}
|
||||
|
||||
footbridge_tc_init();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* void microtime(struct timeval *tvp)
|
||||
*
|
||||
* Fill in the specified timeval struct with the current time
|
||||
* accurate to the microsecond.
|
||||
*/
|
||||
static uint32_t
|
||||
fclk_get_count(struct timecounter *tc)
|
||||
{
|
||||
return (TIMER_MAX_VAL -
|
||||
bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
|
||||
TIMER_3_VALUE));
|
||||
}
|
||||
|
||||
void
|
||||
microtime(struct timeval *tvp)
|
||||
footbridge_tc_init(void)
|
||||
{
|
||||
int s;
|
||||
int tm;
|
||||
int deltatm;
|
||||
static struct timeval oldtv;
|
||||
|
||||
if (clock_sc == NULL || clock_sc->sc_clock_count == 0)
|
||||
return;
|
||||
|
||||
s = splhigh();
|
||||
|
||||
tm = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
|
||||
TIMER_1_VALUE);
|
||||
|
||||
deltatm = clock_sc->sc_clock_count - tm;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (deltatm < 0)
|
||||
panic("opps deltatm < 0 tm=%d deltatm=%d", tm, deltatm);
|
||||
#endif
|
||||
|
||||
/* Fill in the timeval struct */
|
||||
*tvp = time;
|
||||
tvp->tv_usec += ((deltatm << 8) / clock_sc->sc_clock_ticks_per_256us);
|
||||
|
||||
/* Make sure the micro seconds don't overflow. */
|
||||
while (tvp->tv_usec >= 1000000) {
|
||||
tvp->tv_usec -= 1000000;
|
||||
++tvp->tv_sec;
|
||||
}
|
||||
|
||||
/* Make sure the time has advanced. */
|
||||
if (tvp->tv_sec == oldtv.tv_sec &&
|
||||
tvp->tv_usec <= oldtv.tv_usec) {
|
||||
tvp->tv_usec = oldtv.tv_usec + 1;
|
||||
if (tvp->tv_usec >= 1000000) {
|
||||
tvp->tv_usec -= 1000000;
|
||||
++tvp->tv_sec;
|
||||
}
|
||||
}
|
||||
|
||||
oldtv = *tvp;
|
||||
(void)splx(s);
|
||||
static struct timecounter fb_tc = {
|
||||
.tc_get_timecount = fclk_get_count,
|
||||
.tc_counter_mask = TIMER_MAX_VAL,
|
||||
.tc_name = "dc21285_fclk",
|
||||
.tc_quality = 100
|
||||
};
|
||||
fb_tc.tc_frequency = dc21285_fclk;
|
||||
tc_init(&fb_tc);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -362,95 +333,76 @@ microtime(struct timeval *tvp)
|
||||
* rely on an estimated loop, however footbridge is attached very early on.
|
||||
*/
|
||||
|
||||
static int delay_clock_count = 0;
|
||||
static int delay_count_per_usec = 0;
|
||||
|
||||
void
|
||||
calibrate_delay(void)
|
||||
{
|
||||
delay_clock_count = load_timer(TIMER_3_BASE, 100);
|
||||
delay_count_per_usec = delay_clock_count/10000;
|
||||
#ifdef VERBOSE_DELAY_CALIBRATION
|
||||
printf("delay calibration: delay_cc = %d, delay_c/us=%d\n",
|
||||
delay_clock_count, delay_count_per_usec);
|
||||
|
||||
printf("0..");
|
||||
delay(1000000);
|
||||
printf("1..");
|
||||
delay(1000000);
|
||||
printf("2..");
|
||||
delay(1000000);
|
||||
printf("3..");
|
||||
delay(1000000);
|
||||
printf("4..");
|
||||
delay(1000000);
|
||||
printf("5..");
|
||||
delay(1000000);
|
||||
printf("6..");
|
||||
delay(1000000);
|
||||
printf("7..");
|
||||
delay(1000000);
|
||||
printf("8..");
|
||||
delay(1000000);
|
||||
printf("9..");
|
||||
delay(1000000);
|
||||
printf("10\n");
|
||||
#endif
|
||||
/*
|
||||
* For all current footbridge hardware, the fclk runs at a
|
||||
* rate that is sufficiently slow enough that we don't need to
|
||||
* use a prescaler. A prescaler would be needed if the fclk
|
||||
* could wrap within 2 hardclock periods (2 * HZ). With
|
||||
* normal values of HZ (100 and higher), this is unlikely to
|
||||
* ever happen.
|
||||
*
|
||||
* We let TIMER 3 just run free, at the freqeuncy supplied by
|
||||
* dc21285_fclk.
|
||||
*/
|
||||
bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
|
||||
TIMER_3_BASE + TIMER_CONTROL, TIMER_ENABLE);
|
||||
delay_count_per_usec = dc21285_fclk / 1000000;
|
||||
if (dc21285_fclk % 1000000)
|
||||
delay_count_per_usec += 1;
|
||||
}
|
||||
|
||||
int delaycount = 25000;
|
||||
|
||||
void
|
||||
delay(u_int n)
|
||||
delay(unsigned n)
|
||||
{
|
||||
volatile u_int i;
|
||||
uint32_t cur, last, delta, usecs;
|
||||
|
||||
if (n == 0) return;
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* not calibrated the timer yet, so try to live with this horrible
|
||||
* loop!
|
||||
*
|
||||
* Note: a much better solution might be to have the timers
|
||||
* get get calibrated out of mach_init. Of course, the
|
||||
* clock_sc needs to be set up, so we can read/write the clock
|
||||
* registers.
|
||||
*/
|
||||
if (delay_clock_count == 0)
|
||||
if (!delay_count_per_usec)
|
||||
{
|
||||
while (n-- > 0) {
|
||||
for (i = delaycount; --i;);
|
||||
}
|
||||
return;
|
||||
int delaycount = 25000;
|
||||
volatile int i;
|
||||
|
||||
while (n-- > 0) {
|
||||
for (i = delaycount; --i;);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* read the current value (do not reset it as delay is reentrant)
|
||||
*/
|
||||
last = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
|
||||
TIMER_3_VALUE);
|
||||
delta = usecs = 0;
|
||||
|
||||
while (n > usecs) {
|
||||
cur = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
|
||||
TIMER_3_VALUE);
|
||||
|
||||
delta = 0;
|
||||
if (last < cur)
|
||||
/* timer has wrapped */
|
||||
delta += ((TIMER_MAX_VAL - cur) + last);
|
||||
else
|
||||
delta += (last - cur);
|
||||
|
||||
usecs = n * delay_count_per_usec;
|
||||
last = cur;
|
||||
|
||||
while (usecs > delta)
|
||||
{
|
||||
cur = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
|
||||
TIMER_3_VALUE);
|
||||
if (last < cur)
|
||||
/* timer has wrapped */
|
||||
delta += ((delay_clock_count - cur) + last);
|
||||
else
|
||||
delta += (last - cur);
|
||||
|
||||
if (cur == 0)
|
||||
{
|
||||
/*
|
||||
* reset the timer, note that if something blocks us for more
|
||||
* than 1/100s we may delay for too long, but I believe that
|
||||
* is fairly unlikely.
|
||||
*/
|
||||
bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
|
||||
TIMER_3_CLEAR, 0);
|
||||
}
|
||||
last = cur;
|
||||
while (delta >= delay_count_per_usec) {
|
||||
delta -= delay_count_per_usec;
|
||||
usecs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: todclock.c,v 1.9 2005/12/24 20:06:52 perry Exp $ */
|
||||
/* $NetBSD: todclock.c,v 1.10 2006/09/11 15:18:23 gdamore Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-1997 Mark Brinicombe.
|
||||
@ -44,7 +44,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: todclock.c,v 1.9 2005/12/24 20:06:52 perry Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: todclock.c,v 1.10 2006/09/11 15:18:23 gdamore Exp $");
|
||||
|
||||
/* Include header files */
|
||||
|
||||
@ -198,7 +198,7 @@ resettodr()
|
||||
if (todclock_sc->sc_rtc_write == NULL)
|
||||
return;
|
||||
|
||||
sec = time.tv_sec;
|
||||
sec = time_second;
|
||||
sec -= rtc_offset * 60;
|
||||
year = (sec / SECPER4YEARS) * 4;
|
||||
sec %= SECPER4YEARS;
|
||||
@ -269,8 +269,7 @@ inittodr(base)
|
||||
*/
|
||||
|
||||
/* Use the suggested time as a fall back */
|
||||
time.tv_sec = base;
|
||||
time.tv_usec = 0;
|
||||
time_second = base;
|
||||
|
||||
/* Can we read an RTC ? */
|
||||
if (todclock_sc != NULL && todclock_sc->sc_rtc_read) {
|
||||
@ -302,8 +301,7 @@ inittodr(base)
|
||||
|
||||
n += rtc_offset * 60;
|
||||
|
||||
time.tv_sec = n;
|
||||
time.tv_usec = 0;
|
||||
time_second = n;
|
||||
|
||||
/* timeset is used to ensure the time is valid before a resettodr() */
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: types.h,v 1.6 2006/09/03 13:51:23 bjh21 Exp $ */
|
||||
/* $NetBSD: types.h,v 1.7 2006/09/11 15:18:23 gdamore Exp $ */
|
||||
|
||||
#ifndef _ARM32_TYPES_H_
|
||||
#define _ARM32_TYPES_H_
|
||||
@ -6,5 +6,6 @@
|
||||
#include <arm/arm32/types.h>
|
||||
#define __HAVE_GENERIC_SOFT_INTERRUPTS
|
||||
#define __HAVE_DEVICE_REGISTER
|
||||
#define __HAVE_TIMECOUNTER
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: types.h,v 1.5 2006/09/03 13:51:23 bjh21 Exp $ */
|
||||
/* $NetBSD: types.h,v 1.6 2006/09/11 15:18:23 gdamore Exp $ */
|
||||
|
||||
#ifndef _ARM32_TYPES_H_
|
||||
#define _ARM32_TYPES_H_
|
||||
@ -7,5 +7,6 @@
|
||||
|
||||
#define __HAVE_GENERIC_SOFT_INTERRUPTS
|
||||
#define __HAVE_DEVICE_REGISTER
|
||||
#define __HAVE_TIMECOUNTER
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user