Support for timecounters on acorn32, supplied by Mike Pumford. Only

compile-tested by me, but he promises it works.
This commit is contained in:
bjh21 2006-08-03 23:19:06 +00:00
parent cf3258890d
commit 62d6ab40d3
2 changed files with 88 additions and 57 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: types.h,v 1.3 2002/02/28 03:17:24 simonb Exp $ */ /* $NetBSD: types.h,v 1.4 2006/08/03 23:19:06 bjh21 Exp $ */
#ifndef _ARM32_TYPES_H_ #ifndef _ARM32_TYPES_H_
#define _ARM32_TYPES_H_ #define _ARM32_TYPES_H_
@ -7,5 +7,5 @@
#define __HAVE_DEVICE_REGISTER #define __HAVE_DEVICE_REGISTER
#define __HAVE_NWSCONS #define __HAVE_NWSCONS
#define __HAVE_TIMECOUNTER
#endif #endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: iomd_clock.c,v 1.18 2006/06/25 21:32:41 christos Exp $ */ /* $NetBSD: iomd_clock.c,v 1.19 2006/08/03 23:19:06 bjh21 Exp $ */
/* /*
* Copyright (c) 1994-1997 Mark Brinicombe. * Copyright (c) 1994-1997 Mark Brinicombe.
@ -47,12 +47,14 @@
#include <sys/param.h> #include <sys/param.h>
__KERNEL_RCSID(0, "$NetBSD: iomd_clock.c,v 1.18 2006/06/25 21:32:41 christos Exp $"); __KERNEL_RCSID(0, "$NetBSD: iomd_clock.c,v 1.19 2006/08/03 23:19:06 bjh21 Exp $");
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/timetc.h>
#include <sys/device.h> #include <sys/device.h>
#include <sys/lock.h>
#include <dev/clock_subr.h> #include <dev/clock_subr.h>
@ -76,6 +78,7 @@ static void *clockirq;
static void *statclockirq; static void *statclockirq;
static struct clock_softc *clock_sc; static struct clock_softc *clock_sc;
static int timer0_count; static int timer0_count;
static int timeset;
static int clockmatch __P((struct device *parent, struct cfdata *cf, void *aux)); static int clockmatch __P((struct device *parent, struct cfdata *cf, void *aux));
static void clockattach __P((struct device *parent, struct device *self, void *aux)); static void clockattach __P((struct device *parent, struct device *self, void *aux));
@ -83,6 +86,26 @@ static void clockattach __P((struct device *parent, struct device *self, void *a
static void checkdelay __P((void)); static void checkdelay __P((void));
#endif #endif
static u_int iomd_timecounter0_get(struct timecounter *tc);
static volatile uint32_t timer0_lastcount;
static volatile uint32_t timer0_offset;
static volatile int timer0_ticked;
/* TODO: Get IRQ status */
static struct simplelock tmr_lock = SIMPLELOCK_INITIALIZER; /* protect TC timer variables */
static struct timecounter iomd_timecounter = {
iomd_timecounter0_get,
0, /* No poll_pps */
~0, /* 32bit accuracy */
TIMER_FREQUENCY,
"iomd_timer0",
100
};
int clockhandler __P((void *)); int clockhandler __P((void *));
int statclockhandler __P((void *)); int statclockhandler __P((void *));
@ -136,6 +159,24 @@ clockattach(parent, self, aux)
} }
static void
tickle_tc(void)
{
if (timer0_count &&
timecounter->tc_get_timecount == iomd_timecounter0_get) {
simple_lock(&tmr_lock);
if (timer0_ticked)
timer0_ticked = 0;
else {
timer0_offset += timer0_count;
timer0_lastcount = 0;
}
simple_unlock(&tmr_lock);
}
}
/* /*
* int clockhandler(struct clockframe *frame) * int clockhandler(struct clockframe *frame)
* *
@ -149,6 +190,7 @@ clockhandler(cookie)
void *cookie; void *cookie;
{ {
struct clockframe *frame = cookie; struct clockframe *frame = cookie;
tickle_tc();
hardclock(frame); hardclock(frame);
return(0); /* Pass the interrupt on down the chain */ return(0); /* Pass the interrupt on down the chain */
@ -268,35 +310,21 @@ cpu_initclocks()
#ifdef DIAGNOSTIC #ifdef DIAGNOSTIC
checkdelay(); checkdelay();
#endif #endif
tc_init(&iomd_timecounter);
} }
/*
* void microtime(struct timeval *tvp)
*
* Fill in the specified timeval struct with the current time
* accurate to the microsecond.
*/
void static u_int iomd_timecounter0_get(struct timecounter *tc)
microtime(tvp)
struct timeval *tvp;
{ {
int s; int s;
int tm; u_int tm;
int deltatm;
static struct timeval oldtv;
if (timer0_count == 0)
return;
s = splhigh();
/* /*
* Latch the current value of the timer and then read it. * Latch the current value of the timer and then read it.
* This garentees an atmoic reading of the time. * This garentees an atmoic reading of the time.
*/ */
s = splhigh();
bus_space_write_1(clock_sc->sc_iot, clock_sc->sc_ioh, bus_space_write_1(clock_sc->sc_iot, clock_sc->sc_ioh,
IOMD_T0LATCH, 0); IOMD_T0LATCH, 0);
@ -304,37 +332,27 @@ microtime(tvp)
IOMD_T0LOW); IOMD_T0LOW);
tm += (bus_space_read_1(clock_sc->sc_iot, clock_sc->sc_ioh, tm += (bus_space_read_1(clock_sc->sc_iot, clock_sc->sc_ioh,
IOMD_T0HIGH) << 8); IOMD_T0HIGH) << 8);
splx(s);
simple_lock(&tmr_lock);
deltatm = timer0_count - tm; tm = timer0_count - tm;
if (deltatm < 0)
printf("opps deltatm < 0 tm=%d deltatm=%d\n",
tm, deltatm);
/* Fill in the timeval struct */ if (timer0_count &&
*tvp = time; (tm < timer0_lastcount || (!timer0_ticked && FALSE/* XXX: clkintr_pending */))) {
timer0_ticked = 1;
tvp->tv_usec += (deltatm / TICKS_PER_MICROSECOND); timer0_offset += timer0_count;
/* 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. */ timer0_lastcount = tm;
if (tvp->tv_sec == oldtv.tv_sec && tm += timer0_offset;
tvp->tv_usec <= oldtv.tv_usec) {
tvp->tv_usec = oldtv.tv_usec + 1; simple_unlock(&tmr_lock);
if (tvp->tv_usec >= 1000000) { return tm;
tvp->tv_usec -= 1000000;
++tvp->tv_sec;
}
}
oldtv = *tvp;
(void)splx(s);
} }
/* /*
* Estimated loop for n microseconds * Estimated loop for n microseconds
*/ */
@ -389,7 +407,13 @@ inittodr(time_t base)
{ {
time_t deltat; time_t deltat;
int badbase; int badbase;
int badtime;
struct timeval time;
struct timespec tc_time; /* for timecounters */
/* Default is to assume that time from somewhere will be okay.
* If not badtime will be set to 1 */
badtime = 0;
if (base < (MINYEAR - 1970) * SECYR) { if (base < (MINYEAR - 1970) * SECYR) {
printf("WARNING: preposterous time in file system"); printf("WARNING: preposterous time in file system");
/* read the system clock anyway */ /* read the system clock anyway */
@ -411,7 +435,7 @@ inittodr(time_t base)
printf("WARNING: preposterous clock chip time\n"); printf("WARNING: preposterous clock chip time\n");
resettodr(); resettodr();
} }
goto bad; badtime = 1;
} }
if (!badbase) { if (!badbase) {
@ -422,14 +446,20 @@ inittodr(time_t base)
deltat = time.tv_sec - base; deltat = time.tv_sec - base;
if (deltat < 0) if (deltat < 0)
deltat = -deltat; deltat = -deltat;
if (deltat < 2 * SECDAY) if (deltat >= 2 * SECDAY)
return; /* all is well */
printf("WARNING: clock %s %ld days\n", printf("WARNING: clock %s %ld days\n",
time.tv_sec < base ? "lost" : "gained", time.tv_sec < base ? "lost" : "gained",
(long)deltat / SECDAY); (long)deltat / SECDAY);
} }
bad: /* At this point time is a time value we can initialise the system
printf("WARNING: CHECK AND RESET THE DATE!\n"); * clock with */
tc_time.tv_sec = time.tv_sec;
tc_time.tv_nsec = time.tv_usec * 1000;
tc_setclock(&tc_time);
timeset = 1;
if (badtime)
printf("WARNING: CHECK AND RESET THE DATE!\n");
} }
/* /*
@ -440,10 +470,11 @@ inittodr(time_t base)
void void
resettodr(void) resettodr(void)
{ {
struct timeval time;
if (time.tv_sec == 0) if (!timeset)
return; return;
getmicrotime(&time);
if (todr_handle != NULL && if (todr_handle != NULL &&
todr_settime(todr_handle, &time) != 0) todr_settime(todr_handle, &time) != 0)
printf("resettodr: failed to set time\n"); printf("resettodr: failed to set time\n");