1 /* $OpenBSD: power.c,v 1.5 2004/06/11 12:53:09 mickey Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/kernel.h> 31 #include <sys/systm.h> 32 #include <sys/reboot.h> 33 #include <sys/device.h> 34 #include <sys/kthread.h> 35 36 #include <machine/reg.h> 37 #include <machine/pdc.h> 38 #include <machine/autoconf.h> 39 40 #include <hppa/dev/cpudevs.h> 41 42 struct power_softc { 43 struct device sc_dev; 44 void *sc_ih; 45 46 struct proc *sc_thread; 47 void (*sc_kicker)(void *); 48 49 int sc_dr_cnt; 50 paddr_t sc_pwr_reg; 51 volatile int sc_interrupted; 52 }; 53 54 int powermatch(struct device *, void *, void *); 55 void powerattach(struct device *, struct device *, void *); 56 57 struct cfattach power_ca = { 58 sizeof(struct power_softc), powermatch, powerattach 59 }; 60 61 struct cfdriver power_cd = { 62 NULL, "power", DV_DULL 63 }; 64 65 void power_thread_create(void *v); 66 void power_thread_dr(void *v); 67 void power_thread_reg(void *v); 68 void power_cold_hook_reg(int); 69 int power_intr(void *); 70 71 int 72 powermatch(struct device *parent, void *cfdata, void *aux) 73 { 74 struct cfdata *cf = cfdata; 75 struct confargs *ca = aux; 76 77 if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "power")) 78 return (0); 79 80 return (1); 81 } 82 83 void 84 powerattach(struct device *parent, struct device *self, void *aux) 85 { 86 struct power_softc *sc = (struct power_softc *)self; 87 struct confargs *ca = aux; 88 89 switch (cpu_hvers) { 90 case HPPA_BOARD_HP712_60: 91 case HPPA_BOARD_HP712_80: 92 case HPPA_BOARD_HP712_100: 93 case HPPA_BOARD_HP712_120: 94 sc->sc_kicker = power_thread_dr; 95 printf(": DR25\n"); 96 break; 97 98 default: 99 if (ca->ca_hpa) { 100 extern void (*cold_hook)(int); 101 102 sc->sc_pwr_reg = ca->ca_hpa; 103 cold_hook = power_cold_hook_reg; 104 sc->sc_kicker = power_thread_reg; 105 printf("\n"); 106 } else 107 printf(": not available\n"); 108 break; 109 } 110 111 if (ca->ca_irq >= 0) 112 sc->sc_ih = cpu_intr_establish(IPL_CLOCK, ca->ca_irq, 113 power_intr, sc, sc->sc_dev.dv_xname); 114 115 if (sc->sc_kicker) 116 kthread_create_deferred(power_thread_create, sc); 117 } 118 119 int 120 power_intr(void *v) 121 { 122 struct power_softc *sc = v; 123 124 sc->sc_interrupted = 1; 125 126 return (1); 127 } 128 129 void 130 power_thread_create(void *v) 131 { 132 struct power_softc *sc = v; 133 134 if (kthread_create(sc->sc_kicker, sc, &sc->sc_thread, 135 sc->sc_dev.dv_xname)) 136 printf("WARNING: failed to create kernel power thread\n"); 137 } 138 139 void 140 power_thread_dr(void *v) 141 { 142 struct power_softc *sc = v; 143 u_int32_t r; 144 145 for (;;) { 146 mfcpu(DR0_PCXL_SHINT_EN, r); /* XXX don't ask */ 147 if (r & 0x80000000) 148 sc->sc_dr_cnt = 0; 149 else 150 sc->sc_dr_cnt++; 151 152 /* 153 * the bit is undampened straight wire from the power 154 * switch and thus we have do dampen it ourselves. 155 */ 156 if (sc->sc_dr_cnt == hz / 10) 157 boot(RB_POWERDOWN | RB_HALT); 158 159 tsleep(v, PWAIT, "drpower", 10); 160 } 161 } 162 163 void 164 power_thread_reg(void *v) 165 { 166 struct power_softc *sc = v; 167 u_int32_t r; 168 169 for (;;) { 170 __asm __volatile("ldwas 0(%1), %0" 171 : "=&r" (r) : "r" (sc->sc_pwr_reg)); 172 173 if (!(r & 1)) 174 boot(RB_POWERDOWN | RB_HALT); 175 176 tsleep(v, PWAIT, "regpower", 10); 177 } 178 } 179 180 void 181 power_cold_hook_reg(int on) 182 { 183 extern struct pdc_power_info pdc_power_info; /* machdep.c */ 184 int error; 185 186 if ((error = pdc_call((iodcio_t)pdc, 0, PDC_SOFT_POWER, 187 PDC_SOFT_POWER_ENABLE, &pdc_power_info, 188 on == HPPA_COLD_HOT))) 189 printf("power_cold_hook_reg: failed (%d)\n", error); 190 } 191