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_
#define _ARM32_TYPES_H_
@ -7,5 +7,5 @@
#define __HAVE_DEVICE_REGISTER
#define __HAVE_NWSCONS
#define __HAVE_TIMECOUNTER
#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.
@ -47,12 +47,14 @@
#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/kernel.h>
#include <sys/time.h>
#include <sys/timetc.h>
#include <sys/device.h>
#include <sys/lock.h>
#include <dev/clock_subr.h>
@ -76,6 +78,7 @@ static void *clockirq;
static void *statclockirq;
static struct clock_softc *clock_sc;
static int timer0_count;
static int timeset;
static int clockmatch __P((struct device *parent, struct cfdata *cf, 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));
#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 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)
*
@ -149,6 +190,7 @@ clockhandler(cookie)
void *cookie;
{
struct clockframe *frame = cookie;
tickle_tc();
hardclock(frame);
return(0); /* Pass the interrupt on down the chain */
@ -268,35 +310,21 @@ cpu_initclocks()
#ifdef DIAGNOSTIC
checkdelay();
#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
microtime(tvp)
struct timeval *tvp;
static u_int iomd_timecounter0_get(struct timecounter *tc)
{
int s;
int tm;
int deltatm;
static struct timeval oldtv;
if (timer0_count == 0)
return;
s = splhigh();
u_int tm;
/*
* Latch the current value of the timer and then read it.
* This garentees an atmoic reading of the time.
*/
s = splhigh();
bus_space_write_1(clock_sc->sc_iot, clock_sc->sc_ioh,
IOMD_T0LATCH, 0);
@ -304,37 +332,27 @@ microtime(tvp)
IOMD_T0LOW);
tm += (bus_space_read_1(clock_sc->sc_iot, clock_sc->sc_ioh,
IOMD_T0HIGH) << 8);
splx(s);
simple_lock(&tmr_lock);
deltatm = timer0_count - tm;
if (deltatm < 0)
printf("opps deltatm < 0 tm=%d deltatm=%d\n",
tm, deltatm);
tm = timer0_count - tm;
/* Fill in the timeval struct */
*tvp = time;
tvp->tv_usec += (deltatm / TICKS_PER_MICROSECOND);
/* Make sure the micro seconds don't overflow. */
while (tvp->tv_usec >= 1000000) {
tvp->tv_usec -= 1000000;
++tvp->tv_sec;
if (timer0_count &&
(tm < timer0_lastcount || (!timer0_ticked && FALSE/* XXX: clkintr_pending */))) {
timer0_ticked = 1;
timer0_offset += timer0_count;
}
/* 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);
timer0_lastcount = tm;
tm += timer0_offset;
simple_unlock(&tmr_lock);
return tm;
}
/*
* Estimated loop for n microseconds
*/
@ -389,7 +407,13 @@ inittodr(time_t base)
{
time_t deltat;
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) {
printf("WARNING: preposterous time in file system");
/* read the system clock anyway */
@ -411,7 +435,7 @@ inittodr(time_t base)
printf("WARNING: preposterous clock chip time\n");
resettodr();
}
goto bad;
badtime = 1;
}
if (!badbase) {
@ -422,14 +446,20 @@ inittodr(time_t base)
deltat = time.tv_sec - base;
if (deltat < 0)
deltat = -deltat;
if (deltat < 2 * SECDAY)
return; /* all is well */
if (deltat >= 2 * SECDAY)
printf("WARNING: clock %s %ld days\n",
time.tv_sec < base ? "lost" : "gained",
(long)deltat / SECDAY);
time.tv_sec < base ? "lost" : "gained",
(long)deltat / SECDAY);
}
bad:
printf("WARNING: CHECK AND RESET THE DATE!\n");
/* At this point time is a time value we can initialise the system
* 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
resettodr(void)
{
if (time.tv_sec == 0)
struct timeval time;
if (!timeset)
return;
getmicrotime(&time);
if (todr_handle != NULL &&
todr_settime(todr_handle, &time) != 0)
printf("resettodr: failed to set time\n");