Import mcclock from NetBSD/Alpha, mostly replacing the Sprite clock code.

interface.   From Toru Nishimura <nisimura@itc.aist-nara.ac.jp>.

Partly merged back with Alpha code by Jonathan Stone. Needs more merging.
This commit is contained in:
jonathan 1997-06-22 09:34:34 +00:00
parent 045cfc87d2
commit 89868a5f07
5 changed files with 459 additions and 329 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: files.pmax,v 1.43 1997/06/16 00:35:10 jonathan Exp $
# $NetBSD: files.pmax,v 1.44 1997/06/22 09:34:34 jonathan Exp $
# DECstation-specific configuration info
# maxpartitions must be first item in files.${ARCH}.
@ -49,9 +49,10 @@ file arch/pmax/tc/asic.c ioasic
# Real-time clock (not optional)
device clock
attach clock at ioasic, tc, mainbus
file arch/pmax/pmax/clock.c clock
attach clock at ioasic, mainbus with mcclock_ioasic
file arch/pmax/pmax/clock.c
file arch/pmax/pmax/mcclock.c clock
file arch/pmax/tc/mcclock_ioasic.c mcclock_ioasic
#
# Machine-independent SCSI driver.

View File

@ -0,0 +1,68 @@
/* $NetBSD: clock_machdep.h,v 1.1 1997/06/22 09:34:40 jonathan Exp $ */
/*
* System-dependent clock declarations for the ``cpu-independent''
* clock interface.
*
* This file must prototype or define the folluwing functions of
* macros (one or more of which may be no-ops):
*
* CLOCK_RATE default rate at which clock runs. Some platforms
* run the RTC at a fixed rate, independent of
* the acutal RTC hardware in use. clock
*
* clk_rtc_to_systime(struct clocktime *ct, base)
* hook called just after getting a time from the RTC but
* before sanity checks, and before (*ct) is written to
* the RTC hardware.
* Allows machine-dependent ransformation to the clocktime
* (e.g., for compatibility with PROMS which filter out
* high-order RTC bits.)
*
* clk_systime_to_rtc(struct clocktime *ct, base)
*
* hook called just before *ct is written to the RTC hardware.
* Allows machine-dependent transformation of the RTC
* (e.g., forcing the non-volatile RTC to keep time-of-year
* even when the hardware has more higher-order bits.)
*
*/
/* The default clock rate on a pmax is 256 Hz. */
#define CLOCK_RATE 256
/*
* Experiments (and passing years) show that Decstation PROMS
* assume the kernel uses the clock chip as a time-of-year clock.
* The PROM assumes the clock is always set to 1972 or 1973, and contains
* time-of-year in seconds. The PROM checks the clock at boot time,
* and if it's outside that range, sets it to 1972-01-01.
* Use clk_systime_to_rtc() and clk_rtc_to_systime to hide that.
*
* XXX should be at the mc146818 layer?
* XXX should use filesystem base time to convert to a TOY, and
* get rid of the fixed offset which needs changing every two years.
*/
#define DEC_DAY_OFFSET 0 /* maybe 1 */
#define DEC_YR_OFFSET 25 /* good until Dec 31, 1998 */
/*
* convert RTC time to system time.
* On a pmax, add the current year less 1972 to the RTC clock time.
* (should be 1973 in leapyears, but we don't care.)
*/
#define clk_rtc_to_systime(ct, base) \
do { (ct)->year += DEC_YR_OFFSET; (ct)->day += DEC_DAY_OFFSET; } while(0)
/*
* convert RTC time to system time.
* On a pmax, subtract the current year less 1972 from the RTC clock time,
* to give a time in 1972 or 1973..
* (should use 1973 only for leapyears but we don't care.)
*/
#define clk_systime_to_rtc(ct, base) \
do { (ct)->year -= DEC_YR_OFFSET; (ct)->day -= DEC_DAY_OFFSET; } while(0)

View File

@ -1,4 +1,4 @@
/* $NetBSD: clock.c,v 1.19 1997/06/22 07:42:38 jonathan Exp $ */
/* $NetBSD: clock.c,v 1.20 1997/06/22 09:34:43 jonathan Exp $ */
/*
* Copyright (c) 1988 University of Utah.
@ -42,22 +42,50 @@
* @(#)clock.c 8.1 (Berkeley) 6/10/93
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.20 1997/06/22 09:34:43 jonathan Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/clock_machdep.h>
#include <machine/autoconf.h>
#include <machine/bus.h> /* XXX wbflush() */
#include <pmax/pmax/clockreg.h>
#include "tc.h" /* Is a Turbochannel configured? */
#include <dev/tc/clockvar.h>
#if NTC>0
#include <dev/tc/tcvar.h>
#include <dev/tc/ioasicvar.h>
#define SECMIN ((unsigned)60) /* seconds per minute */
#define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */
#define SECDAY ((unsigned)(24*SECHOUR)) /* seconds per day */
#define SECYR ((unsigned)(365*SECDAY)) /* seconds per common year */
#define LEAPYEAR(year) (((year) % 4) == 0)
struct device *clockdev;
const struct clockfns *clockfns;
int clockinitted;
void
clockattach(dev, fns)
struct device *dev;
const struct clockfns *fns;
{
/*
* Just bookkeeping.
*/
printf("\n");
if (clockfns != NULL)
panic("clockattach: multiple clocks");
clockdev = dev;
clockfns = fns;
#ifdef EVCNT_COUNTERS
evcnt_attach(dev, "intr", &clock_intr_evcnt);
#endif
}
/*
* Machine-dependent clock routines.
@ -72,186 +100,6 @@
* Resettodr restores the time of day hardware after a time change.
*/
volatile struct chiptime *Mach_clock_addr;
/* Some values for rates for the RTC interrupt */
#define RATE_32_HZ 0xB /* 31.250 ms */
#define RATE_64_HZ 0xA /* 15.625 ms */
#define RATE_128_HZ 0x9 /* 7.8125 ms */
#define RATE_256_HZ 0x8 /* 3.90625 ms */
#define RATE_512_HZ 0x7 /* 1953.125 us*/
#define RATE_1024_HZ 0x6 /* 976.562 us */
#define RATE_2048_HZ 0x5 /* 488.281 usecs/interrupt */
#undef SELECTED_RATE
#if (HZ == 64)
# define SELECTED_RATE RATE_64_HZ /* 4.4bsd default on pmax */
# define SHIFT_HZ 6
# else /* !64 Hz */
#if (HZ == 128)
# define SELECTED_RATE RATE_128_HZ
# define SHIFT_HZ 7
#else /* !128 Hz */
#if (HZ == 256)
# define SELECTED_RATE RATE_256_HZ
# define SHIFT_HZ 8
#else /*!256Hz*/
#if (HZ == 512)
# define SELECTED_RATE RATE_512_HZ
# define SHIFT_HZ 9
#else /*!512hz*/
#if (HZ == 1024)
# define SELECTED_RATE RATE_1024_HZ
# define SHIFT_HZ 10
#else /* !1024hz*/
# error RTC interrupt rate HZ not recognised; must be a power of 2
#endif /*!64Hz*/
#endif /*!1024Hz*/
#endif /*!512 Hz*/
#endif /*!256 Hz*/
#endif /*!128Hz*/
/*
* RTC interrupt rate: pick one of 64, 128, 256, 512, 1024, 2048.
* The appropriate rate is machine-dependent, or even model-dependent.
*
* Unless a machine has a hardware free-running clock, the RTC interrupt
* rate is an upper limit on gettimeofday(), context switch interval,
* and generally the resolution of real-time. The standard 4.4bsd pmax
* RTC tick rate is 64Hz, which has low overhead but is ludicrous when
* doing serious performance measurement. For machines faster than 3100s,
* 1024Hz gives millisecond resolution. Alphas have an on-chip counter,
* and at least some IOASIC Decstations have a turbochannel cycle-counter,
* either of which which can be interpolated between RTC interrupts, to
* give resolution in ns or tens of ns.
*/
#ifndef HZ
#ifdef __mips__
/*#define HZ 64*/ /* conveniently divides 1 sec */
#define HZ 256 /* default on Ultrix */
#else
# error Kernel config parameter HZ not defined
#endif
#endif
/* Compute value to program clock with, given config parameter RTC_HZ */
/* global autoconfiguration variables -- bus type*/
extern struct cfdriver mainbus_cd;
#if NTC>0
extern struct cfdriver ioasic_cd;
extern struct cfdriver tc_cd;
#endif
/* Definition of the driver for autoconfig. */
static int clockmatch __P((struct device *, void *, void *));
static void clockattach __P((struct device *, struct device *, void *));
struct cfattach clock_ca = {
sizeof(struct device), clockmatch, clockattach
};
struct cfdriver clock_cd = {
NULL, "clock", DV_DULL
};
#ifdef notyet
static void clock_startintr __P((void *));
static void clock_stopintr __P((void *));
#endif
volatile struct chiptime *Mach_clock_addr;
static int
clockmatch(parent, cfdata, aux)
struct device *parent;
void *cfdata;
void *aux;
{
struct cfdata *cf = cfdata;
struct confargs *ca = aux;
#if NTC>0
struct ioasicdev_attach_args *d = aux;
#endif
#ifdef notdef /* XXX */
struct tc_cfloc *asic_locp = (struct asic_cfloc *)cf->cf_loc;
#endif
int nclocks;
#if NTC>0
if (parent->dv_cfdata->cf_driver != &ioasic_cd &&
parent->dv_cfdata->cf_driver != &tc_cd &&
parent->dv_cfdata->cf_driver != &mainbus_cd)
#else
if (parent->dv_cfdata->cf_driver != &mainbus_cd)
#endif
return(0);
/* make sure that we're looking for this type of device. */
#if NTC>0
if (parent->dv_cfdata->cf_driver != &mainbus_cd) {
if (strcmp(d->iada_modname, "mc146818") != 0)
return (0);
} else
#endif
if (strcmp(ca->ca_name, "mc146818") != 0)
return (0);
/* All known decstations have a Dallas RTC */
nclocks = 1;
/* if it can't have the one mentioned, reject it */
if (cf->cf_unit >= nclocks)
return (0);
return (1);
}
static void
clockattach(parent, self, aux)
struct device *parent;
struct device *self;
void *aux;
{
struct confargs *ca = aux;
#if NTC>0
struct ioasicdev_attach_args *d = aux;
#endif
#ifndef pmax
register volatile struct chiptime *c;
#endif
#if NTC>0
if (parent->dv_cfdata->cf_driver != &mainbus_cd)
Mach_clock_addr = (struct chiptime *)
MIPS_PHYS_TO_KSEG1(d->iada_addr);
else
#endif
Mach_clock_addr = (struct chiptime *)
MIPS_PHYS_TO_KSEG1(ca->ca_addr);
#ifdef pmax
printf("\n");
return;
#endif
#ifndef pmax /* Turn interrupts off, just in case. */
c = Mach_clock_addr;
c->regb = REGB_DATA_MODE | REGB_HOURS_FORMAT;
wbflush();
#endif
#ifdef notyet /*XXX*/ /*FIXME*/
BUS_INTR_ESTABLISH(ca, (intr_handler_t)hardclock, NULL);
#endif
}
/*
* Start the real-time and statistics clocks. Leave stathz 0 since there
* are no other timers available.
@ -259,21 +107,13 @@ clockattach(parent, self, aux)
void
cpu_initclocks()
{
register volatile struct chiptime *c;
extern int tickadj;
#ifdef NTP
extern int fixtick;
#endif
register long tmp;
if (Mach_clock_addr == NULL)
panic("cpu_initclocks: no clock to initialize");
if (clockfns == NULL)
panic("cpu_initclocks: no clock attached");
hz = HZ; /* Clock Hz is a configuration parameter */
hz = CLOCK_RATE; /* 256 Hz clock */
tick = 1000000 / hz; /* number of microseconds between interrupts */
#ifdef NTP
fixtick =
#endif
tickfix = 1000000 - (hz * tick);
if (tickfix) {
int ftp;
@ -283,19 +123,26 @@ cpu_initclocks()
tickfixinterval = hz >> (ftp - 1);
}
c = Mach_clock_addr;
c->rega = REGA_TIME_BASE | SELECTED_RATE;
c->regb = REGB_PER_INT_ENA | REGB_DATA_MODE | REGB_HOURS_FORMAT;
wbflush(); /* Alpha needs this */
/*
* Establish the clock interrupt; it's a special case.
*
* We establish the clock interrupt this late because if
* we do it at clock attach time, we may have never been at
* spl0() since taking over the system. Some versions of
* PALcode save a clock interrupt, which would get delivered
* when we spl0() in autoconf.c. If established the clock
* interrupt handler earlier, that interrupt would go to
* hardclock, which would then fall over because p->p_stats
* isn't set at that time.
*/
#ifdef alpha
set_clockintr();
#endif
/*
* Reset tickadj to ntp's idea of what it should be
* XXX this should be in conf/param.c
* Get the clock started.
*/
tmp = (long) tick * 500L;
tickadj = (int)(tmp / 1000000L);
if (tmp % 1000000L > 0)
tickadj++;
(*clockfns->cf_init)(clockdev);
}
/*
@ -307,24 +154,10 @@ void
setstatclockrate(newhz)
int newhz;
{
/* nothing we can do */
}
/*
* This is the amount to add to the value stored in the clock chip
* to get the current year.
*
* Experimentation (and passing years) show that Decstation PROMS
* assume the kernel uses the clock chip as a time-of-year clock.
* The PROM assumes the clock is always set to 1972 or 1973, and contains
* time-of-year in seconds. The PROM checks the clock at boot time,
* and if it's outside that range, sets it to 1972-01-01.
*/
#define YR_OFFSET 25 /* good until dec 31, 1998 */
#define DAY_OFFSET /*1*/ 0
#define BASE_YEAR 1972
/*
* This code is defunct after 2099.
* Will Unix still be here then??
@ -334,7 +167,7 @@ static short dayyr[12] = {
};
/*
* Initialize the time of day register, based on the time base which is, e.g.
* Initialze the time of day register, based on the time base which is, e.g.
* from a filesystem. Base provides the time to within six months,
* and the time of year clock (if any) provides the rest.
*/
@ -342,11 +175,10 @@ void
inittodr(base)
time_t base;
{
register volatile struct chiptime *c;
register int days, yr;
int sec, min, hour, day, mon, year;
long deltat;
int badbase, s;
struct clocktime ct;
time_t deltat;
int badbase;
if (base < 5*SECYR) {
printf("WARNING: preposterous time in file system");
@ -356,39 +188,15 @@ inittodr(base)
} else
badbase = 0;
c = Mach_clock_addr;
(*clockfns->cf_get)(clockdev, base, &ct);
clockinitted = 1;
/*
* Don't read clock registers while they are being updated,
* and make sure we don't re-read the clock's registers
* too often while waiting.
*/
s = splclock();
while ((c->rega & REGA_UIP) == 1) {
splx(s);
DELAY(10);
s = splclock();
}
sec = c->sec;
min = c->min;
hour = c->hour;
day = c->day;
mon = c->mon;
year = c->year;
splx(s);
#ifdef DEBUG_CLOCK
printf("inittodr(): todr hw yy/mm/dd= %d/%d/%d\n", year, mon, day);
#endif
/* convert from PROM time-of-year convention to actual time */
day += DAY_OFFSET;
year += YR_OFFSET;
/* Perform MD RTC-toto-system-time conversion */
clk_rtc_to_systime(&ct, base);
/* simple sanity checks */
if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31 ||
hour > 23 || min > 59 || sec > 59) {
if (ct.year < 70 || ct.mon < 1 || ct.mon > 12 || ct.day < 1 ||
ct.day > 31 || ct.hour > 23 || ct.min > 59 || ct.sec > 59) {
/*
* Believe the time in the file system for lack of
* anything better, resetting the TODR.
@ -401,13 +209,14 @@ inittodr(base)
goto bad;
}
days = 0;
for (yr = 70; yr < year; yr++)
for (yr = 70; yr < ct.year; yr++)
days += LEAPYEAR(yr) ? 366 : 365;
days += dayyr[mon - 1] + day - 1;
if (LEAPYEAR(yr) && mon > 2)
days += dayyr[ct.mon - 1] + ct.day - 1;
if (LEAPYEAR(yr) && ct.mon > 2)
days++;
/* now have days since Jan 1, 1970; the rest is easy... */
time.tv_sec = days * SECDAY + hour * 3600 + min * 60 + sec;
time.tv_sec =
days * SECDAY + ct.hour * SECHOUR + ct.min * SECMIN + ct.sec;
if (!badbase) {
/*
@ -419,8 +228,9 @@ inittodr(base)
deltat = -deltat;
if (deltat < 2 * SECDAY)
return;
printf("WARNING: clock %s %ld days",
time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
printf("WARNING: clock %s %d days",
time.tv_sec < base ? "lost" : "gained",
(int) (deltat / SECDAY));
}
bad:
printf(" -- CHECK AND RESET THE DATE!\n");
@ -436,83 +246,43 @@ bad:
void
resettodr()
{
register volatile struct chiptime *c;
register int t, t2;
int sec, min, hour, day, dow, mon, year;
int s;
struct clocktime ct;
if (!clockinitted)
return;
/* compute the day of week. */
t2 = time.tv_sec / SECDAY;
dow = (t2 + 4) % 7; /* 1/1/1970 was thursday */
ct.dow = (t2 + 4) % 7; /* 1/1/1970 was thursday */
/* compute the year */
t = t2;
year = 69;
ct.year = 69;
t = t2; /* XXX ? */
while (t2 >= 0) { /* whittle off years */
t = t2;
year++;
t2 -= LEAPYEAR(year) ? 366 : 365;
ct.year++;
t2 -= LEAPYEAR(ct.year) ? 366 : 365;
}
/* t = month + day; separate */
t2 = LEAPYEAR(year);
for (mon = 1; mon < 12; mon++)
if (t < dayyr[mon] + (t2 && mon > 1))
t2 = LEAPYEAR(ct.year);
for (ct.mon = 1; ct.mon < 12; ct.mon++)
if (t < dayyr[ct.mon] + (t2 && ct.mon > 1))
break;
day = t - dayyr[mon - 1] + 1;
if (t2 && mon > 2)
day--;
ct.day = t - dayyr[ct.mon - 1] + 1;
if (t2 && ct.mon > 2)
ct.day--;
/* the rest is easy */
t = time.tv_sec % SECDAY;
hour = t / 3600;
ct.hour = t / SECHOUR;
t %= 3600;
min = t / 60;
sec = t % 60;
ct.min = t / SECMIN;
ct.sec = t % SECMIN;
c = Mach_clock_addr;
clk_systime_to_rtc(&ct, time.tv_sec);
/* convert to the format the PROM uses */
day -= DAY_OFFSET;
year -= YR_OFFSET;
s = splclock();
t = c->regd; /* reset VRT */
c->regb = REGB_SET_TIME | REGB_DATA_MODE | REGB_HOURS_FORMAT;
wbflush();
c->rega = 0x70; /* reset time base */
wbflush();
c->sec = sec;
c->min = min;
c->hour = hour;
/*c->dayw = dow;*/
c->day = day;
c->mon = mon;
c->year = year;
wbflush();
c->rega = REGA_TIME_BASE | SELECTED_RATE;
c->regb = REGB_PER_INT_ENA | REGB_DATA_MODE | REGB_HOURS_FORMAT;
wbflush();
splx(s);
#ifdef DEBUG_CLOCK
printf("resettodr(): todr hw yy/mm/dd= %d/%d/%d\n", year, mon, day);
#endif
c->nvram[48*4] |= 1; /* Set PROM time-valid bit */
wbflush();
}
/*XXX*/
/*
* Wait "n" microseconds.
* (scsi code needs this).
*/
void
delay(n)
int n;
{
DELAY(n);
(*clockfns->cf_set)(clockdev, &ct);
}

View File

@ -0,0 +1,140 @@
/* $NetBSD: mcclock.c,v 1.1 1997/06/22 09:34:47 jonathan Exp $ */
/*
* Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: mcclock.c,v 1.1 1997/06/22 09:34:47 jonathan Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <dev/tc/clockvar.h>
#include <dev/tc/mcclockvar.h>
#include <dev/ic/mc146818reg.h>
struct cfdriver clock_cd = {
NULL, "clock", DV_DULL,
};
void mcclock_init __P((struct device *));
void mcclock_get __P((struct device *, time_t, struct clocktime *));
void mcclock_set __P((struct device *, struct clocktime *));
const struct clockfns mcclock_clockfns = {
mcclock_init, mcclock_get, mcclock_set,
};
#define mc146818_write(dev, reg, datum) \
(*(dev)->sc_busfns->mc_bf_write)(dev, reg, datum)
#define mc146818_read(dev, reg) \
(*(dev)->sc_busfns->mc_bf_read)(dev, reg)
void
mcclock_attach(sc, busfns)
struct mcclock_softc *sc;
const struct mcclock_busfns *busfns;
{
printf(": mc146818 or compatible");
sc->sc_busfns = busfns;
/* Turn interrupts off, just in case. */
mc146818_write(sc, MC_REGB, MC_REGB_BINARY | MC_REGB_24HR);
clockattach(&sc->sc_dev, &mcclock_clockfns);
}
void
mcclock_init(dev)
struct device *dev;
{
struct mcclock_softc *sc = (struct mcclock_softc *)dev;
mc146818_write(sc, MC_REGA, MC_BASE_32_KHz | MC_RATE_256_Hz);
mc146818_write(sc, MC_REGB,
MC_REGB_PIE | MC_REGB_SQWE | MC_REGB_BINARY | MC_REGB_24HR);
}
/*
* Get the time of day, based on the clock's value and/or the base value.
*/
void
mcclock_get(dev, base, ct)
struct device *dev;
time_t base;
struct clocktime *ct;
{
struct mcclock_softc *sc = (struct mcclock_softc *)dev;
mc_todregs regs;
int s;
s = splclock();
MC146818_GETTOD(sc, &regs)
splx(s);
ct->sec = regs[MC_SEC];
ct->min = regs[MC_MIN];
ct->hour = regs[MC_HOUR];
ct->dow = regs[MC_DOW];
ct->day = regs[MC_DOM];
ct->mon = regs[MC_MONTH];
ct->year = regs[MC_YEAR];
}
/*
* Reset the TODR based on the time value.
*/
void
mcclock_set(dev, ct)
struct device *dev;
struct clocktime *ct;
{
struct mcclock_softc *sc = (struct mcclock_softc *)dev;
mc_todregs regs;
int s;
s = splclock();
MC146818_GETTOD(sc, &regs);
splx(s);
regs[MC_SEC] = ct->sec;
regs[MC_MIN] = ct->min;
regs[MC_HOUR] = ct->hour;
regs[MC_DOW] = ct->dow;
regs[MC_DOM] = ct->day;
regs[MC_MONTH] = ct->mon;
regs[MC_YEAR] = ct->year;
s = splclock();
MC146818_PUTTOD(sc, &regs);
splx(s);
}

View File

@ -0,0 +1,151 @@
/* $NetBSD: mcclock_ioasic.c,v 1.1 1997/06/22 09:34:50 jonathan Exp $ */
/*
* Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: mcclock_ioasic.c,v 1.1 1997/06/22 09:34:50 jonathan Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/autoconf.h>
#include <dev/tc/clockvar.h>
#include <dev/tc/mcclockvar.h>
#include <dev/ic/mc146818reg.h>
#include <dev/tc/tcreg.h>
#include <dev/tc/tcvar.h>
#include <dev/tc/ioasicvar.h> /* XXX */
struct mcclock_ioasic_clockdatum {
u_char datum;
char pad[3];
};
struct mcclock_ioasic_softc {
struct mcclock_softc sc_mcclock;
struct mcclock_ioasic_clockdatum *sc_dp;
};
int mcclock_ioasic_match __P((struct device *, struct cfdata *, void *));
void mcclock_ioasic_attach __P((struct device *, struct device *, void *));
struct cfattach mcclock_ioasic_ca = {
sizeof (struct mcclock_ioasic_softc), (void *)mcclock_ioasic_match,
mcclock_ioasic_attach,
};
void mcclock_ioasic_write __P((struct mcclock_softc *, u_int, u_int));
u_int mcclock_ioasic_read __P((struct mcclock_softc *, u_int));
const struct mcclock_busfns mcclock_ioasic_busfns = {
mcclock_ioasic_write, mcclock_ioasic_read,
};
volatile struct chiptime *Mach_clock_addr; /* XXX glue for pmax heritage */
int
mcclock_ioasic_match(parent, match, aux)
struct device *parent;
struct cfdata *match;
void *aux;
{
#define CFMATCH(cf,x) !strcmp((cf)->dv_cfdata->cf_driver->cd_name,(x))
char *name;
vm_offset_t addr;
if (CFMATCH(parent, "mainbus")) {
struct confargs *ca = aux;
addr = (vm_offset_t)ca->ca_addr;
name = ca->ca_name;
}
else
if (CFMATCH(parent, "asic")) {
struct ioasicdev_attach_args *d = aux;
addr = d->iada_addr;
name = d->iada_modname;
}
else {
/*panic("clock must be attached with mainbus or ioasic\n");*/
printf("clock on %s: must be attached at mainbus or ioasic\n",
parent->dv_cfdata->cf_driver->cd_name);
return(0);
}
if (strcmp("mc146818", name))
return (0);
Mach_clock_addr = (struct chiptime *)MIPS_PHYS_TO_KSEG1(addr);
return (1);
#undef CFMATCH
}
void
mcclock_ioasic_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct ioasicdev_attach_args *ioasicdev = aux;
struct mcclock_ioasic_softc *sc = (struct mcclock_ioasic_softc *)self;
sc->sc_dp = (struct mcclock_ioasic_clockdatum *)ioasicdev->iada_addr;
mcclock_attach(&sc->sc_mcclock, &mcclock_ioasic_busfns);
}
void
mcclock_ioasic_write(dev, reg, datum)
struct mcclock_softc *dev;
u_int reg, datum;
{
struct mcclock_ioasic_softc *sc = (struct mcclock_ioasic_softc *)dev;
sc->sc_dp[reg].datum = datum;
}
u_int
mcclock_ioasic_read(dev, reg)
struct mcclock_softc *dev;
u_int reg;
{
struct mcclock_ioasic_softc *sc = (struct mcclock_ioasic_softc *)dev;
return (sc->sc_dp[reg].datum);
}
/*XXX*/
/*
* Wait "n" microseconds. (scsi code needs this).
*/
void
delay(n)
int n;
{
DELAY(n);
}