summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2006-06-27 05:18:26 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2006-06-27 05:18:26 +0000
commitb903e886d1fb6afe8c060c76e45b1d113e992f99 (patch)
treea929729449440863e256c1c4ae5d7a61b74efd8e
parent7ed6b13766f8849a36fd96d75d5f95cde2262528 (diff)
Rewritten clock driver for 80219/80321, actually manages seperate stat
clock and tick timer and detects missing ticks.
-rw-r--r--sys/arch/arm/xscale/files.i803214
-rw-r--r--sys/arch/arm/xscale/i80321_clock.c489
-rw-r--r--sys/arch/arm/xscale/i80321_timer.c442
-rw-r--r--sys/arch/arm/xscale/i80321reg.h3
4 files changed, 493 insertions, 445 deletions
diff --git a/sys/arch/arm/xscale/files.i80321 b/sys/arch/arm/xscale/files.i80321
index 0f2032f6fc4..90d2d6d69f0 100644
--- a/sys/arch/arm/xscale/files.i80321
+++ b/sys/arch/arm/xscale/files.i80321
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i80321,v 1.2 2006/06/10 03:51:50 drahn Exp $
+# $OpenBSD: files.i80321,v 1.3 2006/06/27 05:18:25 drahn Exp $
device iopxs {}: pcibus, bus_space_generic, gpiobus
file arch/arm/xscale/i80321_space.c iopxs
file arch/arm/xscale/i80321_mcu.c iopxs
@@ -6,7 +6,7 @@ file arch/arm/xscale/i80321.c iopxs
file arch/arm/xscale/i80321_pci.c iopxs
file arch/arm/xscale/i80321_intr.c iopxs
-file arch/arm/xscale/i80321_timer.c iopxs
+file arch/arm/xscale/i80321_clock.c iopxs
# I2C controller unit
device iopiic: i2cbus
diff --git a/sys/arch/arm/xscale/i80321_clock.c b/sys/arch/arm/xscale/i80321_clock.c
new file mode 100644
index 00000000000..952978c61ff
--- /dev/null
+++ b/sys/arch/arm/xscale/i80321_clock.c
@@ -0,0 +1,489 @@
+/* $OpenBSD: i80321_clock.c,v 1.1 2006/06/27 05:18:25 drahn Exp $ */
+
+/*
+ * Copyright (c) 2006 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/device.h>
+#include <dev/clock_subr.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <arm/cpufunc.h>
+
+#include <arm/xscale/i80321reg.h>
+#include <arm/xscale/i80321var.h>
+
+#define TIMER_FREQUENCY 200000000 /* 200MHz */
+
+static struct evcount clk_count;
+static struct evcount stat_count;
+static int clk_irq = 129; /* XXX */
+static int stat_irq = 130; /* XXX */
+
+uint32_t nextstatevent;
+uint32_t nexttickevent;
+uint32_t ticks_per_intr;
+uint32_t ticks_per_second;
+uint32_t lastnow;
+uint32_t stat_error_cnt, tick_error_cnt;
+uint32_t statvar, statmin;
+int i80321_timer_inited;
+
+u_int32_t tmr0_read(void);
+void tmr0_write(u_int32_t val);
+inline u_int32_t tcr0_read(void);
+void tcr0_write(u_int32_t val);
+u_int32_t trr0_read(void);
+void trr0_write(u_int32_t val);
+u_int32_t tmr1_read(void);
+void tmr1_write(u_int32_t val);
+u_int32_t tcr1_read(void);
+void tcr1_write(u_int32_t val);
+u_int32_t trr1_read(void);
+void trr1_write(u_int32_t val);
+u_int32_t tisr_read(void);
+void tisr_write(u_int32_t val);
+int i80321_intr(void *frame);
+
+/*
+ * TMR0 is used in non-reload mode as it is used for both the clock
+ * timer and sched timer.
+ *
+ * The counters on 80321 are count down interrupt on 0, not match
+ * register based, so it is not possible to find out how much
+ * many interrupts passed while irqs were blocked.
+ * also it is not possible to atomically add to the register
+ * get get it to precisely fire at a non-fixed interval.
+ *
+ * To work around this both timers are used, TMR1 is used as a reference
+ * clock set to auto reload with 0xffffffff, however we just ignore the
+ * interrupt it would generate. NOTE: does this drop one tick
+ * ever wrap? Could the reference timer be used in non-reload mode,
+ * where it would just keep counting, and not stop at 0 ?
+ *
+ * Internally this keeps track of when the next timer should fire
+ * and based on that time and the current value of the reference
+ * clock a number is written into the timer count register to schedule
+ * the next event.
+ */
+
+
+u_int32_t
+tmr0_read(void)
+{
+ u_int32_t ret;
+ __asm volatile ("mrc p6, 0, %0, c0, c1, 0" : "=r" (ret));
+ return ret;
+}
+
+void
+tmr0_write(u_int32_t val)
+{
+ __asm volatile ("mcr p6, 0, %0, c0, c1, 0" :: "r" (val));
+}
+
+inline u_int32_t
+tcr0_read(void)
+{
+ u_int32_t ret;
+ __asm volatile ("mrc p6, 0, %0, c2, c1, 0" : "=r" (ret));
+ return ret;
+}
+
+void
+tcr0_write(u_int32_t val)
+{
+ __asm volatile ("mcr p6, 0, %0, c2, c1, 0" :: "r" (val));
+}
+
+u_int32_t
+trr0_read(void)
+{
+ u_int32_t ret;
+ __asm volatile ("mrc p6, 0, %0, c4, c1, 0" : "=r" (ret));
+ return ret;
+}
+
+void
+trr0_write(u_int32_t val)
+{
+ __asm volatile ("mcr p6, 0, %0, c4, c1, 0" :: "r" (val));
+}
+
+u_int32_t
+tmr1_read(void)
+{
+ u_int32_t ret;
+ __asm volatile ("mrc p6, 0, %0, c1, c1, 0" : "=r" (ret));
+ return ret;
+}
+
+void
+tmr1_write(u_int32_t val)
+{
+ __asm volatile ("mcr p6, 0, %0, c1, c1, 0" :: "r" (val));
+}
+
+u_int32_t
+tcr1_read(void)
+{
+ u_int32_t ret;
+ __asm volatile ("mrc p6, 0, %0, c3, c1, 0" : "=r" (ret));
+ return ret;
+}
+
+void
+tcr1_write(u_int32_t val)
+{
+ __asm volatile ("mcr p6, 0, %0, c3, c1, 0" :: "r" (val));
+}
+
+u_int32_t
+trr1_read(void)
+{
+ u_int32_t ret;
+ __asm volatile ("mrc p6, 0, %0, c5, c1, 0" : "=r" (ret));
+ return ret;
+}
+
+void
+trr1_write(u_int32_t val)
+{
+ __asm volatile ("mcr p6, 0, %0, c5, c1, 0" :: "r" (val));
+}
+
+u_int32_t
+tisr_read()
+{
+ u_int32_t ret;
+ __asm volatile ("mrc p6, 0, %0, c6, c1, 0" : "=r" (ret));
+ return ret;
+}
+
+void
+tisr_write(u_int32_t val)
+{
+ __asm volatile ("mcr p6, 0, %0, c6, c1, 0" :: "r" (val));
+}
+
+/*
+ * timer 1 is running a timebase counter,
+ * ie reload 0xffffffff, reload, interrupt ignored
+ * timer 0 will be programmed with the delay until the next
+ * event. this is not set for reload
+ */
+int
+i80321_intr(void *frame)
+{
+ uint32_t now, r;
+ uint32_t nextevent;
+
+ tisr_write(TISR_TMR0);
+ now = tcr1_read();
+
+#if 0
+ if (lastnow < now) {
+ /* rollover, remove the missing 'tick'; 1-0xffffffff, not 0- */
+ nextstatevent -=1;
+ nexttickevent -=1;
+ }
+#endif
+ while ((int32_t) (now - nexttickevent) < 0) {
+ nexttickevent -= ticks_per_intr;
+ /* XXX - correct nexttickevent? */
+ clk_count.ec_count++;
+ hardclock(frame);
+ }
+ while ((int32_t) (now - nextstatevent) < 0) {
+ do {
+ r = random() & (statvar -1);
+ } while (r == 0); /* random == 0 not allowed */
+ nextstatevent -= statmin + r;
+ /* XXX - correct nextstatevent? */
+ stat_count.ec_count++;
+ statclock(frame);
+ }
+ if ((now - nexttickevent) < (now - nextstatevent))
+ nextevent = now - nexttickevent;
+ else
+ nextevent = now - nextstatevent;
+ if (nextevent < 10 /* XXX */)
+ nextevent = 10;
+ if (nextevent > ticks_per_intr) {
+ printf("nextevent out of bounds %x\n", nextevent);
+ nextevent = ticks_per_intr;
+ }
+
+
+ tcr0_write(nextevent);
+ tmr0_write(TMRx_ENABLE|TMRx_PRIV|TMRx_CSEL_CORE);
+
+ lastnow = now;
+
+ return 1;
+}
+
+void
+cpu_initclocks()
+{
+ int minint;
+ uint32_t now;
+ uint32_t statint;
+ int s;
+
+ s = splclock();
+ /* would it make sense to have this be 100/1000 to round nicely? */
+ /* 100/1000 or 128/1024 ? */
+ stathz = 100;
+ profhz = 1000;
+
+ ticks_per_second = 200 * 1000000; /* 200 MHz */
+ statint = ticks_per_second / stathz;
+ stat_error_cnt = ticks_per_second % stathz;
+
+ /* calculate largest 2^n which is smaller that just over half statint */
+ statvar = 0x40000000;
+ minint = statint / 2 + 100;
+ while (statvar > minint)
+ statvar >>= 1;
+
+ statmin = statint - (statvar >> 1);
+
+ ticks_per_intr = ticks_per_second / hz;
+ tick_error_cnt = ticks_per_second % hz;
+
+ printf("clock: hz= %d stathz = %d\n", hz, stathz);
+ printf("ticks_per_intr %x tick_error_cnt %x statmin %x statvar %x\n",
+ ticks_per_intr, tick_error_cnt, statmin, statvar);
+
+ evcount_attach(&clk_count, "clock", (void *)&clk_irq, &evcount_intr);
+ evcount_attach(&stat_count, "stat", (void *)&stat_irq, &evcount_intr);
+
+ (void) i80321_intr_establish(ICU_INT_TMR0, IPL_CLOCK, i80321_intr,
+ NULL, "tick");
+
+
+ now = 0xffffffff;
+ nextstatevent = now - ticks_per_intr;
+ nexttickevent = now - ticks_per_intr;
+
+ tcr1_write(now);
+ trr1_write(now);
+ tmr1_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_PRIV|TMRx_CSEL_CORE);
+
+ tcr0_write(now); /* known big value */
+ tmr0_write(TMRx_ENABLE|TMRx_PRIV|TMRx_CSEL_CORE);
+ tcr0_write(ticks_per_intr);
+
+ i80321_timer_inited = 1;
+ splx(s);
+}
+
+void
+microtime(struct timeval *tvp)
+{
+ int s, deltacnt;
+ u_int32_t counter, expected;
+
+ if (i80321_timer_inited == 0) {
+ tvp->tv_sec = 0;
+ tvp->tv_usec = 0;
+ return;
+ }
+
+ s = splhigh();
+ counter = tcr1_read();
+ expected = nexttickevent;
+
+ *tvp = time;
+ splx (s);
+
+ deltacnt = ticks_per_intr -counter + expected;
+
+#if 0
+ /* low frequency timer algorithm */
+ tvp->tv_usec +_= deltacnt * 1000000ULL / TIMER_FREQUENCY;
+#else
+ /* high frequency timer algorithm - XXX */
+ tvp->tv_usec += deltacnt / (TIMER_FREQUENCY / 1000000ULL);
+#endif
+
+ while (tvp->tv_usec >= 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+}
+
+void
+delay(u_int usecs)
+{
+ u_int32_t clock, oclock, delta, delaycnt;
+ volatile int j;
+ int csec, usec;
+
+ csec = usecs / 10000;
+ usec = usecs % 10000;
+
+ delaycnt = (TIMER_FREQUENCY / 100) * csec +
+ (TIMER_FREQUENCY / 100) * usec / 10000;
+
+ if (delaycnt <= 1) /* delay too short spin for a bit */
+ for (j = 100; j > 0; j--)
+ ;
+
+ if (i80321_timer_inited == 0) {
+ /* clock isn't initialized yet */
+ for (; usecs > 0; usecs--)
+ for (j = 100; j > 0; j--)
+ ;
+ return;
+ }
+
+ oclock = tcr1_read();
+
+ while(1) {
+ clock = tcr1_read();
+ /* timer counts down, not up so old - new */
+ delta = oclock - clock;
+ if (delta > delaycnt)
+ break;
+ }
+}
+
+void
+setstatclockrate(int newhz)
+{
+ int minint, statint;
+ int s;
+
+ s = splclock();
+
+ statint = ticks_per_second / newhz;
+ statvar = 0x40000000; /* really big power of two */
+ /* find largest 2^n which is nearly smaller than statint/2 */
+ minint = statint / 2 + 100;
+ while (statvar > minint)
+ statvar >>= 1;
+
+ statmin = statint - (statvar >> 1);
+
+ splx(s);
+
+ /*
+ * XXX this allows the next stat timer to occur then it switches
+ * to the new frequency. Rather than switching instantly.
+ */
+}
+
+void
+i80321_calibrate_delay(void)
+{
+
+ tmr1_write(0); /* stop timer */
+ tisr_write(TISR_TMR1); /* clear interrupt */
+ trr1_write(0xffffffff); /* reload value */
+ tcr1_write(0xffffffff); /* current value */
+
+ tmr1_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_PRIV|TMRx_CSEL_CORE);
+}
+
+todr_chip_handle_t todr_handle;
+
+/*
+ * inittodr:
+ *
+ * Initialize time from the time-of-day register.
+ */
+#define MINYEAR 2003 /* minimum plausible year */
+void
+inittodr(time_t base)
+{
+ time_t deltat;
+ struct timeval rtctime;
+ int badbase;
+
+ if (base < (MINYEAR - 1970) * SECYR) {
+ printf("WARNING: preposterous time in file system");
+ /* read the system clock anyway */
+ base = (MINYEAR - 1970) * SECYR;
+ badbase = 1;
+ } else
+ badbase = 0;
+
+ if (todr_handle == NULL ||
+ todr_gettime(todr_handle, &rtctime) != 0 ||
+ rtctime.tv_sec == 0) {
+ /*
+ * Believe the time in the file system for lack of
+ * anything better, resetting the TODR.
+ */
+ time.tv_sec = base;
+ time.tv_usec = 0;
+ if (todr_handle != NULL && !badbase) {
+ printf("WARNING: preposterous clock chip time\n");
+ resettodr();
+ }
+ goto bad;
+ } else {
+ time.tv_sec = rtctime.tv_sec;
+ time.tv_usec = rtctime.tv_usec;
+ }
+
+ if (!badbase) {
+ /*
+ * See if we gained/lost two or more days; if
+ * so, assume something is amiss.
+ */
+ deltat = time.tv_sec - base;
+ if (deltat < 0)
+ deltat = -deltat;
+ if (deltat < 2 * SECDAY)
+ return; /* all is well */
+ printf("WARNING: clock %s %ld days\n",
+ time.tv_sec < base ? "lost" : "gained",
+ (long)deltat / SECDAY);
+ }
+ bad:
+ printf("WARNING: CHECK AND RESET THE DATE!\n");
+}
+
+/*
+ * resettodr:
+ *
+ * Reset the time-of-day register with the current time.
+ */
+void
+resettodr(void)
+{
+ struct timeval rtctime;
+
+ if (time.tv_sec == 0)
+ return;
+
+ rtctime.tv_sec = time.tv_sec;
+ rtctime.tv_usec = time.tv_usec;
+
+ if (todr_handle != NULL &&
+ todr_settime(todr_handle, &rtctime) != 0)
+ printf("resettodr: failed to set time\n");
+}
+
diff --git a/sys/arch/arm/xscale/i80321_timer.c b/sys/arch/arm/xscale/i80321_timer.c
deleted file mode 100644
index bccc5d37c3a..00000000000
--- a/sys/arch/arm/xscale/i80321_timer.c
+++ /dev/null
@@ -1,442 +0,0 @@
-/* $OpenBSD: i80321_timer.c,v 1.4 2006/06/15 20:42:53 drahn Exp $ */
-/* $NetBSD: i80321_timer.c,v 1.13 2005/12/24 20:06:52 perry Exp $ */
-
-/*
- * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
- * All rights reserved.
- *
- * Written by Jason R. Thorpe for Wasabi Systems, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed for the NetBSD Project by
- * Wasabi Systems, Inc.
- * 4. The name of Wasabi Systems, Inc. may not be used to endorse
- * or promote products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * Timer/clock support for the Intel i80321 I/O processor.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/time.h>
-
-#include <dev/clock_subr.h>
-
-#include <machine/bus.h>
-#include <arm/cpufunc.h>
-
-#include <arm/xscale/i80321reg.h>
-#include <arm/xscale/i80321var.h>
-
-void (*i80321_hardclock_hook)(void);
-
-#ifndef COUNTS_PER_SEC
-#define COUNTS_PER_SEC 200000000 /* 200MHz */
-#endif
-#define COUNTS_PER_USEC (COUNTS_PER_SEC / 1000000)
-
-static void *clock_ih;
-
-static uint32_t counts_per_hz;
-
-int clockhandler(void *);
-
-static inline uint32_t
-tmr0_read(void)
-{
- uint32_t rv;
-
- __asm volatile("mrc p6, 0, %0, c0, c1, 0"
- : "=r" (rv));
- return (rv);
-}
-
-static inline void
-tmr0_write(uint32_t val)
-{
-
- __asm volatile("mcr p6, 0, %0, c0, c1, 0"
- :
- : "r" (val));
-}
-
-static inline uint32_t
-tcr0_read(void)
-{
- uint32_t rv;
-
- __asm volatile("mrc p6, 0, %0, c2, c1, 0"
- : "=r" (rv));
- return (rv);
-}
-
-static inline void
-tcr0_write(uint32_t val)
-{
-
- __asm volatile("mcr p6, 0, %0, c2, c1, 0"
- :
- : "r" (val));
-}
-
-static inline void
-trr0_write(uint32_t val)
-{
-
- __asm volatile("mcr p6, 0, %0, c4, c1, 0"
- :
- : "r" (val));
-}
-
-static inline void
-tisr_write(uint32_t val)
-{
-
- __asm volatile("mcr p6, 0, %0, c6, c1, 0"
- :
- : "r" (val));
-}
-
-/*
- * i80321_calibrate_delay:
- *
- * Calibrate the delay loop.
- */
-void
-i80321_calibrate_delay(void)
-{
-
- /*
- * Just use hz=100 for now -- we'll adjust it, if necessary,
- * in cpu_initclocks().
- */
- counts_per_hz = COUNTS_PER_SEC / 100;
-
- tmr0_write(0); /* stop timer */
- tisr_write(TISR_TMR0); /* clear interrupt */
- trr0_write(counts_per_hz); /* reload value */
- tcr0_write(counts_per_hz); /* current value */
-
- tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE);
-}
-
-int foo(void *);
-int
-foo(void *v)
-{
- return 0;
-}
-/*
- * cpu_initclocks:
- *
- * Initialize the clock and get them going.
- */
-void
-cpu_initclocks(void)
-{
- u_int oldirqstate;
-#if defined(PERFCTRS)
- void *pmu_ih;
-#endif
-
- if (hz < 50 || COUNTS_PER_SEC % hz) {
- printf("Cannot get %d Hz clock; using 100 Hz\n", hz);
- hz = 100;
- }
- tick = 1000000 / hz; /* number of microseconds between interrupts */
- tickfix = 1000000 - (hz * tick);
- if (tickfix) {
- int ftp;
-
- ftp = min(ffs(tickfix), ffs(hz));
- tickfix >>= (ftp - 1);
- tickfixinterval = hz >> (ftp - 1);
- }
-
- /*
- * We only have one timer available; stathz and profhz are
- * always left as 0 (the upper-layer clock code deals with
- * this situation).
- */
- if (stathz != 0)
- printf("Cannot get %d Hz statclock\n", stathz);
- stathz = 0;
-
- if (profhz != 0)
- printf("Cannot get %d Hz profclock\n", profhz);
- profhz = 0;
-
- /* Report the clock frequency. */
- printf("clock: hz=%d stathz=%d profhz=%d\n", hz, stathz, profhz);
-
- oldirqstate = disable_interrupts(I32_bit);
-
- /* Hook up the clock interrupt handler. */
- clock_ih = i80321_intr_establish(ICU_INT_TMR0, IPL_CLOCK,
- clockhandler, NULL, "clock");
-#if 1
-i80321_intr_establish(ICU_INT_TMR0, IPL_TTY,
- foo, NULL, "dummyclock");
-#endif
-
- if (clock_ih == NULL)
- panic("cpu_initclocks: unable to register timer interrupt");
-
-#if defined(PERFCTRS)
- pmu_ih = i80321_intr_establish(ICU_INT_PMU, IPL_STATCLOCK,
- xscale_pmc_dispatch, NULL, "pmu");
- if (pmu_ih == NULL)
- panic("cpu_initclocks: unable to register timer interrupt");
-#endif
-
- /* Set up the new clock parameters. */
-
- tmr0_write(0); /* stop timer */
- tisr_write(TISR_TMR0); /* clear interrupt */
-
- counts_per_hz = COUNTS_PER_SEC / hz;
-
- trr0_write(counts_per_hz); /* reload value */
- tcr0_write(counts_per_hz); /* current value */
-
- tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE);
-
- restore_interrupts(oldirqstate);
-}
-
-/*
- * setstatclockrate:
- *
- * Set the rate of the statistics clock.
- *
- * We assume that hz is either stathz or profhz, and that neither
- * will change after being set by cpu_initclocks(). We could
- * recalculate the intervals here, but that would be a pain.
- */
-void
-setstatclockrate(int newhz)
-{
-
- /*
- * XXX Use TMR1?
- */
-}
-
-/*
- * microtime:
- *
- * Fill in the specified timeval struct with the current time
- * accurate to the microsecond.
- */
-void
-microtime(struct timeval *tvp)
-{
- static struct timeval lasttv;
- u_int oldirqstate;
- uint32_t counts;
-
- oldirqstate = disable_interrupts(I32_bit);
-
- counts = counts_per_hz - tcr0_read();
-
- /* Fill in the timeval struct. */
- *tvp = time;
- tvp->tv_usec += (counts / COUNTS_PER_USEC);
-
- /* Make sure microseconds doesn't overflow. */
- while (tvp->tv_usec >= 1000000) {
- tvp->tv_usec -= 1000000;
- tvp->tv_sec++;
- }
-
- /* Make sure the time has advanced. */
- if (tvp->tv_sec == lasttv.tv_sec &&
- tvp->tv_usec <= lasttv.tv_usec) {
- tvp->tv_usec = lasttv.tv_usec + 1;
- if (tvp->tv_usec >= 1000000) {
- tvp->tv_usec -= 1000000;
- tvp->tv_sec++;
- }
- }
-
- lasttv = *tvp;
-
- restore_interrupts(oldirqstate);
-}
-
-/*
- * delay:
- *
- * Delay for at least N microseconds.
- */
-void
-delay(u_int n)
-{
- uint32_t cur, last, delta, usecs;
-
- /*
- * This works by polling the timer and counting the
- * number of microseconds that go by.
- */
- last = tcr0_read();
- delta = usecs = 0;
-
- while (n > usecs) {
- cur = tcr0_read();
-
- /* Check to see if the timer has wrapped around. */
- if (last < cur)
- delta += (last + (counts_per_hz - cur));
- else
- delta += (last - cur);
-
- last = cur;
-
- if (delta >= COUNTS_PER_USEC) {
- usecs += delta / COUNTS_PER_USEC;
- delta %= COUNTS_PER_USEC;
- }
- }
-}
-
-todr_chip_handle_t todr_handle;
-
-#if 0
-/*
- * todr_attach:
- *
- * Set the specified time-of-day register as the system real-time clock.
- */
-void
-todr_attach(todr_chip_handle_t todr)
-{
-
- if (todr_handle)
- panic("todr_attach: rtc already configured");
- todr_handle = todr;
-}
-#endif
-
-/*
- * inittodr:
- *
- * Initialize time from the time-of-day register.
- */
-#define MINYEAR 2003 /* minimum plausible year */
-void
-inittodr(time_t base)
-{
- time_t deltat;
- struct timeval rtctime;
- int badbase;
-
- if (base < (MINYEAR - 1970) * SECYR) {
- printf("WARNING: preposterous time in file system");
- /* read the system clock anyway */
- base = (MINYEAR - 1970) * SECYR;
- badbase = 1;
- } else
- badbase = 0;
-
- if (todr_handle == NULL ||
- todr_gettime(todr_handle, &rtctime) != 0 ||
- rtctime.tv_sec == 0) {
- /*
- * Believe the time in the file system for lack of
- * anything better, resetting the TODR.
- */
- time.tv_sec = base;
- time.tv_usec = 0;
- if (todr_handle != NULL && !badbase) {
- printf("WARNING: preposterous clock chip time\n");
- resettodr();
- }
- goto bad;
- } else {
- time.tv_sec = rtctime.tv_sec;
- time.tv_usec = rtctime.tv_usec;
- }
-
- if (!badbase) {
- /*
- * See if we gained/lost two or more days; if
- * so, assume something is amiss.
- */
- deltat = time.tv_sec - base;
- if (deltat < 0)
- deltat = -deltat;
- if (deltat < 2 * SECDAY)
- return; /* all is well */
- printf("WARNING: clock %s %ld days\n",
- time.tv_sec < base ? "lost" : "gained",
- (long)deltat / SECDAY);
- }
- bad:
- printf("WARNING: CHECK AND RESET THE DATE!\n");
-}
-
-/*
- * resettodr:
- *
- * Reset the time-of-day register with the current time.
- */
-void
-resettodr(void)
-{
- struct timeval rtctime;
-
- if (time.tv_sec == 0)
- return;
-
- rtctime.tv_sec = time.tv_sec;
- rtctime.tv_usec = time.tv_usec;
-
- if (todr_handle != NULL &&
- todr_settime(todr_handle, &rtctime) != 0)
- printf("resettodr: failed to set time\n");
-}
-
-/*
- * clockhandler:
- *
- * Handle the hardclock interrupt.
- */
-int
-clockhandler(void *arg)
-{
- struct clockframe *frame = arg;
-
- tisr_write(TISR_TMR0);
-
- hardclock(frame);
-
- if (i80321_hardclock_hook != NULL)
- (*i80321_hardclock_hook)();
-
- return (1);
-}
diff --git a/sys/arch/arm/xscale/i80321reg.h b/sys/arch/arm/xscale/i80321reg.h
index fd14f858d14..3166e83d559 100644
--- a/sys/arch/arm/xscale/i80321reg.h
+++ b/sys/arch/arm/xscale/i80321reg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: i80321reg.h,v 1.2 2006/05/29 17:27:31 drahn Exp $ */
+/* $OpenBSD: i80321reg.h,v 1.3 2006/06/27 05:18:25 drahn Exp $ */
/* $NetBSD: i80321reg.h,v 1.15 2005/12/11 12:16:51 christos Exp $ */
/*
@@ -299,6 +299,7 @@
#define TMRx_TC (1U << 0)
#define TMRx_ENABLE (1U << 1)
#define TMRx_RELOAD (1U << 2)
+#define TMRx_PRIV (1U << 3)
#define TMRx_CSEL_CORE (0 << 4)
#define TMRx_CSEL_CORE_div4 (1 << 4)
#define TMRx_CSEL_CORE_div8 (2 << 4)