diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2006-06-27 05:18:26 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2006-06-27 05:18:26 +0000 |
commit | b903e886d1fb6afe8c060c76e45b1d113e992f99 (patch) | |
tree | a929729449440863e256c1c4ae5d7a61b74efd8e | |
parent | 7ed6b13766f8849a36fd96d75d5f95cde2262528 (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.i80321 | 4 | ||||
-rw-r--r-- | sys/arch/arm/xscale/i80321_clock.c | 489 | ||||
-rw-r--r-- | sys/arch/arm/xscale/i80321_timer.c | 442 | ||||
-rw-r--r-- | sys/arch/arm/xscale/i80321reg.h | 3 |
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) |