summaryrefslogtreecommitdiff
path: root/sys/arch/arm/xscale
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2005-12-20 02:37:11 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2005-12-20 02:37:11 +0000
commit7dd62395b81413dd2a084718e42ec80d50575932 (patch)
treec0591542bbb137c29387f14fb1e7327437a18454 /sys/arch/arm/xscale
parent39b94e1fd2ba7642a42563ed786e1a280b9477b1 (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/xscale')
-rw-r--r--sys/arch/arm/xscale/files.pxa2x011
-rw-r--r--sys/arch/arm/xscale/pxa2x0_apm.c40
-rw-r--r--sys/arch/arm/xscale/pxa2x0_clock.c334
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;
+ }
+}