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