1 /* $NetBSD: tx39power.c,v 1.16 2006/03/07 23:18:31 he 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 <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: tx39power.c,v 1.16 2006/03/07 23:18:31 he Exp $"); 41 42 #include "opt_tx39power_debug.h" 43 #define TX39POWERDEBUG 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/device.h> 48 49 #include <machine/bus.h> 50 #include <machine/intr.h> 51 #include <machine/config_hook.h> 52 53 #include <hpcmips/tx/tx39var.h> 54 #include <hpcmips/tx/tx39icureg.h> 55 #include <hpcmips/tx/tx39powerreg.h> 56 57 #ifdef TX39POWER_DEBUG 58 #define DPRINTF_ENABLE 59 #define DPRINTF_DEBUG tx39power_debug 60 #endif 61 #include <machine/debug.h> 62 63 #ifdef TX39POWER_DEBUG 64 #define DUMP_REGS(x) __tx39power_dump(x) 65 #else 66 #define DUMP_REGS(x) ((void)0) 67 #endif 68 69 #define ISSETPRINT(r, m) dbg_bitmask_print(r, TX39_POWERCTRL_##m, #m) 70 71 int tx39power_match(struct device *, struct cfdata *, void *); 72 void tx39power_attach(struct device *, struct device *, void *); 73 74 struct tx39power_softc { 75 struct device sc_dev; 76 tx_chipset_tag_t sc_tc; 77 78 /* save interrupt status for resume */ 79 txreg_t sc_icu_state[TX39_INTRSET_MAX + 1]; 80 }; 81 82 CFATTACH_DECL(tx39power, sizeof(struct tx39power_softc), 83 tx39power_match, tx39power_attach, NULL, NULL); 84 85 void tx39power_suspend_cpu(void); /* automatic hardware resume */ 86 87 static int tx39power_intr_p(void *); 88 static int tx39power_intr_n(void *); 89 static int tx39power_ok_intr_p(void *); 90 static int tx39power_ok_intr_n(void *); 91 static int tx39power_button_intr_p(void *); 92 static int tx39power_button_intr_n(void *); 93 #ifdef TX39POWER_DEBUG 94 static void __tx39power_dump(struct tx39power_softc *); 95 #endif 96 97 int 98 tx39power_match(struct device *parent, struct cfdata *cf, void *aux) 99 { 100 return (ATTACH_FIRST); 101 } 102 103 void 104 tx39power_attach(struct device *parent, struct device *self, void *aux) 105 { 106 struct txsim_attach_args *ta = aux; 107 struct tx39power_softc *sc = (void*)self; 108 tx_chipset_tag_t tc; 109 txreg_t reg; 110 111 tc = sc->sc_tc = ta->ta_tc; 112 tx_conf_register_power(tc, self); 113 114 printf("\n"); 115 DUMP_REGS(sc); 116 117 /* power button setting */ 118 reg = tx_conf_read(tc, TX39_POWERCTRL_REG); 119 reg |= TX39_POWERCTRL_DBNCONBUTN; 120 tx_conf_write(tc, TX39_POWERCTRL_REG, reg); 121 122 /* enable stop timer */ 123 reg = tx_conf_read(tc, TX39_POWERCTRL_REG); 124 reg &= ~(TX39_POWERCTRL_STPTIMERVAL_MASK << 125 TX39_POWERCTRL_STPTIMERVAL_SHIFT); 126 reg = TX39_POWERCTRL_STPTIMERVAL_SET(reg, 127 TX39_POWERCTRL_STPTIMERVAL_MAX); 128 reg |= TX39_POWERCTRL_ENSTPTIMER; 129 tx_conf_write(tc, TX39_POWERCTRL_REG, reg); 130 131 /* install power event handler */ 132 /* low priority */ 133 tx_intr_establish(tc, MAKEINTR(5, TX39_INTRSTATUS5_POSPWRINT), 134 IST_EDGE, IPL_CLOCK, 135 tx39power_intr_p, sc); 136 tx_intr_establish(tc, MAKEINTR(5, TX39_INTRSTATUS5_NEGPWRINT), 137 IST_EDGE, IPL_CLOCK, 138 tx39power_intr_n, sc); 139 /* high priority */ 140 tx_intr_establish(tc, MAKEINTR(5, TX39_INTRSTATUS5_POSPWROKINT), 141 IST_EDGE, IPL_CLOCK, 142 tx39power_ok_intr_p, sc); 143 tx_intr_establish(tc, MAKEINTR(5, TX39_INTRSTATUS5_NEGPWROKINT), 144 IST_EDGE, IPL_CLOCK, 145 tx39power_ok_intr_n, sc); 146 /* user driven event */ 147 tx_intr_establish(tc, MAKEINTR(5, TX39_INTRSTATUS5_POSONBUTNINT), 148 IST_EDGE, IPL_CLOCK, 149 tx39power_button_intr_p, sc); 150 tx_intr_establish(tc, MAKEINTR(5, TX39_INTRSTATUS5_NEGONBUTNINT), 151 IST_EDGE, IPL_CLOCK, 152 tx39power_button_intr_n, sc); 153 } 154 155 void 156 tx39power_suspend_cpu() /* I assume already splhigh */ 157 { 158 tx_chipset_tag_t tc = tx_conf_get_tag(); 159 struct tx39power_softc *sc = tc->tc_powert; 160 txreg_t reg, *iregs = sc->sc_icu_state; 161 162 printf ("%s: CPU sleep\n", sc->sc_dev.dv_xname); 163 __asm volatile(".set noreorder"); 164 reg = tx_conf_read(tc, TX39_POWERCTRL_REG); 165 reg |= TX39_POWERCTRL_STOPCPU; 166 /* save interrupt state */ 167 iregs[0] = tx_conf_read(tc, TX39_INTRENABLE6_REG); 168 iregs[1] = tx_conf_read(tc, TX39_INTRENABLE1_REG); 169 iregs[2] = tx_conf_read(tc, TX39_INTRENABLE2_REG); 170 iregs[3] = tx_conf_read(tc, TX39_INTRENABLE3_REG); 171 iregs[4] = tx_conf_read(tc, TX39_INTRENABLE4_REG); 172 iregs[5] = tx_conf_read(tc, TX39_INTRENABLE5_REG); 173 #ifdef TX392X 174 iregs[7] = tx_conf_read(tc, TX39_INTRENABLE7_REG); 175 iregs[8] = tx_conf_read(tc, TX39_INTRENABLE8_REG); 176 #endif 177 /* disable all interrupt (don't disable GLOBALEN) */ 178 tx_conf_write(tc, TX39_INTRENABLE6_REG, TX39_INTRENABLE6_GLOBALEN); 179 tx_conf_write(tc, TX39_INTRENABLE1_REG, 0); 180 tx_conf_write(tc, TX39_INTRENABLE2_REG, 0); 181 tx_conf_write(tc, TX39_INTRENABLE3_REG, 0); 182 tx_conf_write(tc, TX39_INTRENABLE4_REG, 0); 183 tx_conf_write(tc, TX39_INTRENABLE5_REG, 0); 184 #ifdef TX392X 185 tx_conf_write(tc, TX39_INTRENABLE7_REG, 0); 186 tx_conf_write(tc, TX39_INTRENABLE8_REG, 0); 187 #endif 188 /* enable power button interrupt only */ 189 tx_conf_write(tc, TX39_INTRCLEAR5_REG, TX39_INTRSTATUS5_NEGONBUTNINT); 190 tx_conf_write(tc, TX39_INTRENABLE5_REG, TX39_INTRSTATUS5_NEGONBUTNINT); 191 __asm volatile("sync"); 192 193 /* stop CPU clock */ 194 tx_conf_write(tc, TX39_POWERCTRL_REG, reg); 195 __asm volatile("sync"); 196 /* wait until power button pressed */ 197 /* clear interrupt */ 198 tx_conf_write(tc, TX39_INTRCLEAR5_REG, TX39_INTRSTATUS5_NEGONBUTNINT); 199 #ifdef TX392X 200 /* Clear WARMSTART bit to reset vector(0xbfc00000) work correctly */ 201 reg = tx_conf_read(tc, TX39_POWERCTRL_REG); 202 reg &= ~TX39_POWERCTRL_WARMSTART; 203 tx_conf_write(tc, TX39_POWERCTRL_REG, reg); 204 #endif 205 206 /* restore interrupt state */ 207 tx_conf_write(tc, TX39_INTRENABLE6_REG, iregs[0]); 208 tx_conf_write(tc, TX39_INTRENABLE1_REG, iregs[1]); 209 tx_conf_write(tc, TX39_INTRENABLE2_REG, iregs[2]); 210 tx_conf_write(tc, TX39_INTRENABLE3_REG, iregs[3]); 211 tx_conf_write(tc, TX39_INTRENABLE4_REG, iregs[4]); 212 tx_conf_write(tc, TX39_INTRENABLE5_REG, iregs[5]); 213 #ifdef TX392X 214 tx_conf_write(tc, TX39_INTRENABLE7_REG, iregs[7]); 215 tx_conf_write(tc, TX39_INTRENABLE8_REG, iregs[8]); 216 #endif 217 __asm volatile(".set reorder"); 218 219 printf ("%s: CPU wakeup\n", sc->sc_dev.dv_xname); 220 } 221 222 static int 223 tx39power_button_intr_p(void *arg) 224 { 225 config_hook_call(CONFIG_HOOK_BUTTONEVENT, 226 CONFIG_HOOK_BUTTONEVENT_POWER, 227 (void *)1 /* on */); 228 229 return (0); 230 } 231 232 static int 233 tx39power_button_intr_n(void *arg) 234 { 235 config_hook_call(CONFIG_HOOK_BUTTONEVENT, 236 CONFIG_HOOK_BUTTONEVENT_POWER, 237 (void *)0 /* off */); 238 DUMP_REGS(arg); 239 240 return (0); 241 } 242 243 int 244 tx39power_intr_p(void *arg) 245 { 246 /* low priority event */ 247 printf("power_p\n"); 248 DUMP_REGS(arg); 249 250 return (0); 251 } 252 253 static int 254 tx39power_intr_n(void *arg) 255 { 256 /* low priority event */ 257 printf("power_n\n"); 258 DUMP_REGS(arg); 259 260 return (0); 261 } 262 263 static int 264 tx39power_ok_intr_p(void *arg) 265 { 266 /* high priority event */ 267 printf("power NG\n"); 268 DUMP_REGS(arg); 269 config_hook_call(CONFIG_HOOK_PMEVENT, 270 CONFIG_HOOK_PMEVENT_SUSPENDREQ, NULL); 271 272 return (0); 273 } 274 275 static int 276 tx39power_ok_intr_n(void *arg) 277 { 278 /* high priority event */ 279 printf("power OK\n"); 280 DUMP_REGS(arg); 281 282 return (0); 283 } 284 285 #ifdef TX39POWER_DEBUG 286 static void 287 __tx39power_dump (struct tx39power_softc *sc) 288 { 289 tx_chipset_tag_t tc = sc->sc_tc; 290 txreg_t reg; 291 292 reg = tx_conf_read(tc, TX39_POWERCTRL_REG); 293 ISSETPRINT(reg, ONBUTN); 294 ISSETPRINT(reg, PWRINT); 295 ISSETPRINT(reg, PWROK); 296 #ifdef TX392X 297 ISSETPRINT(reg, PWROKNMI); 298 #endif /* TX392X */ 299 ISSETPRINT(reg, SLOWBUS); 300 #ifdef TX391X 301 ISSETPRINT(reg, DIVMOD); 302 #endif /* TX391X */ 303 ISSETPRINT(reg, ENSTPTIMER); 304 ISSETPRINT(reg, ENFORCESHUTDWN); 305 ISSETPRINT(reg, FORCESHUTDWN); 306 ISSETPRINT(reg, FORCESHUTDWNOCC); 307 ISSETPRINT(reg, SELC2MS); 308 #ifdef TX392X 309 ISSETPRINT(reg, WARMSTART); 310 #endif /* TX392X */ 311 ISSETPRINT(reg, BPDBVCC3); 312 ISSETPRINT(reg, STOPCPU); 313 ISSETPRINT(reg, DBNCONBUTN); 314 ISSETPRINT(reg, COLDSTART); 315 ISSETPRINT(reg, PWRCS); 316 ISSETPRINT(reg, VCCON); 317 #ifdef TX391X 318 printf("VIDRF=%d ", TX39_POWERCTRL_VIDRF(reg)); 319 #endif /* TX391X */ 320 printf("STPTIMERVAL=%d ", TX39_POWERCTRL_STPTIMERVAL(reg)); 321 printf("\n"); 322 } 323 #endif /* TX39POWER_DEBUG */ 324