tx39power.c revision 1.9.8.3 1 /* $NetBSD: tx39power.c,v 1.9.8.3 2002/10/18 02:37:13 nathanw 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