Annotation of sys/arch/arm/xscale/pxa2x0_apm.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pxa2x0_apm.c,v 1.28 2007/03/29 18:42:38 uwe Exp $ */
! 2:
! 3: /*-
! 4: * Copyright (c) 2001 Alexander Guy. All rights reserved.
! 5: * Copyright (c) 1998-2001 Michael Shalayeff. All rights reserved.
! 6: * Copyright (c) 1995 John T. Kohl. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed by the University of
! 19: * California, Berkeley and its contributors.
! 20: * 4. Neither the name of the University nor the names of its contributors
! 21: * may be used to endorse or promote products derived from this software
! 22: * without specific prior written permission.
! 23: *
! 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 30: * OR SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 34: * SUCH DAMAGE.
! 35: *
! 36: */
! 37:
! 38: #include <sys/param.h>
! 39: #include <sys/systm.h>
! 40: #include <sys/kernel.h>
! 41: #include <sys/kthread.h>
! 42: #include <sys/lock.h>
! 43: #include <sys/mount.h> /* for vfs_syncwait() */
! 44: #include <sys/proc.h>
! 45: #include <sys/device.h>
! 46: #include <sys/fcntl.h>
! 47: #include <sys/ioctl.h>
! 48: #include <sys/event.h>
! 49:
! 50: #include <machine/conf.h>
! 51: #include <machine/cpu.h>
! 52: #include <machine/apmvar.h>
! 53:
! 54: #include <arm/xscale/pxa2x0reg.h>
! 55: #include <arm/xscale/pxa2x0var.h>
! 56: #include <arm/xscale/pxa2x0_apm.h>
! 57: #include <arm/xscale/pxa2x0_gpio.h>
! 58:
! 59: #if defined(APMDEBUG)
! 60: #define DPRINTF(x) printf x
! 61: #else
! 62: #define DPRINTF(x) /**/
! 63: #endif
! 64:
! 65: #define APM_LOCK(sc) lockmgr(&(sc)->sc_lock, LK_EXCLUSIVE, NULL)
! 66: #define APM_UNLOCK(sc) lockmgr(&(sc)->sc_lock, LK_RELEASE, NULL)
! 67:
! 68: struct cfdriver apm_cd = {
! 69: NULL, "apm", DV_DULL
! 70: };
! 71:
! 72: #define APMUNIT(dev) (minor(dev)&0xf0)
! 73: #define APMDEV(dev) (minor(dev)&0x0f)
! 74: #define APMDEV_NORMAL 0
! 75: #define APMDEV_CTL 8
! 76:
! 77: int apm_userstandbys;
! 78: int apm_suspends;
! 79: int apm_battlow;
! 80:
! 81: /* battery percentage at which we get verbose in our warnings. This
! 82: value can be changed using sysctl(8), value machdep.apmwarn.
! 83: Setting it to zero kills all warnings */
! 84: int cpu_apmwarn = 10;
! 85:
! 86: void apm_power_print(struct pxa2x0_apm_softc *, struct apm_power_info *);
! 87: void apm_power_info(struct pxa2x0_apm_softc *, struct apm_power_info *);
! 88: void apm_suspend(struct pxa2x0_apm_softc *);
! 89: void apm_resume(struct pxa2x0_apm_softc *);
! 90: int apm_get_event(struct pxa2x0_apm_softc *, u_int *);
! 91: int apm_handle_event(struct pxa2x0_apm_softc *, u_int);
! 92: void apm_thread_create(void *);
! 93: void apm_thread(void *);
! 94:
! 95: extern int perflevel;
! 96: int freq;
! 97: void pxa2x0_setperf(int speed);
! 98: int pxa2x0_cpuspeed(int *speed);
! 99:
! 100: int apm_record_event(struct pxa2x0_apm_softc *, u_int);
! 101: void filt_apmrdetach(struct knote *kn);
! 102: int filt_apmread(struct knote *kn, long hint);
! 103: int apmkqfilter(dev_t dev, struct knote *kn);
! 104:
! 105: struct filterops apmread_filtops =
! 106: { 1, NULL, filt_apmrdetach, filt_apmread};
! 107:
! 108: /*
! 109: * Flags to control kernel display
! 110: * SCFLAG_NOPRINT: do not output APM power messages due to
! 111: * a power change event.
! 112: *
! 113: * SCFLAG_PCTPRINT: do not output APM power messages due to
! 114: * to a power change event unless the battery
! 115: * percentage changes.
! 116: */
! 117:
! 118: #define SCFLAG_NOPRINT 0x0008000
! 119: #define SCFLAG_PCTPRINT 0x0004000
! 120: #define SCFLAG_PRINT (SCFLAG_NOPRINT|SCFLAG_PCTPRINT)
! 121:
! 122: #define SCFLAG_OREAD (1 << 0)
! 123: #define SCFLAG_OWRITE (1 << 1)
! 124: #define SCFLAG_OPEN (SCFLAG_OREAD|SCFLAG_OWRITE)
! 125:
! 126: /* This structure must be kept in sync with pxa2x0_apm_asm.S. */
! 127: struct pxa2x0_memcfg {
! 128: /* SDRAM refresh */
! 129: u_int32_t mdrefr_high; /* 0x00 */
! 130: u_int32_t mdrefr_low; /* 0x04 */
! 131: u_int32_t mdrefr_low2; /* 0x08 */
! 132: /* Synchronous, static, or VLIO interfaces */
! 133: u_int32_t msc_high[3]; /* 0x0c */
! 134: u_int32_t msc_low[3]; /* 0x18 */
! 135: /* XXX move up */
! 136: u_int32_t mdrefr_91; /* 0x24 */
! 137: };
! 138:
! 139: /* XXX */
! 140: #define MDREFR_C3000 (MDREFR_K0DB2 | MDREFR_E1PIN | MDREFR_K1RUN | \
! 141: MDREFR_K1DB2 | MDREFR_K2DB2 | MDREFR_APD)
! 142: #define MSC0_HIGH \
! 143: ( 7 << MSC_RRR_SHIFT << 16) | \
! 144: (15 << MSC_RDN_SHIFT << 16) | \
! 145: (15 << MSC_RDF_SHIFT << 16) | \
! 146: (MSC_RT_NONBURST << 16) | \
! 147: ( 2 << MSC_RRR_SHIFT) | \
! 148: (13 << MSC_RDN_SHIFT) | \
! 149: (13 << MSC_RDF_SHIFT) | \
! 150: MSC_RBW /* PXA271 */ | \
! 151: MSC_RT_NONBURST
! 152: #define MSC1_HIGH \
! 153: ( 7 << MSC_RRR_SHIFT << 16) | \
! 154: (15 << MSC_RDN_SHIFT << 16) | \
! 155: (15 << MSC_RDF_SHIFT << 16) | \
! 156: (MSC_RT_VLIO << 16) | \
! 157: ( 3 << MSC_RRR_SHIFT) | \
! 158: ( 4 << MSC_RDN_SHIFT) | \
! 159: (13 << MSC_RDF_SHIFT) | \
! 160: MSC_RT_VLIO
! 161: #define MSC2_HIGH \
! 162: ( 7 << MSC_RRR_SHIFT << 16) | \
! 163: (15 << MSC_RDN_SHIFT << 16) | \
! 164: (15 << MSC_RDF_SHIFT << 16) | \
! 165: (MSC_RT_NONBURST << 16) | \
! 166: ( 3 << MSC_RRR_SHIFT) | \
! 167: ( 4 << MSC_RDN_SHIFT) | \
! 168: (13 << MSC_RDF_SHIFT) | \
! 169: MSC_RT_VLIO
! 170: #define MSC0_LOW \
! 171: ( 7 << MSC_RRR_SHIFT << 16) | \
! 172: (15 << MSC_RDN_SHIFT << 16) | \
! 173: (15 << MSC_RDF_SHIFT << 16) | \
! 174: (MSC_RT_NONBURST << 16) | \
! 175: ( 1 << MSC_RRR_SHIFT) | \
! 176: ( 8 << MSC_RDN_SHIFT) | \
! 177: ( 8 << MSC_RDF_SHIFT) | \
! 178: MSC_RBW /* PXA271 */ | \
! 179: MSC_RT_NONBURST
! 180: #define MSC1_LOW \
! 181: ( 7 << MSC_RRR_SHIFT << 16) | \
! 182: (15 << MSC_RDN_SHIFT << 16) | \
! 183: (15 << MSC_RDF_SHIFT << 16) | \
! 184: (MSC_RT_VLIO << 16) | \
! 185: ( 1 << MSC_RRR_SHIFT) | \
! 186: ( 2 << MSC_RDN_SHIFT) | \
! 187: ( 6 << MSC_RDF_SHIFT) | \
! 188: MSC_RT_VLIO
! 189: #define MSC2_LOW \
! 190: ( 7 << MSC_RRR_SHIFT << 16) | \
! 191: (15 << MSC_RDN_SHIFT << 16) | \
! 192: (15 << MSC_RDF_SHIFT << 16) | \
! 193: (MSC_RT_NONBURST << 16) | \
! 194: ( 1 << MSC_RRR_SHIFT) | \
! 195: ( 2 << MSC_RDN_SHIFT) | \
! 196: ( 6 << MSC_RDF_SHIFT) | \
! 197: MSC_RT_VLIO
! 198: struct pxa2x0_memcfg pxa2x0_memcfg = {
! 199: (MDREFR_C3000 | 0x030),
! 200: (MDREFR_C3000 | 0x00b),
! 201: (MDREFR_C3000 | 0x017),
! 202: { MSC0_HIGH, MSC1_HIGH, MSC2_HIGH },
! 203: { MSC1_LOW, MSC1_LOW, MSC2_LOW },
! 204: (MDREFR_C3000 | 0x013)
! 205: };
! 206:
! 207: #define PI2C_RETRY_COUNT 10
! 208: /* XXX varies depending on voltage regulator IC. */
! 209: #define PI2C_VOLTAGE_LOW 0x13 /* 1.00V */
! 210: #define PI2C_VOLTAGE_HIGH 0x1a /* 1.35V */
! 211:
! 212: void pxa2x0_pi2c_open(bus_space_tag_t, bus_space_handle_t);
! 213: void pxa2x0_pi2c_close(bus_space_tag_t, bus_space_handle_t);
! 214: int pxa2x0_pi2c_read(bus_space_tag_t, bus_space_handle_t, u_char, u_char *);
! 215: int pxa2x0_pi2c_write(bus_space_tag_t, bus_space_handle_t, u_char, u_char);
! 216: int pxa2x0_pi2c_getvoltage(bus_space_tag_t, bus_space_handle_t, u_char *);
! 217: int pxa2x0_pi2c_setvoltage(bus_space_tag_t, bus_space_handle_t, u_char);
! 218: #if 0
! 219: void pxa2x0_pi2c_print(struct pxa2x0_apm_softc *);
! 220: #endif
! 221:
! 222: /* XXX used in pxa2x0_apm_asm.S */
! 223: bus_space_handle_t pxa2x0_gpio_ioh;
! 224: bus_space_handle_t pxa2x0_clkman_ioh;
! 225: bus_space_handle_t pxa2x0_memctl_ioh;
! 226:
! 227: /* pxa2x0_apm_asm.S */
! 228: void pxa27x_run_mode(void);
! 229: void pxa27x_fastbus_run_mode(int, u_int32_t);
! 230: void pxa27x_frequency_change(int, int, struct pxa2x0_memcfg *);
! 231: void pxa2x0_cpu_suspend(void);
! 232: void pxa2x0_cpu_resume(void);
! 233: void pxa27x_cpu_speed_high(void);
! 234: void pxa27x_cpu_speed_low(void);
! 235: void pxa27x_cpu_speed_91(void);
! 236: void pxa27x_cpu_speed_208(void);
! 237:
! 238: void
! 239: apm_power_print(struct pxa2x0_apm_softc *sc, struct apm_power_info *powerp)
! 240: {
! 241:
! 242: if (powerp->battery_life != APM_BATT_LIFE_UNKNOWN)
! 243: printf("%s: battery life expectancy %d%%\n",
! 244: sc->sc_dev.dv_xname, powerp->battery_life);
! 245:
! 246: printf("%s: AC ", sc->sc_dev.dv_xname);
! 247: switch (powerp->ac_state) {
! 248: case APM_AC_OFF:
! 249: printf("off,");
! 250: break;
! 251: case APM_AC_ON:
! 252: printf("on,");
! 253: break;
! 254: case APM_AC_BACKUP:
! 255: printf("backup power,");
! 256: break;
! 257: default:
! 258: case APM_AC_UNKNOWN:
! 259: printf("unknown,");
! 260: break;
! 261: }
! 262:
! 263: printf(" battery is ");
! 264: switch (powerp->battery_state) {
! 265: case APM_BATT_HIGH:
! 266: printf("high");
! 267: break;
! 268: case APM_BATT_LOW:
! 269: printf("low");
! 270: break;
! 271: case APM_BATT_CRITICAL:
! 272: printf("CRITICAL");
! 273: break;
! 274: case APM_BATT_CHARGING:
! 275: printf("charging");
! 276: break;
! 277: case APM_BATT_UNKNOWN:
! 278: printf("unknown");
! 279: break;
! 280: default:
! 281: printf("undecoded (%x)", powerp->battery_state);
! 282: break;
! 283: }
! 284:
! 285: printf("\n");
! 286: }
! 287:
! 288: void
! 289: apm_power_info(struct pxa2x0_apm_softc *sc,
! 290: struct apm_power_info *power)
! 291: {
! 292:
! 293: power->ac_state = APM_AC_UNKNOWN;
! 294: power->battery_state = APM_BATT_UNKNOWN;
! 295: power->battery_life = 0 /* APM_BATT_LIFE_UNKNOWN */;
! 296: power->minutes_left = 0;
! 297:
! 298: if (sc->sc_power_info != NULL)
! 299: sc->sc_power_info(sc, power);
! 300: }
! 301:
! 302: void
! 303: apm_suspend(struct pxa2x0_apm_softc *sc)
! 304: {
! 305:
! 306: resettodr();
! 307:
! 308: dopowerhooks(PWR_SUSPEND);
! 309:
! 310: if (cold)
! 311: vfs_syncwait(0);
! 312:
! 313: if (sc->sc_suspend == NULL)
! 314: pxa2x0_wakeup_config(PXA2X0_WAKEUP_ALL, 1);
! 315: else
! 316: sc->sc_suspend(sc);
! 317:
! 318: pxa2x0_apm_sleep(sc);
! 319: }
! 320:
! 321: void
! 322: apm_resume(struct pxa2x0_apm_softc *sc)
! 323: {
! 324:
! 325: dopowerhooks(PWR_RESUME);
! 326:
! 327: inittodr(0);
! 328:
! 329: /*
! 330: * Clear the OTG Peripheral hold after running the pxaudc and pxaohci
! 331: * powerhooks to re-enable their operation. See 3.8.1.2
! 332: */
! 333: /* XXX ifdef NPXAUDC > 0 */
! 334: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PSSR, PSSR_OTGPH);
! 335: }
! 336:
! 337: int
! 338: apm_get_event(struct pxa2x0_apm_softc *sc, u_int *typep)
! 339: {
! 340:
! 341: if (sc->sc_get_event != NULL)
! 342: return (sc->sc_get_event(sc, typep));
! 343:
! 344: *typep = APM_NOEVENT;
! 345: return (1);
! 346: }
! 347:
! 348: int
! 349: apm_handle_event(struct pxa2x0_apm_softc *sc, u_int type)
! 350: {
! 351: struct apm_power_info power;
! 352: int ret = 0;
! 353:
! 354: switch (type) {
! 355: case APM_NOEVENT:
! 356: ret = 1;
! 357: break;
! 358: case APM_CRIT_SUSPEND_REQ:
! 359: DPRINTF(("suspend required immediately\n"));
! 360: #if 0
! 361: /* XXX apmd would make us suspend again after resume. */
! 362: (void)apm_record_event(sc, type);
! 363: #endif
! 364: /*
! 365: * We ignore APM_CRIT_RESUME and just suspend here as usual
! 366: * to simplify the actual apm_get_event() implementation.
! 367: */
! 368: apm_suspends++;
! 369: ret = 1;
! 370: break;
! 371: case APM_USER_SUSPEND_REQ:
! 372: case APM_SUSPEND_REQ:
! 373: DPRINTF(("suspend requested\n"));
! 374: if (apm_record_event(sc, type)) {
! 375: DPRINTF(("suspend ourselves\n"));
! 376: apm_suspends++;
! 377: }
! 378: break;
! 379: case APM_POWER_CHANGE:
! 380: DPRINTF(("power status change\n"));
! 381: apm_power_info(sc, &power);
! 382: if (power.battery_life != APM_BATT_LIFE_UNKNOWN &&
! 383: power.battery_life < cpu_apmwarn &&
! 384: (sc->sc_flags & SCFLAG_PRINT) != SCFLAG_NOPRINT &&
! 385: ((sc->sc_flags & SCFLAG_PRINT) != SCFLAG_PCTPRINT ||
! 386: sc->sc_batt_life != power.battery_life)) {
! 387: sc->sc_batt_life = power.battery_life;
! 388: apm_power_print(sc, &power);
! 389: }
! 390: apm_record_event(sc, type);
! 391: break;
! 392: case APM_BATTERY_LOW:
! 393: DPRINTF(("Battery low!\n"));
! 394: apm_battlow++;
! 395: apm_record_event(sc, type);
! 396: break;
! 397: default:
! 398: DPRINTF(("apm_handle_event: unsupported event, code %d\n",
! 399: type));
! 400: }
! 401:
! 402: return (ret);
! 403: }
! 404:
! 405: void
! 406: apm_thread_create(void *v)
! 407: {
! 408: struct pxa2x0_apm_softc *sc = v;
! 409:
! 410: if (kthread_create(apm_thread, sc, &sc->sc_thread,
! 411: "%s", sc->sc_dev.dv_xname)) {
! 412: /* apm_disconnect(sc); */
! 413: printf("%s: failed to create kernel thread, disabled",
! 414: sc->sc_dev.dv_xname);
! 415: }
! 416: }
! 417:
! 418: void
! 419: apm_thread(void *v)
! 420: {
! 421: struct pxa2x0_apm_softc *sc = v;
! 422: u_int type;
! 423:
! 424: for (;;) {
! 425: APM_LOCK(sc);
! 426:
! 427: while (1) {
! 428: if (apm_get_event(sc, &type) != 0)
! 429: break;
! 430: if (apm_handle_event(sc, type) != 0)
! 431: break;
! 432: }
! 433: if (apm_suspends || apm_userstandbys /* || apm_battlow*/) {
! 434: apm_suspend(sc);
! 435: apm_resume(sc);
! 436: }
! 437: apm_battlow = apm_suspends = apm_userstandbys = 0;
! 438:
! 439: APM_UNLOCK(sc);
! 440: tsleep(&lbolt, PWAIT, "apmev", 0);
! 441: }
! 442: }
! 443:
! 444: int
! 445: apmopen(dev_t dev, int flag, int mode, struct proc *p)
! 446: {
! 447: struct pxa2x0_apm_softc *sc;
! 448: int error = 0;
! 449:
! 450: /* apm0 only */
! 451: if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
! 452: !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
! 453: return (ENXIO);
! 454:
! 455: DPRINTF(("apmopen: dev %d pid %d flag %x mode %x\n",
! 456: APMDEV(dev), p->p_pid, flag, mode));
! 457:
! 458: switch (APMDEV(dev)) {
! 459: case APMDEV_CTL:
! 460: if (!(flag & FWRITE)) {
! 461: error = EINVAL;
! 462: break;
! 463: }
! 464: if (sc->sc_flags & SCFLAG_OWRITE) {
! 465: error = EBUSY;
! 466: break;
! 467: }
! 468: sc->sc_flags |= SCFLAG_OWRITE;
! 469: break;
! 470: case APMDEV_NORMAL:
! 471: if (!(flag & FREAD) || (flag & FWRITE)) {
! 472: error = EINVAL;
! 473: break;
! 474: }
! 475: sc->sc_flags |= SCFLAG_OREAD;
! 476: break;
! 477: default:
! 478: error = ENXIO;
! 479: break;
! 480: }
! 481: return (error);
! 482: }
! 483:
! 484: int
! 485: apmclose(dev_t dev, int flag, int mode, struct proc *p)
! 486: {
! 487: struct pxa2x0_apm_softc *sc;
! 488:
! 489: /* apm0 only */
! 490: if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
! 491: !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
! 492: return (ENXIO);
! 493:
! 494: DPRINTF(("apmclose: pid %d flag %x mode %x\n", p->p_pid, flag, mode));
! 495:
! 496: switch (APMDEV(dev)) {
! 497: case APMDEV_CTL:
! 498: sc->sc_flags &= ~SCFLAG_OWRITE;
! 499: break;
! 500: case APMDEV_NORMAL:
! 501: sc->sc_flags &= ~SCFLAG_OREAD;
! 502: break;
! 503: }
! 504: return (0);
! 505: }
! 506:
! 507: int
! 508: apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 509: {
! 510: struct pxa2x0_apm_softc *sc;
! 511: struct apm_power_info *power;
! 512: int error = 0;
! 513:
! 514: /* apm0 only */
! 515: if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
! 516: !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
! 517: return (ENXIO);
! 518:
! 519: switch (cmd) {
! 520: /* some ioctl names from linux */
! 521: case APM_IOC_STANDBY:
! 522: if ((flag & FWRITE) == 0)
! 523: error = EBADF;
! 524: else
! 525: apm_userstandbys++;
! 526: break;
! 527: case APM_IOC_SUSPEND:
! 528: if ((flag & FWRITE) == 0)
! 529: error = EBADF;
! 530: else
! 531: apm_suspends++; /* XXX */
! 532: break;
! 533: case APM_IOC_PRN_CTL:
! 534: if ((flag & FWRITE) == 0)
! 535: error = EBADF;
! 536: else {
! 537: int flag = *(int *)data;
! 538: DPRINTF(( "APM_IOC_PRN_CTL: %d\n", flag ));
! 539: switch (flag) {
! 540: case APM_PRINT_ON: /* enable printing */
! 541: sc->sc_flags &= ~SCFLAG_PRINT;
! 542: break;
! 543: case APM_PRINT_OFF: /* disable printing */
! 544: sc->sc_flags &= ~SCFLAG_PRINT;
! 545: sc->sc_flags |= SCFLAG_NOPRINT;
! 546: break;
! 547: case APM_PRINT_PCT: /* disable some printing */
! 548: sc->sc_flags &= ~SCFLAG_PRINT;
! 549: sc->sc_flags |= SCFLAG_PCTPRINT;
! 550: break;
! 551: default:
! 552: error = EINVAL;
! 553: break;
! 554: }
! 555: }
! 556: break;
! 557: case APM_IOC_DEV_CTL:
! 558: if ((flag & FWRITE) == 0)
! 559: error = EBADF;
! 560: break;
! 561: case APM_IOC_GETPOWER:
! 562: power = (struct apm_power_info *)data;
! 563: apm_power_info(sc, power);
! 564: break;
! 565:
! 566: default:
! 567: error = ENOTTY;
! 568: }
! 569:
! 570: return (error);
! 571: }
! 572:
! 573: int
! 574: apm_record_event(struct pxa2x0_apm_softc *sc, u_int type)
! 575: {
! 576: static int apm_evindex;
! 577:
! 578: /* skip if no user waiting */
! 579: if ((sc->sc_flags & SCFLAG_OPEN) == 0)
! 580: return (1);
! 581:
! 582: apm_evindex++;
! 583: KNOTE(&sc->sc_note, APM_EVENT_COMPOSE(type, apm_evindex));
! 584:
! 585: return (0);
! 586: }
! 587:
! 588: void
! 589: filt_apmrdetach(struct knote *kn)
! 590: {
! 591: struct pxa2x0_apm_softc *sc =
! 592: (struct pxa2x0_apm_softc *)kn->kn_hook;
! 593:
! 594: SLIST_REMOVE(&sc->sc_note, kn, knote, kn_selnext);
! 595: }
! 596:
! 597: int
! 598: filt_apmread(struct knote *kn, long hint)
! 599: {
! 600: /* XXX weird kqueue_scan() semantics */
! 601: if (hint && !kn->kn_data)
! 602: kn->kn_data = (int)hint;
! 603:
! 604: return (1);
! 605: }
! 606:
! 607: int
! 608: apmkqfilter(dev_t dev, struct knote *kn)
! 609: {
! 610: struct pxa2x0_apm_softc *sc;
! 611:
! 612: /* apm0 only */
! 613: if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
! 614: !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
! 615: return (ENXIO);
! 616:
! 617: switch (kn->kn_filter) {
! 618: case EVFILT_READ:
! 619: kn->kn_fop = &apmread_filtops;
! 620: break;
! 621: default:
! 622: return (1);
! 623: }
! 624:
! 625: kn->kn_hook = (caddr_t)sc;
! 626: SLIST_INSERT_HEAD(&sc->sc_note, kn, kn_selnext);
! 627:
! 628: return (0);
! 629: }
! 630:
! 631: void
! 632: pxa2x0_apm_attach_sub(struct pxa2x0_apm_softc *sc)
! 633: {
! 634:
! 635: sc->sc_iot = &pxa2x0_bs_tag;
! 636:
! 637: if (bus_space_map(sc->sc_iot, PXA2X0_POWMAN_BASE,
! 638: PXA2X0_POWMAN_SIZE, 0, &sc->sc_pm_ioh)) {
! 639: printf("pxa2x0_apm_attach_sub: failed to map POWMAN\n");
! 640: return;
! 641: }
! 642:
! 643: lockinit(&sc->sc_lock, PWAIT, "apmlk", 0, 0);
! 644:
! 645: kthread_create_deferred(apm_thread_create, sc);
! 646:
! 647: printf("\n");
! 648:
! 649: if (bus_space_map(sc->sc_iot, PXA2X0_CLKMAN_BASE, PXA2X0_CLKMAN_SIZE,
! 650: 0, &pxa2x0_clkman_ioh)) {
! 651: printf("%s: failed to map CLKMAN\n", sc->sc_dev.dv_xname);
! 652: return;
! 653: }
! 654:
! 655: if (bus_space_map(sc->sc_iot, PXA2X0_MEMCTL_BASE, PXA2X0_MEMCTL_SIZE,
! 656: 0, &pxa2x0_memctl_ioh)) {
! 657: printf("%s: failed to map MEMCTL\n", sc->sc_dev.dv_xname);
! 658: return;
! 659: }
! 660: sc->sc_memctl_ioh = pxa2x0_memctl_ioh;
! 661:
! 662: if (bus_space_map(sc->sc_iot, PXA2X0_GPIO_BASE, PXA2X0_GPIO_SIZE,
! 663: 0, &pxa2x0_gpio_ioh)) {
! 664: printf("%s: can't map GPIO\n", sc->sc_dev.dv_xname);
! 665: return;
! 666: }
! 667:
! 668: /* Clear all reset status flags. */
! 669: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_RCSR,
! 670: RCSR_GPR | RCSR_SMR | RCSR_WDR | RCSR_HWR);
! 671: }
! 672:
! 673: void
! 674: pxa2x0_wakeup_config(u_int wsrc, int enable)
! 675: {
! 676: struct pxa2x0_apm_softc *sc;
! 677: u_int32_t prer;
! 678: u_int32_t pfer;
! 679: u_int32_t pkwr;
! 680:
! 681: if (apm_cd.cd_ndevs < 1 || apm_cd.cd_devs[0] == NULL)
! 682: return;
! 683: sc = apm_cd.cd_devs[0];
! 684:
! 685: prer = pfer = pkwr = 0;
! 686:
! 687: if ((wsrc & PXA2X0_WAKEUP_POWERON) != 0) {
! 688: prer |= (1<<0);
! 689: pfer |= (1<<0);
! 690: pkwr |= (1<<12); /* XXX */
! 691: }
! 692:
! 693: if ((wsrc & PXA2X0_WAKEUP_GPIORST) != 0)
! 694: pfer |= (1<<1);
! 695: if ((wsrc & PXA2X0_WAKEUP_SD) != 0)
! 696: prer |= (1<<9);
! 697: if ((wsrc & PXA2X0_WAKEUP_RC) != 0)
! 698: prer |= (1<<13);
! 699: if ((wsrc & PXA2X0_WAKEUP_SYNC) != 0)
! 700: pkwr |= (1<<1);
! 701: if ((wsrc & PXA2X0_WAKEUP_KEYNS0) != 0)
! 702: prer |= (1<<12);
! 703: if ((wsrc & PXA2X0_WAKEUP_KEYNS1) != 0)
! 704: pkwr |= (1<<2);
! 705: if ((wsrc & PXA2X0_WAKEUP_KEYNS2) != 0)
! 706: pkwr |= (1<<9);
! 707: if ((wsrc & PXA2X0_WAKEUP_KEYNS3) != 0)
! 708: pkwr |= (1<<3);
! 709: if ((wsrc & PXA2X0_WAKEUP_KEYNS4) != 0)
! 710: pkwr |= (1<<4);
! 711: if ((wsrc & PXA2X0_WAKEUP_KEYNS5) != 0)
! 712: pkwr |= (1<<6);
! 713: if ((wsrc & PXA2X0_WAKEUP_KEYNS6) != 0)
! 714: pkwr |= (1<<7);
! 715: if ((wsrc & PXA2X0_WAKEUP_CF0) != 0)
! 716: pkwr |= (1<<11);
! 717: if ((wsrc & PXA2X0_WAKEUP_CF1) != 0)
! 718: pkwr |= (1<<10);
! 719: if ((wsrc & PXA2X0_WAKEUP_USBD) != 0)
! 720: prer |= (1<<24);
! 721:
! 722: if ((wsrc & PXA2X0_WAKEUP_LOCKSW) != 0) {
! 723: prer |= (1<<15);
! 724: pfer |= (1<<15);
! 725: }
! 726:
! 727: if ((wsrc & PXA2X0_WAKEUP_JACKIN) != 0) {
! 728: prer |= (1<<23);
! 729: pfer |= (1<<23);
! 730: }
! 731:
! 732: if ((wsrc & PXA2X0_WAKEUP_CHRGFULL) != 0)
! 733: pkwr |= (1<<18);
! 734: if ((wsrc & PXA2X0_WAKEUP_RTC) != 0)
! 735: prer |= (1<<31);
! 736:
! 737: if (enable) {
! 738: sc->sc_wakeon |= wsrc;
! 739: prer |= bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh,
! 740: POWMAN_PRER);
! 741: pfer |= bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh,
! 742: POWMAN_PFER);
! 743: pkwr |= bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh,
! 744: POWMAN_PKWR);
! 745: } else {
! 746: sc->sc_wakeon &= ~wsrc;
! 747: prer = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh,
! 748: POWMAN_PRER) & ~prer;
! 749: pfer = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh,
! 750: POWMAN_PFER) & ~pfer;
! 751: pkwr = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh,
! 752: POWMAN_PKWR) & ~pkwr;
! 753: }
! 754:
! 755: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PKWR, pkwr);
! 756: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PRER, prer);
! 757: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PFER, pfer);
! 758: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PWER,
! 759: prer | pfer);
! 760: }
! 761:
! 762: u_int
! 763: pxa2x0_wakeup_status(void)
! 764: {
! 765: struct pxa2x0_apm_softc *sc;
! 766: u_int32_t rv;
! 767: u_int wsrc;
! 768:
! 769: if (apm_cd.cd_ndevs < 1 || apm_cd.cd_devs[0] == NULL)
! 770: return (0);
! 771:
! 772: sc = apm_cd.cd_devs[0];
! 773: wsrc = 0;
! 774:
! 775: rv = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PEDR);
! 776: if ((rv & (1<<0)) != 0)
! 777: wsrc |= PXA2X0_WAKEUP_POWERON;
! 778: if ((rv & (1<<1)) != 0)
! 779: wsrc |= PXA2X0_WAKEUP_GPIORST;
! 780: if ((rv & (1<<9)) != 0)
! 781: wsrc |= PXA2X0_WAKEUP_SD;
! 782: if ((rv & (1<<12)) != 0)
! 783: wsrc |= PXA2X0_WAKEUP_KEYNS0;
! 784: if ((rv & (1<<13)) != 0)
! 785: wsrc |= PXA2X0_WAKEUP_RC;
! 786: if ((rv & (1<<15)) != 0)
! 787: wsrc |= PXA2X0_WAKEUP_LOCKSW;
! 788: if ((rv & (1<<23)) != 0)
! 789: wsrc |= PXA2X0_WAKEUP_JACKIN;
! 790: if ((rv & (1<<24)) != 0)
! 791: wsrc |= PXA2X0_WAKEUP_USBD;
! 792: if ((rv & (1<<31)) != 0)
! 793: wsrc |= PXA2X0_WAKEUP_RTC;
! 794:
! 795: rv = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PKSR);
! 796: if ((rv & (1<<1)) != 0)
! 797: wsrc |= PXA2X0_WAKEUP_SYNC;
! 798: if ((rv & (1<<2)) != 0)
! 799: wsrc |= PXA2X0_WAKEUP_KEYNS1;
! 800: if ((rv & (1<<9)) != 0)
! 801: wsrc |= PXA2X0_WAKEUP_KEYNS2;
! 802: if ((rv & (1<<3)) != 0)
! 803: wsrc |= PXA2X0_WAKEUP_KEYNS3;
! 804: if ((rv & (1<<4)) != 0)
! 805: wsrc |= PXA2X0_WAKEUP_KEYNS4;
! 806: if ((rv & (1<<6)) != 0)
! 807: wsrc |= PXA2X0_WAKEUP_KEYNS5;
! 808: if ((rv & (1<<7)) != 0)
! 809: wsrc |= PXA2X0_WAKEUP_KEYNS6;
! 810: if ((rv & (1<<10)) != 0)
! 811: wsrc |= PXA2X0_WAKEUP_CF1;
! 812: if ((rv & (1<<11)) != 0)
! 813: wsrc |= PXA2X0_WAKEUP_CF0;
! 814: if ((rv & (1<<12)) != 0)
! 815: wsrc |= PXA2X0_WAKEUP_POWERON;
! 816: if ((rv & (1<<18)) != 0)
! 817: wsrc |= PXA2X0_WAKEUP_CHRGFULL;
! 818:
! 819: return (wsrc);
! 820: }
! 821:
! 822: struct pxa2x0_sleep_data {
! 823: /* OS timer registers */
! 824: u_int32_t sd_osmr0, sd_osmr1, sd_osmr2, sd_osmr3;
! 825: u_int32_t sd_oscr0;
! 826: u_int32_t sd_osmr4, sd_osmr5;
! 827: u_int32_t sd_oscr4;
! 828: u_int32_t sd_omcr4, sd_omcr5;
! 829: u_int32_t sd_oier;
! 830: /* GPIO registers */
! 831: u_int32_t sd_gpdr0, sd_gpdr1, sd_gpdr2, sd_gpdr3;
! 832: u_int32_t sd_grer0, sd_grer1, sd_grer2, sd_grer3;
! 833: u_int32_t sd_gfer0, sd_gfer1, sd_gfer2, sd_gfer3;
! 834: u_int32_t sd_gafr0_l, sd_gafr1_l, sd_gafr2_l, sd_gafr3_l;
! 835: u_int32_t sd_gafr0_u, sd_gafr1_u, sd_gafr2_u, sd_gafr3_u;
! 836: u_int32_t sd_gplr0, sd_gplr1, sd_gplr2, sd_gplr3;
! 837: /* Interrupt controller registers */
! 838: u_int32_t sd_iclr;
! 839: u_int32_t sd_icmr;
! 840: u_int32_t sd_iccr;
! 841: /* Memory controller registers */
! 842: u_int32_t sd_mecr;
! 843: u_int32_t sd_mcmem0, sd_mcmem1;
! 844: u_int32_t sd_mcatt0, sd_mcatt1;
! 845: u_int32_t sd_mcio0, sd_mcio1;
! 846: /* Clocks manager registers */
! 847: u_int32_t sd_cken;
! 848: };
! 849:
! 850: void
! 851: pxa2x0_apm_sleep(struct pxa2x0_apm_softc *sc)
! 852: {
! 853: struct pxa2x0_sleep_data sd;
! 854: bus_space_handle_t ost_ioh;
! 855: int save;
! 856: u_int32_t rv;
! 857:
! 858: ost_ioh = (bus_space_handle_t)0;
! 859: if (bus_space_map(sc->sc_iot, PXA2X0_OST_BASE, PXA2X0_OST_SIZE, 0,
! 860: &ost_ioh)) {
! 861: printf("pxa2x0_apm_sleep: can't map OST\n");
! 862: goto out;
! 863: }
! 864:
! 865: save = disable_interrupts(I32_bit|F32_bit);
! 866:
! 867: sd.sd_oscr0 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSCR0);
! 868: sd.sd_oscr4 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSCR4);
! 869: sd.sd_omcr4 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OMCR4);
! 870: sd.sd_omcr5 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OMCR5);
! 871: sd.sd_osmr0 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSMR0);
! 872: sd.sd_osmr1 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSMR1);
! 873: sd.sd_osmr2 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSMR2);
! 874: sd.sd_osmr3 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSMR3);
! 875: sd.sd_osmr4 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSMR4);
! 876: sd.sd_osmr5 = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OSMR5);
! 877: sd.sd_oier = bus_space_read_4(sc->sc_iot, ost_ioh, OST_OIER);
! 878:
! 879: /* Bring the PXA27x into 416MHz turbo mode. */
! 880: if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA27X &&
! 881: bus_space_read_4(sc->sc_iot, pxa2x0_clkman_ioh, CLKMAN_CCCR) !=
! 882: (CCCR_A | CCCR_TURBO_X2 | CCCR_RUN_X16)) {
! 883: #if 0
! 884: pxa27x_cpu_speed_high();
! 885: #else
! 886: #define CLKCFG_T (1<<0) /* turbo */
! 887: #define CLKCFG_F (1<<1) /* frequency change */
! 888: #define CLKCFG_B (1<<3) /* fast-bus */
! 889: pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X2 |
! 890: CCCR_RUN_X16, CLKCFG_B | CLKCFG_F | CLKCFG_T,
! 891: &pxa2x0_memcfg);
! 892: #endif
! 893: delay(500000); /* XXX */
! 894: }
! 895:
! 896: suspend_again:
! 897: /* Clear wake-up status. */
! 898: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PEDR,
! 899: 0xffffffff);
! 900: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PKSR,
! 901: 0xffffffff);
! 902:
! 903: /* XXX control battery charging in sleep mode. */
! 904:
! 905: /* XXX schedule RTC alarm to check the battery, or schedule
! 906: XXX wake-up shortly before an already programmed alarm? */
! 907:
! 908: pxa27x_run_mode();
! 909: #define MDREFR_LOW (MDREFR_C3000 | 0x00b)
! 910: pxa27x_fastbus_run_mode(0, MDREFR_LOW);
! 911: delay(1);
! 912: #if 1
! 913: pxa27x_cpu_speed_91();
! 914: #else
! 915: pxa27x_frequency_change(CCCR_TURBO_X1 | CCCR_RUN_X7, CLKCFG_F,
! 916: &pxa2x0_memcfg);
! 917: #endif
! 918: pxa2x0_pi2c_setvoltage(sc->sc_iot, sc->sc_pm_ioh, PI2C_VOLTAGE_LOW);
! 919:
! 920: sd.sd_gpdr0 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR0);
! 921: sd.sd_gpdr1 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR1);
! 922: sd.sd_gpdr2 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR2);
! 923: sd.sd_gpdr3 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR3);
! 924:
! 925: sd.sd_grer0 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER0);
! 926: sd.sd_grer1 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER1);
! 927: sd.sd_grer2 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER2);
! 928: sd.sd_grer3 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER3);
! 929:
! 930: sd.sd_gfer0 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER0);
! 931: sd.sd_gfer1 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER1);
! 932: sd.sd_gfer2 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER2);
! 933: sd.sd_gfer3 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER3);
! 934:
! 935: sd.sd_gafr0_l = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR0_L);
! 936: sd.sd_gafr1_l = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR1_L);
! 937: sd.sd_gafr2_l = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR2_L);
! 938: sd.sd_gafr3_l = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR3_L);
! 939:
! 940: sd.sd_gafr0_u = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR0_U);
! 941: sd.sd_gafr1_u = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR1_U);
! 942: sd.sd_gafr2_u = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR2_U);
! 943: sd.sd_gafr3_u = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR3_U);
! 944:
! 945: sd.sd_gplr0 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPLR0);
! 946: sd.sd_gplr1 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPLR1);
! 947: sd.sd_gplr2 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPLR2);
! 948: sd.sd_gplr3 = bus_space_read_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPLR3);
! 949:
! 950: sd.sd_iclr = read_icu(INTCTL_ICLR);
! 951: sd.sd_icmr = read_icu(INTCTL_ICMR);
! 952: sd.sd_iccr = read_icu(INTCTL_ICCR);
! 953: write_icu(INTCTL_ICMR, 0);
! 954:
! 955: sd.sd_mecr = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
! 956: MEMCTL_MECR);
! 957: sd.sd_mcmem0 = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
! 958: MEMCTL_MCMEM(0));
! 959: sd.sd_mcmem1 = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
! 960: MEMCTL_MCMEM(1));
! 961: sd.sd_mcatt0 = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
! 962: MEMCTL_MCATT(0));
! 963: sd.sd_mcatt1 = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
! 964: MEMCTL_MCATT(1));
! 965: sd.sd_mcio0 = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
! 966: MEMCTL_MCIO(0));
! 967: sd.sd_mcio1 = bus_space_read_4(sc->sc_iot, pxa2x0_memctl_ioh,
! 968: MEMCTL_MCIO(1));
! 969:
! 970: sd.sd_cken = bus_space_read_4(sc->sc_iot, pxa2x0_clkman_ioh,
! 971: CLKMAN_CKEN);
! 972:
! 973: /*
! 974: * Stop clocks to all units except to the memory controller, and
! 975: * to the keypad controller if it is enabled as a wake-up source.
! 976: */
! 977: rv = CKEN_MEM;
! 978: if ((sc->sc_wakeon & PXA2X0_WAKEUP_KEYNS_ALL) != 0)
! 979: rv |= CKEN_KEY;
! 980: bus_space_write_4(sc->sc_iot, pxa2x0_clkman_ioh, CLKMAN_CKEN, rv);
! 981:
! 982: /* Disable nRESET_OUT. */
! 983: rv = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PSLR);
! 984: #define PSLR_SL_ROD (1<<20)
! 985: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PSLR,
! 986: rv | PSLR_SL_ROD);
! 987:
! 988: /* Clear all reset status flags. */
! 989: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_RCSR,
! 990: RCSR_GPR | RCSR_SMR | RCSR_WDR | RCSR_HWR);
! 991:
! 992: /* Stop 3/13MHz oscillator; do not float PCMCIA and chip-selects. */
! 993: rv = PCFR_OPDE;
! 994: if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA27X)
! 995: /* Enable nRESET_GPIO as a GPIO reset input. */
! 996: rv |= PCFR_GPR_EN;
! 997: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PCFR, rv);
! 998:
! 999: /* XXX C3000 */
! 1000: #define GPIO_G0_STROBE_BIT 0x0f800000
! 1001: #define GPIO_G1_STROBE_BIT 0x00100000
! 1002: #define GPIO_G2_STROBE_BIT 0x01000000
! 1003: #define GPIO_G3_STROBE_BIT 0x00041880
! 1004: #define GPIO_KEY_STROBE0 88
! 1005: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR0,
! 1006: 0x00144018);
! 1007: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR1,
! 1008: 0x00ef0000);
! 1009: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR2,
! 1010: 0x0121c000);
! 1011: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR3,
! 1012: 0x00600000);
! 1013: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR0,
! 1014: 0x00144018 & ~GPIO_G0_STROBE_BIT);
! 1015: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR1,
! 1016: 0x00ef0000 & ~GPIO_G1_STROBE_BIT);
! 1017: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR2,
! 1018: 0x0121c000 & ~GPIO_G2_STROBE_BIT);
! 1019: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR3,
! 1020: 0x00600000 & ~GPIO_G3_STROBE_BIT);
! 1021: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PGSR2,
! 1022: (0x0121c000 & ~GPIO_G2_STROBE_BIT) |
! 1023: GPIO_BIT(GPIO_KEY_STROBE0));
! 1024:
! 1025: /* C3000 */
! 1026: #define GPIO_EXT_BUS_READY 18
! 1027: pxa2x0_gpio_set_function(GPIO_EXT_BUS_READY, GPIO_SET | GPIO_OUT);
! 1028: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR0, 0xd01c4418);
! 1029: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR1, 0xfcefbd21);
! 1030: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR2, 0x13a5ffff);
! 1031: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR3, 0x01e3e10c);
! 1032:
! 1033: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PSPR,
! 1034: (u_int32_t)&pxa2x0_cpu_resume - 0xc0200000 + 0xa0200000);
! 1035:
! 1036: pxa2x0_cpu_suspend();
! 1037:
! 1038: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PSPR, 0);
! 1039:
! 1040: pxa2x0_clkman_config(CKEN_SSP|CKEN_PWM0|CKEN_PWM1, 1);
! 1041: pxa2x0_clkman_config(CKEN_KEY, 0);
! 1042:
! 1043: #if 1
! 1044: /* Clear all GPIO interrupt sources. */
! 1045: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GEDR0, 0xffffffff);
! 1046: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GEDR1, 0xffffffff);
! 1047: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GEDR2, 0xffffffff);
! 1048: #endif
! 1049:
! 1050: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR0, sd.sd_gpdr0);
! 1051: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR1, sd.sd_gpdr1);
! 1052: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR2, sd.sd_gpdr2);
! 1053: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER0, sd.sd_grer0);
! 1054: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER1, sd.sd_grer1);
! 1055: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER2, sd.sd_grer2);
! 1056: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER0, sd.sd_gfer0);
! 1057: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER1, sd.sd_gfer1);
! 1058: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER2, sd.sd_gfer2);
! 1059: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR0_L, sd.sd_gafr0_l);
! 1060: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR1_L, sd.sd_gafr1_l);
! 1061: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR2_L, sd.sd_gafr2_l);
! 1062: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR0_U, sd.sd_gafr0_u);
! 1063: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR1_U, sd.sd_gafr1_u);
! 1064: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR2_U, sd.sd_gafr2_u);
! 1065: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPSR0, sd.sd_gplr0 &
! 1066: sd.sd_gpdr0);
! 1067: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPSR1, sd.sd_gplr1 &
! 1068: sd.sd_gpdr1);
! 1069: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPSR2, sd.sd_gplr2 &
! 1070: sd.sd_gpdr2);
! 1071: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPCR0, ~sd.sd_gplr0 &
! 1072: sd.sd_gpdr0);
! 1073: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPCR1, ~sd.sd_gplr1 &
! 1074: sd.sd_gpdr1);
! 1075: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPCR2, ~sd.sd_gplr2 &
! 1076: sd.sd_gpdr2);
! 1077:
! 1078: /* PXA27x */
! 1079: #if 0
! 1080: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GEDR3, 0xffffffff);
! 1081: #endif
! 1082: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPDR3, sd.sd_gpdr3);
! 1083: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GRER3, sd.sd_grer3);
! 1084: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GFER3, sd.sd_gfer3);
! 1085: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR3_L, sd.sd_gafr3_l);
! 1086: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GAFR3_U, sd.sd_gafr3_u);
! 1087: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPSR3, sd.sd_gplr3 &
! 1088: sd.sd_gpdr3);
! 1089: bus_space_write_4(sc->sc_iot, pxa2x0_gpio_ioh, GPIO_GPCR3, ~sd.sd_gplr3 &
! 1090: sd.sd_gpdr3);
! 1091:
! 1092: bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MECR,
! 1093: sd.sd_mecr);
! 1094: bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MCMEM(0),
! 1095: sd.sd_mcmem0);
! 1096: bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MCMEM(1),
! 1097: sd.sd_mcmem1);
! 1098: bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MCATT(0),
! 1099: sd.sd_mcatt0);
! 1100: bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MCATT(1),
! 1101: sd.sd_mcatt1);
! 1102: bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MCIO(0),
! 1103: sd.sd_mcio0);
! 1104: bus_space_write_4(sc->sc_iot, pxa2x0_memctl_ioh, MEMCTL_MCIO(1),
! 1105: sd.sd_mcio1);
! 1106:
! 1107: bus_space_write_4(sc->sc_iot, pxa2x0_clkman_ioh, CLKMAN_CKEN,
! 1108: sd.sd_cken);
! 1109:
! 1110: write_icu(INTCTL_ICLR, sd.sd_iclr);
! 1111: write_icu(INTCTL_ICCR, sd.sd_iccr);
! 1112: write_icu(INTCTL_ICMR, sd.sd_icmr);
! 1113:
! 1114: if ((read_icu(INTCTL_ICIP) & 0x1) != 0)
! 1115: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PEDR, 0x1);
! 1116:
! 1117: bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR0, sd.sd_osmr0);
! 1118: bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR1, sd.sd_osmr1);
! 1119: bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR2, sd.sd_osmr2);
! 1120: bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR3, sd.sd_osmr3);
! 1121: bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR4, sd.sd_osmr4);
! 1122: bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSMR5, sd.sd_osmr5);
! 1123: bus_space_write_4(sc->sc_iot, ost_ioh, OST_OMCR4, sd.sd_omcr4);
! 1124: bus_space_write_4(sc->sc_iot, ost_ioh, OST_OMCR5, sd.sd_omcr5);
! 1125: bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSCR0, sd.sd_oscr0);
! 1126: bus_space_write_4(sc->sc_iot, ost_ioh, OST_OSCR4, sd.sd_oscr4);
! 1127: bus_space_write_4(sc->sc_iot, ost_ioh, OST_OIER, sd.sd_oier);
! 1128:
! 1129: pxa2x0_pi2c_setvoltage(sc->sc_iot, sc->sc_pm_ioh, PI2C_VOLTAGE_HIGH);
! 1130:
! 1131: /* Change to 208MHz run mode with fast-bus still disabled. */
! 1132: pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X2 | CCCR_RUN_X16,
! 1133: CLKCFG_F, &pxa2x0_memcfg);
! 1134: delay(1); /* XXX is the delay long enough, and necessary at all? */
! 1135: pxa27x_fastbus_run_mode(1, pxa2x0_memcfg.mdrefr_high);
! 1136:
! 1137: /* Change to 416MHz turbo mode with fast-bus enabled. */
! 1138: pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X2 | CCCR_RUN_X16,
! 1139: CLKCFG_B | CLKCFG_F | CLKCFG_T, &pxa2x0_memcfg);
! 1140:
! 1141: if (sc->sc_resume != NULL) {
! 1142: if (!sc->sc_resume(sc))
! 1143: goto suspend_again;
! 1144: }
! 1145:
! 1146: /*
! 1147: * Allow immediate entry into deep-sleep mode if power fails.
! 1148: * Resume from immediate deep-sleep is not implemented yet.
! 1149: */
! 1150: bus_space_write_4(sc->sc_iot, sc->sc_pm_ioh, POWMAN_PMCR, 0);
! 1151:
! 1152:
! 1153: restore_interrupts(save);
! 1154:
! 1155: pxa2x0_setperf(perflevel);
! 1156:
! 1157: out:
! 1158: if (ost_ioh != (bus_space_handle_t)0)
! 1159: bus_space_unmap(sc->sc_iot, ost_ioh, PXA2X0_OST_SIZE);
! 1160: }
! 1161:
! 1162: void
! 1163: pxa2x0_pi2c_open(bus_space_tag_t iot, bus_space_handle_t ioh)
! 1164: {
! 1165: u_int32_t rv;
! 1166:
! 1167: /* Enable the I2C unit, and disable automatic voltage change. */
! 1168: rv = bus_space_read_4(iot, ioh, POWMAN_PCFR);
! 1169: bus_space_write_4(iot, ioh, POWMAN_PCFR, rv | PCFR_PI2C_EN);
! 1170: rv = bus_space_read_4(iot, ioh, POWMAN_PCFR);
! 1171: bus_space_write_4(iot, ioh, POWMAN_PCFR, rv & ~PCFR_FVC);
! 1172: delay(1);
! 1173:
! 1174: /* Enable the clock to the power manager I2C unit. */
! 1175: pxa2x0_clkman_config(CKEN_PI2C, 1);
! 1176: delay(1);
! 1177: }
! 1178:
! 1179: void
! 1180: pxa2x0_pi2c_close(bus_space_tag_t iot, bus_space_handle_t ioh)
! 1181: {
! 1182: u_int32_t rv;
! 1183:
! 1184: bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_UR);
! 1185: bus_space_write_4(iot, ioh, POWMAN_PISAR, 0);
! 1186: delay(1);
! 1187:
! 1188: /* Disable the clock to the power manager I2C unit. */
! 1189: pxa2x0_clkman_config(CKEN_PI2C, 0);
! 1190: delay(1);
! 1191:
! 1192: /* Disable the I2C unit, and disable automatic voltage change. */
! 1193: rv = bus_space_read_4(iot, ioh, POWMAN_PCFR);
! 1194: bus_space_write_4(iot, ioh, POWMAN_PCFR,
! 1195: rv & ~(PCFR_PI2C_EN | PCFR_FVC));
! 1196: delay(1);
! 1197: }
! 1198:
! 1199: int
! 1200: pxa2x0_pi2c_read(bus_space_tag_t iot, bus_space_handle_t ioh,
! 1201: u_char slave, u_char *valuep)
! 1202: {
! 1203: u_int32_t rv;
! 1204: int timeout;
! 1205: int tries = PI2C_RETRY_COUNT;
! 1206:
! 1207: retry:
! 1208:
! 1209: bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_UR);
! 1210: bus_space_write_4(iot, ioh, POWMAN_PISAR, 0x00);
! 1211: delay(1);
! 1212: bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_IUE | PICR_SCLE);
! 1213:
! 1214: /* Write slave device address. */
! 1215: bus_space_write_4(iot, ioh, POWMAN_PIDBR, (slave<<1) | 0x1);
! 1216: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1217: bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_START);
! 1218: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1219: bus_space_write_4(iot, ioh, POWMAN_PICR, rv & ~PICR_STOP);
! 1220: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1221: bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_TB);
! 1222:
! 1223: timeout = 10000;
! 1224: while ((bus_space_read_4(iot, ioh, POWMAN_PISR) & PISR_ITE) == 0) {
! 1225: if (timeout-- == 0) {
! 1226: bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
! 1227: goto err;
! 1228: }
! 1229: delay(1);
! 1230: }
! 1231:
! 1232: bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
! 1233:
! 1234: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1235: bus_space_write_4(iot, ioh, POWMAN_PICR, rv & ~PICR_START);
! 1236:
! 1237: /* Read data value. */
! 1238: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1239: bus_space_write_4(iot, ioh, POWMAN_PICR, rv |
! 1240: (PICR_STOP | PICR_ACKNAK));
! 1241: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1242: bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_TB);
! 1243:
! 1244: timeout = 10000;
! 1245: while ((bus_space_read_4(iot, ioh, POWMAN_PISR) & PISR_IRF) == 0) {
! 1246: if (timeout-- == 0) {
! 1247: bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_IRF);
! 1248: goto err;
! 1249: }
! 1250: delay(1);
! 1251: }
! 1252:
! 1253: bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_IRF);
! 1254: rv = bus_space_read_4(iot, ioh, POWMAN_PIDBR);
! 1255: *valuep = (u_char)rv;
! 1256: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1257: bus_space_write_4(iot, ioh, POWMAN_PICR, rv &
! 1258: ~(PICR_STOP | PICR_ACKNAK));
! 1259:
! 1260: return (0);
! 1261: err:
! 1262: if (tries-- >= 0)
! 1263: goto retry;
! 1264:
! 1265: bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_UR);
! 1266: bus_space_write_4(iot, ioh, POWMAN_PISAR, 0x00);
! 1267: bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_IUE | PICR_SCLE);
! 1268:
! 1269: return (-EIO);
! 1270: }
! 1271:
! 1272: int
! 1273: pxa2x0_pi2c_write(bus_space_tag_t iot, bus_space_handle_t ioh,
! 1274: u_char slave, u_char value)
! 1275: {
! 1276: u_int32_t rv;
! 1277: int timeout;
! 1278: int tries = PI2C_RETRY_COUNT;
! 1279:
! 1280: retry:
! 1281:
! 1282: bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_UR);
! 1283: bus_space_write_4(iot, ioh, POWMAN_PISAR, 0x00);
! 1284: delay(1);
! 1285: bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_IUE | PICR_SCLE);
! 1286:
! 1287: /* Write slave device address. */
! 1288: bus_space_write_4(iot, ioh, POWMAN_PIDBR, (slave<<1));
! 1289: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1290: bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_START);
! 1291: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1292: bus_space_write_4(iot, ioh, POWMAN_PICR, rv & ~PICR_STOP);
! 1293: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1294: bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_TB);
! 1295:
! 1296: timeout = 10000;
! 1297: while ((bus_space_read_4(iot, ioh, POWMAN_PISR) & PISR_ITE) == 0) {
! 1298: if (timeout-- == 0) {
! 1299: bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
! 1300: goto err;
! 1301: }
! 1302: delay(1);
! 1303: }
! 1304: if ((bus_space_read_4(iot, ioh, POWMAN_PISR) & PISR_ACKNAK) != 0)
! 1305: goto err;
! 1306: bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
! 1307:
! 1308: /* Write data. */
! 1309: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1310: bus_space_write_4(iot, ioh, POWMAN_PICR, rv & ~PICR_START);
! 1311: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1312: bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_STOP);
! 1313: bus_space_write_4(iot, ioh, POWMAN_PIDBR, value);
! 1314: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1315: bus_space_write_4(iot, ioh, POWMAN_PICR, rv | PICR_TB);
! 1316:
! 1317: timeout = 10000;
! 1318: while ((bus_space_read_4(iot, ioh, POWMAN_PISR) & PISR_ITE) == 0) {
! 1319: if (timeout-- == 0) {
! 1320: #if 0
! 1321: bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
! 1322: #endif
! 1323: goto err;
! 1324: }
! 1325: delay(1);
! 1326: }
! 1327: if ((bus_space_read_4(iot, ioh, POWMAN_PISR) & PISR_ACKNAK) != 0)
! 1328: goto err;
! 1329: bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
! 1330:
! 1331: rv = bus_space_read_4(iot, ioh, POWMAN_PICR);
! 1332: bus_space_write_4(iot, ioh, POWMAN_PICR, rv & ~PICR_STOP);
! 1333:
! 1334: return (0);
! 1335: err:
! 1336: bus_space_write_4(iot, ioh, POWMAN_PISR, PISR_ITE);
! 1337: if (tries-- >= 0)
! 1338: goto retry;
! 1339:
! 1340: bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_UR);
! 1341: bus_space_write_4(iot, ioh, POWMAN_PISAR, 0x00);
! 1342: bus_space_write_4(iot, ioh, POWMAN_PICR, PICR_IUE | PICR_SCLE);
! 1343:
! 1344: return (-EIO);
! 1345: }
! 1346:
! 1347: int
! 1348: pxa2x0_pi2c_getvoltage(bus_space_tag_t iot, bus_space_handle_t ioh,
! 1349: u_char *valuep)
! 1350: {
! 1351: int res;
! 1352:
! 1353: pxa2x0_pi2c_open(iot, ioh);
! 1354: res = pxa2x0_pi2c_read(iot, ioh, 0x0c, valuep);
! 1355: pxa2x0_pi2c_close(iot, ioh);
! 1356: return (res);
! 1357: }
! 1358:
! 1359: int
! 1360: pxa2x0_pi2c_setvoltage(bus_space_tag_t iot, bus_space_handle_t ioh,
! 1361: u_char value)
! 1362: {
! 1363: int res;
! 1364:
! 1365: pxa2x0_pi2c_open(iot, ioh);
! 1366: res = pxa2x0_pi2c_write(iot, ioh, 0x0c, value);
! 1367: pxa2x0_pi2c_close(iot, ioh);
! 1368: return (res);
! 1369: }
! 1370:
! 1371: #if 0
! 1372: void
! 1373: pxa2x0_pi2c_print(struct pxa2x0_apm_softc *sc)
! 1374: {
! 1375: u_char value = 0;
! 1376:
! 1377: (void)pxa2x0_pi2c_getvoltage(sc->sc_iot, sc->sc_pm_ioh, &value);
! 1378: printf("xscale core voltage: %s\n", value == PI2C_VOLTAGE_HIGH ?
! 1379: "high" : (value == PI2C_VOLTAGE_LOW ? "low" : "unknown"));
! 1380: }
! 1381: #endif
! 1382:
! 1383: struct {
! 1384: int maxspeed;
! 1385: int numspeeds;
! 1386: int hz [6];
! 1387: int rate [6]; /* could this be simplfied by not having 100% in table? */
! 1388: }
! 1389: speedtables[] = {
! 1390: { 91, 1, { 91 }, { 100 }},
! 1391: { 208, 2, { 91, 208}, {50, 100}},
! 1392: { 416, 3, { 91, 208, 416}, {25, 50, 100}},
! 1393: { 520, 4, { 91, 208, 416, 520}, {18, 40 ,80, 100}},
! 1394: { 624, 5, { 91, 208, 416, 520, 624}, {15, 34, 67, 82, 100}},
! 1395: { 0 }
! 1396: };
! 1397: int xscale_maxspeed = 416; /* XXX */
! 1398:
! 1399: int speed_to_freq(int speed);
! 1400:
! 1401: int
! 1402: speed_to_freq(int speed)
! 1403: {
! 1404: int i, j;
! 1405: int newspeed = 0;
! 1406: int numspeeds;
! 1407: for (i = 0; speedtables[i].maxspeed != 0; i++) {
! 1408: if (speedtables[i].maxspeed != xscale_maxspeed)
! 1409: continue;
! 1410:
! 1411: if (speed <= speedtables[i].rate[0]) {
! 1412: return speedtables[i].hz[0];
! 1413:
! 1414: }
! 1415: numspeeds = speedtables[i].numspeeds;
! 1416: if (speed == speedtables[i].rate[numspeeds-1]) {
! 1417: return speedtables[i].hz[numspeeds-1];
! 1418: }
! 1419: for (j = 1; j < numspeeds; j++) {
! 1420: if (speed < speedtables[i].rate[j]) {
! 1421: return speedtables[i].hz[j-1];
! 1422: }
! 1423: }
! 1424: }
! 1425: return newspeed;
! 1426: }
! 1427:
! 1428:
! 1429: void
! 1430: pxa2x0_setperf(int speed)
! 1431: {
! 1432: struct pxa2x0_apm_softc *sc;
! 1433: int s;
! 1434: int newfreq;
! 1435:
! 1436: sc = apm_cd.cd_devs[0];
! 1437:
! 1438: newfreq = speed_to_freq(speed);
! 1439:
! 1440: if (newfreq == 0) {
! 1441: printf("bogus new frequency 0 for rate %d maxclock %d\n",
! 1442: speed, xscale_maxspeed);
! 1443: }
! 1444:
! 1445: DPRINTF(("setperf speed %d newfreq %d, maxfreq %d\n",
! 1446: speed, newfreq, xscale_maxspeed));
! 1447:
! 1448: s = disable_interrupts(I32_bit|F32_bit);
! 1449:
! 1450: if (newfreq == 91) {
! 1451: if (freq > 91) {
! 1452: pxa27x_run_mode();
! 1453: pxa27x_fastbus_run_mode(0, MDREFR_LOW);
! 1454: pxa27x_cpu_speed_91();
! 1455: pxa2x0_pi2c_setvoltage(sc->sc_iot, sc->sc_pm_ioh,
! 1456: PI2C_VOLTAGE_LOW);
! 1457: freq = 91;
! 1458: }
! 1459: } else if (newfreq == 208) {
! 1460: if (freq < 208)
! 1461: pxa2x0_pi2c_setvoltage(sc->sc_iot, sc->sc_pm_ioh,
! 1462: PI2C_VOLTAGE_HIGH);
! 1463: if (freq != 208) {
! 1464: pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X2 |
! 1465: CCCR_RUN_X16, CLKCFG_F, &pxa2x0_memcfg);
! 1466: pxa27x_fastbus_run_mode(1, pxa2x0_memcfg.mdrefr_high);
! 1467: freq = 208;
! 1468: }
! 1469: } else if (newfreq == 416) {
! 1470: if (freq < 208) {
! 1471: pxa2x0_pi2c_setvoltage(sc->sc_iot, sc->sc_pm_ioh,
! 1472: PI2C_VOLTAGE_HIGH);
! 1473: pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X2 |
! 1474: CCCR_RUN_X16, CLKCFG_F, &pxa2x0_memcfg);
! 1475: pxa27x_fastbus_run_mode(1, pxa2x0_memcfg.mdrefr_high);
! 1476: }
! 1477: if (freq != 416) {
! 1478: pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X2 |
! 1479: CCCR_RUN_X16, CLKCFG_B | CLKCFG_F | CLKCFG_T,
! 1480: &pxa2x0_memcfg);
! 1481: freq = 416;
! 1482: }
! 1483: } else if (newfreq == 520) {
! 1484: if (freq < 208) {
! 1485: pxa2x0_pi2c_setvoltage(sc->sc_iot, sc->sc_pm_ioh,
! 1486: PI2C_VOLTAGE_HIGH);
! 1487: pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X2 |
! 1488: CCCR_RUN_X16, CLKCFG_F, &pxa2x0_memcfg);
! 1489: pxa27x_fastbus_run_mode(1, pxa2x0_memcfg.mdrefr_high);
! 1490: }
! 1491: if (freq != 520) {
! 1492: pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X25 |
! 1493: CCCR_RUN_X16, CLKCFG_B | CLKCFG_F | CLKCFG_T,
! 1494: &pxa2x0_memcfg);
! 1495: freq = 520;
! 1496: }
! 1497: } else if (newfreq == 624) {
! 1498: if (freq < 208) {
! 1499: pxa2x0_pi2c_setvoltage(sc->sc_iot, sc->sc_pm_ioh,
! 1500: PI2C_VOLTAGE_HIGH);
! 1501: pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X2 |
! 1502: CCCR_RUN_X16, CLKCFG_F, &pxa2x0_memcfg);
! 1503: pxa27x_fastbus_run_mode(1, pxa2x0_memcfg.mdrefr_high);
! 1504: }
! 1505: if (freq != 624) {
! 1506: pxa27x_frequency_change(CCCR_A | CCCR_TURBO_X3 |
! 1507: CCCR_RUN_X16, CLKCFG_B | CLKCFG_F | CLKCFG_T,
! 1508: &pxa2x0_memcfg);
! 1509: freq = 624;
! 1510: }
! 1511: }
! 1512:
! 1513: restore_interrupts(s);
! 1514: }
! 1515:
! 1516: int
! 1517: pxa2x0_cpuspeed(int *freqp)
! 1518: {
! 1519: *freqp = freq;
! 1520: return 0;
! 1521: }
! 1522:
! 1523: void pxa2x0_maxspeed(int *speedp);
! 1524:
! 1525: void
! 1526: pxa2x0_maxspeed(int *speedp)
! 1527: {
! 1528: /* XXX assumes a pxa270 */
! 1529:
! 1530: if (*speedp < 207) {
! 1531: *speedp = 91;
! 1532: } else if (*speedp < 415) {
! 1533: *speedp = 208;
! 1534: } else if (*speedp < 519) {
! 1535: *speedp = 416;
! 1536: } else if (*speedp < 624) {
! 1537: *speedp = 520;
! 1538: #if 0
! 1539: } else if (*speedp < 651) {
! 1540: *speedp = 624;
! 1541: #endif
! 1542: } else {
! 1543: *speedp = 520; /* hope this is safe. */
! 1544: }
! 1545: xscale_maxspeed = *speedp;
! 1546: pxa2x0_setperf(perflevel);
! 1547: }
CVSweb