1 /* $OpenBSD: power.c,v 1.9 2014/07/13 09:09:16 miod 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/proc.h> 31 #include <sys/signalvar.h> 32 #include <sys/kernel.h> 33 #include <sys/systm.h> 34 #include <sys/device.h> 35 #include <sys/kthread.h> 36 37 #include <machine/reg.h> 38 #include <machine/pdc.h> 39 #include <machine/autoconf.h> 40 41 #include <hppa/dev/cpudevs.h> 42 43 struct power_softc { 44 struct device sc_dev; 45 void *sc_ih; 46 47 struct proc *sc_thread; 48 void (*sc_kicker)(void *); 49 50 int sc_dr_cnt; 51 paddr_t sc_pwr_reg; 52 volatile int sc_interrupted; 53 }; 54 55 int powermatch(struct device *, void *, void *); 56 void powerattach(struct device *, struct device *, void *); 57 58 struct cfattach power_ca = { 59 sizeof(struct power_softc), powermatch, powerattach 60 }; 61 62 struct cfdriver power_cd = { 63 NULL, "power", DV_DULL 64 }; 65 66 void power_thread_create(void *v); 67 void power_thread_dr(void *v); 68 void power_thread_reg(void *v); 69 void power_cold_hook_reg(int); 70 int power_intr(void *); 71 72 int 73 powermatch(struct device *parent, void *cfdata, void *aux) 74 { 75 struct cfdata *cf = cfdata; 76 struct confargs *ca = aux; 77 78 if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "power")) 79 return (0); 80 81 return (1); 82 } 83 84 void 85 powerattach(struct device *parent, struct device *self, void *aux) 86 { 87 struct power_softc *sc = (struct power_softc *)self; 88 struct confargs *ca = aux; 89 90 switch (cpu_hvers) { 91 case HPPA_BOARD_HP712_60: 92 case HPPA_BOARD_HP712_80: 93 case HPPA_BOARD_HP712_100: 94 case HPPA_BOARD_HP712_120: 95 sc->sc_kicker = power_thread_dr; 96 printf(": DR25\n"); 97 break; 98 99 default: 100 if (ca->ca_hpa) { 101 extern void (*cold_hook)(int); 102 103 sc->sc_pwr_reg = ca->ca_hpa; 104 cold_hook = power_cold_hook_reg; 105 sc->sc_kicker = power_thread_reg; 106 printf("\n"); 107 } else 108 printf(": not available\n"); 109 break; 110 } 111 112 if (ca->ca_irq >= 0) 113 sc->sc_ih = cpu_intr_establish(IPL_CLOCK, ca->ca_irq, 114 power_intr, sc, sc->sc_dev.dv_xname); 115 116 if (sc->sc_kicker) 117 kthread_create_deferred(power_thread_create, sc); 118 } 119 120 int 121 power_intr(void *v) 122 { 123 struct power_softc *sc = v; 124 125 sc->sc_interrupted = 1; 126 127 return (1); 128 } 129 130 void 131 power_thread_create(void *v) 132 { 133 struct power_softc *sc = v; 134 135 if (kthread_create(sc->sc_kicker, sc, &sc->sc_thread, 136 sc->sc_dev.dv_xname)) 137 printf("WARNING: failed to create kernel power thread\n"); 138 } 139 140 void 141 power_thread_dr(void *v) 142 { 143 struct power_softc *sc = v; 144 u_int32_t r; 145 146 for (;;) { 147 mfcpu(DR0_PCXL_SHINT_EN, r); /* XXX don't ask */ 148 if (r & 0x80000000) 149 sc->sc_dr_cnt = 0; 150 else 151 sc->sc_dr_cnt++; 152 153 /* 154 * the bit is undampened straight wire from the power 155 * switch and thus we have do dampen it ourselves. 156 */ 157 if (sc->sc_dr_cnt == hz / 10) 158 prsignal(initprocess, SIGUSR2); 159 160 tsleep(v, PWAIT, "drpower", 10); 161 } 162 } 163 164 void 165 power_thread_reg(void *v) 166 { 167 struct power_softc *sc = v; 168 u_int32_t r; 169 170 for (;;) { 171 __asm volatile("ldwas 0(%1), %0" 172 : "=&r" (r) : "r" (sc->sc_pwr_reg)); 173 174 if (!(r & 1)) 175 prsignal(initprocess, SIGUSR2); 176 177 tsleep(v, PWAIT, "regpower", 10); 178 } 179 } 180 181 void 182 power_cold_hook_reg(int on) 183 { 184 extern struct pdc_power_info pdc_power_info; /* machdep.c */ 185 int error; 186 187 if ((error = pdc_call((iodcio_t)pdc, 0, PDC_SOFT_POWER, 188 PDC_SOFT_POWER_ENABLE, &pdc_power_info, 189 on == HPPA_COLD_HOT))) 190 printf("power_cold_hook_reg: failed (%d)\n", error); 191 } 192