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