xref: /dragonfly/sys/dev/powermng/wbsio/wbsio.c (revision 5d302545)
1a5261280SConstantine A. Murenin /*	$NetBSD: wbsio.c,v 1.1 2010/02/21 05:16:29 cnst Exp $	*/
2a5261280SConstantine A. Murenin /*	$OpenBSD: wbsio.c,v 1.5 2009/03/29 21:53:52 sthen Exp $	*/
3a5261280SConstantine A. Murenin /*
4a5261280SConstantine A. Murenin  * Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org>
5f81520edSConstantine A. Murenin  * Copyright (c) 2010 Constantine A. Murenin <cnst++@dragonflybsd.org>
6a5261280SConstantine A. Murenin  *
7a5261280SConstantine A. Murenin  * Permission to use, copy, modify, and distribute this software for any
8a5261280SConstantine A. Murenin  * purpose with or without fee is hereby granted, provided that the above
9a5261280SConstantine A. Murenin  * copyright notice and this permission notice appear in all copies.
10a5261280SConstantine A. Murenin  *
11a5261280SConstantine A. Murenin  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12a5261280SConstantine A. Murenin  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13a5261280SConstantine A. Murenin  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14a5261280SConstantine A. Murenin  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15a5261280SConstantine A. Murenin  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16a5261280SConstantine A. Murenin  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17a5261280SConstantine A. Murenin  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18a5261280SConstantine A. Murenin  */
19a5261280SConstantine A. Murenin 
20a5261280SConstantine A. Murenin /*
21a5261280SConstantine A. Murenin  * Winbond LPC Super I/O driver.
22a5261280SConstantine A. Murenin  */
23a5261280SConstantine A. Murenin 
24a5261280SConstantine A. Murenin #include <sys/param.h>
25f81520edSConstantine A. Murenin #include <sys/bus.h>
26a5261280SConstantine A. Murenin #include <sys/kernel.h>
27f81520edSConstantine A. Murenin #include <sys/module.h>
28f81520edSConstantine A. Murenin #include <sys/rman.h>
29a5261280SConstantine A. Murenin #include <sys/systm.h>
30a5261280SConstantine A. Murenin 
31f81520edSConstantine A. Murenin #include <bus/isa/isavar.h>
321d3c4164SMatthew Dillon #include <bus/isa/isa_common.h>
33a5261280SConstantine A. Murenin 
341d3c4164SMatthew Dillon #include "wbsioreg.h"
351d3c4164SMatthew Dillon #include "wbsiovar.h"
36a5261280SConstantine A. Murenin 
37*5d302545SFrançois Tigeot static void	wbsio_identify(driver_t *, device_t);
38*5d302545SFrançois Tigeot static int	wbsio_probe(device_t);
39*5d302545SFrançois Tigeot static int	wbsio_attach(device_t);
40*5d302545SFrançois Tigeot static int	wbsio_detach(device_t);
41a5261280SConstantine A. Murenin 
42f81520edSConstantine A. Murenin static device_method_t wbsio_methods[] = {
431d3c4164SMatthew Dillon 	/* Device interface */
44fa130c02SConstantine A. Murenin 	DEVMETHOD(device_identify,	wbsio_identify),
45f81520edSConstantine A. Murenin 	DEVMETHOD(device_probe,		wbsio_probe),
46f81520edSConstantine A. Murenin 	DEVMETHOD(device_attach, 	wbsio_attach),
47f81520edSConstantine A. Murenin 	DEVMETHOD(device_detach,	wbsio_detach),
48f81520edSConstantine A. Murenin 
491d3c4164SMatthew Dillon 	/* Bus interface */
501d3c4164SMatthew Dillon 	DEVMETHOD(bus_add_child,	bus_generic_add_child),
511d3c4164SMatthew Dillon 	DEVMETHOD(bus_set_resource,	bus_generic_set_resource),
521d3c4164SMatthew Dillon 	DEVMETHOD(bus_alloc_resource,	isa_alloc_resource),
531d3c4164SMatthew Dillon 	DEVMETHOD(bus_release_resource,	isa_release_resource),
541d3c4164SMatthew Dillon 	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
551d3c4164SMatthew Dillon 	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
561d3c4164SMatthew Dillon 
571d3c4164SMatthew Dillon 	DEVMETHOD_END
58f81520edSConstantine A. Murenin };
59f81520edSConstantine A. Murenin 
60f81520edSConstantine A. Murenin static driver_t wbsio_driver = {
61f81520edSConstantine A. Murenin 	"wbsio",
62f81520edSConstantine A. Murenin 	wbsio_methods,
63f81520edSConstantine A. Murenin 	sizeof(struct wbsio_softc)
64f81520edSConstantine A. Murenin };
65f81520edSConstantine A. Murenin 
66f81520edSConstantine A. Murenin static devclass_t wbsio_devclass;
67f81520edSConstantine A. Murenin 
68f81520edSConstantine A. Murenin DRIVER_MODULE(wbsio, isa, wbsio_driver, wbsio_devclass, NULL, NULL);
69f81520edSConstantine A. Murenin 
70a5261280SConstantine A. Murenin 
71a5261280SConstantine A. Murenin static __inline void
wbsio_conf_enable(bus_space_tag_t iot,bus_space_handle_t ioh)72a5261280SConstantine A. Murenin wbsio_conf_enable(bus_space_tag_t iot, bus_space_handle_t ioh)
73a5261280SConstantine A. Murenin {
74a5261280SConstantine A. Murenin 	bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC);
75a5261280SConstantine A. Murenin 	bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_EN_MAGIC);
76a5261280SConstantine A. Murenin }
77a5261280SConstantine A. Murenin 
78a5261280SConstantine A. Murenin static __inline void
wbsio_conf_disable(bus_space_tag_t iot,bus_space_handle_t ioh)79a5261280SConstantine A. Murenin wbsio_conf_disable(bus_space_tag_t iot, bus_space_handle_t ioh)
80a5261280SConstantine A. Murenin {
81a5261280SConstantine A. Murenin 	bus_space_write_1(iot, ioh, WBSIO_INDEX, WBSIO_CONF_DS_MAGIC);
82a5261280SConstantine A. Murenin }
83a5261280SConstantine A. Murenin 
84a5261280SConstantine A. Murenin static __inline u_int8_t
wbsio_conf_read(bus_space_tag_t iot,bus_space_handle_t ioh,u_int8_t index)85a5261280SConstantine A. Murenin wbsio_conf_read(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t index)
86a5261280SConstantine A. Murenin {
87a5261280SConstantine A. Murenin 	bus_space_write_1(iot, ioh, WBSIO_INDEX, index);
88a5261280SConstantine A. Murenin 	return (bus_space_read_1(iot, ioh, WBSIO_DATA));
89a5261280SConstantine A. Murenin }
90a5261280SConstantine A. Murenin 
91a5261280SConstantine A. Murenin static __inline void
wbsio_conf_write(bus_space_tag_t iot,bus_space_handle_t ioh,u_int8_t index,u_int8_t data)92a5261280SConstantine A. Murenin wbsio_conf_write(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t index,
93a5261280SConstantine A. Murenin     u_int8_t data)
94a5261280SConstantine A. Murenin {
95a5261280SConstantine A. Murenin 	bus_space_write_1(iot, ioh, WBSIO_INDEX, index);
96a5261280SConstantine A. Murenin 	bus_space_write_1(iot, ioh, WBSIO_DATA, data);
97a5261280SConstantine A. Murenin }
98a5261280SConstantine A. Murenin 
99fa130c02SConstantine A. Murenin static void
wbsio_identify(driver_t * driver,device_t parent)100*5d302545SFrançois Tigeot wbsio_identify(driver_t *driver, device_t parent)
101fa130c02SConstantine A. Murenin {
102fa130c02SConstantine A. Murenin #ifdef KLD_MODULE
103*5d302545SFrançois Tigeot 	device_t child[2];
104fa130c02SConstantine A. Murenin 	const int port[2] = { 0x2e, 0x4e };
105fa130c02SConstantine A. Murenin 
106fa130c02SConstantine A. Murenin 	for (int i = 0; i < 2; i++) {
107fa130c02SConstantine A. Murenin 		child[i] = device_find_child(parent, driver->name, i);
108fa130c02SConstantine A. Murenin 		if (child[i] == NULL) {
109fa130c02SConstantine A. Murenin 			child[i] = BUS_ADD_CHILD(parent, parent, ISA_ORDER_PNP,
110fa130c02SConstantine A. Murenin 			    driver->name, i);
111fa130c02SConstantine A. Murenin 			if (child[i] == NULL) {
112fa130c02SConstantine A. Murenin 				kprintf("%s: cannot add child[%i]\n",
113fa130c02SConstantine A. Murenin 				    __func__, i);
114fa130c02SConstantine A. Murenin 				continue;
115fa130c02SConstantine A. Murenin 			}
116fa130c02SConstantine A. Murenin 		} else
117fa130c02SConstantine A. Murenin 			continue;
118fa130c02SConstantine A. Murenin 		if (bus_set_resource(child[i], SYS_RES_IOPORT, 0,
119b47b3275SSepherosa Ziehau 			port[i], WBSIO_IOSIZE, -1))
120fa130c02SConstantine A. Murenin 			kprintf("%s: cannot set resource for child[%i]\n",
121fa130c02SConstantine A. Murenin 			    __func__, i);
122fa130c02SConstantine A. Murenin 	}
123fa130c02SConstantine A. Murenin #endif
124fa130c02SConstantine A. Murenin }
125fa130c02SConstantine A. Murenin 
126f81520edSConstantine A. Murenin static int
wbsio_probe(device_t dev)127*5d302545SFrançois Tigeot wbsio_probe(device_t dev)
128a5261280SConstantine A. Murenin {
129f81520edSConstantine A. Murenin 	struct resource *iores;
130f81520edSConstantine A. Murenin 	int iorid = 0;
131a5261280SConstantine A. Murenin 	bus_space_tag_t iot;
132a5261280SConstantine A. Murenin 	bus_space_handle_t ioh;
133f81520edSConstantine A. Murenin 	uint8_t reg_id, reg_rev;
134f81520edSConstantine A. Murenin 	const char *desc = NULL;
135f81520edSConstantine A. Murenin 	char fulldesc[64];
136a5261280SConstantine A. Murenin 
137a5261280SConstantine A. Murenin 	/* Match by device ID */
138f81520edSConstantine A. Murenin 
139f81520edSConstantine A. Murenin 	iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
140f81520edSConstantine A. Murenin 	    0ul, ~0ul, WBSIO_IOSIZE,
141f81520edSConstantine A. Murenin 	    RF_ACTIVE);
142f81520edSConstantine A. Murenin 	if (iores == NULL)
143f81520edSConstantine A. Murenin 		return ENXIO;
144f81520edSConstantine A. Murenin 	iot = rman_get_bustag(iores);
145f81520edSConstantine A. Murenin 	ioh = rman_get_bushandle(iores);
146f81520edSConstantine A. Murenin 
147a5261280SConstantine A. Murenin 	wbsio_conf_enable(iot, ioh);
148a5261280SConstantine A. Murenin 	/* Read device ID */
149f81520edSConstantine A. Murenin 	reg_id = wbsio_conf_read(iot, ioh, WBSIO_ID);
150f81520edSConstantine A. Murenin 	/* Read device revision */
151f81520edSConstantine A. Murenin 	reg_rev = wbsio_conf_read(iot, ioh, WBSIO_REV);
152f81520edSConstantine A. Murenin 	wbsio_conf_disable(iot, ioh);
153f81520edSConstantine A. Murenin 	bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
154f81520edSConstantine A. Murenin 
155f81520edSConstantine A. Murenin 	switch (reg_id) {
156a5261280SConstantine A. Murenin 	case WBSIO_ID_W83627HF:
157a5261280SConstantine A. Murenin 		desc = "W83627HF";
158a5261280SConstantine A. Murenin 		break;
159a5261280SConstantine A. Murenin 	case WBSIO_ID_W83627THF:
160a5261280SConstantine A. Murenin 		desc = "W83627THF";
161a5261280SConstantine A. Murenin 		break;
162a5261280SConstantine A. Murenin 	case WBSIO_ID_W83627EHF:
163a5261280SConstantine A. Murenin 		desc = "W83627EHF";
164a5261280SConstantine A. Murenin 		break;
165a5261280SConstantine A. Murenin 	case WBSIO_ID_W83627DHG:
166a5261280SConstantine A. Murenin 		desc = "W83627DHG";
167a5261280SConstantine A. Murenin 		break;
1682c20825bSConstantine A. Murenin 	case WBSIO_ID_W83627DHGP:
1692c20825bSConstantine A. Murenin 		desc = "W83627DHG-P";
1702c20825bSConstantine A. Murenin 		break;
171245ec76bSConstantine A. Murenin 	case WBSIO_ID_W83627UHG:
172245ec76bSConstantine A. Murenin 		desc = "W83627UHG";
173245ec76bSConstantine A. Murenin 		break;
174a5261280SConstantine A. Murenin 	case WBSIO_ID_W83637HF:
175a5261280SConstantine A. Murenin 		desc = "W83637HF";
176a5261280SConstantine A. Murenin 		break;
1771c486d4bSConstantine A. Murenin 	case WBSIO_ID_W83667HG:
1781c486d4bSConstantine A. Murenin 		desc = "W83667HG";
1791c486d4bSConstantine A. Murenin 		break;
18098037633SConstantine A. Murenin 	case WBSIO_ID_W83687THF:
18198037633SConstantine A. Murenin 		desc = "W83687THF";
18298037633SConstantine A. Murenin 		break;
183a5261280SConstantine A. Murenin 	case WBSIO_ID_W83697HF:
184a5261280SConstantine A. Murenin 		desc = "W83697HF";
185a5261280SConstantine A. Murenin 		break;
1861d3c4164SMatthew Dillon 	case WBSIO_ID_NCT6776F:
1871d3c4164SMatthew Dillon 		desc = "NCT6776F";
1881d3c4164SMatthew Dillon 		break;
189a5261280SConstantine A. Murenin 	}
190a5261280SConstantine A. Murenin 
1912d0bc204SConstantine A. Murenin 	if (desc == NULL) {
1922d0bc204SConstantine A. Murenin #ifndef KLD_MODULE
1932d0bc204SConstantine A. Murenin 		if (bootverbose)
1942d0bc204SConstantine A. Murenin #endif
19527a3408eSConstantine A. Murenin 			if (!(reg_id == 0xff && reg_rev == 0xff))
1962d0bc204SConstantine A. Murenin 				device_printf(dev, "%s port 0x%02x: "
1972d0bc204SConstantine A. Murenin 				    "Device ID 0x%02x, Rev 0x%02x\n",
19827a3408eSConstantine A. Murenin 				    __func__, isa_get_port(dev),
19927a3408eSConstantine A. Murenin 				    reg_id, reg_rev);
200f81520edSConstantine A. Murenin 		return ENXIO;
2012d0bc204SConstantine A. Murenin 	}
202a5261280SConstantine A. Murenin 
203f81520edSConstantine A. Murenin 	ksnprintf(fulldesc, sizeof(fulldesc),
204f81520edSConstantine A. Murenin 	    "Winbond LPC Super I/O %s rev 0x%02x", desc, reg_rev);
205f81520edSConstantine A. Murenin 	device_set_desc_copy(dev, fulldesc);
206f81520edSConstantine A. Murenin 	return 0;
207f81520edSConstantine A. Murenin }
208f81520edSConstantine A. Murenin 
209f81520edSConstantine A. Murenin static int
wbsio_attach(device_t dev)210*5d302545SFrançois Tigeot wbsio_attach(device_t dev)
211f81520edSConstantine A. Murenin {
212f81520edSConstantine A. Murenin 	struct wbsio_softc *sc = device_get_softc(dev);
213f81520edSConstantine A. Murenin 	uint8_t reg0, reg1;
214f81520edSConstantine A. Murenin 	uint16_t iobase;
215*5d302545SFrançois Tigeot 	device_t child;
216f81520edSConstantine A. Murenin 
217f81520edSConstantine A. Murenin 	/* Map ISA I/O space */
218f81520edSConstantine A. Murenin 	sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid,
219f81520edSConstantine A. Murenin 	    0ul, ~0ul, WBSIO_IOSIZE,
220f81520edSConstantine A. Murenin 	    RF_ACTIVE);
221f81520edSConstantine A. Murenin 	if (sc->sc_iores == NULL) {
222f81520edSConstantine A. Murenin 		device_printf(dev, "can't map i/o space\n");
223f81520edSConstantine A. Murenin 		return ENXIO;
224f81520edSConstantine A. Murenin 	}
225f81520edSConstantine A. Murenin 	sc->sc_iot = rman_get_bustag(sc->sc_iores);
226f81520edSConstantine A. Murenin 	sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
227f81520edSConstantine A. Murenin 
228f81520edSConstantine A. Murenin 	/* Enter configuration mode */
229f81520edSConstantine A. Murenin 	wbsio_conf_enable(sc->sc_iot, sc->sc_ioh);
230a5261280SConstantine A. Murenin 
2311d3c4164SMatthew Dillon 	/* Read device ID */
2321d3c4164SMatthew Dillon 	sc->sc_devid = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_ID);
2331d3c4164SMatthew Dillon 
234a5261280SConstantine A. Murenin 	/* Select HM logical device */
235a5261280SConstantine A. Murenin 	wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_HM);
236a5261280SConstantine A. Murenin 
237a5261280SConstantine A. Murenin 	/*
238a5261280SConstantine A. Murenin 	 * The address should be 8-byte aligned, but it seems some
239a5261280SConstantine A. Murenin 	 * BIOSes ignore this.  They get away with it, because
240a5261280SConstantine A. Murenin 	 * Apparently the hardware simply ignores the lower three
241a5261280SConstantine A. Murenin 	 * bits.  We do the same here.
242a5261280SConstantine A. Murenin 	 */
243a5261280SConstantine A. Murenin 	reg0 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_LSB);
244a5261280SConstantine A. Murenin 	reg1 = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_HM_ADDR_MSB);
245a5261280SConstantine A. Murenin 	iobase = (reg1 << 8) | (reg0 & ~0x7);
246f81520edSConstantine A. Murenin 	device_printf(dev, "hardware monitor iobase is 0x%x\n", iobase);
247a5261280SConstantine A. Murenin 
248a5261280SConstantine A. Murenin 	/* Escape from configuration mode */
249a5261280SConstantine A. Murenin 	wbsio_conf_disable(sc->sc_iot, sc->sc_ioh);
250a5261280SConstantine A. Murenin 
251f81520edSConstantine A. Murenin 	if (iobase == 0) {
252f81520edSConstantine A. Murenin 		device_printf(dev, "no hardware monitor configured\n");
253f81520edSConstantine A. Murenin 		return 0;
254a5261280SConstantine A. Murenin 	}
255a5261280SConstantine A. Murenin 
2561d3c4164SMatthew Dillon 	child = BUS_ADD_CHILD(dev, dev, 0, "lm", -1);
257f81520edSConstantine A. Murenin 	if (child == NULL) {
258f81520edSConstantine A. Murenin 		device_printf(dev, "cannot add child\n");
259f81520edSConstantine A. Murenin 		return ENXIO;
260f81520edSConstantine A. Murenin 	}
261b47b3275SSepherosa Ziehau 	if (bus_set_resource(child, SYS_RES_IOPORT, 0, iobase, 8, -1)) {
262f81520edSConstantine A. Murenin 		device_printf(dev, "cannot set resource\n");
263f81520edSConstantine A. Murenin 		return ENXIO;
264f81520edSConstantine A. Murenin 	}
265f81520edSConstantine A. Murenin 	return device_probe_and_attach(child);
266f81520edSConstantine A. Murenin }
267a5261280SConstantine A. Murenin 
268f81520edSConstantine A. Murenin static int
wbsio_detach(device_t dev)269*5d302545SFrançois Tigeot wbsio_detach(device_t dev)
270f81520edSConstantine A. Murenin {
271f81520edSConstantine A. Murenin 	struct wbsio_softc *sc = device_get_softc(dev);
272f81520edSConstantine A. Murenin 
273f81520edSConstantine A. Murenin 	return bus_release_resource(dev, SYS_RES_IOPORT,
274f81520edSConstantine A. Murenin 	    sc->sc_iorid, sc->sc_iores);
275a5261280SConstantine A. Murenin }
276