xref: /openbsd-src/sys/arch/sparc64/dev/pmc.c (revision eb7eaf8de3ff431d305450f61b441e5460c82246)
1*eb7eaf8dSmpi /*	$OpenBSD: pmc.c,v 1.5 2021/10/24 17:05:04 mpi Exp $	*/
2353a7d7cSkettenis 
3353a7d7cSkettenis /*
4353a7d7cSkettenis  * Copyright (c) 2007 Mark Kettenis
5353a7d7cSkettenis  *
6353a7d7cSkettenis  * Permission to use, copy, modify, and distribute this software for any
7353a7d7cSkettenis  * purpose with or without fee is hereby granted, provided that the above
8353a7d7cSkettenis  * copyright notice and this permission notice appear in all copies.
9353a7d7cSkettenis  *
10353a7d7cSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11353a7d7cSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12353a7d7cSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13353a7d7cSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14353a7d7cSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15353a7d7cSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16353a7d7cSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17353a7d7cSkettenis  */
18353a7d7cSkettenis 
19353a7d7cSkettenis /*
20353a7d7cSkettenis  * Driver for watchdog device on Blade 1000, Fire 280R, Fire V480 etc.
21353a7d7cSkettenis  */
22353a7d7cSkettenis 
23353a7d7cSkettenis #include <sys/param.h>
24353a7d7cSkettenis #include <sys/kernel.h>
25353a7d7cSkettenis #include <sys/device.h>
26353a7d7cSkettenis #include <sys/malloc.h>
27353a7d7cSkettenis #include <sys/systm.h>
28353a7d7cSkettenis 
29353a7d7cSkettenis #include <machine/bus.h>
30353a7d7cSkettenis #include <machine/autoconf.h>
31353a7d7cSkettenis 
32353a7d7cSkettenis #include <sparc64/dev/ebusreg.h>
33353a7d7cSkettenis #include <sparc64/dev/ebusvar.h>
34353a7d7cSkettenis 
35353a7d7cSkettenis /*
36353a7d7cSkettenis  * Register access is indirect, through an address and data port.
37353a7d7cSkettenis  */
38353a7d7cSkettenis 
39353a7d7cSkettenis #define	PMC_ADDR	0
40353a7d7cSkettenis #define	PMC_DATA	1
41353a7d7cSkettenis 
42353a7d7cSkettenis /* Watchdog time-out register. */
43353a7d7cSkettenis #define PMC_WDTO	0x05
44353a7d7cSkettenis 
45353a7d7cSkettenis struct pmc_softc {
46353a7d7cSkettenis 	struct device		sc_dv;
47353a7d7cSkettenis 	bus_space_tag_t		sc_iot;
48353a7d7cSkettenis 	bus_space_handle_t	sc_ioh;
49353a7d7cSkettenis };
50353a7d7cSkettenis 
51353a7d7cSkettenis int	pmc_match(struct device *, void *, void *);
52353a7d7cSkettenis void	pmc_attach(struct device *, struct device *, void *);
533b06f262Smikeb int	pmc_activate(struct device *, int);
54353a7d7cSkettenis int	pmc_wdog_cb(void *, int);
55353a7d7cSkettenis 
56*eb7eaf8dSmpi const struct cfattach pmc_ca = {
573b06f262Smikeb 	sizeof(struct pmc_softc), pmc_match, pmc_attach, NULL, pmc_activate
58353a7d7cSkettenis };
59353a7d7cSkettenis 
60353a7d7cSkettenis struct cfdriver pmc_cd = {
61353a7d7cSkettenis 	NULL, "pmc", DV_DULL
62353a7d7cSkettenis };
63353a7d7cSkettenis 
64353a7d7cSkettenis int
pmc_match(struct device * parent,void * cf,void * aux)65353a7d7cSkettenis pmc_match(struct device *parent, void *cf, void *aux)
66353a7d7cSkettenis {
67353a7d7cSkettenis 	struct ebus_attach_args *ea = aux;
68353a7d7cSkettenis 
69353a7d7cSkettenis 	if (strcmp("pmc", ea->ea_name) == 0)
70353a7d7cSkettenis 		return (1);
71353a7d7cSkettenis 	return (0);
72353a7d7cSkettenis }
73353a7d7cSkettenis 
74353a7d7cSkettenis void
pmc_attach(struct device * parent,struct device * self,void * aux)75353a7d7cSkettenis pmc_attach(struct device *parent, struct device *self, void *aux)
76353a7d7cSkettenis {
77353a7d7cSkettenis 	struct pmc_softc *sc = (void *)self;
78353a7d7cSkettenis 	struct ebus_attach_args *ea = aux;
79353a7d7cSkettenis 
80353a7d7cSkettenis 	/* Use prom address if available, otherwise map it. */
81353a7d7cSkettenis 	if (ea->ea_nvaddrs) {
82353a7d7cSkettenis 		if (bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
83353a7d7cSkettenis 		    BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh)) {
84353a7d7cSkettenis 			printf(": can't map PROM register space\n");
85353a7d7cSkettenis 			return;
86353a7d7cSkettenis 		}
87353a7d7cSkettenis 		sc->sc_iot = ea->ea_memtag;
88353a7d7cSkettenis 	} else if (ebus_bus_map(ea->ea_iotag, 0,
89353a7d7cSkettenis 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
90353a7d7cSkettenis 	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
91353a7d7cSkettenis 		sc->sc_iot = ea->ea_iotag;
92353a7d7cSkettenis 	} else if (ebus_bus_map(ea->ea_memtag, 0,
93353a7d7cSkettenis 	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
94353a7d7cSkettenis 	    ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
95353a7d7cSkettenis 		sc->sc_iot = ea->ea_memtag;
96353a7d7cSkettenis 	} else {
9750e1d102Skettenis 		printf(": can't map register space\n");
98353a7d7cSkettenis 		return;
99353a7d7cSkettenis 	}
100353a7d7cSkettenis 
101353a7d7cSkettenis 	printf("\n");
102353a7d7cSkettenis 
1032bc62decSderaadt 	wdog_register(pmc_wdog_cb, sc);
104353a7d7cSkettenis }
105353a7d7cSkettenis 
106353a7d7cSkettenis int
pmc_activate(struct device * self,int act)1073b06f262Smikeb pmc_activate(struct device *self, int act)
1083b06f262Smikeb {
1093b06f262Smikeb 	switch (act) {
1103b06f262Smikeb 	case DVACT_POWERDOWN:
1113b06f262Smikeb 		wdog_shutdown(self);
1123b06f262Smikeb 		break;
1133b06f262Smikeb 	}
1143b06f262Smikeb 
1153b06f262Smikeb 	return (0);
1163b06f262Smikeb }
1173b06f262Smikeb 
1183b06f262Smikeb int
pmc_wdog_cb(void * arg,int period)119353a7d7cSkettenis pmc_wdog_cb(void *arg, int period)
120353a7d7cSkettenis {
121353a7d7cSkettenis 	struct pmc_softc *sc = arg;
122353a7d7cSkettenis 	int mins;
123353a7d7cSkettenis 
124353a7d7cSkettenis 	mins = (period + 59) / 60;
125353a7d7cSkettenis 	if (mins > 255)
126353a7d7cSkettenis 		mins = 255;
127353a7d7cSkettenis 
128353a7d7cSkettenis 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, PMC_ADDR, PMC_WDTO);
129353a7d7cSkettenis 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, PMC_DATA, mins);
130353a7d7cSkettenis 
131353a7d7cSkettenis 	return (mins * 60);
132353a7d7cSkettenis }
133