xref: /netbsd/sys/arch/hpcmips/tx/tx39power.c (revision c4a72b64)
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