1 /* $NetBSD: tx39power.c,v 1.12 2002/10/02 05:26:51 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include "opt_tx39power_debug.h" 40 #define TX39POWERDEBUG 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/device.h> 45 46 #include <machine/bus.h> 47 #include <machine/intr.h> 48 #include <machine/config_hook.h> 49 50 #include <hpcmips/tx/tx39var.h> 51 #include <hpcmips/tx/tx39icureg.h> 52 #include <hpcmips/tx/tx39powerreg.h> 53 54 #ifdef TX39POWER_DEBUG 55 #define DPRINTF_ENABLE 56 #define DPRINTF_DEBUG tx39power_debug 57 #endif 58 #include <machine/debug.h> 59 60 #ifdef TX39POWER_DEBUG 61 #define DUMP_REGS(x) __tx39power_dump(x) 62 #else 63 #define DUMP_REGS(x) ((void)0) 64 #endif 65 66 #define ISSET(x, v) ((x) & (v)) 67 #define ISSETPRINT(r, m) dbg_bitmask_print(r, TX39_POWERCTRL_##m, #m) 68 69 int tx39power_match(struct device *, struct cfdata *, void *); 70 void tx39power_attach(struct device *, struct device *, void *); 71 72 struct tx39power_softc { 73 struct device sc_dev; 74 tx_chipset_tag_t sc_tc; 75 76 /* save interrupt status for resume */ 77 txreg_t sc_icu_state[TX39_INTRSET_MAX + 1]; 78 }; 79 80 CFATTACH_DECL(tx39power, sizeof(struct tx39power_softc), 81 tx39power_match, tx39power_attach, NULL, NULL); 82 83 void tx39power_suspend_cpu(void); /* automatic hardware resume */ 84 85 static int tx39power_intr_p(void *); 86 static int tx39power_intr_n(void *); 87 static int tx39power_ok_intr_p(void *); 88 static int tx39power_ok_intr_n(void *); 89 static int tx39power_button_intr_p(void *); 90 static int tx39power_button_intr_n(void *); 91 #ifdef TX39POWER_DEBUG 92 static void __tx39power_dump(struct tx39power_softc *); 93 #endif 94 95 int 96 tx39power_match(struct device *parent, struct cfdata *cf, void *aux) 97 { 98 return (ATTACH_FIRST); 99 } 100 101 void 102 tx39power_attach(struct device *parent, struct device *self, void *aux) 103 { 104 struct txsim_attach_args *ta = aux; 105 struct tx39power_softc *sc = (void*)self; 106 tx_chipset_tag_t tc; 107 txreg_t reg; 108 109 tc = sc->sc_tc = ta->ta_tc; 110 tx_conf_register_power(tc, self); 111 112 printf("\n"); 113 DUMP_REGS(sc); 114 115 /* power button setting */ 116 reg = tx_conf_read(tc, TX39_POWERCTRL_REG); 117 reg |= TX39_POWERCTRL_DBNCONBUTN; 118 tx_conf_write(tc, TX39_POWERCTRL_REG, reg); 119 120 /* enable stop timer */ 121 reg = tx_conf_read(tc, TX39_POWERCTRL_REG); 122 reg &= ~(TX39_POWERCTRL_STPTIMERVAL_MASK << 123 TX39_POWERCTRL_STPTIMERVAL_SHIFT); 124 reg = TX39_POWERCTRL_STPTIMERVAL_SET(reg, 125 TX39_POWERCTRL_STPTIMERVAL_MAX); 126 reg |= TX39_POWERCTRL_ENSTPTIMER; 127 tx_conf_write(tc, TX39_POWERCTRL_REG, reg); 128 129 /* install power event handler */ 130 /* low priority */ 131 tx_intr_establish(tc, MAKEINTR(5, TX39_INTRSTATUS5_POSPWRINT), 132 IST_EDGE, IPL_CLOCK, 133 tx39power_intr_p, sc); 134 tx_intr_establish(tc, MAKEINTR(5, TX39_INTRSTATUS5_NEGPWRINT), 135 IST_EDGE, IPL_CLOCK, 136 tx39power_intr_n, sc); 137 /* high priority */ 138 tx_intr_establish(tc, MAKEINTR(5, TX39_INTRSTATUS5_POSPWROKINT), 139 IST_EDGE, IPL_CLOCK, 140 tx39power_ok_intr_p, sc); 141 tx_intr_establish(tc, MAKEINTR(5, TX39_INTRSTATUS5_NEGPWROKINT), 142 IST_EDGE, IPL_CLOCK, 143 tx39power_ok_intr_n, sc); 144 /* user driven event */ 145 tx_intr_establish(tc, MAKEINTR(5, TX39_INTRSTATUS5_POSONBUTNINT), 146 IST_EDGE, IPL_CLOCK, 147 tx39power_button_intr_p, sc); 148 tx_intr_establish(tc, MAKEINTR(5, TX39_INTRSTATUS5_NEGONBUTNINT), 149 IST_EDGE, IPL_CLOCK, 150 tx39power_button_intr_n, sc); 151 } 152 153 void 154 tx39power_suspend_cpu() /* I assume already splhigh */ 155 { 156 tx_chipset_tag_t tc = tx_conf_get_tag(); 157 struct tx39power_softc *sc = tc->tc_powert; 158 txreg_t reg, *iregs = sc->sc_icu_state; 159 160 printf ("%s: CPU sleep\n", sc->sc_dev.dv_xname); 161 __asm__ __volatile__(".set noreorder"); 162 reg = tx_conf_read(tc, TX39_POWERCTRL_REG); 163 reg |= TX39_POWERCTRL_STOPCPU; 164 /* save interrupt state */ 165 iregs[0] = tx_conf_read(tc, TX39_INTRENABLE6_REG); 166 iregs[1] = tx_conf_read(tc, TX39_INTRENABLE1_REG); 167 iregs[2] = tx_conf_read(tc, TX39_INTRENABLE2_REG); 168 iregs[3] = tx_conf_read(tc, TX39_INTRENABLE3_REG); 169 iregs[4] = tx_conf_read(tc, TX39_INTRENABLE4_REG); 170 iregs[5] = tx_conf_read(tc, TX39_INTRENABLE5_REG); 171 #ifdef TX392X 172 iregs[7] = tx_conf_read(tc, TX39_INTRENABLE7_REG); 173 iregs[8] = tx_conf_read(tc, TX39_INTRENABLE8_REG); 174 #endif 175 /* disable all interrupt (don't disable GLOBALEN) */ 176 tx_conf_write(tc, TX39_INTRENABLE6_REG, TX39_INTRENABLE6_GLOBALEN); 177 tx_conf_write(tc, TX39_INTRENABLE1_REG, 0); 178 tx_conf_write(tc, TX39_INTRENABLE2_REG, 0); 179 tx_conf_write(tc, TX39_INTRENABLE3_REG, 0); 180 tx_conf_write(tc, TX39_INTRENABLE4_REG, 0); 181 tx_conf_write(tc, TX39_INTRENABLE5_REG, 0); 182 #ifdef TX392X 183 tx_conf_write(tc, TX39_INTRENABLE7_REG, 0); 184 tx_conf_write(tc, TX39_INTRENABLE8_REG, 0); 185 #endif 186 /* enable power button interrupt only */ 187 tx_conf_write(tc, TX39_INTRCLEAR5_REG, TX39_INTRSTATUS5_NEGONBUTNINT); 188 tx_conf_write(tc, TX39_INTRENABLE5_REG, TX39_INTRSTATUS5_NEGONBUTNINT); 189 __asm__ __volatile__("sync"); 190 191 /* stop CPU clock */ 192 tx_conf_write(tc, TX39_POWERCTRL_REG, reg); 193 __asm__ __volatile__("sync"); 194 /* wait until power button pressed */ 195 /* clear interrupt */ 196 tx_conf_write(tc, TX39_INTRCLEAR5_REG, TX39_INTRSTATUS5_NEGONBUTNINT); 197 #ifdef TX392X 198 /* Clear WARMSTART bit to reset vector(0xbfc00000) work correctly */ 199 reg = tx_conf_read(tc, TX39_POWERCTRL_REG); 200 reg &= ~TX39_POWERCTRL_WARMSTART; 201 tx_conf_write(tc, TX39_POWERCTRL_REG, reg); 202 #endif 203 204 /* restore interrupt state */ 205 tx_conf_write(tc, TX39_INTRENABLE6_REG, iregs[0]); 206 tx_conf_write(tc, TX39_INTRENABLE1_REG, iregs[1]); 207 tx_conf_write(tc, TX39_INTRENABLE2_REG, iregs[2]); 208 tx_conf_write(tc, TX39_INTRENABLE3_REG, iregs[3]); 209 tx_conf_write(tc, TX39_INTRENABLE4_REG, iregs[4]); 210 tx_conf_write(tc, TX39_INTRENABLE5_REG, iregs[5]); 211 #ifdef TX392X 212 tx_conf_write(tc, TX39_INTRENABLE7_REG, iregs[7]); 213 tx_conf_write(tc, TX39_INTRENABLE8_REG, iregs[8]); 214 #endif 215 __asm__ __volatile__(".set reorder"); 216 217 printf ("%s: CPU wakeup\n", sc->sc_dev.dv_xname); 218 } 219 220 static int 221 tx39power_button_intr_p(void *arg) 222 { 223 config_hook_call(CONFIG_HOOK_BUTTONEVENT, 224 CONFIG_HOOK_BUTTONEVENT_POWER, 225 (void *)1 /* on */); 226 227 return (0); 228 } 229 230 static int 231 tx39power_button_intr_n(void *arg) 232 { 233 config_hook_call(CONFIG_HOOK_BUTTONEVENT, 234 CONFIG_HOOK_BUTTONEVENT_POWER, 235 (void *)0 /* off */); 236 DUMP_REGS(arg); 237 238 return (0); 239 } 240 241 int 242 tx39power_intr_p(void *arg) 243 { 244 /* low priority event */ 245 printf("power_p\n"); 246 DUMP_REGS(arg); 247 248 return (0); 249 } 250 251 static int 252 tx39power_intr_n(void *arg) 253 { 254 /* low priority event */ 255 printf("power_n\n"); 256 DUMP_REGS(arg); 257 258 return (0); 259 } 260 261 static int 262 tx39power_ok_intr_p(void *arg) 263 { 264 /* high priority event */ 265 printf("power NG\n"); 266 DUMP_REGS(arg); 267 config_hook_call(CONFIG_HOOK_PMEVENT, 268 CONFIG_HOOK_PMEVENT_SUSPENDREQ, NULL); 269 270 return (0); 271 } 272 273 static int 274 tx39power_ok_intr_n(void *arg) 275 { 276 /* high priority event */ 277 printf("power OK\n"); 278 DUMP_REGS(arg); 279 280 return (0); 281 } 282 283 #ifdef TX39POWER_DEBUG 284 static void 285 __tx39power_dump (struct tx39power_softc *sc) 286 { 287 tx_chipset_tag_t tc = sc->sc_tc; 288 txreg_t reg; 289 290 reg = tx_conf_read(tc, TX39_POWERCTRL_REG); 291 ISSETPRINT(reg, ONBUTN); 292 ISSETPRINT(reg, PWRINT); 293 ISSETPRINT(reg, PWROK); 294 #ifdef TX392X 295 ISSETPRINT(reg, PWROKNMI); 296 #endif /* TX392X */ 297 ISSETPRINT(reg, SLOWBUS); 298 #ifdef TX391X 299 ISSETPRINT(reg, DIVMOD); 300 #endif /* TX391X */ 301 ISSETPRINT(reg, ENSTPTIMER); 302 ISSETPRINT(reg, ENFORCESHUTDWN); 303 ISSETPRINT(reg, FORCESHUTDWN); 304 ISSETPRINT(reg, FORCESHUTDWNOCC); 305 ISSETPRINT(reg, SELC2MS); 306 #ifdef TX392X 307 ISSETPRINT(reg, WARMSTART); 308 #endif /* TX392X */ 309 ISSETPRINT(reg, BPDBVCC3); 310 ISSETPRINT(reg, STOPCPU); 311 ISSETPRINT(reg, DBNCONBUTN); 312 ISSETPRINT(reg, COLDSTART); 313 ISSETPRINT(reg, PWRCS); 314 ISSETPRINT(reg, VCCON); 315 #ifdef TX391X 316 printf("VIDRF=%d ", TX39_POWERCTRL_VIDRF(reg)); 317 #endif /* TX391X */ 318 printf("STPTIMERVAL=%d ", TX39_POWERCTRL_STPTIMERVAL(reg)); 319 printf("\n"); 320 } 321 #endif /* TX39POWER_DEBUG */ 322