diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2005-12-20 02:37:11 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2005-12-20 02:37:11 +0000 |
commit | 7dd62395b81413dd2a084718e42ec80d50575932 (patch) | |
tree | c0591542bbb137c29387f14fb1e7327437a18454 /sys/arch/arm | |
parent | 39b94e1fd2ba7642a42563ed786e1a280b9477b1 (diff) |
switch to using clock4 instead of clock0 so that we get clocks when running
at 91MHz (clock4 is programmed to be based of the 32.768KHz clock.
Diffstat (limited to 'sys/arch/arm')
-rw-r--r-- | sys/arch/arm/xscale/files.pxa2x0 | 11 | ||||
-rw-r--r-- | sys/arch/arm/xscale/pxa2x0_apm.c | 40 | ||||
-rw-r--r-- | sys/arch/arm/xscale/pxa2x0_clock.c | 334 |
3 files changed, 361 insertions, 24 deletions
diff --git a/sys/arch/arm/xscale/files.pxa2x0 b/sys/arch/arm/xscale/files.pxa2x0 index 4ef2574ee58..d37eb8edc0a 100644 --- a/sys/arch/arm/xscale/files.pxa2x0 +++ b/sys/arch/arm/xscale/files.pxa2x0 @@ -1,4 +1,4 @@ -# $OpenBSD: files.pxa2x0,v 1.17 2005/09/15 20:23:10 miod Exp $ +# $OpenBSD: files.pxa2x0,v 1.18 2005/12/20 02:37:09 drahn Exp $ # $NetBSD: files.pxa2x0,v 1.6 2004/05/01 19:09:14 thorpej Exp $ # # Configuration info for Intel PXA2[51]0 CPU support @@ -34,11 +34,10 @@ device pxadmac attach pxadmac at pxaip file arch/arm/xscale/pxa2x0_dmac.c pxadmac needs-flag -# clock device -# PXA2x0's built-in timer is compatible to SA-1110. -device saost -attach saost at pxaip -file arch/arm/sa11x0/sa11x0_ost.c saost needs-flag +# PXA2x0's built-in timer. +device pxaost +attach pxaost at pxaip +file arch/arm/xscale/pxa2x0_clock.c pxaost needs-flag # NS16550 compatible serial ports attach com at pxaip with com_pxaip diff --git a/sys/arch/arm/xscale/pxa2x0_apm.c b/sys/arch/arm/xscale/pxa2x0_apm.c index e7f81333304..8b2f570b0e5 100644 --- a/sys/arch/arm/xscale/pxa2x0_apm.c +++ b/sys/arch/arm/xscale/pxa2x0_apm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pxa2x0_apm.c,v 1.21 2005/12/05 21:13:13 uwe Exp $ */ +/* $OpenBSD: pxa2x0_apm.c,v 1.22 2005/12/20 02:37:09 drahn Exp $ */ /*- * Copyright (c) 2001 Alexander Guy. All rights reserved. @@ -828,6 +828,9 @@ struct pxa2x0_sleep_data { /* OS timer registers */ u_int32_t sd_osmr0, sd_osmr1, sd_osmr2, sd_osmr3; u_int32_t sd_oscr0; + u_int32_t sd_osmr4, sd_osmr5; + u_int32_t sd_oscr4; + u_int32_t sd_omcr4, sd_omcr5; u_int32_t sd_oier; /* GPIO registers */ u_int32_t sd_gpdr0, sd_gpdr1, sd_gpdr2, sd_gpdr3; @@ -867,10 +870,15 @@ pxa2x0_apm_sleep(struct pxa2x0_apm_softc *sc) save = disable_interrupts(I32_bit|F32_bit); sd.sd_oscr0 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSCR0); + sd.sd_oscr4 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSCR4); + sd.sd_omcr4 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OMCR4); + sd.sd_omcr5 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OMCR5); sd.sd_osmr0 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSMR0); sd.sd_osmr1 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSMR1); sd.sd_osmr2 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSMR2); sd.sd_osmr3 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSMR3); + sd.sd_osmr4 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSMR4); + sd.sd_osmr5 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSMR5); sd.sd_oier = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OIER); /* Bring the PXA27x into 416Mhz turbo mode. */ @@ -1119,6 +1127,18 @@ suspend_again: scoop_check_mcr(); scoop_resume(); + bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR0, sd.sd_osmr0); + bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR1, sd.sd_osmr1); + bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR2, sd.sd_osmr2); + bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR3, sd.sd_osmr3); + bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR4, sd.sd_osmr4); + bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR5, sd.sd_osmr5); + bus_space_write_4(sc->sc_iot, ost_ioh, OST_OMCR4, sd.sd_omcr4); + bus_space_write_4(sc->sc_iot, ost_ioh, OST_OMCR5, sd.sd_omcr5); + bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSCR0, sd.sd_oscr0); + bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSCR4, sd.sd_oscr4); + bus_space_write_4(sc->sc_iot, ost_ioh, OST_OIER, sd.sd_oier); + pxa2x0_pi2c_setvoltage(sc->sc_iot, sc->sc_pm_ioh, PI2C_VOLTAGE_HIGH); /* Change to 208Mhz run mode with fast-bus still disabled. */ @@ -1132,12 +1152,6 @@ suspend_again: CLKCFG_B | CLKCFG_F | CLKCFG_T, &pxa2x0_memcfg); if (sc->sc_resume != NULL) { - /* Restore OS timers only to allow the use of delay(). */ - bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR1, sd.sd_osmr1); - bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR2, sd.sd_osmr2); - bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR3, sd.sd_osmr3); - bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSCR0, sd.sd_oscr0); - bus_space_write_4(sc->sc_iot, ost_ioh, OST_OIER, sd.sd_oier); if (!sc->sc_resume(sc)) goto suspend_again; } @@ -1148,12 +1162,6 @@ suspend_again: */ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PMCR, 0); - bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR0, sd.sd_osmr0); - bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR1, sd.sd_osmr1); - bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR2, sd.sd_osmr2); - bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR3, sd.sd_osmr3); - bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSCR0, sd.sd_oscr0); - bus_space_write_4(sc->sc_iot, ost_ioh, OST_OIER, sd.sd_oier); restore_interrupts(save); @@ -1395,8 +1403,6 @@ pxa2x0_setperf(int speed) s = disable_interrupts(I32_bit|F32_bit); -#if 0 - /* Not yet, because OSCR0 does not run in low-power mode. */ if (speed <= 30) { if (freq > 91) { pxa27x_run_mode(); @@ -1406,9 +1412,7 @@ pxa2x0_setperf(int speed) PI2C_VOLTAGE_LOW); freq = 91; } - } else -#endif - if (speed < 60) { + } else if (speed < 60) { if (freq < 208) pxa2x0_pi2c_setvoltage(sc->sc_iot, sc->sc_pm_ioh, PI2C_VOLTAGE_HIGH); diff --git a/sys/arch/arm/xscale/pxa2x0_clock.c b/sys/arch/arm/xscale/pxa2x0_clock.c new file mode 100644 index 00000000000..25fbfe53664 --- /dev/null +++ b/sys/arch/arm/xscale/pxa2x0_clock.c @@ -0,0 +1,334 @@ +/* $OpenBSD: pxa2x0_clock.c,v 1.1 2005/12/20 02:37:09 drahn Exp $ */ + +/* + * Copyright (c) 2005 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 <machine/bus.h> +#include <machine/intr.h> + +#include <arm/cpufunc.h> + +#include <arm/sa11x0/sa11x0_reg.h> +#include <arm/sa11x0/sa11x0_var.h> +#include <arm/sa11x0/sa11x0_ostreg.h> +#include <arm/xscale/pxa2x0reg.h> + +int pxaost_match(struct device *, void *, void *); +void pxaost_attach(struct device *, struct device *, void *); + +int doclockintr(void *); +int clockintr(void *); +int statintr(void *); +void rtcinit(void); + +struct pxaost_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + u_int32_t sc_clock_count; + u_int32_t sc_statclock_count; + u_int32_t sc_statclock_step; + u_int32_t sc_clock_step; + u_int32_t sc_clock_step_err_cnt; + u_int32_t sc_clock_step_error; +}; + +static struct pxaost_softc *pxaost_sc = NULL; + +#define CLK4_TIMER_FREQUENCY 32768 /* 32.768KHz */ + +#define CLK0_TIMER_FREQUENCY 3250000 /* 3.2500MHz */ + +#ifndef STATHZ +#define STATHZ 64 +#endif + +struct cfattach pxaost_ca = { + sizeof (struct pxaost_softc), pxaost_match, pxaost_attach +}; + +struct cfdriver pxaost_cd = { + NULL, "pxaost", DV_DULL +}; + +int +pxaost_match(parent, match, aux) + struct device *parent; + void *match; + void *aux; +{ + return (1); +} + + +void +pxaost_attach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct pxaost_softc *sc = (struct pxaost_softc*)self; + struct sa11x0_attach_args *sa = aux; + + printf("\n"); + + sc->sc_iot = sa->sa_iot; + + pxaost_sc = sc; + + if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0, + &sc->sc_ioh)) + panic("%s: Cannot map registers", self->dv_xname); + + /* disable all channel and clear interrupt status */ + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_IR, 0); + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_SR, 0x3f); + + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OMCR4, 0xc1); + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OMCR5, 0x41); + + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSMR4, + pxaost_sc->sc_clock_count); + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSMR5, + pxaost_sc->sc_statclock_count); + + /* Zero the counter value */ + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSCR4, 0); + +} + +int +clockintr(arg) + void *arg; +{ + struct clockframe *frame = arg; + u_int32_t oscr, match; + u_int32_t match_error; + + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_SR, 0x10); + + match = pxaost_sc->sc_clock_count; + + do { + match += CLK4_TIMER_FREQUENCY / hz; + pxaost_sc->sc_clock_step_error += + pxaost_sc->sc_clock_step_err_cnt; + if (pxaost_sc->sc_clock_count > hz) { + match_error = pxaost_sc->sc_clock_step_error / hz; + pxaost_sc->sc_clock_step_error -= (match_error * hz); + match += match_error; + } + pxaost_sc->sc_clock_count = match; + hardclock(frame); + + oscr = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, + OST_OSCR4); + + } while ((signed)(oscr - match) > 0); + + /* prevent missed interrupts */ + if (oscr - match < 5) + match += 5; + + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSMR4, + match); + + + return(1); +} + +int +statintr(arg) + void *arg; +{ + struct clockframe *frame = arg; + u_int32_t oscr, match; + + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_SR, 0x20); + + /* schedule next clock intr */ + match = pxaost_sc->sc_statclock_count; + do { + match += pxaost_sc->sc_statclock_step; + pxaost_sc->sc_statclock_count = match; + statclock(frame); + + oscr = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, + OST_OSCR4); + + } while ((signed)(oscr - match) > 0); + + /* prevent missed interrupts */ + if (oscr - match < 5) + match += 5; + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSMR5, + match); + + return(1); +} + + +void +setstatclockrate(hz) + int hz; +{ + u_int32_t count; + + pxaost_sc->sc_statclock_step = CLK4_TIMER_FREQUENCY / hz; + count = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSCR4); + count += pxaost_sc->sc_statclock_step; + pxaost_sc->sc_statclock_count = count; + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, + OST_OSMR5, count); +} + +int +doclockintr(void *arg) +{ + u_int32_t status; + int result = 0; + + status = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_SR); + if (status & 0x10) + result |= clockintr(arg); + if (status & 0x20) + result |= statintr(arg); + + return (result); +} + +void +cpu_initclocks() +{ + u_int32_t clk; + + stathz = STATHZ; + profhz = stathz; + pxaost_sc->sc_statclock_step = CLK4_TIMER_FREQUENCY / stathz; + pxaost_sc->sc_clock_step = CLK4_TIMER_FREQUENCY / hz; + pxaost_sc->sc_clock_step_err_cnt = CLK4_TIMER_FREQUENCY % hz; + pxaost_sc->sc_clock_step_error = 0; + + printf("clock: hz=%d stathz=%d\n", hz, stathz); + + /* Use the channels 0 and 1 for hardclock and statclock, respectively */ + pxaost_sc->sc_clock_count = CLK4_TIMER_FREQUENCY / hz; + pxaost_sc->sc_statclock_count = CLK4_TIMER_FREQUENCY / stathz; + + pxa2x0_intr_establish(7, IPL_CLOCK, doclockintr, 0, "clock"); + + + clk = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSCR4); + + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_SR, 0x3f); + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, SAOST_IR, 0x30); + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSMR4, + clk + pxaost_sc->sc_clock_count); + bus_space_write_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, OST_OSMR5, + clk + pxaost_sc->sc_statclock_count); +} + +void +microtime(tvp) + register struct timeval *tvp; +{ + int s, tm, deltatm; + static struct timeval lasttime; + + if (pxaost_sc == NULL) { + tvp->tv_sec = 0; + tvp->tv_usec = 0; + return; + } + + s = splhigh(); + /* XXX will not work in slow mode */ + tm = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, + SAOST_CR); + + deltatm = pxaost_sc->sc_clock_count - tm; + +#ifdef OST_DEBUG + printf("deltatm = %d\n",deltatm); +#endif + + *tvp = time; + tvp->tv_usec++; /* XXX */ + while (tvp->tv_usec >= 1000000) { + tvp->tv_sec++; + tvp->tv_usec -= 1000000; + } + + if (tvp->tv_sec == lasttime.tv_sec && + tvp->tv_usec <= lasttime.tv_usec && + (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) { + tvp->tv_sec++; + tvp->tv_usec -= 1000000; + } + lasttime = *tvp; + splx(s); +} + +void +delay(usecs) + u_int usecs; +{ + u_int32_t clock, oclock, delta, delaycnt; + int j, csec, usec; + + if (usecs > (0x80000000 / (CLK4_TIMER_FREQUENCY))) { + csec = usecs / 10000; + usec = usecs % 10000; + + delaycnt = (CLK4_TIMER_FREQUENCY / 100) * csec + + (CLK4_TIMER_FREQUENCY / 100) * usec / 10000; + } else { + delaycnt = CLK4_TIMER_FREQUENCY * usecs / 1000000; + } + + if (delaycnt <= 1) + for(j = 100; j > 0; j--) + ; + + if (!pxaost_sc) { + /* clock isn't initialized yet */ + for(; usecs > 0; usecs--) + for(j = 100; j > 0; j--) + ; + return; + } + + oclock = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, + OST_OSCR4); + + while (1) { + for(j = 100; j > 0; j--) + ; + clock = bus_space_read_4(pxaost_sc->sc_iot, pxaost_sc->sc_ioh, + OST_OSCR4); + delta = clock - oclock; + if (delta > delaycnt) + break; + } +} |