xref: /openbsd/sys/dev/pci/viapm.c (revision cecf84d4)
1 /*	$OpenBSD: viapm.c,v 1.16 2012/10/05 10:51:28 haesbaert Exp $	*/
2 
3 /*
4  * Copyright (c) 2005 Mark Kettenis <kettenis@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*	$NetBSD: viaenv.c,v 1.9 2002/10/02 16:51:59 thorpej Exp $	*/
20 
21 /*
22  * Copyright (c) 2000 Johan Danielsson
23  * All rights reserved.
24  *
25  * Redistribution and use in source and binary forms, with or without
26  * modification, are permitted provided that the following conditions
27  * are met:
28  *
29  * 1. Redistributions of source code must retain the above copyright
30  *    notice, this list of conditions and the following disclaimer.
31  *
32  * 2. Redistributions in binary form must reproduce the above copyright
33  *    notice, this list of conditions and the following disclaimer in the
34  *    documentation and/or other materials provided with the distribution.
35  *
36  * 3. Neither the name of author nor the names of any contributors may
37  *    be used to endorse or promote products derived from this
38  *    software without specific prior written permission.
39  *
40  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS
41  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
42  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
44  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
45  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
46  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
48  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
50  * POSSIBILITY OF SUCH DAMAGE.
51  */
52 
53 /*
54  * Driver for the SMBus controller and power management timer
55  * in the VIA VT82C596[B], VT82C686A, VT8231, VT8233[A], VT8235, VT8237[A,S],
56  * VT8251, CX700, VX800 and VX855 South Bridges.
57  * Also for the hardware monitoring part of the VIA VT82C686A and VT8231.
58  */
59 
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/device.h>
63 #include <sys/kernel.h>
64 #include <sys/rwlock.h>
65 #include <sys/sensors.h>
66 #include <sys/timeout.h>
67 #include <sys/timetc.h>
68 
69 #include <machine/bus.h>
70 
71 #include <dev/pci/pcidevs.h>
72 #include <dev/pci/pcireg.h>
73 #include <dev/pci/pcivar.h>
74 
75 #include <dev/i2c/i2cvar.h>
76 
77 /*
78  * Register definitions.
79  */
80 
81 /* PCI configuration registers */
82 #define VIAPM_PM_CFG1		0x40	/* general configuration */
83 #define VIAPM_PM_CFG2		0x80
84 #define VIAPM_PM_CFG_TMR32	(1 << 11)	/* 32-bit PM timer */
85 #define VIAPM_PM_CFG_PMEN	(1 << 15)	/* enable PM I/O space */
86 #define VIAPM_PM_BASE1		0x48	/* power management I/O base address */
87 #define VIAPM_PM_BASE2		0x88
88 #define VIAPM_PM_BASE_MASK	0xff80
89 
90 #define VIAPM_HWMON_BASE	0x70	/* HWMon I/O base address */
91 #define VIAPM_HWMON_BASE_MASK	0xff80
92 #define VIAPM_HWMON_CFG		0x74	/* HWMon control register */
93 #define VIAPM_HWMON_CFG_HWEN	(1 << 0)	/* enable HWMon I/O space */
94 
95 #define VIAPM_SMB_BASE1		0x90	/* SMBus I/O base address */
96 #define VIAPM_SMB_BASE2		0x80
97 #define VIAPM_SMB_BASE3		0xd0
98 #define VIAPM_SMB_BASE_MASK	0xfff0
99 #define VIAPM_SMB_CFG1		0xd2	/* host configuration */
100 #define VIAPM_SMB_CFG2		0x84
101 #define VIAPM_SMB_CFG_HSTEN	(1 << 0)	/* enable SMBus I/O space */
102 #define VIAPM_SMB_CFG_INTEN	(1 << 1)	/* enable SCI/SMI */
103 #define VIAPM_SMB_CFG_SCIEN	(1 << 3)	/* interrupt type (SCI/SMI) */
104 
105 #define VIAPM_PM_SIZE		256	/* Power management I/O space size */
106 #define VIAPM_HWMON_SIZE	128	/* HWMon I/O space size */
107 #define VIAPM_SMB_SIZE		16	/* SMBus I/O space size */
108 
109 /* HWMon I/O registers */
110 #define VIAPM_HWMON_TSENS3	0x1f
111 #define VIAPM_HWMON_TSENS1	0x20
112 #define VIAPM_HWMON_TSENS2	0x21
113 #define VIAPM_HWMON_VSENS1	0x22
114 #define VIAPM_HWMON_VSENS2	0x23
115 #define VIAPM_HWMON_VCORE	0x24
116 #define VIAPM_HWMON_VSENS3	0x25
117 #define VIAPM_HWMON_VSENS4	0x26
118 #define VIAPM_HWMON_FAN1	0x29
119 #define VIAPM_HWMON_FAN2	0x2a
120 #define VIAPM_HWMON_FANCONF	0x47	/* fan configuration */
121 #define VIAPM_HWMON_TLOW	0x49	/* temperature low order value */
122 #define VIAPM_HWMON_TIRQ	0x4b	/* temperature interrupt configuration */
123 
124 /* ACPI I/O registers */
125 #define VIAPM_PM_TMR		0x08	/* PM timer */
126 
127 /* SMBus I/O registers */
128 #define VIAPM_SMB_HS		0x00	/* host status */
129 #define VIAPM_SMB_HS_BUSY	(1 << 0)	/* running a command */
130 #define VIAPM_SMB_HS_INTR	(1 << 1)	/* command completed */
131 #define VIAPM_SMB_HS_DEVERR	(1 << 2)	/* command error */
132 #define VIAPM_SMB_HS_BUSERR	(1 << 3)	/* transaction collision */
133 #define VIAPM_SMB_HS_FAILED	(1 << 4)	/* failed bus transaction */
134 #define VIAPM_SMB_HS_INUSE	(1 << 6)	/* bus semaphore */
135 #define VIAPM_SMB_HS_BITS	\
136   "\020\001BUSY\002INTR\003DEVERR\004BUSERR\005FAILED\007INUSE"
137 #define VIAPM_SMB_HC		0x02	/* host control */
138 #define VIAPM_SMB_HC_INTREN	(1 << 0)	/* enable interrupts */
139 #define VIAPM_SMB_HC_KILL	(1 << 1)	/* kill current transaction */
140 #define VIAPM_SMB_HC_CMD_QUICK	(0 << 2)	/* QUICK command */
141 #define VIAPM_SMB_HC_CMD_BYTE	(1 << 2)	/* BYTE command */
142 #define VIAPM_SMB_HC_CMD_BDATA	(2 << 2)	/* BYTE DATA command */
143 #define VIAPM_SMB_HC_CMD_WDATA	(3 << 2)	/* WORD DATA command */
144 #define VIAPM_SMB_HC_CMD_PCALL	(4 << 2)	/* PROCESS CALL command */
145 #define VIAPM_SMB_HC_CMD_BLOCK	(5 << 2)	/* BLOCK command */
146 #define VIAPM_SMB_HC_START	(1 << 6)	/* start transaction */
147 #define VIAPM_SMB_HCMD		0x03	/* host command */
148 #define VIAPM_SMB_TXSLVA	0x04	/* transmit slave address */
149 #define VIAPM_SMB_TXSLVA_READ	(1 << 0)	/* read direction */
150 #define VIAPM_SMB_TXSLVA_ADDR(x) (((x) & 0x7f) << 1) /* 7-bit address */
151 #define VIAPM_SMB_HD0		0x05	/* host data 0 */
152 #define VIAPM_SMB_HD1		0x06	/* host data 1 */
153 #define VIAPM_SMB_HBDB		0x07	/* host block data byte */
154 
155 #ifdef VIAPM_DEBUG
156 #define DPRINTF(x...) printf(x)
157 #else
158 #define DPRINTF(x...)
159 #endif
160 
161 #define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
162 
163 #define VIAPM_SMBUS_DELAY	100
164 #define VIAPM_SMBUS_TIMEOUT	1
165 
166 #define VIAPM_NUM_SENSORS	10	/* three temp, two fan, five voltage */
167 
168 u_int	viapm_get_timecount(struct timecounter *tc);
169 
170 #ifndef VIAPM_FREQUENCY
171 #define VIAPM_FREQUENCY 3579545
172 #endif
173 
174 static struct timecounter viapm_timecounter = {
175 	viapm_get_timecount,	/* get_timecount */
176 	0,			/* no poll_pps */
177 	0xffffff,		/* counter_mask */
178 	VIAPM_FREQUENCY,	/* frequency */
179 	"VIAPM",		/* name */
180 	1000			/* quality */
181 };
182 
183 struct timeout viapm_timeout;
184 
185 struct viapm_softc {
186 	struct device		sc_dev;
187 
188 	bus_space_tag_t		sc_iot;
189 	bus_space_handle_t	sc_pm_ioh;
190 	bus_space_handle_t	sc_smbus_ioh;
191 	bus_space_handle_t	sc_hwmon_ioh;
192 	void *			sc_ih;
193 	int			sc_poll;
194 
195 	int			sc_fan_div[2];	/* fan RPM divisor */
196 
197 	struct ksensor		sc_data[VIAPM_NUM_SENSORS];
198 	struct ksensordev	sc_sensordev;
199 
200 	struct i2c_controller	sc_i2c_tag;
201 	struct rwlock		sc_i2c_lock;
202 	struct {
203 		i2c_op_t     op;
204 		void *       buf;
205 		size_t       len;
206 		int          flags;
207 		volatile int error;
208 	}			sc_i2c_xfer;
209 };
210 
211 int	viapm_match(struct device *, void *, void *);
212 void	viapm_attach(struct device *, struct device *, void *);
213 
214 int	viapm_i2c_acquire_bus(void *, int);
215 void	viapm_i2c_release_bus(void *, int);
216 int	viapm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
217 	    void *, size_t, int);
218 
219 int	viapm_intr(void *);
220 
221 int	val_to_uK(unsigned int);
222 int	val_to_rpm(unsigned int, int);
223 long	val_to_uV(unsigned int, int);
224 void	viapm_refresh_sensor_data(struct viapm_softc *);
225 void	viapm_refresh(void *);
226 
227 struct cfattach viapm_ca = {
228 	sizeof(struct viapm_softc), viapm_match, viapm_attach
229 };
230 
231 struct cfdriver viapm_cd = {
232 	NULL, "viapm", DV_DULL
233 };
234 
235 const struct pci_matchid viapm_ids[] = {
236 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596 },
237 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596B_PM },
238 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_SMB },
239 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8231_PWR },
240 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_ISA },
241 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233A_ISA },
242 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8235_ISA },
243 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237_ISA },
244 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237A_ISA },
245 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237S_ISA },
246 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8251_ISA },
247 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_CX700_ISA },
248 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VX800_ISA },
249 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VX855_ISA }
250 };
251 
252 /*
253  * XXX there doesn't seem to exist much hard documentation on how to
254  * convert the raw values to usable units, this code is more or less
255  * stolen from the Linux driver, but changed to suit our conditions
256  */
257 
258 /*
259  * lookup-table to translate raw values to uK, this is the same table
260  * used by the Linux driver (modulo units); there is a fifth degree
261  * polynomial that supposedly been used to generate this table, but I
262  * haven't been able to figure out how -- it doesn't give the same values
263  */
264 
265 static const long val_to_temp[] = {
266 	20225, 20435, 20645, 20855, 21045, 21245, 21425, 21615, 21785, 21955,
267 	22125, 22285, 22445, 22605, 22755, 22895, 23035, 23175, 23315, 23445,
268 	23565, 23695, 23815, 23925, 24045, 24155, 24265, 24365, 24465, 24565,
269 	24665, 24765, 24855, 24945, 25025, 25115, 25195, 25275, 25355, 25435,
270 	25515, 25585, 25655, 25725, 25795, 25865, 25925, 25995, 26055, 26115,
271 	26175, 26235, 26295, 26355, 26405, 26465, 26515, 26575, 26625, 26675,
272 	26725, 26775, 26825, 26875, 26925, 26975, 27025, 27065, 27115, 27165,
273 	27205, 27255, 27295, 27345, 27385, 27435, 27475, 27515, 27565, 27605,
274 	27645, 27685, 27735, 27775, 27815, 27855, 27905, 27945, 27985, 28025,
275 	28065, 28105, 28155, 28195, 28235, 28275, 28315, 28355, 28405, 28445,
276 	28485, 28525, 28565, 28615, 28655, 28695, 28735, 28775, 28825, 28865,
277 	28905, 28945, 28995, 29035, 29075, 29125, 29165, 29205, 29245, 29295,
278 	29335, 29375, 29425, 29465, 29505, 29555, 29595, 29635, 29685, 29725,
279 	29765, 29815, 29855, 29905, 29945, 29985, 30035, 30075, 30125, 30165,
280 	30215, 30255, 30305, 30345, 30385, 30435, 30475, 30525, 30565, 30615,
281 	30655, 30705, 30755, 30795, 30845, 30885, 30935, 30975, 31025, 31075,
282 	31115, 31165, 31215, 31265, 31305, 31355, 31405, 31455, 31505, 31545,
283 	31595, 31645, 31695, 31745, 31805, 31855, 31905, 31955, 32005, 32065,
284 	32115, 32175, 32225, 32285, 32335, 32395, 32455, 32515, 32575, 32635,
285 	32695, 32755, 32825, 32885, 32955, 33025, 33095, 33155, 33235, 33305,
286 	33375, 33455, 33525, 33605, 33685, 33765, 33855, 33935, 34025, 34115,
287 	34205, 34295, 34395, 34495, 34595, 34695, 34805, 34905, 35015, 35135,
288 	35245, 35365, 35495, 35615, 35745, 35875, 36015, 36145, 36295, 36435,
289 	36585, 36745, 36895, 37065, 37225, 37395, 37575, 37755, 37935, 38125,
290 	38325, 38525, 38725, 38935, 39155, 39375, 39605, 39835, 40075, 40325,
291 	40575, 40835, 41095, 41375, 41655, 41935,
292 };
293 
294 int
295 viapm_match(struct device *parent, void *match, void *aux)
296 {
297 	return (pci_matchbyid(aux, viapm_ids, nitems(viapm_ids)));
298 }
299 
300 void
301 viapm_attach(struct device *parent, struct device *self, void *aux)
302 {
303 	struct viapm_softc *sc = (struct viapm_softc *)self;
304 	struct pci_attach_args *pa = aux;
305 	struct i2cbus_attach_args iba;
306 	pcireg_t conf, iobase;
307 	pci_intr_handle_t ih;
308 	const char *intrstr = NULL;
309 	int basereg, cfgreg;
310 	int i, v;
311 
312 	sc->sc_iot = pa->pa_iot;
313 
314 	/* SMBus */
315 	switch (PCI_PRODUCT(pa->pa_id)) {
316 	case PCI_PRODUCT_VIATECH_VT82C596:
317 	case PCI_PRODUCT_VIATECH_VT82C596B_PM:
318 	case PCI_PRODUCT_VIATECH_VT82C686A_SMB:
319 	case PCI_PRODUCT_VIATECH_VT8231_PWR:
320 		basereg = VIAPM_SMB_BASE1;
321 		break;
322 	default:
323 		basereg = VIAPM_SMB_BASE3;
324 	}
325 
326 	cfgreg = (VIAPM_SMB_CFG1 & (~0x03));	/* XXX 4-byte aligned */
327 
328 	/* Check 2nd address for VT82C596 */
329 	iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, basereg);
330 	if ((PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT82C596) &&
331 	    ((iobase & 0x0001) == 0)) {
332 		iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_SMB_BASE2);
333 		cfgreg = VIAPM_SMB_CFG2;
334 	}
335 
336 	/* Check if SMBus I/O space is enabled */
337 	conf = pci_conf_read(pa->pa_pc, pa->pa_tag, cfgreg);
338 	if (cfgreg != VIAPM_SMB_CFG2)
339 		conf >>= 16;
340 	DPRINTF(": conf 0x%02x", conf & 0xff);
341 
342 	if ((conf & VIAPM_SMB_CFG_HSTEN) == 0) {
343 		printf(": SMBus disabled\n");
344 		goto nosmb;
345 	}
346 
347 	/* Map SMBus I/O space */
348 	iobase &= VIAPM_SMB_BASE_MASK;
349 	if (iobase == 0 || bus_space_map(sc->sc_iot, iobase,
350 	    VIAPM_SMB_SIZE, 0, &sc->sc_smbus_ioh)) {
351 		printf(": can't map SMBus i/o space\n");
352 		goto nosmb;
353 	}
354 
355 	sc->sc_poll = 1;
356 	if ((conf & VIAPM_SMB_CFG_SCIEN) == 0) {
357 		/* No PCI IRQ */
358 		printf(": SMI");
359 	} else {
360 		/* Install interrupt handler */
361 		if (pci_intr_map(pa, &ih) == 0) {
362 			intrstr = pci_intr_string(pa->pa_pc, ih);
363 			sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
364 			    viapm_intr, sc, DEVNAME(sc));
365 			if (sc->sc_ih != NULL) {
366 				printf(": %s", intrstr);
367 				sc->sc_poll = 0;
368 			}
369 		}
370 		if (sc->sc_poll)
371 			printf(": polling");
372 	}
373 
374 	printf("\n");
375 
376 	/* Attach I2C bus */
377 	rw_init(&sc->sc_i2c_lock, "iiclk");
378 	sc->sc_i2c_tag.ic_cookie = sc;
379 	sc->sc_i2c_tag.ic_acquire_bus = viapm_i2c_acquire_bus;
380 	sc->sc_i2c_tag.ic_release_bus = viapm_i2c_release_bus;
381 	sc->sc_i2c_tag.ic_exec = viapm_i2c_exec;
382 
383 	bzero(&iba, sizeof iba);
384 	iba.iba_name = "iic";
385 	iba.iba_tag = &sc->sc_i2c_tag;
386 	config_found(self, &iba, iicbus_print);
387 
388 nosmb:
389 
390 	/* Power management */
391 	switch (PCI_PRODUCT(pa->pa_id)) {
392 	case PCI_PRODUCT_VIATECH_VT82C596:
393 	case PCI_PRODUCT_VIATECH_VT82C596B_PM:
394 	case PCI_PRODUCT_VIATECH_VT82C686A_SMB:
395 	case PCI_PRODUCT_VIATECH_VT8231_PWR:
396 		basereg = VIAPM_PM_BASE1;
397 		cfgreg = VIAPM_PM_CFG1;
398 		break;
399 	default:
400 		basereg = VIAPM_PM_BASE2;
401 		cfgreg = VIAPM_PM_CFG2;
402 	}
403 
404 	/* Check if power management I/O space is enabled */
405 	conf = pci_conf_read(pa->pa_pc, pa->pa_tag, cfgreg);
406 	if ((conf & VIAPM_PM_CFG_PMEN) == 0) {
407 		printf("%s: PM disabled\n", DEVNAME(sc));
408 		goto nopm;
409 	}
410 
411 	/* Map power management I/O space */
412 	iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, basereg);
413 	iobase &= VIAPM_PM_BASE_MASK;
414 	if (iobase == 0 || bus_space_map(sc->sc_iot, iobase,
415 	    VIAPM_PM_SIZE, 0, &sc->sc_pm_ioh)) {
416 		/* XXX can't map PM i/o space if ACPI mode */
417 		DPRINTF("%s: can't map PM i/o space\n", DEVNAME(sc));
418 		goto nopm;
419 	}
420 
421 	/* Check for 32-bit PM timer */
422 	if (conf & VIAPM_PM_CFG_TMR32)
423 		viapm_timecounter.tc_counter_mask = 0xffffffff;
424 
425 	/* Register new timecounter */
426 	viapm_timecounter.tc_priv = sc;
427 	tc_init(&viapm_timecounter);
428 
429 	printf("%s: %s-bit timer at %lluHz\n", DEVNAME(sc),
430 	    (viapm_timecounter.tc_counter_mask == 0xffffffff ? "32" : "24"),
431 	    (unsigned long long)viapm_timecounter.tc_frequency);
432 
433 nopm:
434 
435 	/* HWMon */
436 	switch (PCI_PRODUCT(pa->pa_id)) {
437 	case PCI_PRODUCT_VIATECH_VT82C686A_SMB:
438 	case PCI_PRODUCT_VIATECH_VT8231_PWR:
439 		break;
440 	default:
441 		return;
442 	}
443 
444 	/* Check if HWMon I/O space is enabled */
445 	conf = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_HWMON_CFG);
446 	if ((conf & VIAPM_HWMON_CFG_HWEN) == 0) {
447 		printf("%s: HWM disabled\n", DEVNAME(sc));
448 		return;
449 	}
450 
451 	/* Map HWMon I/O space */
452 	iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_HWMON_BASE);
453 	iobase &= VIAPM_HWMON_BASE_MASK;
454 	if (iobase == 0 || bus_space_map(sc->sc_iot, iobase,
455 	    VIAPM_HWMON_SIZE, 0, &sc->sc_hwmon_ioh)) {
456 		printf("%s: can't map HWM i/o space\n", DEVNAME(sc));
457 		return;
458 	}
459 
460 	v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_FANCONF);
461 
462 	sc->sc_fan_div[0] = 1 << ((v >> 4) & 0x3);
463 	sc->sc_fan_div[1] = 1 << ((v >> 6) & 0x3);
464 
465 	for (i = 0; i <= 2; i++)
466 		sc->sc_data[i].type = SENSOR_TEMP;
467 	for (i = 3; i <= 4; i++)
468 		sc->sc_data[i].type = SENSOR_FANRPM;
469 	for (i = 5; i <= 9; ++i)
470 		sc->sc_data[i].type = SENSOR_VOLTS_DC;
471 
472 	strlcpy(sc->sc_data[5].desc, "VSENS1",
473 	    sizeof(sc->sc_data[5].desc));	/* CPU core (2V) */
474 	strlcpy(sc->sc_data[6].desc, "VSENS2",
475 	    sizeof(sc->sc_data[6].desc));	/* NB core? (2.5V) */
476 	strlcpy(sc->sc_data[7].desc, "Vcore",
477 	    sizeof(sc->sc_data[7].desc));	/* Vcore (3.3V) */
478 	strlcpy(sc->sc_data[8].desc, "VSENS3",
479 	    sizeof(sc->sc_data[8].desc));	/* VSENS3 (5V) */
480 	strlcpy(sc->sc_data[9].desc, "VSENS4",
481 	    sizeof(sc->sc_data[9].desc));	/* VSENS4 (12V) */
482 
483 	/* Get initial set of sensor values. */
484 	viapm_refresh_sensor_data(sc);
485 
486 	/* Register sensors with sysctl */
487 	strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
488 	    sizeof(sc->sc_sensordev.xname));
489 	for (i = 0; i < VIAPM_NUM_SENSORS; ++i)
490 		sensor_attach(&sc->sc_sensordev, &sc->sc_data[i]);
491 	sensordev_install(&sc->sc_sensordev);
492 
493 	/* Refresh sensors data every 1.5 seconds */
494 	timeout_set(&viapm_timeout, viapm_refresh, sc);
495 	timeout_add_msec(&viapm_timeout, 1500);
496 }
497 
498 int
499 viapm_i2c_acquire_bus(void *cookie, int flags)
500 {
501 	struct viapm_softc *sc = cookie;
502 
503 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
504 		return (0);
505 
506 	return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
507 }
508 
509 void
510 viapm_i2c_release_bus(void *cookie, int flags)
511 {
512 	struct viapm_softc *sc = cookie;
513 
514 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
515 		return;
516 
517 	rw_exit(&sc->sc_i2c_lock);
518 }
519 
520 int
521 viapm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
522     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
523 {
524 	struct viapm_softc *sc = cookie;
525 	u_int8_t *b;
526 	u_int8_t ctl, st;
527 	int retries;
528 
529 	/* Check if there's a transfer already running */
530 	st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS);
531 	DPRINTF("%s: exec op %d, addr 0x%x, cmdlen %d, len %d, "
532 	    "flags 0x%x, status 0x%b\n", DEVNAME(sc), op, addr,
533 	    cmdlen, len, flags, st, VIAPM_SMB_HS_BITS);
534 	if (st & VIAPM_SMB_HS_BUSY)
535 		return (1);
536 
537 	if (cold || sc->sc_poll)
538 		flags |= I2C_F_POLL;
539 
540 	if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
541 		return (1);
542 
543 	/* Setup transfer */
544 	sc->sc_i2c_xfer.op = op;
545 	sc->sc_i2c_xfer.buf = buf;
546 	sc->sc_i2c_xfer.len = len;
547 	sc->sc_i2c_xfer.flags = flags;
548 	sc->sc_i2c_xfer.error = 0;
549 
550 	/* Set slave address and transfer direction */
551 	bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_TXSLVA,
552 	    VIAPM_SMB_TXSLVA_ADDR(addr) |
553 	    (I2C_OP_READ_P(op) ? VIAPM_SMB_TXSLVA_READ : 0));
554 
555 	b = (void *)cmdbuf;
556 	if (cmdlen > 0)
557 		/* Set command byte */
558 		bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh,
559 		    VIAPM_SMB_HCMD, b[0]);
560 
561 	if (I2C_OP_WRITE_P(op)) {
562 		/* Write data */
563 		b = buf;
564 		if (len > 0)
565 			bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh,
566 			    VIAPM_SMB_HD0, b[0]);
567 		if (len > 1)
568 			bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh,
569 			    VIAPM_SMB_HD1, b[1]);
570 	}
571 
572 	/* Set SMBus command */
573 	if (len == 0)
574 		ctl = VIAPM_SMB_HC_CMD_BYTE;
575 	else if (len == 1)
576 		ctl = VIAPM_SMB_HC_CMD_BDATA;
577 	else if (len == 2)
578 		ctl = VIAPM_SMB_HC_CMD_WDATA;
579 	else
580 		panic("%s: unexpected len %zd", __func__, len);
581 
582 	if ((flags & I2C_F_POLL) == 0)
583 		ctl |= VIAPM_SMB_HC_INTREN;
584 
585 	/* Start transaction */
586 	ctl |= VIAPM_SMB_HC_START;
587 	bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HC, ctl);
588 
589 	if (flags & I2C_F_POLL) {
590 		/* Poll for completion */
591 		DELAY(VIAPM_SMBUS_DELAY);
592 		for (retries = 1000; retries > 0; retries--) {
593 			st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh,
594 			    VIAPM_SMB_HS);
595 			if ((st & VIAPM_SMB_HS_BUSY) == 0)
596 				break;
597 			DELAY(VIAPM_SMBUS_DELAY);
598 		}
599 		if (st & VIAPM_SMB_HS_BUSY)
600 			goto timeout;
601 		viapm_intr(sc);
602 	} else {
603 		/* Wait for interrupt */
604 		if (tsleep(sc, PRIBIO, "iicexec", VIAPM_SMBUS_TIMEOUT * hz))
605 			goto timeout;
606 	}
607 
608 	if (sc->sc_i2c_xfer.error)
609 		return (1);
610 
611 	return (0);
612 
613 timeout:
614 	/*
615 	 * Transfer timeout. Kill the transaction and clear status bits.
616 	 */
617 	printf("%s: timeout, status 0x%b\n", DEVNAME(sc), st,
618 	    VIAPM_SMB_HS_BITS);
619 	bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HC,
620 	    VIAPM_SMB_HC_KILL);
621 	DELAY(VIAPM_SMBUS_DELAY);
622 	st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS);
623 	if ((st & VIAPM_SMB_HS_FAILED) == 0)
624 		printf("%s: transaction abort failed, status 0x%b\n",
625 		    DEVNAME(sc), st, VIAPM_SMB_HS_BITS);
626 	bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS, st);
627 	return (1);
628 }
629 
630 int
631 viapm_intr(void *arg)
632 {
633 	struct viapm_softc *sc = arg;
634 	u_int8_t st;
635 	u_int8_t *b;
636 	size_t len;
637 
638 	/* Read status */
639 	st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS);
640 	if ((st & VIAPM_SMB_HS_BUSY) != 0 || (st & (VIAPM_SMB_HS_INTR |
641 	    VIAPM_SMB_HS_DEVERR | VIAPM_SMB_HS_BUSERR |
642 	    VIAPM_SMB_HS_FAILED)) == 0)
643 		/* Interrupt was not for us */
644 		return (0);
645 
646 	DPRINTF("%s: intr st 0x%b\n", DEVNAME(sc), st, VIAPM_SMB_HS_BITS);
647 
648 	/* Clear status bits */
649 	bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS, st);
650 
651 	/* Check for errors */
652 	if (st & (VIAPM_SMB_HS_DEVERR | VIAPM_SMB_HS_BUSERR |
653 	    VIAPM_SMB_HS_FAILED)) {
654 		sc->sc_i2c_xfer.error = 1;
655 		goto done;
656 	}
657 
658 	if (st & VIAPM_SMB_HS_INTR) {
659 		if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
660 			goto done;
661 
662 		/* Read data */
663 		b = sc->sc_i2c_xfer.buf;
664 		len = sc->sc_i2c_xfer.len;
665 		if (len > 0)
666 			b[0] = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh,
667 			    VIAPM_SMB_HD0);
668 		if (len > 1)
669 			b[1] = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh,
670 			    VIAPM_SMB_HD1);
671 	}
672 
673 done:
674 	if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
675 		wakeup(sc);
676 	return (1);
677 }
678 
679 int
680 val_to_uK(unsigned int val)
681 {
682 	int i = val / 4;
683 	int j = val % 4;
684 
685 	KASSERT(i >= 0 && i <= 255);
686 
687 	if (j == 0 || i == 255)
688 		return val_to_temp[i] * 10000;
689 
690 	/* is linear interpolation ok? */
691 	return (val_to_temp[i] * (4 - j) +
692 	    val_to_temp[i + 1] * j) * 2500 /* really: / 4 * 10000 */ ;
693 }
694 
695 int
696 val_to_rpm(unsigned int val, int div)
697 {
698 	if (val == 0)
699 		return 0;
700 
701 	return 1350000 / val / div;
702 }
703 
704 long
705 val_to_uV(unsigned int val, int index)
706 {
707 	static const long mult[] =
708 	    {1250000, 1250000, 1670000, 2600000, 6300000};
709 
710 	KASSERT(index >= 0 && index <= 4);
711 
712 	return (25LL * val + 133) * mult[index] / 2628;
713 }
714 
715 void
716 viapm_refresh_sensor_data(struct viapm_softc *sc)
717 {
718 	int i;
719 	u_int8_t v, v2;
720 
721 	/* temperature */
722 	v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TIRQ);
723 	v2 = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TSENS1);
724 	DPRINTF("%s: TSENS1 = %d\n", DEVNAME(sc), (v2 << 2) | (v >> 6));
725 	sc->sc_data[0].value = val_to_uK((v2 << 2) | (v >> 6));
726 
727 	v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TLOW);
728 	v2 = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TSENS2);
729 	DPRINTF("%s: TSENS2 = %d\n", DEVNAME(sc), (v2 << 2) | ((v >> 4) & 0x3));
730 	sc->sc_data[1].value = val_to_uK((v2 << 2) | ((v >> 4) & 0x3));
731 
732 	v2 = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TSENS3);
733 	DPRINTF("%s: TSENS3 = %d\n", DEVNAME(sc), (v2 << 2) | (v >> 6));
734 	sc->sc_data[2].value = val_to_uK((v2 << 2) | (v >> 6));
735 
736 	/* fan */
737 	for (i = 3; i <= 4; i++) {
738 		v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh,
739 		    VIAPM_HWMON_FAN1 + i - 3);
740 		DPRINTF("%s: FAN%d = %d / %d\n", DEVNAME(sc), i - 3, v,
741 		    sc->sc_fan_div[i - 3]);
742 		sc->sc_data[i].value = val_to_rpm(v, sc->sc_fan_div[i - 3]);
743 	}
744 
745 	/* voltage */
746 	for (i = 5; i <= 9; i++) {
747 		v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh,
748 		    VIAPM_HWMON_VSENS1 + i - 5);
749 		DPRINTF("%s: V%d = %d\n", DEVNAME(sc), i - 5, v);
750 		sc->sc_data[i].value = val_to_uV(v, i - 5);
751 	}
752 }
753 
754 void
755 viapm_refresh(void *arg)
756 {
757 	struct viapm_softc *sc = (struct viapm_softc *)arg;
758 
759 	viapm_refresh_sensor_data(sc);
760 	timeout_add_msec(&viapm_timeout, 1500);
761 }
762 
763 u_int
764 viapm_get_timecount(struct timecounter *tc)
765 {
766 	struct viapm_softc *sc = tc->tc_priv;
767 	u_int u1, u2, u3;
768 
769 	u2 = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, VIAPM_PM_TMR);
770 	u3 = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, VIAPM_PM_TMR);
771 	do {
772 		u1 = u2;
773 		u2 = u3;
774 		u3 = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, VIAPM_PM_TMR);
775 	} while (u1 > u2 || u2 > u3);
776 
777 	return (u2);
778 }
779