1/* $OpenBSD: power.c,v 1.11 2022/03/13 08:04:38 mpi 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 43struct 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 55int powermatch(struct device *, void *, void *); 56void powerattach(struct device *, struct device *, void *); 57 58const struct cfattach power_ca = { 59 sizeof(struct power_softc), powermatch, powerattach 60}; 61 62struct cfdriver power_cd = { 63 NULL, "power", DV_DULL 64}; 65 66void power_thread_create(void *v); 67void power_thread_dr(void *v); 68void power_thread_reg(void *v); 69void power_cold_hook_reg(int); 70int power_intr(void *); 71 72int 73powermatch(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 84void 85powerattach(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 120int 121power_intr(void *v) 122{ 123 struct power_softc *sc = v; 124 125 sc->sc_interrupted = 1; 126 127 return (1); 128} 129 130void 131power_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 140void 141power_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_nsec(v, PWAIT, "drpower", MSEC_TO_NSEC(100)); 161 } 162} 163 164void 165power_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_nsec(v, PWAIT, "regpower", MSEC_TO_NSEC(100)); 178 } 179} 180 181void 182power_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