Add microSPARC-IIep support. Protect mostek clock code with NMK48TXX

so that this file doesn't require obio, iommu and sbus to link the kernel.
Make todr_handle and establish_hostid() non-static.
This commit is contained in:
uwe 2001-12-11 04:17:48 +00:00
parent 59ee8a3dfb
commit 0a2b7fe7d7
1 changed files with 196 additions and 73 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: clock.c,v 1.82 2001/12/04 00:05:06 darrenr Exp $ */
/* $NetBSD: clock.c,v 1.83 2001/12/11 04:17:48 uwe Exp $ */
/*
* Copyright (c) 1992, 1993
@ -60,6 +60,30 @@
*/
#include "opt_sparc_arch.h"
/*
* This file lumps together a lot of loosely related stuff with
* confusingly similar names.
*
* First, there are kernel's clocks provided by "timer" device. The
* hardclock is provided by the timer register (aka system counter).
* The statclock is provided by per cpu counter register(s) (aka
* processor counter(s)).
*
* The "clock" device is the time-of-day clock provided by MK48Txx.
* idprom is located in the NVRAM area of the chip.
*
* microSPARC-IIep machines use DS1287A at EBus for TOD clock and the
* driver for it ("rtc") is in a separate file to prevent this file
* from being cluttered even further.
*/
/*
* ifdef out mk48txx TOD clock code for the sake of ms-IIep so that
* this file doesn't require obio, iommu and sbus to link the kernel.
*/
#include "mk48txx.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/device.h>
@ -87,6 +111,20 @@
#include <sparc/sparc/cpuvar.h>
#include <sparc/sparc/timerreg.h>
#if defined(MSIIEP)
#include <sparc/sparc/msiiepreg.h>
/* XXX: move this stuff to msiiepreg.h? */
/* ms-IIep PCIC registers mapped at fixed VA (see vaddrs.h) */
#define msiiep ((volatile struct msiiep_pcic_reg *)MSIIEP_PCIC_VA)
/*
* ms-IIep counters tick every 4 cpu clock @100MHz.
* counter is reset to 1 when new limit is written.
*/
#define tmr_ustolimIIep(n) ((n)* 25 + 1)
#endif /* MSIIEP */
/*
* Statistics clock interval and variance, in usec. Variance must be a
* power of two. Since this gives us an even number, not an odd number,
@ -124,11 +162,7 @@ extern struct idprom sun4_idprom_store;
static int oldclk = 0;
bus_space_tag_t i7_bt;
bus_space_handle_t i7_bh;
#endif
/* Location and size of the MK48xx TOD clock, if present */
static bus_space_handle_t mk_nvram_base;
static bus_size_t mk_nvram_size;
#endif /* SUN4 */
static int oclockmatch(struct device *, struct cfdata *, void *);
static void oclockattach(struct device *, struct device *, void *);
@ -137,11 +171,6 @@ struct cfattach oclock_ca = {
sizeof(struct device), oclockmatch, oclockattach
};
extern struct cfdriver oclock_cd;
static struct intrhand level10 = { clockintr };
static struct intrhand level14 = { statintr };
/*
* Sun 4 machines use the old-style (a'la Sun 3) EEPROM. On the
* 4/100's and 4/200's, this is at a separate obio space. On the
@ -168,7 +197,13 @@ struct cfattach eeprom_ca = {
sizeof(struct device), eeprom_match, eeprom_attach
};
extern struct cfdriver eeprom_cd;
#if NMK48TXX > 0
/* Location and size of the MK48xx TOD clock, if present */
static bus_space_handle_t mk_nvram_base;
static bus_size_t mk_nvram_size;
static int clk_wenable(todr_chip_handle_t, int);
static int clockmatch_mainbus (struct device *, struct cfdata *, void *);
static int clockmatch_obio(struct device *, struct cfdata *, void *);
@ -184,8 +219,11 @@ struct cfattach clock_mainbus_ca = {
struct cfattach clock_obio_ca = {
sizeof(struct device), clockmatch_obio, clockattach_obio
};
#endif /* NMK48TXX > 0 */
extern struct cfdriver clock_cd;
static struct intrhand level10 = { clockintr };
static struct intrhand level14 = { statintr };
static int timermatch_mainbus(struct device *, struct cfdata *, void *);
static int timermatch_obio(struct device *, struct cfdata *, void *);
@ -194,6 +232,13 @@ static void timerattach_obio(struct device *, struct device *, void *);
static void timerattach(volatile int *, volatile int *);
/*
* On ms-IIep counters are part of PCIC, so msiiep_attach will simply
* call this function to configure the counters.
*/
void timerattach_msiiep(void);
/*struct counter_4m *counterreg_4m;*/
struct timer_4m *timerreg4m;
#define counterreg4m cpuinfo.counterreg_4m
@ -209,16 +254,15 @@ struct cfattach timer_obio_ca = {
};
/* Global TOD clock handle & idprom pointer */
static todr_chip_handle_t todr_handle;
todr_chip_handle_t todr_handle;
struct idprom *idprom;
static int clk_wenable(todr_chip_handle_t, int);
static void stopcounter(struct counter_4m *);
static void establish_hostid(struct idprom *);
void establish_hostid(struct idprom *);
void myetheraddr(u_char *);
int timerblurb = 10; /* Guess a value; used before clock is attached */
/*
* old clock match routine
*/
@ -324,7 +368,7 @@ oclockattach(parent, self, aux)
if ((todr_handle = intersil7170_attach(bt, bh, 1968)) == NULL)
panic("Can't attach tod clock");
establish_hostid(idprom = &sun4_idprom_store);
establish_hostid(&sun4_idprom_store);
#endif /* SUN4 */
}
@ -393,6 +437,9 @@ eeprom_attach(parent, self, aux)
#endif /* SUN4 */
}
#if NMK48TXX > 0
/*
* The OPENPROM calls the clock the "eeprom", so we have to have our
* own special match function to call it the "clock".
@ -573,6 +620,42 @@ clockattach(node, bt, bh)
establish_hostid(idp);
}
/*
* Write en/dis-able TOD clock registers. This is a safety net to
* save idprom (part of mk48txx TOD clock) from being accidentally
* stomped on by a buggy code. We coordinate so that several writers
* can run simultaneously.
*/
int
clk_wenable(handle, onoff)
todr_chip_handle_t handle;
int onoff;
{
int s;
vm_prot_t prot;/* nonzero => change prot */
int npages;
vaddr_t base;
static int writers;
/* XXX - we ignore `handle' here... */
s = splhigh();
if (onoff)
prot = writers++ == 0 ? VM_PROT_READ|VM_PROT_WRITE : 0;
else
prot = --writers == 0 ? VM_PROT_READ : 0;
splx(s);
npages = round_page((vsize_t)mk_nvram_size) << PAGE_SHIFT;
base = trunc_page((vaddr_t)mk_nvram_base);
if (prot)
pmap_changeprot(pmap_kernel(), base, prot, npages);
return (0);
}
#endif /* NMK48TXX > 0 */ /* "clock" device driver */
/*
* The sun4c OPENPROM calls the timer the "counter-timer".
*/
@ -783,48 +866,59 @@ timerattach(cntreg, limreg)
timerok = 1;
}
#if defined(MSIIEP)
/*
* Write en/dis-able clock registers. We coordinate so that several
* writers can run simultaneously.
* Attach system and cpu counters (kernel hard and stat clocks) for ms-IIep.
* Counters are part of the PCIC and there's no PROM node for them.
* msiiep_attach() will call this function directly.
*/
int
clk_wenable(handle, onoff)
todr_chip_handle_t handle;
int onoff;
{
int s;
vm_prot_t prot;/* nonzero => change prot */
int npages;
vaddr_t base;
static int writers;
/* XXX - we ignore `handle' here... */
s = splhigh();
if (onoff)
prot = writers++ == 0 ? VM_PROT_READ|VM_PROT_WRITE : 0;
else
prot = --writers == 0 ? VM_PROT_READ : 0;
splx(s);
npages = round_page((vsize_t)mk_nvram_size) << PAGE_SHIFT;
base = trunc_page((vaddr_t)mk_nvram_base);
if (prot)
pmap_changeprot(pmap_kernel(), base, prot, npages);
return (0);
}
void
stopcounter(creg)
struct counter_4m *creg;
timerattach_msiiep()
{
/* Stop the clock */
/* Put processor counter in "counter" mode */
msiiep->pcic_pc_ctl = 0; /* stop user timer (just in case) */
msiiep->pcic_pc_cfg = 0; /* timer mode disabled (processor counter) */
/*
* Calibrate delay() by tweaking the magic constant
* until a delay(100) actually reads (at least) 100 us on the clock.
* Note: ms-IIep clocks ticks every 4 processor cycles.
*/
for (timerblurb = 1; ; ++timerblurb) {
volatile int discard;
discard = creg->t_limit;
creg->t_limit = 0;
creg->t_ss = 0;
int t;
discard = msiiep->pcic_pclr; /* clear the limit bit */
msiiep->pcic_pclr = 0; /* reset counter to 1, free run */
delay(100);
t = msiiep->pcic_pccr;
if (t & TMR_LIMIT) /* cannot happen */
panic("delay calibration");
/* counter ticks -> usec, inverse of tmr_ustolimIIep */
t = (t - 1) / 25;
if (t >= 100)
break;
}
printf(" delay constant %d\n", timerblurb);
/*
* Set counter interrupt priority assignment:
* upper 4 bits are for system counter: level 10
* lower 4 bits are for processor counter: level 14
*/
msiiep->pcic_cipar = 0xae;
/* link interrupt handlers */
intr_establish(10, &level10);
intr_establish(14, &level14);
timerok = 1;
}
#endif /* MSIIEP */
/*
* XXX this belongs elsewhere
@ -863,8 +957,8 @@ establish_hostid(idp)
/*
* Set up the real-time and statistics clocks. Leave stathz 0 only if
* no alternative timer is available.
* Set up the real-time and statistics clocks.
* Leave stathz 0 only if no alternative timer is available.
*
* The frequencies of these clocks must be an even number of microseconds.
*/
@ -911,7 +1005,9 @@ cpu_initclocks()
minint = statint / 2 + 100;
while (statvar > minint)
statvar >>= 1;
statmin = statint - (statvar >> 1);
#if defined(SUN4M) && !defined(MSIIEP)
if (CPU_ISSUN4M) {
int n;
timerreg4m->t_limit = tmr_ustolim4m(tick);
@ -921,23 +1017,25 @@ cpu_initclocks()
continue;
cpi->counterreg_4m->t_limit = tmr_ustolim4m(statint);
}
ienab_bic(SINTR_T);
}
#endif
#if defined(MSIIEP)
/* ms-IIep kernels support *only* IIep */ {
msiiep->pcic_sclr = tmr_ustolimIIep(tick);
msiiep->pcic_pclr = tmr_ustolimIIep(statint);
/* XXX: ensure interrupt target mask doesn't masks them? */
}
#endif
#if defined(SUN4) || defined(SUN4C)
if (CPU_ISSUN4OR4C) {
timerreg4->t_c10.t_limit = tmr_ustolim(tick);
timerreg4->t_c14.t_limit = tmr_ustolim(statint);
}
statmin = statint - (statvar >> 1);
#if defined(SUN4M)
if (CPU_ISSUN4M)
ienab_bic(SINTR_T);
#endif
if (CPU_ISSUN4OR4C)
ienab_bis(IE_L14 | IE_L10);
}
#endif
}
/*
@ -952,9 +1050,9 @@ setstatclockrate(newhz)
}
/*
* Level 10 (clock) interrupts. If we are using the FORTH PROM for
* console input, we need to check for that here as well, and generate
* a software interrupt to read it.
* Level 10 (clock) interrupts from system counter.
* If we are using the FORTH PROM for console input, we need to check
* for that here as well, and generate a software interrupt to read it.
*/
int
clockintr(cap)
@ -979,9 +1077,14 @@ clockintr(cap)
goto forward;
}
#endif
/* read the limit register to clear the interrupt */
if (CPU_ISSUN4M) {
#if !defined(MSIIEP)
discard = timerreg4m->t_limit;
#else
discard = msiiep->pcic_sclr;
#endif
}
if (CPU_ISSUN4OR4C) {
@ -997,7 +1100,7 @@ forward:
}
/*
* Level 14 (stat clock) interrupt handler.
* Level 14 (stat clock) interrupts from processor counter.
*/
int
statintr(cap)
@ -1015,12 +1118,27 @@ statintr(cap)
/* read the limit register to clear the interrupt */
if (CPU_ISSUN4M) {
#if !defined(MSIIEP)
discard = counterreg4m->t_limit;
#else
discard = msiiep->pcic_pclr;
#endif
if (timerok == 0) {
/* Stop the clock */
printf("note: counter running!\n");
stopcounter(counterreg4m);
#if !defined(MSIIEP)
discard = counterreg4m->t_limit;
counterreg4m->t_limit = 0;
counterreg4m->t_ss = 0;
timerreg4m->t_cfg = TMR_CFG_USER;
#else
/*
* Turn interrupting processor counter
* into non-interrupting user timer.
*/
msiiep->pcic_pc_cfg = 1; /* make it a user timer */
msiiep->pcic_pc_ctl = 0; /* stop user timer */
#endif
return 1;
}
}
@ -1028,6 +1146,7 @@ statintr(cap)
if (CPU_ISSUN4OR4C) {
discard = timerreg4->t_c14.t_limit;
}
statclock((struct clockframe *)cap);
/*
@ -1047,7 +1166,11 @@ statintr(cap)
* loose the counter ticks that happened since this
* interrupt was raised.
*/
#if !defined(MSIIEP)
counterreg4m->t_limit_nr = tmr_ustolim4m(newint);
#else
msiiep->pcic_pclr_nr = tmr_ustolimIIep(newint);
#endif
}
if (CPU_ISSUN4OR4C) {