xref: /openbsd-src/sys/arch/hppa/dev/power.c (revision 78d5ff0ec949396ff3bbc97f51b741a17179ba18)
1*78d5ff0eSmpi /*	$OpenBSD: power.c,v 1.11 2022/03/13 08:04:38 mpi Exp $	*/
2185647a5Smickey 
3185647a5Smickey /*
4185647a5Smickey  * Copyright (c) 2003 Michael Shalayeff
5185647a5Smickey  * All rights reserved.
6185647a5Smickey  *
7185647a5Smickey  * Redistribution and use in source and binary forms, with or without
8185647a5Smickey  * modification, are permitted provided that the following conditions
9185647a5Smickey  * are met:
10185647a5Smickey  * 1. Redistributions of source code must retain the above copyright
11185647a5Smickey  *    notice, this list of conditions and the following disclaimer.
12185647a5Smickey  * 2. Redistributions in binary form must reproduce the above copyright
13185647a5Smickey  *    notice, this list of conditions and the following disclaimer in the
14185647a5Smickey  *    documentation and/or other materials provided with the distribution.
15185647a5Smickey  *
16185647a5Smickey  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17185647a5Smickey  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18185647a5Smickey  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19185647a5Smickey  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20185647a5Smickey  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21185647a5Smickey  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22185647a5Smickey  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23185647a5Smickey  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24185647a5Smickey  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25185647a5Smickey  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26185647a5Smickey  * THE POSSIBILITY OF SUCH DAMAGE.
27185647a5Smickey  */
28185647a5Smickey 
29185647a5Smickey #include <sys/param.h>
3002d8e5b1Suebayasi #include <sys/proc.h>
3102d8e5b1Suebayasi #include <sys/signalvar.h>
32185647a5Smickey #include <sys/kernel.h>
33185647a5Smickey #include <sys/systm.h>
34185647a5Smickey #include <sys/device.h>
35185647a5Smickey #include <sys/kthread.h>
36185647a5Smickey 
37185647a5Smickey #include <machine/reg.h>
380c7cde72Smickey #include <machine/pdc.h>
39185647a5Smickey #include <machine/autoconf.h>
40185647a5Smickey 
41185647a5Smickey #include <hppa/dev/cpudevs.h>
42185647a5Smickey 
43185647a5Smickey struct power_softc {
44185647a5Smickey 	struct device sc_dev;
45a5549269Smickey 	void *sc_ih;
46185647a5Smickey 
47185647a5Smickey 	struct proc *sc_thread;
48185647a5Smickey 	void (*sc_kicker)(void *);
49185647a5Smickey 
50185647a5Smickey 	int sc_dr_cnt;
510c7cde72Smickey 	paddr_t sc_pwr_reg;
52a5549269Smickey 	volatile int sc_interrupted;
53185647a5Smickey };
54185647a5Smickey 
55185647a5Smickey int	powermatch(struct device *, void *, void *);
56185647a5Smickey void	powerattach(struct device *, struct device *, void *);
57185647a5Smickey 
58*78d5ff0eSmpi const struct cfattach power_ca = {
59185647a5Smickey 	sizeof(struct power_softc), powermatch, powerattach
60185647a5Smickey };
61185647a5Smickey 
62185647a5Smickey struct cfdriver power_cd = {
63185647a5Smickey 	NULL, "power", DV_DULL
64185647a5Smickey };
65185647a5Smickey 
66185647a5Smickey void power_thread_create(void *v);
67185647a5Smickey void power_thread_dr(void *v);
680c7cde72Smickey void power_thread_reg(void *v);
690c7cde72Smickey void power_cold_hook_reg(int);
70a5549269Smickey int power_intr(void *);
71185647a5Smickey 
72185647a5Smickey int
powermatch(struct device * parent,void * cfdata,void * aux)73185647a5Smickey powermatch(struct device *parent, void *cfdata, void *aux)
74185647a5Smickey {
75185647a5Smickey 	struct cfdata *cf = cfdata;
76185647a5Smickey 	struct confargs *ca = aux;
77185647a5Smickey 
78185647a5Smickey 	if (cf->cf_unit > 0 && !strcmp(ca->ca_name, "power"))
79185647a5Smickey 		return (0);
80185647a5Smickey 
81185647a5Smickey 	return (1);
82185647a5Smickey }
83185647a5Smickey 
84185647a5Smickey void
powerattach(struct device * parent,struct device * self,void * aux)85185647a5Smickey powerattach(struct device *parent, struct device *self, void *aux)
86185647a5Smickey {
87185647a5Smickey 	struct power_softc *sc = (struct power_softc *)self;
88a5549269Smickey 	struct confargs *ca = aux;
89185647a5Smickey 
90185647a5Smickey 	switch (cpu_hvers) {
91185647a5Smickey 	case HPPA_BOARD_HP712_60:
92185647a5Smickey 	case HPPA_BOARD_HP712_80:
93185647a5Smickey 	case HPPA_BOARD_HP712_100:
94185647a5Smickey 	case HPPA_BOARD_HP712_120:
95185647a5Smickey 		sc->sc_kicker = power_thread_dr;
960c7cde72Smickey 		printf(": DR25\n");
97185647a5Smickey 		break;
980c7cde72Smickey 
99185647a5Smickey 	default:
100a5549269Smickey 		if (ca->ca_hpa) {
1010c7cde72Smickey 			extern void (*cold_hook)(int);
1020c7cde72Smickey 
103a5549269Smickey 			sc->sc_pwr_reg = ca->ca_hpa;
1040c7cde72Smickey 			cold_hook = power_cold_hook_reg;
1050c7cde72Smickey 			sc->sc_kicker = power_thread_reg;
106a5549269Smickey 			printf("\n");
107a5549269Smickey 		} else
108a5549269Smickey 			printf(": not available\n");
109185647a5Smickey 		break;
110185647a5Smickey 	}
111185647a5Smickey 
112a5549269Smickey 	if (ca->ca_irq >= 0)
113a5549269Smickey 		sc->sc_ih = cpu_intr_establish(IPL_CLOCK, ca->ca_irq,
114a5549269Smickey 		    power_intr, sc, sc->sc_dev.dv_xname);
115a5549269Smickey 
116185647a5Smickey 	if (sc->sc_kicker)
117185647a5Smickey 		kthread_create_deferred(power_thread_create, sc);
118185647a5Smickey }
119185647a5Smickey 
120a5549269Smickey int
power_intr(void * v)121a5549269Smickey power_intr(void *v)
122a5549269Smickey {
123a5549269Smickey 	struct power_softc *sc = v;
124a5549269Smickey 
125a5549269Smickey 	sc->sc_interrupted = 1;
126a5549269Smickey 
127a5549269Smickey 	return (1);
128a5549269Smickey }
129a5549269Smickey 
130185647a5Smickey void
power_thread_create(void * v)131185647a5Smickey power_thread_create(void *v)
132185647a5Smickey {
133185647a5Smickey 	struct power_softc *sc = v;
134185647a5Smickey 
135185647a5Smickey 	if (kthread_create(sc->sc_kicker, sc, &sc->sc_thread,
136308f2339Smickey 	    sc->sc_dev.dv_xname))
137185647a5Smickey 		printf("WARNING: failed to create kernel power thread\n");
138185647a5Smickey }
139185647a5Smickey 
140185647a5Smickey void
power_thread_dr(void * v)141185647a5Smickey power_thread_dr(void *v)
142185647a5Smickey {
143185647a5Smickey 	struct power_softc *sc = v;
144185647a5Smickey 	u_int32_t r;
145185647a5Smickey 
146185647a5Smickey 	for (;;) {
147185647a5Smickey 		mfcpu(DR0_PCXL_SHINT_EN, r);	/* XXX don't ask */
148185647a5Smickey 		if (r & 0x80000000)
149185647a5Smickey 			sc->sc_dr_cnt = 0;
150185647a5Smickey 		else
151185647a5Smickey 			sc->sc_dr_cnt++;
152185647a5Smickey 
153185647a5Smickey 		/*
154185647a5Smickey 		 * the bit is undampened straight wire from the power
155185647a5Smickey 		 * switch and thus we have do dampen it ourselves.
156185647a5Smickey 		 */
157185647a5Smickey 		if (sc->sc_dr_cnt == hz / 10)
15802d8e5b1Suebayasi 			prsignal(initprocess, SIGUSR2);
159185647a5Smickey 
160448a8ce5Scheloha 		tsleep_nsec(v, PWAIT, "drpower", MSEC_TO_NSEC(100));
161185647a5Smickey 	}
162185647a5Smickey }
1630c7cde72Smickey 
1640c7cde72Smickey void
power_thread_reg(void * v)1650c7cde72Smickey power_thread_reg(void *v)
1660c7cde72Smickey {
1670c7cde72Smickey 	struct power_softc *sc = v;
1680c7cde72Smickey 	u_int32_t r;
1690c7cde72Smickey 
1700c7cde72Smickey 	for (;;) {
1712df76cc2Sguenther 		__asm volatile("ldwas 0(%1), %0"
1720c7cde72Smickey 		    : "=&r" (r) : "r" (sc->sc_pwr_reg));
1730c7cde72Smickey 
1740c7cde72Smickey 		if (!(r & 1))
175cc18e21dSmiod 			prsignal(initprocess, SIGUSR2);
1760c7cde72Smickey 
177448a8ce5Scheloha 		tsleep_nsec(v, PWAIT, "regpower", MSEC_TO_NSEC(100));
1780c7cde72Smickey 	}
1790c7cde72Smickey }
1800c7cde72Smickey 
1810c7cde72Smickey void
power_cold_hook_reg(int on)1820c7cde72Smickey power_cold_hook_reg(int on)
1830c7cde72Smickey {
184a5549269Smickey 	extern struct pdc_power_info pdc_power_info;	/* machdep.c */
1850c7cde72Smickey 	int error;
1860c7cde72Smickey 
1870c7cde72Smickey 	if ((error = pdc_call((iodcio_t)pdc, 0, PDC_SOFT_POWER,
1880c7cde72Smickey 	    PDC_SOFT_POWER_ENABLE, &pdc_power_info,
1890c7cde72Smickey 	    on == HPPA_COLD_HOT)))
1900c7cde72Smickey 		printf("power_cold_hook_reg: failed (%d)\n", error);
1910c7cde72Smickey }
192