1 /* $NetBSD: wbsio.c,v 1.1 2010/02/21 05:16:29 cnst Exp $ */
2 /* $OpenBSD: wbsio.c,v 1.5 2009/03/29 21:53:52 sthen Exp $ */
4 * Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org>
5 * Copyright (c) 2010 Constantine A. Murenin <cnst++@dragonflybsd.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Winbond LPC Super I/O driver.
24 #include <sys/param.h>
26 #include <sys/kernel.h>
27 #include <sys/module.h>
29 #include <sys/systm.h>
31 #include <bus/isa/isavar.h>
33 /* ISA bus registers */
34 #define WBSIO_INDEX 0x00 /* Configuration Index Register */
35 #define WBSIO_DATA 0x01 /* Configuration Data Register */
37 #define WBSIO_IOSIZE 0x02 /* ISA I/O space size */
39 #define WBSIO_CONF_EN_MAGIC 0x87 /* enable configuration mode */
40 #define WBSIO_CONF_DS_MAGIC 0xaa /* disable configuration mode */
42 /* Configuration Space Registers */
43 #define WBSIO_LDN 0x07 /* Logical Device Number */
44 #define WBSIO_ID 0x20 /* Device ID */
45 #define WBSIO_REV 0x21 /* Device Revision */
47 #define WBSIO_ID_W83627HF 0x52
48 #define WBSIO_ID_W83627THF 0x82
49 #define WBSIO_ID_W83627EHF 0x88
50 #define WBSIO_ID_W83627DHG 0xa0
51 #define WBSIO_ID_W83627SF 0x59
52 #define WBSIO_ID_W83637HF 0x70
53 #define WBSIO_ID_W83697HF 0x60
55 /* Logical Device Number (LDN) Assignments */
56 #define WBSIO_LDN_HM 0x0b
58 /* Hardware Monitor Control Registers (LDN B) */
59 #define WBSIO_HM_ADDR_MSB 0x60 /* Address [15:8] */
60 #define WBSIO_HM_ADDR_LSB 0x61 /* Address [7:0] */
63 struct device
*sc_dev
;
65 struct resource
*sc_iores
;
68 bus_space_tag_t sc_iot
;
69 bus_space_handle_t sc_ioh
;
72 static int wbsio_probe(struct device
*);
73 static int wbsio_attach(struct device
*);
74 static int wbsio_detach(struct device
*);
76 static device_method_t wbsio_methods
[] = {
77 DEVMETHOD(device_probe
, wbsio_probe
),
78 DEVMETHOD(device_attach
, wbsio_attach
),
79 DEVMETHOD(device_detach
, wbsio_detach
),
84 static driver_t wbsio_driver
= {
87 sizeof(struct wbsio_softc
)
90 static devclass_t wbsio_devclass
;
92 DRIVER_MODULE(wbsio
, isa
, wbsio_driver
, wbsio_devclass
, NULL
, NULL
);
96 wbsio_conf_enable(bus_space_tag_t iot
, bus_space_handle_t ioh
)
98 bus_space_write_1(iot
, ioh
, WBSIO_INDEX
, WBSIO_CONF_EN_MAGIC
);
99 bus_space_write_1(iot
, ioh
, WBSIO_INDEX
, WBSIO_CONF_EN_MAGIC
);
103 wbsio_conf_disable(bus_space_tag_t iot
, bus_space_handle_t ioh
)
105 bus_space_write_1(iot
, ioh
, WBSIO_INDEX
, WBSIO_CONF_DS_MAGIC
);
108 static __inline u_int8_t
109 wbsio_conf_read(bus_space_tag_t iot
, bus_space_handle_t ioh
, u_int8_t index
)
111 bus_space_write_1(iot
, ioh
, WBSIO_INDEX
, index
);
112 return (bus_space_read_1(iot
, ioh
, WBSIO_DATA
));
116 wbsio_conf_write(bus_space_tag_t iot
, bus_space_handle_t ioh
, u_int8_t index
,
119 bus_space_write_1(iot
, ioh
, WBSIO_INDEX
, index
);
120 bus_space_write_1(iot
, ioh
, WBSIO_DATA
, data
);
124 wbsio_probe(struct device
*dev
)
126 struct resource
*iores
;
129 bus_space_handle_t ioh
;
130 uint8_t reg_id
, reg_rev
;
131 const char *desc
= NULL
;
134 /* Match by device ID */
136 iores
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &iorid
,
137 0ul, ~0ul, WBSIO_IOSIZE
,
141 iot
= rman_get_bustag(iores
);
142 ioh
= rman_get_bushandle(iores
);
144 wbsio_conf_enable(iot
, ioh
);
146 reg_id
= wbsio_conf_read(iot
, ioh
, WBSIO_ID
);
147 /* Read device revision */
148 reg_rev
= wbsio_conf_read(iot
, ioh
, WBSIO_REV
);
149 wbsio_conf_disable(iot
, ioh
);
150 bus_release_resource(dev
, SYS_RES_IOPORT
, iorid
, iores
);
153 case WBSIO_ID_W83627HF
:
156 case WBSIO_ID_W83627THF
:
159 case WBSIO_ID_W83627EHF
:
162 case WBSIO_ID_W83627DHG
:
165 case WBSIO_ID_W83637HF
:
168 case WBSIO_ID_W83697HF
:
176 ksnprintf(fulldesc
, sizeof(fulldesc
),
177 "Winbond LPC Super I/O %s rev 0x%02x", desc
, reg_rev
);
178 device_set_desc_copy(dev
, fulldesc
);
183 wbsio_attach(struct device
*dev
)
185 struct wbsio_softc
*sc
= device_get_softc(dev
);
188 struct device
*parent
= device_get_parent(dev
);
189 struct device
*child
;
190 struct devclass
*c_dc
;
193 /* Map ISA I/O space */
194 sc
->sc_iores
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &sc
->sc_iorid
,
195 0ul, ~0ul, WBSIO_IOSIZE
,
197 if (sc
->sc_iores
== NULL
) {
198 device_printf(dev
, "can't map i/o space\n");
201 sc
->sc_iot
= rman_get_bustag(sc
->sc_iores
);
202 sc
->sc_ioh
= rman_get_bushandle(sc
->sc_iores
);
204 /* Enter configuration mode */
205 wbsio_conf_enable(sc
->sc_iot
, sc
->sc_ioh
);
207 /* Select HM logical device */
208 wbsio_conf_write(sc
->sc_iot
, sc
->sc_ioh
, WBSIO_LDN
, WBSIO_LDN_HM
);
211 * The address should be 8-byte aligned, but it seems some
212 * BIOSes ignore this. They get away with it, because
213 * Apparently the hardware simply ignores the lower three
214 * bits. We do the same here.
216 reg0
= wbsio_conf_read(sc
->sc_iot
, sc
->sc_ioh
, WBSIO_HM_ADDR_LSB
);
217 reg1
= wbsio_conf_read(sc
->sc_iot
, sc
->sc_ioh
, WBSIO_HM_ADDR_MSB
);
218 iobase
= (reg1
<< 8) | (reg0
& ~0x7);
219 device_printf(dev
, "hardware monitor iobase is 0x%x\n", iobase
);
221 /* Escape from configuration mode */
222 wbsio_conf_disable(sc
->sc_iot
, sc
->sc_ioh
);
225 device_printf(dev
, "no hardware monitor configured\n");
230 c_dc
= devclass_find("lm");
232 device_printf(dev
, "lm devclass not found\n");
235 c_maxunit
= devclass_get_maxunit(c_dc
);
236 for (int u
= 0; u
< c_maxunit
; u
++) {
237 child
= devclass_get_device(c_dc
, u
);
240 if (isa_get_port(child
) == iobase
) {
241 if (device_is_attached(child
)) {
243 "%s is already attached at 0x%x\n",
244 device_get_nameunit(child
), iobase
);
249 if (device_is_attached(child
)) {
254 "found unused %s at 0x%x with state %i, reusing at 0x%x\n",
255 device_get_nameunit(child
), isa_get_port(child
),
256 device_get_state(child
), iobase
);
260 child
= BUS_ADD_CHILD(parent
, parent
, ISA_ORDER_PNP
,
262 // child = BUS_ADD_CHILD(parent, parent, ISA_ORDER_PNP,
263 // "lm", 3 + device_get_unit(dev));
265 device_printf(dev
, "cannot add child\n");
268 if (bus_set_resource(child
, SYS_RES_IOPORT
, 0, iobase
, 8)) {
269 device_printf(dev
, "cannot set resource\n");
272 return device_probe_and_attach(child
);
276 wbsio_detach(struct device
*dev
)
278 struct wbsio_softc
*sc
= device_get_softc(dev
);
280 return bus_release_resource(dev
, SYS_RES_IOPORT
,
281 sc
->sc_iorid
, sc
->sc_iores
);