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