summaryrefslogtreecommitdiff
path: root/sys/arch/arm
diff options
context:
space:
mode:
authorUwe Stuehler <uwe@cvs.openbsd.org>2005-02-22 21:53:04 +0000
committerUwe Stuehler <uwe@cvs.openbsd.org>2005-02-22 21:53:04 +0000
commita5bb1e03d878a3671b987aeade87b83329b8a222 (patch)
treeb8493e19ba1723dd82ab5c5c382fe89aa287664b /sys/arch/arm
parentd717ccdc439590ad4ff2eadc559fdf0e51fad5d9 (diff)
Initial suspend/resume code with additional powerhooks. Enter/exit
suspend mode with power button or zzz. May not work for everyone yet. ok drahn@ and deraadt@
Diffstat (limited to 'sys/arch/arm')
-rw-r--r--sys/arch/arm/xscale/files.pxa2x03
-rw-r--r--sys/arch/arm/xscale/pxa2x0_apm.c829
-rw-r--r--sys/arch/arm/xscale/pxa2x0_apm.h37
-rw-r--r--sys/arch/arm/xscale/pxa2x0_apm_asm.S577
-rw-r--r--sys/arch/arm/xscale/pxa2x0_lcd.c48
-rw-r--r--sys/arch/arm/xscale/pxa2x0reg.h62
6 files changed, 1520 insertions, 36 deletions
diff --git a/sys/arch/arm/xscale/files.pxa2x0 b/sys/arch/arm/xscale/files.pxa2x0
index 0e3d4a1ba67..b9523ad7590 100644
--- a/sys/arch/arm/xscale/files.pxa2x0
+++ b/sys/arch/arm/xscale/files.pxa2x0
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pxa2x0,v 1.8 2005/02/17 22:10:35 dlg Exp $
+# $OpenBSD: files.pxa2x0,v 1.9 2005/02/22 21:53:03 uwe Exp $
# $NetBSD: files.pxa2x0,v 1.6 2004/05/01 19:09:14 thorpej Exp $
#
# Configuration info for Intel PXA2[51]0 CPU support
@@ -59,6 +59,7 @@ file arch/arm/xscale/pxa2x0_lcd.c lcd needs-flag
# Power manager and APM emulation
device apm
file arch/arm/xscale/pxa2x0_apm.c apm needs-flag
+file arch/arm/xscale/pxa2x0_apm_asm.S apm
include "dev/pcmcia/files.pcmcia"
diff --git a/sys/arch/arm/xscale/pxa2x0_apm.c b/sys/arch/arm/xscale/pxa2x0_apm.c
index 242cdf2ca0e..9b05b1e375d 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.3 2005/01/26 06:34:53 uwe Exp $ */
+/* $OpenBSD: pxa2x0_apm.c,v 1.4 2005/02/22 21:53:03 uwe Exp $ */
/*-
* Copyright (c) 2001 Alexander Guy. All rights reserved.
@@ -54,6 +54,7 @@
#include <arm/xscale/pxa2x0reg.h>
#include <arm/xscale/pxa2x0var.h>
#include <arm/xscale/pxa2x0_apm.h>
+#include <arm/xscale/pxa2x0_gpio.h>
#if defined(APMDEBUG)
#define DPRINTF(x) printf x
@@ -75,7 +76,7 @@ struct cfdriver apm_cd = {
int apm_userstandbys;
int apm_suspends;
-int apm_battlow;
+int apm_battlow; /* XXX unused */
void apm_power_info(struct pxa2x0_apm_softc *,
struct apm_power_info *);
@@ -86,9 +87,6 @@ void apm_periodic_check(struct pxa2x0_apm_softc *);
void apm_thread_create(void *);
void apm_thread(void *);
-void pxa2x0_apm_standby(struct pxa2x0_apm_softc *);
-void pxa2x0_apm_sleep(struct pxa2x0_apm_softc *);
-
void filt_apmrdetach(struct knote *kn);
int filt_apmread(struct knote *kn, long hint);
int apmkqfilter(dev_t dev, struct knote *kn);
@@ -114,6 +112,125 @@ struct filterops apmread_filtops =
#define SCFLAG_OWRITE (1 << 1)
#define SCFLAG_OPEN (SCFLAG_OREAD|SCFLAG_OWRITE)
+/* This structure must be keept in sync with pxa2x0_apm_asm.S. */
+struct pxa2x0_memcfg {
+ /* SDRAM refresh */
+ u_int32_t mdrefr_high; /* 0x00 */
+ u_int32_t mdrefr_low; /* 0x04 */
+ u_int32_t mdrefr_low2; /* 0x08 */
+ /* Synchronous, static, or VLIO interfaces */
+ u_int32_t msc_high[3]; /* 0x0c */
+ u_int32_t msc_low[3]; /* 0x18 */
+ /* XXX move up */
+ u_int32_t mdrefr_91; /* 0x24 */
+};
+
+/* XXX */
+#define MDREFR_C3000 (MDREFR_K0DB2 | MDREFR_E1PIN | MDREFR_K1RUN | \
+ MDREFR_K1DB2 | MDREFR_K2DB2 | MDREFR_APD)
+#define MSC0_HIGH \
+ ( 7 << MSC_RRR_SHIFT << 16) | \
+ (15 << MSC_RDN_SHIFT << 16) | \
+ (15 << MSC_RDF_SHIFT << 16) | \
+ (MSC_RT_NONBURST << 16) | \
+ ( 2 << MSC_RRR_SHIFT) | \
+ (13 << MSC_RDN_SHIFT) | \
+ (13 << MSC_RDF_SHIFT) | \
+ MSC_RBW /* PXA271 */ | \
+ MSC_RT_NONBURST
+#define MSC1_HIGH \
+ ( 7 << MSC_RRR_SHIFT << 16) | \
+ (15 << MSC_RDN_SHIFT << 16) | \
+ (15 << MSC_RDF_SHIFT << 16) | \
+ (MSC_RT_VLIO << 16) | \
+ ( 3 << MSC_RRR_SHIFT) | \
+ ( 4 << MSC_RDN_SHIFT) | \
+ (13 << MSC_RDF_SHIFT) | \
+ MSC_RT_VLIO
+#define MSC2_HIGH \
+ ( 7 << MSC_RRR_SHIFT << 16) | \
+ (15 << MSC_RDN_SHIFT << 16) | \
+ (15 << MSC_RDF_SHIFT << 16) | \
+ (MSC_RT_NONBURST << 16) | \
+ ( 3 << MSC_RRR_SHIFT) | \
+ ( 4 << MSC_RDN_SHIFT) | \
+ (13 << MSC_RDF_SHIFT) | \
+ MSC_RT_VLIO
+#define MSC0_LOW \
+ ( 7 << MSC_RRR_SHIFT << 16) | \
+ (15 << MSC_RDN_SHIFT << 16) | \
+ (15 << MSC_RDF_SHIFT << 16) | \
+ (MSC_RT_NONBURST << 16) | \
+ ( 1 << MSC_RRR_SHIFT) | \
+ ( 8 << MSC_RDN_SHIFT) | \
+ ( 8 << MSC_RDF_SHIFT) | \
+ MSC_RBW /* PXA271 */ | \
+ MSC_RT_NONBURST
+#define MSC1_LOW \
+ ( 7 << MSC_RRR_SHIFT << 16) | \
+ (15 << MSC_RDN_SHIFT << 16) | \
+ (15 << MSC_RDF_SHIFT << 16) | \
+ (MSC_RT_VLIO << 16) | \
+ ( 1 << MSC_RRR_SHIFT) | \
+ ( 2 << MSC_RDN_SHIFT) | \
+ ( 6 << MSC_RDF_SHIFT) | \
+ MSC_RT_VLIO
+#define MSC2_LOW \
+ ( 7 << MSC_RRR_SHIFT << 16) | \
+ (15 << MSC_RDN_SHIFT << 16) | \
+ (15 << MSC_RDF_SHIFT << 16) | \
+ (MSC_RT_NONBURST << 16) | \
+ ( 1 << MSC_RRR_SHIFT) | \
+ ( 2 << MSC_RDN_SHIFT) | \
+ ( 6 << MSC_RDF_SHIFT) | \
+ MSC_RT_VLIO
+struct pxa2x0_memcfg pxa2x0_memcfg = {
+ (MDREFR_C3000 | 0x030),
+ (MDREFR_C3000 | 0x00b),
+ (MDREFR_C3000 | 0x017),
+ { MSC0_HIGH, MSC1_HIGH, MSC2_HIGH },
+ { MSC1_LOW, MSC1_LOW, MSC2_LOW },
+ (MDREFR_C3000 | 0x013)
+};
+
+#define PI2C_RETRY_COUNT 10
+/* XXX varies depending on voltage regulator IC. */
+#define PI2C_VOLTAGE_LOW 0x13 /* 1.00V */
+#define PI2C_VOLTAGE_HIGH 0x1a /* 1.35V */
+
+void pxa2x0_apm_standby(struct pxa2x0_apm_softc *);
+void pxa2x0_apm_sleep(struct pxa2x0_apm_softc *);
+
+void pxa2x0_pi2c_open(bus_space_tag_t, bus_space_handle_t);
+int pxa2x0_pi2c_read(bus_space_tag_t, bus_space_handle_t, u_char, u_char *);
+int pxa2x0_pi2c_write(bus_space_tag_t, bus_space_handle_t, u_char, u_char);
+void pxa2x0_pi2c_close(bus_space_tag_t, bus_space_handle_t);
+int pxa2x0_pi2c_getvoltage(bus_space_tag_t, bus_space_handle_t, u_char *);
+int pxa2x0_pi2c_setvoltage(bus_space_tag_t, bus_space_handle_t, u_char);
+void pxa2x0_pi2c_printregs(bus_space_tag_t, bus_space_handle_t);
+void pxa2x0_pi2c_print(struct pxa2x0_apm_softc *);
+
+/* XXX used in pxa2x0_apm_asm.S */
+bus_space_handle_t pxa2x0_gpio_ioh = 0;
+bus_space_handle_t pxa2x0_clkman_ioh = 0;
+bus_space_handle_t pxa2x0_memctl_ioh = 0;
+
+/* pxa2x0_apm_asm.S */
+void pxa27x_run_mode(void);
+void pxa27x_fastbus_run_mode(int, u_int32_t);
+void pxa27x_frequency_change(int, int, struct pxa2x0_memcfg *);
+void pxa2x0_cpu_suspend(void);
+void pxa2x0_cpu_resume(void);
+void pxa27x_cpu_speed_high(void);
+void pxa27x_cpu_speed_low(void);
+void pxa27x_cpu_speed_91(void);
+void pxa27x_cpu_speed_208(void);
+
+/* XXX */
+void scoop_check_mcr(void);
+void scoop_suspend(void);
+void scoop_resume(void);
+
void
apm_power_info(struct pxa2x0_apm_softc *sc,
struct apm_power_info *power)
@@ -137,6 +254,21 @@ apm_standby(struct pxa2x0_apm_softc *sc)
if (cold)
vfs_syncwait(0);
+ /*
+ * Clear pending standby requests. Do not enter standby mode if
+ * suspend was requested in the meantime.
+ */
+ apm_userstandbys = 0;
+ if (apm_suspends) {
+ /*
+ * Arbitrary delay to avoid reinitializing some devices
+ * too fast, since PWR_RESUME hooks will be run before
+ * PWR_SUSPEND hooks. Perhaps this is overly paranoid.
+ */
+ delay(500000);
+ return;
+ }
+
pxa2x0_apm_standby((struct pxa2x0_apm_softc *)sc);
}
@@ -144,16 +276,15 @@ void
apm_suspend(struct pxa2x0_apm_softc *sc)
{
-#if 0
- /* XXX something is not restored in PWR_RESUME. */
dopowerhooks(PWR_SUSPEND);
-#else
- dopowerhooks(PWR_STANDBY);
-#endif
if (cold)
vfs_syncwait(0);
+ /* Clear pending standby and suspend requests. */
+ apm_userstandbys = 0;
+ apm_suspends = 0;
+
pxa2x0_apm_sleep((struct pxa2x0_apm_softc *)sc);
}
@@ -171,13 +302,15 @@ apm_periodic_check(struct pxa2x0_apm_softc *sc)
if (sc->sc_periodic_check != NULL)
sc->sc_periodic_check(sc);
+ /*
+ * Counters for pending requests are cleared just before changing
+ * the processor run mode to avoid falling back to sleep after a
+ * wake-up event.
+ */
if (apm_suspends) {
- apm_userstandbys = 0;
- apm_suspends = 0;
apm_suspend(sc);
apm_resume(sc);
} else if (apm_userstandbys) {
- apm_userstandbys = 0;
apm_standby(sc);
apm_resume(sc);
}
@@ -335,7 +468,7 @@ apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
error = ENOTTY;
}
- return error;
+ return (error);
}
void
@@ -382,40 +515,680 @@ apmkqfilter(dev_t dev, struct knote *kn)
}
void
+pxa2x0_apm_attach_sub(struct pxa2x0_apm_softc *sc)
+{
+
+ sc->sc_iot = &pxa2x0_bs_tag;
+
+ if (bus_space_map(sc->sc_iot, PXA2X0_POWMAN_BASE,
+ PXA2X0_POWMAN_SIZE, 0, &sc->sc_pm_ioh)) {
+ printf("pxa2x0_apm_attach_sub: failed to map POWMAN\n");
+ return;
+ }
+
+ lockinit(&sc->sc_lock, PWAIT, "apmlk", 0, 0);
+
+ kthread_create_deferred(apm_thread_create, sc);
+
+ printf("\n");
+
+ if (bus_space_map(sc->sc_iot, PXA2X0_CLKMAN_BASE, PXA2X0_CLKMAN_SIZE,
+ 0, &pxa2x0_clkman_ioh)) {
+ printf("%s: failed to map CLKMAN\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ if (bus_space_map(sc->sc_iot, PXA2X0_MEMCTL_BASE, PXA2X0_MEMCTL_SIZE,
+ 0, &pxa2x0_memctl_ioh)) {
+ printf("%s: failed to map MEMCTL\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ if (bus_space_map(sc->sc_iot, PXA2X0_GPIO_BASE, PXA2X0_GPIO_SIZE,
+ 0, &pxa2x0_gpio_ioh)) {
+ printf("pxa2x0_apm_sleep: can't map GPIO\n");
+ return;
+ }
+}
+
+void
+pxa2x0_wakeup_config(u_int32_t wsrc, int enable)
+{
+ struct pxa2x0_apm_softc *sc;
+ u_int32_t prer;
+ u_int32_t pfer;
+ u_int32_t pkwr;
+
+ if (apm_cd.cd_ndevs < 1 || apm_cd.cd_devs[0] == NULL)
+ return;
+ sc = apm_cd.cd_devs[0];
+
+ prer = pfer = pkwr = 0;
+
+ if ((wsrc & PXA2X0_WAKEUP_POWERON) != 0) {
+ prer |= (1<<0);
+ pfer |= (1<<0);
+ pkwr |= (1<<12);
+ }
+
+ if ((wsrc & PXA2X0_WAKEUP_GPIORST) != 0)
+ pfer |= (1<<1);
+ if ((wsrc & PXA2X0_WAKEUP_SD) != 0)
+ prer |= (1<<9);
+ if ((wsrc & PXA2X0_WAKEUP_RC) != 0)
+ prer |= (1<<13);
+ if ((wsrc & PXA2X0_WAKEUP_SYNC) != 0)
+ pkwr |= (1<<1);
+ if ((wsrc & PXA2X0_WAKEUP_KEYNS0) != 0)
+ prer |= (1<<12);
+ if ((wsrc & PXA2X0_WAKEUP_KEYNS1) != 0)
+ pkwr |= (1<<2);
+ if ((wsrc & PXA2X0_WAKEUP_KEYNS2) != 0)
+ pkwr |= (1<<9);
+ if ((wsrc & PXA2X0_WAKEUP_KEYNS3) != 0)
+ pkwr |= (1<<3);
+ if ((wsrc & PXA2X0_WAKEUP_KEYNS4) != 0)
+ pkwr |= (1<<4);
+ if ((wsrc & PXA2X0_WAKEUP_KEYNS5) != 0)
+ pkwr |= (1<<6);
+ if ((wsrc & PXA2X0_WAKEUP_KEYNS6) != 0)
+ pkwr |= (1<<7);
+ if ((wsrc & PXA2X0_WAKEUP_CF0) != 0)
+ pkwr |= (1<<11);
+ if ((wsrc & PXA2X0_WAKEUP_CF1) != 0)
+ pkwr |= (1<<10);
+ if ((wsrc & PXA2X0_WAKEUP_USBD) != 0)
+ prer |= (1<<24);
+
+ if ((wsrc & PXA2X0_WAKEUP_LOCKSW) != 0) {
+ prer |= (1<<15);
+ pfer |= (1<<15);
+ }
+
+ if ((wsrc & PXA2X0_WAKEUP_JACKIN) != 0) {
+ prer |= (1<<23);
+ pfer |= (1<<23);
+ }
+
+ if ((wsrc & PXA2X0_WAKEUP_CHRGFULL) != 0)
+ pkwr |= (1<<18);
+ if ((wsrc & PXA2X0_WAKEUP_RTC) != 0)
+ prer |= (1<<31);
+
+ if (enable) {
+ prer |= bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh,
+ POWMAN_PRER);
+ pfer |= bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh,
+ POWMAN_PFER);
+ pkwr |= bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh,
+ POWMAN_PKWR);
+ } else {
+ prer = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh,
+ POWMAN_PRER) & ~prer;
+ pfer = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh,
+ POWMAN_PFER) & ~pfer;
+ pkwr = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh,
+ POWMAN_PKWR) & ~pkwr;
+ }
+
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PRER, prer);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PFER, pfer);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PWER,
+ prer | pfer);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PEDR,
+ 0xffffffff);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PKWR, pkwr);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PKSR,
+ 0xffffffff);
+
+ /* XXX do that just before suspend. */
+ pxa2x0_clkman_config(CKEN_KEY,
+ (wsrc & PXA2X0_WAKEUP_KEYNS_ALL) != 0);
+}
+
+void
pxa2x0_apm_standby(struct pxa2x0_apm_softc *sc)
{
+
+ /* XXX standby mode is not supported. */
+ delay(1000000);
+}
+
+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_oier;
+ /* GPIO registers */
+ u_int32_t sd_gpdr0, sd_gpdr1, sd_gpdr2, sd_gpdr3;
+ u_int32_t sd_grer0, sd_grer1, sd_grer2, sd_grer3;
+ u_int32_t sd_gfer0, sd_gfer1, sd_gfer2, sd_gfer3;
+ u_int32_t sd_gafr0_l, sd_gafr1_l, sd_gafr2_l, sd_gafr3_l;
+ u_int32_t sd_gafr0_u, sd_gafr1_u, sd_gafr2_u, sd_gafr3_u;
+ u_int32_t sd_gplr0, sd_gplr1, sd_gplr2, sd_gplr3;
+ /* Interrupt controller registers */
+ u_int32_t sd_iclr;
+ u_int32_t sd_icmr;
+ u_int32_t sd_iccr;
+ /* Memory controller registers */
+ u_int32_t sd_mecr;
+ u_int32_t sd_mcmem0, sd_mcmem1;
+ u_int32_t sd_mcatt0, sd_mcatt1;
+ u_int32_t sd_mcio0, sd_mcio1;
+ /* Clocks manager registers */
+ u_int32_t sd_cken;
+};
+
+void
+pxa2x0_apm_sleep(struct pxa2x0_apm_softc *sc)
+{
+ struct pxa2x0_sleep_data sd;
+ bus_space_handle_t ost_ioh;
+ bus_space_handle_t intctl_ioh;
int save;
+ u_int32_t rv;
+
+ ost_ioh = (bus_space_handle_t)0;
+ intctl_ioh = (bus_space_handle_t)0;
+
+ if (bus_space_map(sc->sc_iot, PXA2X0_OST_BASE, PXA2X0_OST_SIZE, 0,
+ &ost_ioh)) {
+ printf("pxa2x0_apm_sleep: can't map OST\n");
+ goto out;
+ }
+
+ if (bus_space_map(sc->sc_iot, PXA2X0_INTCTL_BASE,
+ PXA2X0_INTCTL_SIZE, 0, &intctl_ioh)) {
+ printf("pxa2x0_apm_sleep: can't map INTCTL\n");
+ goto out;
+ }
save = disable_interrupts(I32_bit|F32_bit);
- /* XXX add power hooks elsewhere, first. */
+ sd.sd_oscr0 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSCR0);
+ 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_oier = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OIER);
+
+ /* Bring the PXA27x into 416Mhz turbo mode. */
+ if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA27X &&
+ bus_space_read_4(sc->sc_iot, pxa2x0_clkman_ioh, CLKMAN_CCCR) !=
+ (CCCR_A | CCCR_TURBO_X2 | CCCR_RUN_X16)) {
+#if 0
+ pxa27x_cpu_speed_high();
+#else
+#define CLKCFG_T (1<<0) /* turbo */
+#define CLKCFG_F (1<<1) /* frequency change */
+#define CLKCFG_B (1<<3) /* fast-bus */
+ pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X2 |
+ CCCR_RUN_X16, CLKCFG_B | CLKCFG_F | CLKCFG_T,
+ &pxa2x0_memcfg);
+#endif
+ delay(500000); /* XXX */
+ }
+
+ scoop_check_mcr();
+
+ /* XXX control battery charging in sleep mode. */
+
+ /* XXX schedule RTC alarm to check the battery? */
+
+ pxa2x0_wakeup_config(PXA2X0_WAKEUP_ALL, 1);
+
+ pxa27x_run_mode();
+#define MDREFR_LOW (MDREFR_C3000 | 0x00b)
+ pxa27x_fastbus_run_mode(0, MDREFR_LOW);
+ delay(1);
+#if 1
+ pxa27x_cpu_speed_91();
+#else
+ pxa27x_frequency_change(CCCR_TURBO_X1 | CCCR_RUN_X7, CLKCFG_F,
+ &pxa2x0_memcfg);
+#endif
+ pxa2x0_pi2c_setvoltage(sc->sc_iot, sc->sc_pm_ioh, PI2C_VOLTAGE_LOW);
+
+ scoop_check_mcr();
+ scoop_suspend();
+
+ sd.sd_gpdr0 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR0);
+ sd.sd_gpdr1 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR1);
+ sd.sd_gpdr2 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR2);
+ sd.sd_gpdr3 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR3);
+
+ sd.sd_grer0 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER0);
+ sd.sd_grer1 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER1);
+ sd.sd_grer2 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER2);
+ sd.sd_grer3 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER3);
+
+ sd.sd_gfer0 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER0);
+ sd.sd_gfer1 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER1);
+ sd.sd_gfer2 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER2);
+ sd.sd_gfer3 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER3);
+
+ sd.sd_gafr0_l = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR0_L);
+ sd.sd_gafr1_l = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR1_L);
+ sd.sd_gafr2_l = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR2_L);
+ sd.sd_gafr3_l = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR3_L);
+
+ sd.sd_gafr0_u = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR0_U);
+ sd.sd_gafr1_u = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR1_U);
+ sd.sd_gafr2_u = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR2_U);
+ sd.sd_gafr3_u = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR3_U);
+
+ sd.sd_gplr0 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPLR0);
+ sd.sd_gplr1 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPLR1);
+ sd.sd_gplr2 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPLR2);
+ sd.sd_gplr3 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPLR3);
+
+ sd.sd_iclr = bus_space_read_4(sc->sc_iot, intctl_ioh, INTCTL_ICLR);
+ sd.sd_icmr = bus_space_read_4(sc->sc_iot, intctl_ioh, INTCTL_ICMR);
+ sd.sd_iccr = bus_space_read_4(sc->sc_iot, intctl_ioh, INTCTL_ICCR);
+ bus_space_write_4(sc->sc_iot, intctl_ioh, INTCTL_ICMR, 0);
+
+ sd.sd_mecr = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
+ MEMCTL_MECR);
+ sd.sd_mcmem0 = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
+ MEMCTL_MCMEM(0));
+ sd.sd_mcmem1 = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
+ MEMCTL_MCMEM(1));
+ sd.sd_mcatt0 = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
+ MEMCTL_MCATT(0));
+ sd.sd_mcatt1 = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
+ MEMCTL_MCATT(1));
+ sd.sd_mcio0 = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
+ MEMCTL_MCIO(0));
+ sd.sd_mcio1 = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
+ MEMCTL_MCIO(1));
+
+ sd.sd_cken = bus_space_read_4(sc->sc_iot, pxa2x0_clkman_ioh,
+ CLKMAN_CKEN);
+ bus_space_write_4(sc->sc_iot, pxa2x0_clkman_ioh, CLKMAN_CKEN,
+ CKEN_MEM | CKEN_KEY);
+
+ /* Disable nRESET_OUT. */
+ rv = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PSLR);
+#define PSLR_SL_ROD (1<<20)
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PSLR,
+ rv | PSLR_SL_ROD);
+
+ /* Clear reset controller status. */
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_RCSR,
+ RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR);
+
+ /* Stop 3/13Mhz oscillator, do not float PCMCIA and chip-selects. */
+ rv = PCFR_OPDE;
+ if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA27X)
+ /* Enable nRESET_GPIO as a GPIO reset input. */
+ rv |= PCFR_GPR_EN;
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PCFR, rv);
+
+ /* XXX C3000 */
+#define GPIO_G0_STROBE_BIT 0x0f800000
+#define GPIO_G1_STROBE_BIT 0x00100000
+#define GPIO_G2_STROBE_BIT 0x01000000
+#define GPIO_G3_STROBE_BIT 0x00041880
+#define GPIO_KEY_STROBE0 88
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR0,
+ 0x00144018);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR1,
+ 0x00ef0000);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR2,
+ 0x0121c000);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR3,
+ 0x00600000);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR0,
+ 0x00144018 & ~GPIO_G0_STROBE_BIT);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR1,
+ 0x00ef0000 & ~GPIO_G1_STROBE_BIT);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR2,
+ 0x0121c000 & ~GPIO_G2_STROBE_BIT);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR3,
+ 0x00600000 & ~GPIO_G3_STROBE_BIT);
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR2,
+ (0x0121c000 & ~GPIO_G2_STROBE_BIT) |
+ GPIO_BIT(GPIO_KEY_STROBE0));
+
+ /* C3000 */
+#define GPIO_EXT_BUS_READY 18
+ pxa2x0_gpio_set_function(GPIO_EXT_BUS_READY, GPIO_SET | GPIO_OUT);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR0, 0xd01c4418);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR1, 0xfcefbd21);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR2, 0x13a5ffff);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR3, 0x01e3e10c);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PSPR,
+ (u_int32_t)&pxa2x0_cpu_resume - 0xc0200000 + 0xa0200000);
+
+ pxa2x0_cpu_suspend();
+
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PSPR, 0);
+
+ pxa2x0_clkman_config(CKEN_SSP|CKEN_PWM0|CKEN_PWM1, 1);
+ pxa2x0_clkman_config(CKEN_KEY, 0);
+
+ /* Clear all GPIO interrupt sources. */
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GEDR0, 0xffffffff);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GEDR1, 0xffffffff);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GEDR2, 0xffffffff);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR0, sd.sd_gpdr0);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR1, sd.sd_gpdr1);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR2, sd.sd_gpdr2);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER0, sd.sd_grer0);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER1, sd.sd_grer1);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER2, sd.sd_grer2);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER0, sd.sd_gfer0);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER1, sd.sd_gfer1);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER2, sd.sd_gfer2);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR0_L, sd.sd_gafr0_l);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR1_L, sd.sd_gafr1_l);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR2_L, sd.sd_gafr2_l);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR0_U, sd.sd_gafr0_u);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR1_U, sd.sd_gafr1_u);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR2_U, sd.sd_gafr2_u);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPSR0, sd.sd_gplr0 &
+ sd.sd_gpdr0);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPSR1, sd.sd_gplr1 &
+ sd.sd_gpdr1);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPSR2, sd.sd_gplr2 &
+ sd.sd_gpdr2);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPCR0, ~sd.sd_gplr0 &
+ sd.sd_gpdr0);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPCR1, ~sd.sd_gplr1 &
+ sd.sd_gpdr1);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPCR2, ~sd.sd_gplr2 &
+ sd.sd_gpdr2);
+
+ /* PXA27x */
+#if 0
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GEDR3, 0xffffffff);
+#endif
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR3, sd.sd_gpdr3);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER3, sd.sd_grer3);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER3, sd.sd_gfer3);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR3_L, sd.sd_gafr3_l);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR3_U, sd.sd_gafr3_u);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPSR3, sd.sd_gplr3 &
+ sd.sd_gpdr3);
+ bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPCR3, ~sd.sd_gplr3 &
+ sd.sd_gpdr3);
+
+ bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MECR,
+ sd.sd_mecr);
+ bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MCMEM(0),
+ sd.sd_mcmem0);
+ bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MCMEM(1),
+ sd.sd_mcmem1);
+ bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MCATT(0),
+ sd.sd_mcatt0);
+ bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MCATT(1),
+ sd.sd_mcatt1);
+ bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MCIO(0),
+ sd.sd_mcio0);
+ bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MCIO(1),
+ sd.sd_mcio1);
+
+ bus_space_write_4(sc->sc_iot, pxa2x0_clkman_ioh, CLKMAN_CKEN,
+ sd.sd_cken);
+
+ bus_space_write_4(sc->sc_iot, intctl_ioh, INTCTL_ICLR, sd.sd_iclr);
+ bus_space_write_4(sc->sc_iot, intctl_ioh, INTCTL_ICCR, sd.sd_iccr);
+ bus_space_write_4(sc->sc_iot, intctl_ioh, INTCTL_ICMR, sd.sd_icmr);
+
+ if ((bus_space_read_4(sc->sc_iot, intctl_ioh, INTCTL_ICIP) & 0x1) != 0)
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PEDR, 0x1);
+
+ scoop_check_mcr();
+ scoop_resume();
+
+ pxa2x0_pi2c_setvoltage(sc->sc_iot, sc->sc_pm_ioh, PI2C_VOLTAGE_HIGH);
+
+ /* Change to 208Mhz run mode with fast-bus still disabled. */
+ pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X2 | CCCR_RUN_X16,
+ CLKCFG_F, &pxa2x0_memcfg);
+ delay(1); /* XXX is the delay long enough, and necessary at all? */
+ pxa27x_fastbus_run_mode(1, pxa2x0_memcfg.mdrefr_high);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PMCR, 0);
+
+ /* Change to 416Mhz turbo mode with fast-bus enabled. */
+ pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X2 | CCCR_RUN_X16,
+ CLKCFG_B | CLKCFG_F | CLKCFG_T, &pxa2x0_memcfg);
+
+ 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);
+
+ /* XXX update ticks from RTC. */
restore_interrupts(save);
+
+ out:
+ if (ost_ioh != (bus_space_handle_t)0)
+ bus_space_unmap(sc->sc_iot, ost_ioh, PXA2X0_OST_SIZE);
+ if (intctl_ioh != (bus_space_handle_t)0)
+ bus_space_unmap(sc->sc_iot, intctl_ioh, PXA2X0_INTCTL_SIZE);
}
void
-pxa2x0_apm_sleep(struct pxa2x0_apm_softc *sc)
+pxa2x0_pi2c_open(bus_space_tag_t iot, bus_space_handle_t ioh)
{
-
- /* XXX first make standby work, and then sleep mode. */
- pxa2x0_apm_standby(sc);
+ u_int32_t rv;
+
+ /* Enable the I2C unit, and disable automatic voltage change. */
+ rv = bus_space_read_4(iot, ioh, POWMAN_PCFR);
+ bus_space_write_4(iot, ioh, POWMAN_PCFR, rv | PCFR_PI2C_EN);
+ rv = bus_space_read_4(iot, ioh, POWMAN_PCFR);
+ bus_space_write_4(iot, ioh, POWMAN_PCFR, rv & ~PCFR_FVC);
+ delay(1);
+
+ /* Enable the clock to the power manager I2C unit. */
+ pxa2x0_clkman_config(CKEN_PI2C, 1);
+ delay(1);
}
void
-pxa2x0_apm_attach_sub(struct pxa2x0_apm_softc *sc)
+pxa2x0_pi2c_close(bus_space_tag_t iot, bus_space_handle_t ioh)
{
+ u_int32_t rv;
- sc->sc_iot = &pxa2x0_bs_tag;
+ bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_UR);
+ bus_space_write_4(iot, ioh, POWMAN_PISAR, 0);
+ delay(1);
- if (bus_space_map(sc->sc_iot, PXA2X0_POWMAN_BASE,
- PXA2X0_POWMAN_SIZE, 0, &sc->sc_pm_ioh)) {
- printf("pxa2x0_apm_attach_sub: failed to map POWMAN\n");
- return;
+ /* Disable the clock to the power manager I2C unit. */
+ pxa2x0_clkman_config(CKEN_PI2C, 0);
+ delay(1);
+
+ /* Disable the I2C unit, and disable automatic voltage change. */
+ rv = bus_space_read_4(iot, ioh, POWMAN_PCFR);
+ bus_space_write_4(iot, ioh, POWMAN_PCFR,
+ rv & ~(PCFR_PI2C_EN | PCFR_FVC));
+ delay(1);
+}
+
+int
+pxa2x0_pi2c_read(bus_space_tag_t iot, bus_space_handle_t ioh,
+ u_char slave, u_char *valuep)
+{
+ u_int32_t rv;
+ int timeout;
+ int tries = PI2C_RETRY_COUNT;
+
+retry:
+
+ bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_UR);
+ bus_space_write_4(iot, ioh, POWMAN_PISAR, 0x00);
+ delay(1);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_IUE | PICR_SCLE);
+
+ /* Write slave device address. */
+ bus_space_write_4(iot, ioh, POWMAN_PIDBR, (slave<<1) | 0x1);
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_START);
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv & ~PICR_STOP);
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_TB);
+
+ timeout = 10000;
+ while ((bus_space_read_4(iot, ioh, POWMAN_PISR) & PISR_ITE) == 0) {
+ if (timeout-- == 0) {
+ bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
+ goto err;
+ }
+ delay(1);
}
- lockinit(&sc->sc_lock, PWAIT, "apmlk", 0, 0);
+ bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
- kthread_create_deferred(apm_thread_create, sc);
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv & ~PICR_START);
- printf("\n");
+ /* Read data value. */
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv |
+ (PICR_STOP | PICR_ACKNAK));
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_TB);
+
+ timeout = 10000;
+ while ((bus_space_read_4(iot, ioh, POWMAN_PISR) & PISR_IRF) == 0) {
+ if (timeout-- == 0) {
+ bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_IRF);
+ goto err;
+ }
+ delay(1);
+ }
+
+ bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_IRF);
+ rv = bus_space_read_4(iot, ioh, POWMAN_PIDBR);
+ *valuep = (u_char)rv;
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv &
+ ~(PICR_STOP | PICR_ACKNAK));
+
+ return (0);
+err:
+ if (tries-- >= 0)
+ goto retry;
+
+ bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_UR);
+ bus_space_write_4(iot, ioh, POWMAN_PISAR, 0x00);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_IUE | PICR_SCLE);
+
+ return (-EIO);
+}
+
+int
+pxa2x0_pi2c_write(bus_space_tag_t iot, bus_space_handle_t ioh,
+ u_char slave, u_char value)
+{
+ u_int32_t rv;
+ int timeout;
+ int tries = PI2C_RETRY_COUNT;
+
+retry:
+
+ bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_UR);
+ bus_space_write_4(iot, ioh, POWMAN_PISAR, 0x00);
+ delay(1);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_IUE | PICR_SCLE);
+
+ /* Write slave device address. */
+ bus_space_write_4(iot, ioh, POWMAN_PIDBR, (slave<<1));
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_START);
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv & ~PICR_STOP);
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_TB);
+
+ timeout = 10000;
+ while ((bus_space_read_4(iot, ioh, POWMAN_PISR) & PISR_ITE) == 0) {
+ if (timeout-- == 0) {
+ bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
+ goto err;
+ }
+ delay(1);
+ }
+ if ((bus_space_read_4(iot, ioh, POWMAN_PISR) & PISR_ACKNAK) != 0)
+ goto err;
+ bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
+
+ /* Write data. */
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv & ~PICR_START);
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_STOP);
+ bus_space_write_4(iot, ioh, POWMAN_PIDBR, value);
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_TB);
+
+ timeout = 10000;
+ while ((bus_space_read_4(iot, ioh, POWMAN_PISR) & PISR_ITE) == 0) {
+ if (timeout-- == 0) {
+#if 0
+ bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
+#endif
+ goto err;
+ }
+ delay(1);
+ }
+ if ((bus_space_read_4(iot, ioh, POWMAN_PISR) & PISR_ACKNAK) != 0)
+ goto err;
+ bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
+
+ rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, rv & ~PICR_STOP);
+
+ return (0);
+err:
+ bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
+ if (tries-- >= 0)
+ goto retry;
+
+ bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_UR);
+ bus_space_write_4(iot, ioh, POWMAN_PISAR, 0x00);
+ bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_IUE | PICR_SCLE);
+
+ return (-EIO);
+}
+
+int
+pxa2x0_pi2c_getvoltage(bus_space_tag_t iot, bus_space_handle_t ioh,
+ u_char *valuep)
+{
+ int res;
+
+ pxa2x0_pi2c_open(iot, ioh);
+ res = pxa2x0_pi2c_read(iot, ioh, 0x0c, valuep);
+ pxa2x0_pi2c_close(iot, ioh);
+ return (res);
+}
+
+int
+pxa2x0_pi2c_setvoltage(bus_space_tag_t iot, bus_space_handle_t ioh,
+ u_char value)
+{
+ int res;
+
+ pxa2x0_pi2c_open(iot, ioh);
+ res = pxa2x0_pi2c_write(iot, ioh, 0x0c, value);
+ pxa2x0_pi2c_close(iot, ioh);
+ return (res);
+}
+
+void
+pxa2x0_pi2c_print(struct pxa2x0_apm_softc *sc)
+{
+ u_char value = 0;
+
+ (void)pxa2x0_pi2c_getvoltage(sc->sc_iot, sc->sc_pm_ioh, &value);
+ printf("xscale core voltage: %s\n", value == PI2C_VOLTAGE_HIGH ?
+ "high" : (value == PI2C_VOLTAGE_LOW ? "low" : "unkown"));
}
diff --git a/sys/arch/arm/xscale/pxa2x0_apm.h b/sys/arch/arm/xscale/pxa2x0_apm.h
index 9891822b118..1abd374de6c 100644
--- a/sys/arch/arm/xscale/pxa2x0_apm.h
+++ b/sys/arch/arm/xscale/pxa2x0_apm.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pxa2x0_apm.h,v 1.3 2005/01/26 06:34:53 uwe Exp $ */
+/* $OpenBSD: pxa2x0_apm.h,v 1.4 2005/02/22 21:53:03 uwe Exp $ */
/*
* Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
@@ -36,7 +36,40 @@ struct pxa2x0_apm_softc {
void (*sc_power_info)(struct pxa2x0_apm_softc *,
struct apm_power_info *);
};
+void pxa2x0_apm_attach_sub(struct pxa2x0_apm_softc *);
-extern void pxa2x0_apm_attach_sub(struct pxa2x0_apm_softc *);
+#define PXA2X0_WAKEUP_POWERON (1<<0)
+#define PXA2X0_WAKEUP_GPIORST (1<<1)
+#define PXA2X0_WAKEUP_SD (1<<2)
+#define PXA2X0_WAKEUP_RC (1<<3)
+#define PXA2X0_WAKEUP_SYNC (1<<4)
+#define PXA2X0_WAKEUP_KEYNS0 (1<<5)
+#define PXA2X0_WAKEUP_KEYNS1 (1<<6)
+#define PXA2X0_WAKEUP_KEYNS2 (1<<7)
+#define PXA2X0_WAKEUP_KEYNS3 (1<<8)
+#define PXA2X0_WAKEUP_KEYNS4 (1<<9)
+#define PXA2X0_WAKEUP_KEYNS5 (1<<10)
+#define PXA2X0_WAKEUP_KEYNS6 (1<<11)
+#define PXA2X0_WAKEUP_CF0 (1<<12)
+#define PXA2X0_WAKEUP_CF1 (1<<13)
+#define PXA2X0_WAKEUP_USBD (1<<14)
+#define PXA2X0_WAKEUP_LOCKSW (1<<15)
+#define PXA2X0_WAKEUP_JACKIN (1<<16)
+#define PXA2X0_WAKEUP_CHRGFULL (1<<17)
+#define PXA2X0_WAKEUP_RTC (1<<18)
+
+#define PXA2X0_WAKEUP_KEYNS_ALL (PXA2X0_WAKEUP_KEYNS0| \
+ PXA2X0_WAKEUP_KEYNS1|PXA2X0_WAKEUP_KEYNS2|PXA2X0_WAKEUP_KEYNS3| \
+ PXA2X0_WAKEUP_KEYNS4|PXA2X0_WAKEUP_KEYNS5|PXA2X0_WAKEUP_KEYNS6)
+
+#define PXA2X0_WAKEUP_CF_ALL (PXA2X0_WAKEUP_CF0|PXA2X0_WAKEUP_CF1)
+
+#define PXA2X0_WAKEUP_ALL (PXA2X0_WAKEUP_POWERON| \
+ PXA2X0_WAKEUP_GPIORST|PXA2X0_WAKEUP_SD|PXA2X0_WAKEUP_RC| \
+ PXA2X0_WAKEUP_SYNC|PXA2X0_WAKEUP_KEYNS_ALL|PXA2X0_WAKEUP_CF_ALL| \
+ PXA2X0_WAKEUP_USBD|PXA2X0_WAKEUP_LOCKSW|PXA2X0_WAKEUP_JACKIN| \
+ PXA2X0_WAKEUP_CHRGFULL|PXA2X0_WAKEUP_RTC)
+
+void pxa2x0_wakeup_config(u_int32_t, int);
#endif
diff --git a/sys/arch/arm/xscale/pxa2x0_apm_asm.S b/sys/arch/arm/xscale/pxa2x0_apm_asm.S
new file mode 100644
index 00000000000..d4c79ec4484
--- /dev/null
+++ b/sys/arch/arm/xscale/pxa2x0_apm_asm.S
@@ -0,0 +1,577 @@
+/* $OpenBSD: pxa2x0_apm_asm.S,v 1.1 2005/02/22 21:53:03 uwe Exp $ */
+
+/*
+ * Copyright (c) 2005 Uwe Stuehler <uwe@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 <machine/asm.h>
+#include <machine/cpu.h>
+
+#include <arch/arm/xscale/pxa2x0reg.h>
+#include <arch/arm/sa11x0/sa11x0_reg.h>
+
+/* XXX replace with values defined elsewhere. */
+#define DCACHE_CACHELINECOUNT 1024
+#define CACHELINESIZE 32
+
+/* cp14 register 6 */
+#define CLKCFG_T (1<<0) /* turbo */
+#define CLKCFG_F (1<<1) /* frequency change */
+#define CLKCFG_HT (1<<2) /* half-turbo */
+#define CLKCFG_B (1<<3) /* fast-bus */
+
+/* cp14 register 7 */
+#define PWRMODE_NORMAL (0<<0)
+#define PWRMODE_IDLE (1<<0)
+#define PWRMODE_STANDBY (2<<0)
+#define PWRMODE_SLEEP (3<<0)
+#define PWRMODE_DEEP_SLEEP (7<<0)
+
+/* XXX */
+#define MDREFR_C3000 (MDREFR_K0DB2|MDREFR_E1PIN|MDREFR_K1RUN|\
+ MDREFR_K1DB2|MDREFR_K2DB2|MDREFR_APD)
+#define MDREFR_DRI_91MHZ (0x13<<0)
+#define MDREFR_HIGH (MDREFR_C3000 | 0x030)
+#define MDREFR_LOW (MDREFR_C3000 | 0x00b)
+#define MDREFR_SPEED_91 (MDREFR_C3000 | MDREFR_DRI_91MHZ)
+#define MDREFR_SPEED_LOW (MDREFR_C3000 | 0x017)
+#define MSC0_HIGH \
+ ( 7 << MSC_RRR_SHIFT << 16) | \
+ (15 << MSC_RDN_SHIFT << 16) | \
+ (15 << MSC_RDF_SHIFT << 16) | \
+ (MSC_RT_NONBURST << 16) | \
+ ( 2 << MSC_RRR_SHIFT) | \
+ (13 << MSC_RDN_SHIFT) | \
+ (13 << MSC_RDF_SHIFT) | \
+ MSC_RBW /* PXA271 */ | \
+ MSC_RT_NONBURST
+#define MSC1_HIGH \
+ ( 7 << MSC_RRR_SHIFT << 16) | \
+ (15 << MSC_RDN_SHIFT << 16) | \
+ (15 << MSC_RDF_SHIFT << 16) | \
+ (MSC_RT_VLIO << 16) | \
+ ( 3 << MSC_RRR_SHIFT) | \
+ ( 4 << MSC_RDN_SHIFT) | \
+ (13 << MSC_RDF_SHIFT) | \
+ MSC_RT_VLIO
+#define MSC2_HIGH \
+ ( 7 << MSC_RRR_SHIFT << 16) | \
+ (15 << MSC_RDN_SHIFT << 16) | \
+ (15 << MSC_RDF_SHIFT << 16) | \
+ (MSC_RT_NONBURST << 16) | \
+ ( 3 << MSC_RRR_SHIFT) | \
+ ( 4 << MSC_RDN_SHIFT) | \
+ (13 << MSC_RDF_SHIFT) | \
+ MSC_RT_VLIO
+#define MSC0_LOW \
+ ( 7 << MSC_RRR_SHIFT << 16) | \
+ (15 << MSC_RDN_SHIFT << 16) | \
+ (15 << MSC_RDF_SHIFT << 16) | \
+ (MSC_RT_NONBURST << 16) | \
+ ( 1 << MSC_RRR_SHIFT) | \
+ ( 8 << MSC_RDN_SHIFT) | \
+ ( 8 << MSC_RDF_SHIFT) | \
+ MSC_RBW /* PXA271 */ | \
+ MSC_RT_NONBURST
+#define MSC1_LOW \
+ ( 7 << MSC_RRR_SHIFT << 16) | \
+ (15 << MSC_RDN_SHIFT << 16) | \
+ (15 << MSC_RDF_SHIFT << 16) | \
+ (MSC_RT_VLIO << 16) | \
+ ( 1 << MSC_RRR_SHIFT) | \
+ ( 2 << MSC_RDN_SHIFT) | \
+ ( 6 << MSC_RDF_SHIFT) | \
+ MSC_RT_VLIO
+#define MSC2_LOW \
+ ( 7 << MSC_RRR_SHIFT << 16) | \
+ (15 << MSC_RDN_SHIFT << 16) | \
+ (15 << MSC_RDF_SHIFT << 16) | \
+ (MSC_RT_NONBURST << 16) | \
+ ( 1 << MSC_RRR_SHIFT) | \
+ ( 2 << MSC_RDN_SHIFT) | \
+ ( 6 << MSC_RDF_SHIFT) | \
+ MSC_RT_VLIO
+
+ .text
+ .global _C_LABEL(vector_page)
+ .global _C_LABEL(xscale_cache_clean_addr)
+ .global _C_LABEL(pxa2x0_clkman_ioh)
+ .global _C_LABEL(pxa2x0_memctl_ioh)
+
+.Lvector_page:
+ .word _C_LABEL(vector_page)
+.Lxscale_cache_clean_addr:
+ .word _C_LABEL(xscale_cache_clean_addr)
+
+.Lgpioiohp: .word _C_LABEL(pxa2x0_gpio_ioh)
+.Lclkmaniohp: .word _C_LABEL(pxa2x0_clkman_ioh)
+.Lmemctliohp: .word _C_LABEL(pxa2x0_memctl_ioh)
+
+.Lsleepdata: .word sleepdata
+.Lsleepdata_phys: .word sleepdata - 0xc0200000 + 0xa0200000 /* XXX */
+.Lsleepdata_svc: .word sleepdata_svc
+
+.Lcccr_high: .word CCCR_A | CCCR_TURBO_X2 | CCCR_RUN_X16
+.Lmdrefr_high: .word MDREFR_HIGH
+.Lmsc0_high: .word MSC0_HIGH
+.Lmsc1_high: .word MSC1_HIGH
+.Lmsc2_high: .word MSC2_HIGH
+.Lmdrefr_low: .word MDREFR_LOW
+.Lmsc0_low: .word MSC0_LOW
+.Lmsc1_low: .word MSC1_LOW
+.Lmsc2_low: .word MSC2_LOW
+
+/*
+ * void pxa2x0_cpu_suspend(void)
+ *
+ * Enter sleep mode without automatic voltage change. The core must
+ * be in low power mode, and interrupts disabled.
+ */
+ENTRY(pxa2x0_cpu_suspend)
+ stmdb sp!, {r0-r12, lr}
+
+ ldr r3, .Lsleepdata /* Point to the data area. */
+ ldr r2, =pxa2x0_cpu_resume_virt
+ str r2, [r3], #4
+
+ mrc p15, 0, r2, c1, c0, 0 /* Load MMU control register. */
+ mov r0, #0xff000000
+ orr r0, r0, #0x00ff0000
+ bic r2, r2, r0 /* Clear undefined bits. */
+ str r2, [r3], #4 /* Save MMU control register. */
+
+ mrc p15, 0, r2, c2, c0, 0 /* Load TTB address. */
+ mov r0, #0x00003f00
+ orr r0, r0, #0x000000ff
+ bic r2, r2, r0 /* Clear undefined bits. */
+ str r2, [r3], #4 /* Save TTB address. */
+
+ mrc p15, 0, r2, c3, c0, 0 /* Load domain access control. */
+ str r2, [r3], #4 /* Save domain access control. */
+
+ mrs r2, spsr /* Load SVC saved CPSR. */
+ str r2, [r3], #4 /* Save SVC saved CPSR. */
+ str sp, [r3], #4 /* Save SVC stack pointer. */
+
+ mov r1, #(PSR_FIQ32_MODE | I32_bit | F32_bit)
+ msr cpsr, r1 /* Enter FIQ mode. */
+ mrs r2, spsr /* Load FIQ mode saved CPSR. */
+ stmia r3!, {r2, r8-r12, sp, lr} /* Save FIQ mode registers. */
+
+ mov r1, #(PSR_IRQ32_MODE | I32_bit | F32_bit)
+ msr cpsr, r1 /* Enter IRQ mode. */
+ mrs r0, spsr /* Load IRQ mode saved CPSR. */
+ stmia r3!, {r0, sp, lr} /* Save IRQ mode registers. */
+
+ mov r1, #(PSR_ABT32_MODE | I32_bit | F32_bit)
+ msr cpsr, r1 /* Enter ABT mode. */
+ mrs r0, spsr /* Load ABT mode saved CPSR. */
+ stmia r3!, {r0, sp, lr} /* Save ABT mode registers. */
+
+ mov r1, #(PSR_UND32_MODE | I32_bit | F32_bit)
+ msr cpsr, r1 /* Enter UND mode. */
+ mrs r0, spsr /* Load UND mode saved CPSR. */
+ stmia r3!, {r0, sp, lr} /* Save UND mode registers. */
+
+ mov r1, #(PSR_SYS32_MODE | I32_bit | F32_bit)
+ msr cpsr, r1 /* Enter SYS mode. */
+ stmia r3!, {sp, lr} /* Save SYS mode registers. */
+
+ mov r1, #(PSR_SVC32_MODE | I32_bit | F32_bit)
+ msr cpsr, r1 /* Return to SVC mode. */
+
+ /* At this point all critical registers have been saved. */
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4 /* XXX does exactly what? */
+
+ mov r1, #DCACHE_CACHELINECOUNT
+ ldr r0, .Lxscale_cache_clean_addr
+
+cache_flush_loop:
+ mrs r2, cpsr
+ orr r2, r2, #(I32_bit|F32_bit)
+ msr cpsr_c, r2 /* disable IRQ/FIQ */
+
+ mcr p15, 0, r0, c7, c2, 5 /* allocate cache line */
+ mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */
+
+ mrs r2, cpsr
+ and r2, r2, #~(I32_bit|F32_bit)
+ msr cpsr_c, r2 /* enable IRQ/FIQ */
+
+ add r0, r0, #CACHELINESIZE
+ subs r1, r1, #1
+ bne cache_flush_loop
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
+
+ b 1f
+1:
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ /* Prepare to enter sleep mode. */
+ mov r1, #PWRMODE_SLEEP
+
+ /* Prepare to put SDRAM into self-refresh mode. */
+ ldr r4, .Lmemctliohp
+ ldr r4, [r4]
+ add r4, r4, #MEMCTL_MDREFR
+ ldr r5, [r4]
+ orr r5, r5, #MDREFR_SLFRSH
+
+ /* XXX prepare pointer to physical address 0, but for whom? */
+ ldr r2, .Lvector_page
+
+ /*
+ * Execute the rest of this routine from cache. The needed values
+ * are now in registers.
+ */
+ b 1f
+ /* XXX tell as(1) to dump the literal pool here, but why? */
+ .ltorg
+ .align 5
+1:
+
+ /* Put SDRAM into self-refresh mode manually. */
+ str r5, [r4]
+ nop
+
+ /*
+ * Enter sleep mode. Exit from sleep mode returns the processor
+ * to normal run mode. Execution resumes at the physical address
+ * stored in the PSPR after the required boot sequence (a short
+ * excursion into the ROM boot loader).
+ */
+ mcr p14, 0, r1, c7, c0, 0
+
+ /* Just in case that wake-up does not resume at */
+ nop
+ nop
+ nop
+1:
+ b 1b
+
+/*
+ * void pxa2x0_cpu_resume(void)
+ */
+ .align 5
+ENTRY(pxa2x0_cpu_resume)
+ /* XXX C3000-specific */
+ ldr r0, .Lmdrefr_addr_phys
+ b 1f
+ .align 5
+1:
+ ldr r2, [r0]
+ bic r2, r2, #MDREFR_DRI & 0x000000ff
+ bic r2, r2, #MDREFR_DRI & 0x0000ff00
+ orr r2, r2, #MDREFR_DRI_91MHZ
+ str r2, [r0]
+ b 1f
+ .align 5
+1:
+ ldr r0, .Lsleepdata_phys /* Point to PA of saved data. */
+
+ ldmia r0!, {r7-r10}
+ mcr p15, 0, r10, c3, c0, 0 /* Restore domain access control. */
+ mcr p15, 0, r9, c2, c0, 0 /* Restore TTB address. */
+ mcr p15, 0, r0, c8, c7, 0 /* Flush I+D TLBs. */
+ mcr p15, 0, r0, c7, c7, 0 /* Flush I+D BTB. */
+ mcr p15, 0, r8, c1, c0, 0 /* Restore MMU control. */
+ mov pc, r7 /* Jump to virtual address. */
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+pxa2x0_cpu_resume_virt:
+ ldr r2, .Lsleepdata_svc /* Load VA of saved registers. */
+
+ /* Restore SVC mode SPSR and stack pointer. */
+ ldr r0, [r2], #4
+ msr spsr, r0
+ ldr sp, [r2], #4
+
+ /* Restore FIQ mode registers. */
+ mov r1, #(PSR_FIQ32_MODE | I32_bit | F32_bit)
+ msr cpsr, r1
+ ldr r0, [r2], #4
+ msr spsr, r0
+ ldr r8, [r2], #4
+ ldr r9, [r2], #4
+ ldr r10, [r2], #4
+ ldr r11, [r2], #4
+ ldr r12, [r2], #4
+ ldr sp, [r2], #4
+ ldr lr, [r2], #4
+
+ /* Restore IRQ mode registers. */
+ mov r1, #(PSR_IRQ32_MODE | I32_bit | F32_bit)
+ msr cpsr, r1
+ ldr r0, [r2], #4
+ msr spsr, r0
+ ldr sp, [r2], #4
+ ldr lr, [r2], #4
+
+ /* Restore ABT mode registers. */
+ mov r1, #(PSR_ABT32_MODE | I32_bit | F32_bit)
+ msr cpsr, r1
+ ldr r0, [r2], #4
+ msr spsr, r0
+ ldr sp, [r2], #4
+ ldr lr, [r2], #4
+
+ /* Restore UND mode registers. */
+ mov r1, #(PSR_UND32_MODE | I32_bit | F32_bit)
+ msr cpsr, r1
+ ldr r0, [r2], #4
+ msr spsr, r0
+ ldr sp, [r2], #4
+ ldr lr, [r2], #4
+
+ /* Restore SYS mode registers. */
+ mov r1, #(PSR_SYS32_MODE | I32_bit | F32_bit)
+ msr cpsr, r1
+ ldr sp, [r2], #4
+ ldr lr, [r2], #4
+
+ /* Return to SVC mode. */
+ mov r1, #(PSR_SVC32_MODE | I32_bit | F32_bit)
+ msr cpsr, r1
+
+ ldmia sp!, {r0-r12, pc}
+
+.Lmdrefr_addr_phys:
+ .word PXA2X0_MEMCTL_BASE + MEMCTL_MDREFR
+
+ .data
+
+/*
+ * Saved processor state
+ */
+sleepdata:
+ .word 0 /* =pxa2x0_cpu_resume_virt */
+ .word 0 /* MMU control */
+ .word 0 /* MMU TTB address */
+ .word 0 /* MMU domain access control */
+sleepdata_svc:
+ .word 0 /* SVC mode saved CPSR */
+ .word 0 /* SVC mode stack pointer */
+ .word 0 /* FIQ mode saved CPSR */
+ .word 0 /* FIQ mode r8 */
+ .word 0 /* FIQ mode r9 */
+ .word 0 /* FIQ mode r10 */
+ .word 0 /* FIQ mode r11 */
+ .word 0 /* FIQ mode r12 */
+ .word 0 /* FIQ mode stack pointer */
+ .word 0 /* FIQ mode link register */
+ .word 0 /* IRQ mode saved CPSR */
+ .word 0 /* IRQ mode stack pointer */
+ .word 0 /* IRQ mode link register */
+ .word 0 /* ABT mode saved CPSR */
+ .word 0 /* ABT mode stack pointer */
+ .word 0 /* ABT mode link register */
+ .word 0 /* UND mode saved CPSR */
+ .word 0 /* UND mode stack pointer */
+ .word 0 /* UND mode link register */
+ .word 0 /* SYS mode stack pointer */
+ .word 0 /* SYS mode link register */
+
+ .text
+
+/*
+ * void pxa27x_run_mode(void)
+ *
+ * Disable half-turbo and turbo mode, but keep fast-bus mode.
+ * Memory and LCD clock is not changed, so no reconfiguration is
+ * necessary.
+ */
+ENTRY(pxa27x_run_mode)
+ stmdb sp!, {r0}
+ mrc p14, 0, r0, c6, c0, 0
+ and r0, r0, #~(CLKCFG_HT | CLKCFG_F| CLKCFG_T)
+ mcr p14, 0, r0, c6, c0, 0
+ ldmia sp!, {r0}
+ mov pc, lr
+
+/*
+ * void pxa27x_fastbus_run_mode(int enable, u_int32_t mdrefr)
+ *
+ * Enter normal run mode with fast-bus mode enabled or disabled.
+ * The new value of MDREFR is programmed before or after CLKCFG,
+ * as appropriate.
+ */
+ .align 5
+ENTRY(pxa27x_fastbus_run_mode)
+ stmdb sp!, {r0-r2, lr}
+ ldr r2, .Lmemctliohp
+ ldr r2, [r2]
+ cmp r0, #0
+ beq disable_fastbus
+ b enable_fastbus
+ .align 5
+enable_fastbus:
+ /* Enter normal run mode with fast-bus mode enabled. */
+ mov r0, #CLKCFG_B
+ mcr p14, 0, r0, c6, c0, 0
+ /* Set the new SDRAM refresh rate. */
+ str r1, [r2, #MEMCTL_MDREFR]
+ ldr r0, [r2, #MEMCTL_MDREFR]
+ mov r0, r0
+ ldmia sp!, {r0-r2, pc}
+ .align 5
+disable_fastbus:
+ /* Set the new SDRAM refresh rate. */
+ str r1, [r2, #MEMCTL_MDREFR]
+ ldr r0, [r2, #MEMCTL_MDREFR]
+ mov r0, r0
+ /* Enter normal run mode with fast-bus mode disabled. */
+ mov r0, #0x0
+ mcr p14, 0, r0, c6, c0, 0
+ ldmia sp!, {r0-r2, pc}
+
+/* Keep these offsets in sync with struct memcfg. */
+#define memcfg_mdrefr_high 0x00
+#define memcfg_mdrefr_low 0x04
+#define memcfg_mdrefr_low2 0x08 /* unused */
+#define memcfg_msc_high 0x0c
+#define memcfg_msc_low 0x18
+#define memcfg_mdrefr_91 0x24
+
+/*
+ * void pxa27x_frequency_change(int cccr, int clkcfg,
+ * struct pxa2x0_memcfg *memcfg)
+ *
+ * Change the core PLL frequency and SDRAM refresh rate, ensuring the
+ * proper sequence of operations. If the CCCR_A bit is clear and L
+ * is not equal to 7 the result is undefined.
+ */
+ .align 5
+ENTRY(pxa27x_frequency_change)
+ stmdb sp!, {r0-r5, lr}
+
+ /* Always write to CCCR before a frequency change. */
+ ldr r3, .Lclkmaniohp
+ ldr r3, [r3]
+ str r0, [r3, #CLKMAN_CCCR]
+
+ /* Load the needed values into registers to avoid SDRAM access. */
+ and r3, r0, #CCCR_L_MASK
+ ldr r0, .Lmemctliohp
+ ldr r0, [r0]
+ cmp r3, #CCCR_RUN_X7 /* L=7 is 91Mhz mode */
+ beq frequency_change_91
+ and r3, r1, #CLKCFG_B
+ cmp r3, #CLKCFG_B
+ bne frequency_change_208
+ /* FALLTHROUGH */
+frequency_change_high:
+ ldr r3, [r2, #memcfg_mdrefr_low]
+ ldr r4, [r2, #memcfg_mdrefr_high]
+ add r2, r2, #memcfg_msc_high
+ bl frequency_change_on_cache /* XXX why BL? */
+frequency_change_208:
+ ldr r3, [r2, #memcfg_mdrefr_low]
+ ldr r4, [r2, #memcfg_mdrefr_low]
+ add r2, r2, #memcfg_msc_high
+ bl frequency_change_on_cache
+frequency_change_91:
+ ldr r3, [r2, #memcfg_mdrefr_low]
+ ldr r4, [r2, #memcfg_mdrefr_91]
+ add r2, r2, #memcfg_msc_low
+ bl frequency_change_on_cache
+
+ /* Align execution to a cache line. */
+ .align 5
+frequency_change_on_cache:
+ /* Change to a low SDRAM refresh rate. Wait until the store to
+ * MDREFR is complete, following section 2.4 I/O Ordering and
+ * 6.5.1.4 of the PXA27x Developer's Manual. */
+ str r3, [r0, #MEMCTL_MDREFR]
+ ldr r5, [r0, #MEMCTL_MDREFR]
+ mov r5, r5
+ /* Program new CLKCFG value, starting a core PLL frequency change
+ * if CLKCFG_F is set. */
+ mcr p14, 0, r1, c6, c0, 0
+ /* Change SDRAM clock frequency to 104Mhz, and ensure that the
+ * store to MDREFR is complete before the next SDRAM access. */
+ str r4, [r0, #MEMCTL_MDREFR]
+ ldr r5, [r0, #MEMCTL_MDREFR]
+ mov r5, r5
+ /* Configure synchronous, static, and VLIO interfaces. */
+ ldr r1, [r2], #4
+ str r1, [r0, #MEMCTL_MSC0]
+ ldr r1, [r2], #4
+ str r1, [r0, #MEMCTL_MSC1]
+ ldr r1, [r2]
+ str r1, [r0, #MEMCTL_MSC2]
+ ldmia sp!, {r0-r5, pc}
+
+/*
+ * void pxa27x_cpu_speed_91(void)
+ *
+ * Switch core run frequency to 91 Mhz.
+ */
+ .align 5
+ENTRY(pxa27x_cpu_speed_91)
+ stmdb sp!, {r0-r3, lr}
+
+ ldr r0, .Lclkmaniohp
+ ldr r0, [r0]
+ ldr r1, .Lcccr_91
+ str r1, [r0, #CLKMAN_CCCR]
+
+ ldr r0, .Lmemctliohp
+ ldr r0, [r0]
+ ldr r2, .Lmdrefr_91
+ ldr r3, .Lmdrefr_low
+
+ bl 1f
+ .align 5
+1:
+ str r3, [r0, #MEMCTL_MDREFR]
+ ldr r3, [r0, #MEMCTL_MDREFR]
+
+ mov r1, #CLKCFG_F
+ mcr p14, 0, r1, c6, c0, 0
+ str r2, [r0, #MEMCTL_MDREFR]
+ ldr r2, [r0, #MEMCTL_MDREFR]
+
+ ldr r1, .Lmsc0_low
+ str r1, [r0, #MEMCTL_MSC0]
+ ldr r1, .Lmsc1_low
+ str r1, [r0, #MEMCTL_MSC1]
+ ldr r1, .Lmsc2_low
+ str r1, [r0, #MEMCTL_MSC2]
+
+ ldmia sp!, {r0-r3, pc}
+
+.Lcccr_91: .word CCCR_TURBO_X1 | CCCR_RUN_X7
+.Lmdrefr_91: .word MDREFR_SPEED_91
diff --git a/sys/arch/arm/xscale/pxa2x0_lcd.c b/sys/arch/arm/xscale/pxa2x0_lcd.c
index 06f52f1b149..c7f55b49d83 100644
--- a/sys/arch/arm/xscale/pxa2x0_lcd.c
+++ b/sys/arch/arm/xscale/pxa2x0_lcd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pxa2x0_lcd.c,v 1.15 2005/02/17 23:16:33 drahn Exp $ */
+/* $OpenBSD: pxa2x0_lcd.c,v 1.16 2005/02/22 21:53:03 uwe Exp $ */
/* $NetBSD: pxa2x0_lcd.c,v 1.8 2003/10/03 07:24:05 bsh Exp $ */
/*
@@ -89,6 +89,9 @@ void pxa2x0_lcd_setup_rasops(struct rasops_info *,
void pxa2x0_lcd_start_dma(bus_space_tag_t, bus_space_handle_t,
struct pxa2x0_lcd_screen *);
void pxa2x0_lcd_stop_dma(bus_space_tag_t, bus_space_handle_t);
+void pxa2x0_lcd_suspend(struct pxa2x0_lcd_softc *);
+void pxa2x0_lcd_resume(struct pxa2x0_lcd_softc *);
+void pxa2x0_lcd_powerhook(int, void *);
/*
* Setup display geometry parameters.
@@ -261,6 +264,8 @@ pxa2x0_lcd_attach_sub(struct pxa2x0_lcd_softc *sc,
bzero(&dummy, sizeof(dummy));
pxa2x0_lcd_setup_rasops(&dummy, descr, geom);
}
+
+ (void)powerhook_establish(pxa2x0_lcd_powerhook, sc);
}
/*
@@ -817,3 +822,44 @@ pxa2x0_lcd_mmap(void *v, off_t offset, int prot)
return (bus_dmamem_mmap(sc->dma_tag, screen->segs, screen->nsegs,
offset, prot, BUS_DMA_WAITOK | BUS_DMA_COHERENT));
}
+
+void
+pxa2x0_lcd_suspend(struct pxa2x0_lcd_softc *sc)
+{
+
+ if (sc->active != NULL) {
+ pxa2x0_lcd_stop_dma(sc->iot, sc->ioh);
+ pxa2x0_clkman_config(CKEN_LCD, 0);
+ delay(1000000); /* XXX */
+ }
+}
+
+void
+pxa2x0_lcd_resume(struct pxa2x0_lcd_softc *sc)
+{
+
+ if (sc->active != NULL) {
+ pxa2x0_lcd_initialize(sc->iot, sc->ioh, sc->geometry,
+ pxa2x0_clkman_config);
+ pxa2x0_lcd_start_dma(sc->iot, sc->ioh, sc->active);
+ /* XXX wait here to avoid a weird fade-in effect. */
+ delay(1000000);
+ }
+}
+
+void
+pxa2x0_lcd_powerhook(int why, void *v)
+{
+ struct pxa2x0_lcd_softc *sc = v;
+
+ switch (why) {
+ case PWR_SUSPEND:
+ case PWR_STANDBY:
+ pxa2x0_lcd_suspend(sc);
+ break;
+
+ case PWR_RESUME:
+ pxa2x0_lcd_resume(sc);
+ break;
+ }
+}
diff --git a/sys/arch/arm/xscale/pxa2x0reg.h b/sys/arch/arm/xscale/pxa2x0reg.h
index cd0c053c352..c614a8d4823 100644
--- a/sys/arch/arm/xscale/pxa2x0reg.h
+++ b/sys/arch/arm/xscale/pxa2x0reg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pxa2x0reg.h,v 1.11 2005/02/17 22:10:35 dlg Exp $ */
+/* $OpenBSD: pxa2x0reg.h,v 1.12 2005/02/22 21:53:03 uwe Exp $ */
/* $NetBSD: pxa2x0reg.h,v 1.4 2003/06/11 20:43:01 scw Exp $ */
/*
@@ -107,7 +107,7 @@
#define PXA2X0_GPIO_BASE 0x40e00000
#define PXA2X0_GPIO_SIZE 0x70
#define PXA2X0_POWMAN_BASE 0x40f00000 /* Power management */
-#define PXA2X0_POWMAN_SIZE 0x100
+#define PXA2X0_POWMAN_SIZE 0x1a4 /* incl. PI2C unit */
#define PXA2X0_SSP_BASE 0x41000000 /* SSP serial port */
#define PXA2X0_SSP1_BASE 0x41700000 /* PXA270 */
#define PXA2X0_SSP2_BASE 0x41900000 /* PXA270 */
@@ -153,6 +153,15 @@
#define PXA2X0_INT_RTCHZ 30
#define PXA2X0_INT_ALARM 31 /* RTC Alarm interrupt */
+/* Interrupt Controller similar to SA11x0's, but not exactly the same. */
+#define INTCTL_ICIP 0x00
+#define INTCTL_ICMR 0x04
+#define INTCTL_ICLR 0x08
+#define INTCTL_ICFP 0x0c
+#define INTCTL_ICPR 0x10
+#define INTCTL_ICCR 0x14
+#define ICCR_DIM (1<<0)
+
/* DMAC */
#define DMAC_N_CHANNELS 16
#define DMAC_N_PRIORITIES 3
@@ -221,25 +230,59 @@ struct pxa2x0_dma_desc {
#define I2C_ISAR 0x16a0 /* Slave address */
/* Power Manager */
+#define POWMAN_PMCR 0x00
#define POWMAN_PSSR 0x04 /* Sleep Status register */
#define PSSR_RDH (1<<5)
+#define POWMAN_PSPR 0x08
+#define POWMAN_PWER 0x0c
+#define POWMAN_PRER 0x10
+#define POWMAN_PFER 0x14
+#define POWMAN_PEDR 0x18
#define POWMAN_PCFR 0x1c /* General Configuration register */
-#define PCFR_GRP_EN (1<<4) /* PXA270 */
+#define PCFR_OPDE (1<<0)
+#define PCFR_GPR_EN (1<<4) /* PXA270 */
+#define PCFR_PI2C_EN (1<<6) /* PXA270 */
#define PCFR_GP_ROD (1<<8) /* PXA270 */
+#define PCFR_FVC (1<<10) /* PXA270 */
+#define POWMAN_PGSR0 0x20 /* GPIO Sleep State register */
+#define POWMAN_PGSR1 0x24
+#define POWMAN_PGSR2 0x28
+#define POWMAN_PGSR3 0x2c /* PXA270 */
#define POWMAN_RCSR 0x30 /* Reset Controller Status register */
#define RCSR_HWR (1<<0)
#define RCSR_WDR (1<<1)
#define RCSR_SMR (1<<2)
#define RCSR_GPR (1<<3)
+#define POWMAN_PSLR 0x34 /* PXA270 */
+#define POWMAN_PKWR 0x50 /* PXA270 */
+#define POWMAN_PKSR 0x54 /* PXA270 */
+
+/* Power Manager I2C unit */
+#define POWMAN_PIDBR 0x188
+#define POWMAN_PICR 0x190
+#define PICR_START ICR_START
+#define PICR_STOP ICR_STOP
+#define PICR_ACKNAK ICR_ACKNAK
+#define PICR_TB ICR_TB
+#define PICR_SCLE (1<<5) /* PXA270? */
+#define PICR_IUE (1<<6) /* PXA270? */
+#define PICR_UR (1<<14) /* PXA270? */
+#define POWMAN_PISR 0x198
+#define PISR_ACKNAK (1<<1)
+#define PISR_ITE (1<<6)
+#define PISR_IRF (1<<7)
+#define POWMAN_PISAR 0x1a0
/* Clock Manager */
#define CLKMAN_CCCR 0x00 /* Core Clock Configuration */
-#define CCCR_CPDIS (1<<31) /* PXA270 */
+#define CCCR_CPDIS (1<<31) /* PXA270 */
+#define CCCR_A (1<<25) /* PXA270 */
#define CCCR_TURBO_X1 (2<<7)
#define CCCR_TURBO_X15 (3<<7) /* x 1.5 */
#define CCCR_TURBO_X2 (4<<7)
#define CCCR_TURBO_X25 (5<<7) /* x 2.5 */
#define CCCR_TURBO_X3 (6<<7) /* x 3.0 */
+/* PXA255 */
#define CCCR_RUN_X1 (1<<5)
#define CCCR_RUN_X2 (2<<5)
#define CCCR_RUN_X4 (3<<5)
@@ -249,6 +292,10 @@ struct pxa2x0_dma_desc {
#define CCCR_MEM_X40 (4<<0) /* x27, 99.53MHz */
#define CCCR_MEM_X45 (5<<0) /* x27, 99.53MHz */
#define CCCR_MEM_X9 (0x1f<<0) /* x9, 33.2MHz */
+/* PXA27x: L is the core run frequency to 13Mhz oscillator ratio. */
+#define CCCR_RUN_X7 (7<<0) /* 91Mhz, 91Mhz mem, 91Mhz LCD */
+#define CCCR_RUN_X8 (8<<0) /* 104Mhz, 104Mhz mem, 52Mhz LCD */
+#define CCCR_RUN_X16 (16<<0) /* 208Mhz, 104/208Mhz mem, 104Mhz LCD */
#define CLKMAN_CKEN 0x04 /* Clock Enable Register */
#define CLKMAN_OSCC 0x08 /* Osillcator Configuration Register */
@@ -272,7 +319,10 @@ struct pxa2x0_dma_desc {
#define CKEN_MMC (1<<12)
#define CKEN_FICP (1<<13)
#define CKEN_I2C (1<<14)
+#define CKEN_PI2C (1<<15) /* PXA270? */
#define CKEN_LCD (1<<16)
+#define CKEN_KEY (1<<19) /* PXA270? */
+#define CKEN_MEM (1<<22) /* PXA270? */
#define OSCC_OOK (1<<0) /* 32.768KHz oscillator status */
#define OSCC_OON (1<<1) /* 32.768KHz oscillator */
@@ -283,6 +333,9 @@ struct pxa2x0_dma_desc {
#define RTC_RCNR 0x0000 /* count register */
#define RTC_RTAR 0x0004 /* alarm register */
#define RTC_RTSR 0x0008 /* status register */
+#define RTSR_AL (1<<0)
+#define RTSR_HZ (1<<1)
+#define RTSR_ALE (1<<2)
#define RTC_RTTR 0x000c /* trim register */
/*
* GPIO
@@ -689,6 +742,7 @@ struct pxa2x0_dma_desc {
#define OST_OSMR2 0x0008 /* Match 2 */
#define OST_OSMR3 0x000c /* Match 3 */
#define OST_OSCR0 0x0010 /* Counter 0 */
+#define OST_OSSR 0x0014 /* Status (all counters) */
#define OST_OWER 0x0018 /* Watchdog Enable */
#define OWER_WME (1<<0)
#define OST_OIER 0x001c /* Interrupt Enable */