summaryrefslogtreecommitdiff
path: root/sys/arch/mvme88k/dev/clock.c
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2004-08-25 21:47:55 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2004-08-25 21:47:55 +0000
commit1f755f5c3eadbc9cd7cb48cc9d4ccda2a64d5984 (patch)
treeed83def6db756bab97e2bae682c5df20d6d3a91b /sys/arch/mvme88k/dev/clock.c
parent0b111ba984e8a2d8c5711474583d88396eaa55b0 (diff)
Swap the sources for clock and statclock on MVME188 (the Z8536 being more
reliable), and add a large block of comments to explain the timer mess^Wsituation on MVME188.
Diffstat (limited to 'sys/arch/mvme88k/dev/clock.c')
-rw-r--r--sys/arch/mvme88k/dev/clock.c148
1 files changed, 83 insertions, 65 deletions
diff --git a/sys/arch/mvme88k/dev/clock.c b/sys/arch/mvme88k/dev/clock.c
index 55839281c54..a68832f3242 100644
--- a/sys/arch/mvme88k/dev/clock.c
+++ b/sys/arch/mvme88k/dev/clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clock.c,v 1.41 2004/08/25 20:18:46 miod Exp $ */
+/* $OpenBSD: clock.c,v 1.42 2004/08/25 21:47:54 miod Exp $ */
/*
* Copyright (c) 1999 Steve Murphree, Jr.
* Copyright (c) 1995 Theo de Raadt
@@ -209,13 +209,13 @@ clockattach(struct device *parent, struct device *self, void *args)
sc->sc_profih.ih_arg = 0;
sc->sc_profih.ih_wantframe = 1;
sc->sc_profih.ih_ipl = ca->ca_ipl;
- sysconintr_establish(SYSCV_TIMER1, &sc->sc_profih, "clock");
+ sysconintr_establish(SYSCV_TIMER2, &sc->sc_profih, "clock");
md.clock_init_func = m188_initclock;
sc->sc_statih.ih_fn = m188_statintr;
sc->sc_statih.ih_arg = 0;
sc->sc_statih.ih_wantframe = 1;
sc->sc_statih.ih_ipl = ca->ca_ipl;
- sysconintr_establish(SYSCV_TIMER2, &sc->sc_statih, "stat");
+ sysconintr_establish(SYSCV_TIMER1, &sc->sc_statih, "stat");
md.statclock_init_func = m188_initstatclock;
break;
#endif /* NSYSCON */
@@ -339,77 +339,88 @@ sbc_statintr(void *eframe)
#endif /* NPCCTWO */
#if NSYSCON > 0
+
+/*
+ * Notes on the MVME188 clock usage:
+ *
+ * We have two sources for timers:
+ * - two counter/timers in the DUART (MC68681/MC68692)
+ * - three counter/timers in the Zilog Z8536
+ *
+ * However:
+ * - Z8536 CT#3 is reserved as a watchdog device; and its input is
+ * user-controllable with jumpers on the SYSCON board, so we can't
+ * really use it.
+ * - When using the Z8536 in timer mode, it _seems_ like it resets at
+ * 0xffff instead of the initial count value...
+ * - Despite having per-counter programmable interrupt vectors, the
+ * SYSCON logic forces fixed vectors for the DUART and the Z8536 timer
+ * interrupts.
+ * - The DUART timers keep counting down from 0xffff even after
+ * interrupting, and need to be manually stopped, then restarted, to
+ * resume counting down the initial count value.
+ *
+ * Also, while the Z8536 has a very reliable 4MHz clock source, the
+ * 3.6864MHz clock source of the DUART timers does not seem to be correct.
+ *
+ * As a result, clock is run on a Z8536 counter, kept in counter mode and
+ * retriggered every interrupt, while statclock is run on a DUART counter,
+ * but in practice runs at an average 96Hz instead of the expected 100Hz.
+ *
+ * It should be possible to run statclock on the Z8536 counter #2, but
+ * this would make interrupt handling more tricky, in the case both
+ * counters interrupt at the same time...
+ */
+
int
m188_clockintr(void *eframe)
{
- volatile u_int32_t tmp;
-
- tmp = *(volatile u_int32_t *)DART_STOPC;
- /* acknowledge the timer interrupt */
- tmp = *(volatile u_int32_t *)DART_ISR;
- tmp = *(volatile u_int32_t *)DART_STARTC;
+ CIO_LOCK;
+ write_cio(CIO_CSR1, CIO_GCB | CIO_CIP); /* Ack the interrupt */
intrcnt[M88K_CLK_IRQ]++;
-
hardclock(eframe);
#if NBUGTTY > 0
bugtty_chkinput();
#endif /* NBUGTTY */
+ /* restart counter */
+ write_cio(CIO_CSR1, CIO_GCB | CIO_TCB | CIO_IE);
+ CIO_UNLOCK;
+
return (1);
}
void
m188_initclock(void)
{
- volatile int imr;
- int counter;
-
#ifdef CLOCK_DEBUG
printf("VME188 clock init\n");
#endif
+#ifdef DIAGNOSTIC
if (1000000 % hz) {
printf("cannot get %d Hz clock; using 100 Hz\n", hz);
hz = 100;
}
+#endif
tick = 1000000 / hz;
- /*
- * The DUART runs at 3.6864 MHz in PCLK/16 mode, hence for a
- * 100 Hz timer, it needs (3686400 / 16) / 100 ticks per cycle.
- */
- counter = (3686400 / 16) / hz;
-
-#ifdef CLOCK_DEBUG
- printf("tick == %d, counter == %d\n", tick, counter);
-#endif
- /* clear the counter/timer output OP3 while we program the DART */
- *(volatile u_int32_t *)DART_OPCR = 0x00;
- /* set interrupt vec */
- *(volatile u_int32_t *)DART_IVR = SYSCON_VECT + SYSCV_TIMER1;
- /* do the stop counter/timer command */
- imr = *(volatile u_int32_t *)DART_STOPC;
- /* set counter/timer to counter mode, clock/16 */
- *(volatile u_int32_t *)DART_ACR = 0x30;
- *(volatile u_int32_t *)DART_CTUR = (counter >> 8);
- *(volatile u_int32_t *)DART_CTLR = (counter & 0xff);
- /* set the counter/timer output OP3 */
- *(volatile u_int32_t *)DART_OPCR = 0x04;
- /* give the start counter/timer command */
- imr = *(volatile u_int32_t *)DART_STARTC;
+ simple_lock_init(&cio_lock);
+ m188_cio_init(tick);
}
int
m188_statintr(void *eframe)
{
+ volatile u_int32_t tmp;
u_long newint, r, var;
- CIO_LOCK;
+ /* stop counter and acknowledge interrupt */
+ tmp = *(volatile u_int32_t *)DART_STOPC;
+ tmp = *(volatile u_int32_t *)DART_ISR;
intrcnt[M88K_SCLK_IRQ]++;
-
statclock((struct clockframe *)eframe);
- write_cio(CIO_CSR1, CIO_GCB | CIO_CIP); /* Ack the interrupt */
/*
* Compute new randomized interval. The intervals are uniformly
@@ -422,41 +433,56 @@ m188_statintr(void *eframe)
} while (r == 0);
newint = statmin + r;
- /* Load time constant CTC #1 */
- newint <<= 1; /* CT1 runs at PCLK/2, hence 2MHz */
- write_cio(CIO_CT1MSB, newint >> 8);
- write_cio(CIO_CT1LSB, newint);
-
- /* Start CTC #1 running */
- write_cio(CIO_CSR1, CIO_GCB | CIO_TCB | CIO_IE);
+ /* setup new value and restart counter */
+ *(volatile u_int32_t *)DART_CTUR = (newint >> 8);
+ *(volatile u_int32_t *)DART_CTLR = (newint & 0xff);
+ tmp = *(volatile u_int32_t *)DART_STARTC;
- CIO_UNLOCK;
return (1);
}
void
m188_initstatclock(void)
{
+ volatile u_int32_t imr;
int statint, minint;
#ifdef CLOCK_DEBUG
printf("VME188 statclock init\n");
#endif
- simple_lock_init(&cio_lock);
if (stathz == 0)
stathz = hz;
+#ifdef DIAGNOSTIC
if (1000000 % stathz) {
printf("cannot get %d Hz statclock; using 100 Hz\n", stathz);
stathz = 100;
}
+#endif
profhz = stathz; /* always */
- statint = 1000000 / stathz;
+ /*
+ * The DUART runs at 3.6864 MHz, CT#1 will run in PCLK/16 mode.
+ */
+ statint = (3686400 / 16) / stathz;
minint = statint / 2 + 100;
while (statvar > minint)
statvar >>= 1;
- m188_cio_init(statint);
statmin = statint - (statvar >> 1);
+
+ /* clear the counter/timer output OP3 while we program the DART */
+ *(volatile u_int32_t *)DART_OPCR = 0x00;
+ /* set interrupt vec */
+ *(volatile u_int32_t *)DART_IVR = SYSCON_VECT + SYSCV_TIMER1;
+ /* do the stop counter/timer command */
+ imr = *(volatile u_int32_t *)DART_STOPC;
+ /* set counter/timer to counter mode, PCLK/16 */
+ *(volatile u_int32_t *)DART_ACR = 0x30;
+ *(volatile u_int32_t *)DART_CTUR = (statint >> 8);
+ *(volatile u_int32_t *)DART_CTLR = (statint & 0xff);
+ /* set the counter/timer output OP3 */
+ *(volatile u_int32_t *)DART_OPCR = 0x04;
+ /* give the start counter/timer command */
+ imr = *(volatile u_int32_t *)DART_STARTC;
}
/* Write CIO register */
@@ -474,8 +500,8 @@ write_cio(int reg, u_int val)
*cio_ctrl = 0; /* take CIO out of RESET */
i = *cio_ctrl; /* reset CIO state machine */
- *cio_ctrl = (reg & 0xff); /* Select register */
- *cio_ctrl = (val & 0xff); /* Write the value */
+ *cio_ctrl = (reg & 0xff); /* select register */
+ *cio_ctrl = (val & 0xff); /* write the value */
CIO_UNLOCK;
splx(s);
@@ -492,9 +518,9 @@ read_cio(int reg)
s = splclock();
CIO_LOCK;
- /* Select register */
+ /* select register */
*cio_ctrl = (reg & 0xff);
- /* Delay for a short time to allow 8536 to settle */
+ /* delay for a short time to allow 8536 to settle */
for (i = 0; i < 100; i++)
;
/* read the value */
@@ -507,9 +533,7 @@ read_cio(int reg)
/*
* Initialize the CTC (8536)
* Only the counter/timers are used - the IO ports are un-comitted.
- * Channels 1 and 2 are linked to provide a /32 counter.
*/
-
void
m188_cio_init(unsigned period)
{
@@ -517,8 +541,6 @@ m188_cio_init(unsigned period)
CIO_LOCK;
- /* Initialize 8536 CTC */
-
/* Start by forcing chip into known state */
read_cio(CIO_MICR);
write_cio(CIO_MICR, CIO_MICR_RESET); /* Reset the CTC */
@@ -532,21 +554,17 @@ m188_cio_init(unsigned period)
while ((read_cio(CIO_MICR) & CIO_MICR_RJA) == 0)
;
- /* Initialize the 8536 */
+ /* Initialize the 8536 for real */
write_cio(CIO_MICR,
CIO_MICR_MIE /* | CIO_MICR_NV */ | CIO_MICR_RJA | CIO_MICR_DLC);
write_cio(CIO_CTMS1, CIO_CTMS_CSC); /* Continuous count */
write_cio(CIO_PDCB, 0xff); /* set port B to input */
- /* Load time constant CTC #1 */
- period <<= 1; /* CT1 runs at PCLK/2, hence 2MHz */
+ period <<= 1; /* CT#1 runs at PCLK/2, hence 2MHz */
write_cio(CIO_CT1MSB, period >> 8);
write_cio(CIO_CT1LSB, period);
-
- /* enable counter 1 */
+ /* enable counter #1 */
write_cio(CIO_MCCR, CIO_MCCR_CT1E | CIO_MCCR_PBE);
-
- /* Start CTC #1 running */
write_cio(CIO_CSR1, CIO_GCB | CIO_TCB | CIO_IE);
CIO_UNLOCK;