summaryrefslogtreecommitdiff
path: root/sys/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/arm')
-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;
+ }
+}