1 /* $NetBSD: power.c,v 1.3 2009/05/08 09:33:58 skrll Exp $ */
4 * Copyright (c) 2004 Jochen Kunz.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of Jochen Kunz may not be used to endorse or promote
16 * products derived from this software without specific prior
19 * THIS SOFTWARE IS PROVIDED BY JOCHEN KUNZ
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 JOCHEN KUNZ
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.
32 /* $OpenBSD: power.c,v 1.5 2004/06/11 12:53:09 mickey Exp $ */
35 * Copyright (c) 2003 Michael Shalayeff
36 * All rights reserved.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
51 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
52 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
53 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
55 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
56 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
57 * THE POSSIBILITY OF SUCH DAMAGE.
60 #include <sys/param.h>
61 #include <sys/kernel.h>
62 #include <sys/systm.h>
63 #include <sys/reboot.h>
64 #include <sys/device.h>
65 #include <sys/sysctl.h>
68 #include <machine/reg.h>
69 #include <machine/pdc.h>
70 #include <machine/autoconf.h>
72 #include <hp700/dev/cpudevs.h>
73 #include <hp700/hp700/intr.h>
75 #include <dev/sysmon/sysmon_taskq.h>
76 #include <dev/sysmon/sysmonvar.h>
78 /* Enable / disable control over the power switch. */
79 #define PWR_SW_CTRL_DISABLE 0
80 #define PWR_SW_CTRL_ENABLE 1
81 #define PWR_SW_CTRL_LOCK 2
82 #define PWR_SW_CTRL_MAX PWR_SW_CTRL_LOCK
86 bus_space_tag_t sc_bst
;
87 bus_space_handle_t sc_bsh
;
89 void (*sc_kicker
)(void *);
91 struct callout sc_callout
;
97 int powermatch(device_t
, cfdata_t
, void *);
98 void powerattach(device_t
, device_t
, void *);
100 CFATTACH_DECL_NEW(power
, sizeof(struct power_softc
),
101 powermatch
, powerattach
, NULL
, NULL
);
103 static struct pdc_power_info pdc_power_info PDC_ALIGNMENT
;
104 static bool pswitch_on
; /* power switch */
105 static int pwr_sw_control
;
106 static const char *pwr_sw_control_str
[] = {"disabled", "enabled", "locked"};
107 static struct sysmon_pswitch
*pwr_sw_sysmon
;
109 static int pwr_sw_sysctl_state(SYSCTLFN_PROTO
);
110 static int pwr_sw_sysctl_ctrl(SYSCTLFN_PROTO
);
111 static void pwr_sw_sysmon_cb(void *);
112 static void pwr_sw_ctrl(int);
113 static int pwr_sw_init(struct power_softc
*);
115 void power_thread_dr(void *v
);
116 void power_thread_reg(void *v
);
117 void power_cold_hook_reg(int);
120 powermatch(device_t parent
, cfdata_t cf
, void *aux
)
122 struct confargs
*ca
= aux
;
124 if (cf
->cf_unit
> 0 && !strcmp(ca
->ca_name
, "power"))
131 powerattach(device_t parent
, device_t self
, void *aux
)
133 struct power_softc
*sc
= device_private(self
);
134 struct confargs
*ca
= aux
;
137 sc
->sc_kicker
= NULL
;
139 if (!pdc_call((iodcio_t
)pdc
, 0, PDC_SOFT_POWER
,
140 PDC_SOFT_POWER_INFO
, &pdc_power_info
, 0)) {
141 ca
->ca_hpa
= pdc_power_info
.addr
;
145 case HPPA_BOARD_HP712_60
:
146 case HPPA_BOARD_HP712_80
:
147 case HPPA_BOARD_HP712_100
:
148 case HPPA_BOARD_HP712_120
:
149 sc
->sc_kicker
= power_thread_dr
;
151 /* Diag Reg. needs software dampening, poll at 0.2 Hz.*/
152 sc
->sc_timeout
= hz
/ 5;
154 aprint_normal(": DR25\n");
159 sc
->sc_bst
= ca
->ca_iot
;
160 if (bus_space_map(sc
->sc_bst
, ca
->ca_hpa
, 4, 0,
162 aprint_error_dev(self
,
163 "Can't map power switch status reg.\n");
165 cold_hook
= power_cold_hook_reg
;
166 sc
->sc_kicker
= power_thread_reg
;
168 /* Power Reg. is hardware dampened, poll at 1 Hz. */
173 aprint_normal(": not available\n");
182 pwr_sw_control
= PWR_SW_CTRL_ENABLE
;
187 * If the power switch is turned off we schedule a sysmon task
188 * to register that event for this power switch device.
191 check_pwr_state(struct power_softc
*sc
)
193 if (pswitch_on
== false && pwr_sw_control
!= PWR_SW_CTRL_LOCK
)
194 sysmon_task_queue_sched(0, pwr_sw_sysmon_cb
, NULL
);
196 callout_reset(&sc
->sc_callout
, sc
->sc_timeout
,
201 power_thread_dr(void *v
)
203 struct power_softc
*sc
= v
;
206 /* Get Power Fail status from CPU Diagnose Register 25 */
210 * On power failure, the hardware clears bit DR25_PCXL_POWFAIL
211 * in CPU Diagnose Register 25.
213 if (r
& (1 << DR25_PCXL_POWFAIL
))
219 * the bit is undampened straight wire from the power
220 * switch and thus we have do dampen it ourselves.
222 if (sc
->sc_dr_cnt
== sc
->sc_timeout
)
231 power_thread_reg(void *v
)
233 struct power_softc
*sc
= v
;
236 r
= bus_space_read_4(sc
->sc_bst
, sc
->sc_bsh
, 0);
247 power_cold_hook_reg(int on
)
251 if ((error
= pdc_call((iodcio_t
)pdc
, 0, PDC_SOFT_POWER
,
252 PDC_SOFT_POWER_ENABLE
, &pdc_power_info
,
253 on
== HPPA_COLD_HOT
)))
254 aprint_error("PDC_SOFT_POWER_ENABLE failed (%d)\n", error
);
258 pwr_sw_init(struct power_softc
*sc
)
260 struct sysctllog
*sysctl_log
= NULL
;
261 const struct sysctlnode
*pwr_sw_node
;
266 * Ensure that we are on a PCX-L / PA7100LC CPU if it is a
269 if (pdc_power_info
.addr
== 0 && hppa_cpu_info
->hci_cputype
!= hpcxl
) {
270 aprint_error_dev(sc
->sc_dev
, "No soft power available.\n");
274 errmsg
= "Can't create sysctl machdep.power_switch (or children)\n";
275 error
= sysctl_createv(&sysctl_log
, 0, NULL
, NULL
, 0,
276 CTLTYPE_NODE
, "machdep", NULL
, NULL
, 0, NULL
, 0,
277 CTL_MACHDEP
, CTL_EOL
);
282 error
= sysctl_createv(&sysctl_log
, 0, NULL
, &pwr_sw_node
, 0,
283 CTLTYPE_NODE
, "power_switch", NULL
, NULL
, 0, NULL
, 0,
284 CTL_MACHDEP
, CTL_CREATE
, CTL_EOL
);
289 error
= sysctl_createv(&sysctl_log
, 0, NULL
, NULL
,
290 CTLFLAG_READONLY
, CTLTYPE_STRING
, "state", NULL
,
291 pwr_sw_sysctl_state
, 0, NULL
, 16,
292 CTL_MACHDEP
, pwr_sw_node
->sysctl_num
, CTL_CREATE
, CTL_EOL
);
297 error
= sysctl_createv(&sysctl_log
, 0, NULL
, NULL
,
298 CTLFLAG_READWRITE
, CTLTYPE_STRING
, "control", NULL
,
299 pwr_sw_sysctl_ctrl
, 0, NULL
, 16,
300 CTL_MACHDEP
, pwr_sw_node
->sysctl_num
, CTL_CREATE
, CTL_EOL
);
305 errmsg
= "Can't alloc sysmon power switch.\n";
306 pwr_sw_sysmon
= kmem_zalloc(sizeof(*pwr_sw_sysmon
), KM_SLEEP
);
307 if (pwr_sw_sysmon
== NULL
) {
312 errmsg
= "Can't register power switch with sysmon.\n";
313 sysmon_task_queue_init();
314 pwr_sw_sysmon
->smpsw_name
= "power switch";
315 pwr_sw_sysmon
->smpsw_type
= PSWITCH_TYPE_POWER
;
316 error
= sysmon_pswitch_register(pwr_sw_sysmon
);
321 callout_init(&sc
->sc_callout
, 0);
322 callout_reset(&sc
->sc_callout
, sc
->sc_timeout
, sc
->sc_kicker
, sc
);
330 kmem_free(pwr_sw_sysmon
, sizeof(*pwr_sw_sysmon
));
333 sysctl_teardown(&sysctl_log
);
335 aprint_error_dev(sc
->sc_dev
, errmsg
);
341 pwr_sw_sysmon_cb(void *not_used
)
343 sysmon_pswitch_event(pwr_sw_sysmon
, PSWITCH_EVENT_PRESSED
);
347 pwr_sw_ctrl(int enable
)
352 printf("pwr_sw_control=%d enable=%d\n", pwr_sw_control
, enable
);
355 if (cold_hook
== NULL
)
359 case PWR_SW_CTRL_DISABLE
:
362 case PWR_SW_CTRL_ENABLE
:
363 case PWR_SW_CTRL_LOCK
:
367 panic("invalid power state in pwr_sw_control: %d", enable
);
370 pwr_sw_control
= enable
;
377 pwr_sw_sysctl_state(SYSCTLFN_ARGS
)
379 struct sysctlnode node
;
382 if (pswitch_on
== true)
388 node
.sysctl_data
= __UNCONST(status
);
389 return sysctl_lookup(SYSCTLFN_CALL(&node
));
393 pwr_sw_sysctl_ctrl(SYSCTLFN_ARGS
)
395 struct sysctlnode node
;
400 strcpy(val
, pwr_sw_control_str
[pwr_sw_control
]);
402 node
.sysctl_data
= val
;
404 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
406 if (error
|| newp
== NULL
)
409 for (i
= 0; i
<= PWR_SW_CTRL_MAX
; i
++)
410 if (strcmp(val
, pwr_sw_control_str
[i
]) == 0) {