xref: /openbsd-src/sys/dev/pci/viapm.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /*	$OpenBSD: viapm.c,v 1.19 2020/07/06 13:33:09 pirofti 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, VX855 and VX900 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 	NULL,			/* private bits */
182 	0,			/* expose to user */
183 };
184 
185 struct timeout viapm_timeout;
186 
187 struct viapm_softc {
188 	struct device		sc_dev;
189 
190 	bus_space_tag_t		sc_iot;
191 	bus_space_handle_t	sc_pm_ioh;
192 	bus_space_handle_t	sc_smbus_ioh;
193 	bus_space_handle_t	sc_hwmon_ioh;
194 	void *			sc_ih;
195 	int			sc_poll;
196 
197 	int			sc_fan_div[2];	/* fan RPM divisor */
198 
199 	struct ksensor		sc_data[VIAPM_NUM_SENSORS];
200 	struct ksensordev	sc_sensordev;
201 
202 	struct i2c_controller	sc_i2c_tag;
203 	struct rwlock		sc_i2c_lock;
204 	struct {
205 		i2c_op_t     op;
206 		void *       buf;
207 		size_t       len;
208 		int          flags;
209 		volatile int error;
210 	}			sc_i2c_xfer;
211 };
212 
213 int	viapm_match(struct device *, void *, void *);
214 void	viapm_attach(struct device *, struct device *, void *);
215 
216 int	viapm_i2c_acquire_bus(void *, int);
217 void	viapm_i2c_release_bus(void *, int);
218 int	viapm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
219 	    void *, size_t, int);
220 
221 int	viapm_intr(void *);
222 
223 int	val_to_uK(unsigned int);
224 int	val_to_rpm(unsigned int, int);
225 long	val_to_uV(unsigned int, int);
226 void	viapm_refresh_sensor_data(struct viapm_softc *);
227 void	viapm_refresh(void *);
228 
229 struct cfattach viapm_ca = {
230 	sizeof(struct viapm_softc), viapm_match, viapm_attach
231 };
232 
233 struct cfdriver viapm_cd = {
234 	NULL, "viapm", DV_DULL
235 };
236 
237 const struct pci_matchid viapm_ids[] = {
238 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596 },
239 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596B_PM },
240 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_SMB },
241 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8231_PWR },
242 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_ISA },
243 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233A_ISA },
244 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8235_ISA },
245 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237_ISA },
246 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237A_ISA },
247 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237S_ISA },
248 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8251_ISA },
249 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_CX700_ISA },
250 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VX800_ISA },
251 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VX855_ISA },
252 	{ PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VX900_ISA }
253 };
254 
255 /*
256  * XXX there doesn't seem to exist much hard documentation on how to
257  * convert the raw values to usable units, this code is more or less
258  * stolen from the Linux driver, but changed to suit our conditions
259  */
260 
261 /*
262  * lookup-table to translate raw values to uK, this is the same table
263  * used by the Linux driver (modulo units); there is a fifth degree
264  * polynomial that supposedly been used to generate this table, but I
265  * haven't been able to figure out how -- it doesn't give the same values
266  */
267 
268 static const long val_to_temp[] = {
269 	20225, 20435, 20645, 20855, 21045, 21245, 21425, 21615, 21785, 21955,
270 	22125, 22285, 22445, 22605, 22755, 22895, 23035, 23175, 23315, 23445,
271 	23565, 23695, 23815, 23925, 24045, 24155, 24265, 24365, 24465, 24565,
272 	24665, 24765, 24855, 24945, 25025, 25115, 25195, 25275, 25355, 25435,
273 	25515, 25585, 25655, 25725, 25795, 25865, 25925, 25995, 26055, 26115,
274 	26175, 26235, 26295, 26355, 26405, 26465, 26515, 26575, 26625, 26675,
275 	26725, 26775, 26825, 26875, 26925, 26975, 27025, 27065, 27115, 27165,
276 	27205, 27255, 27295, 27345, 27385, 27435, 27475, 27515, 27565, 27605,
277 	27645, 27685, 27735, 27775, 27815, 27855, 27905, 27945, 27985, 28025,
278 	28065, 28105, 28155, 28195, 28235, 28275, 28315, 28355, 28405, 28445,
279 	28485, 28525, 28565, 28615, 28655, 28695, 28735, 28775, 28825, 28865,
280 	28905, 28945, 28995, 29035, 29075, 29125, 29165, 29205, 29245, 29295,
281 	29335, 29375, 29425, 29465, 29505, 29555, 29595, 29635, 29685, 29725,
282 	29765, 29815, 29855, 29905, 29945, 29985, 30035, 30075, 30125, 30165,
283 	30215, 30255, 30305, 30345, 30385, 30435, 30475, 30525, 30565, 30615,
284 	30655, 30705, 30755, 30795, 30845, 30885, 30935, 30975, 31025, 31075,
285 	31115, 31165, 31215, 31265, 31305, 31355, 31405, 31455, 31505, 31545,
286 	31595, 31645, 31695, 31745, 31805, 31855, 31905, 31955, 32005, 32065,
287 	32115, 32175, 32225, 32285, 32335, 32395, 32455, 32515, 32575, 32635,
288 	32695, 32755, 32825, 32885, 32955, 33025, 33095, 33155, 33235, 33305,
289 	33375, 33455, 33525, 33605, 33685, 33765, 33855, 33935, 34025, 34115,
290 	34205, 34295, 34395, 34495, 34595, 34695, 34805, 34905, 35015, 35135,
291 	35245, 35365, 35495, 35615, 35745, 35875, 36015, 36145, 36295, 36435,
292 	36585, 36745, 36895, 37065, 37225, 37395, 37575, 37755, 37935, 38125,
293 	38325, 38525, 38725, 38935, 39155, 39375, 39605, 39835, 40075, 40325,
294 	40575, 40835, 41095, 41375, 41655, 41935,
295 };
296 
297 int
298 viapm_match(struct device *parent, void *match, void *aux)
299 {
300 	return (pci_matchbyid(aux, viapm_ids, nitems(viapm_ids)));
301 }
302 
303 void
304 viapm_attach(struct device *parent, struct device *self, void *aux)
305 {
306 	struct viapm_softc *sc = (struct viapm_softc *)self;
307 	struct pci_attach_args *pa = aux;
308 	struct i2cbus_attach_args iba;
309 	pcireg_t conf, iobase;
310 	pci_intr_handle_t ih;
311 	const char *intrstr = NULL;
312 	int basereg, cfgreg;
313 	int i, v;
314 
315 	sc->sc_iot = pa->pa_iot;
316 
317 	/* SMBus */
318 	switch (PCI_PRODUCT(pa->pa_id)) {
319 	case PCI_PRODUCT_VIATECH_VT82C596:
320 	case PCI_PRODUCT_VIATECH_VT82C596B_PM:
321 	case PCI_PRODUCT_VIATECH_VT82C686A_SMB:
322 	case PCI_PRODUCT_VIATECH_VT8231_PWR:
323 		basereg = VIAPM_SMB_BASE1;
324 		break;
325 	default:
326 		basereg = VIAPM_SMB_BASE3;
327 	}
328 
329 	cfgreg = (VIAPM_SMB_CFG1 & (~0x03));	/* XXX 4-byte aligned */
330 
331 	/* Check 2nd address for VT82C596 */
332 	iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, basereg);
333 	if ((PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT82C596) &&
334 	    ((iobase & 0x0001) == 0)) {
335 		iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_SMB_BASE2);
336 		cfgreg = VIAPM_SMB_CFG2;
337 	}
338 
339 	/* Check if SMBus I/O space is enabled */
340 	conf = pci_conf_read(pa->pa_pc, pa->pa_tag, cfgreg);
341 	if (cfgreg != VIAPM_SMB_CFG2)
342 		conf >>= 16;
343 	DPRINTF(": conf 0x%02x", conf & 0xff);
344 
345 	if ((conf & VIAPM_SMB_CFG_HSTEN) == 0) {
346 		printf(": SMBus disabled\n");
347 		goto nosmb;
348 	}
349 
350 	/* Map SMBus I/O space */
351 	iobase &= VIAPM_SMB_BASE_MASK;
352 	if (iobase == 0 || bus_space_map(sc->sc_iot, iobase,
353 	    VIAPM_SMB_SIZE, 0, &sc->sc_smbus_ioh)) {
354 		printf(": can't map SMBus i/o space\n");
355 		goto nosmb;
356 	}
357 
358 	sc->sc_poll = 1;
359 	if ((conf & VIAPM_SMB_CFG_SCIEN) == 0) {
360 		/* No PCI IRQ */
361 		printf(": SMI");
362 	} else {
363 		/* Install interrupt handler */
364 		if (pci_intr_map(pa, &ih) == 0) {
365 			intrstr = pci_intr_string(pa->pa_pc, ih);
366 			sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
367 			    viapm_intr, sc, DEVNAME(sc));
368 			if (sc->sc_ih != NULL) {
369 				printf(": %s", intrstr);
370 				sc->sc_poll = 0;
371 			}
372 		}
373 		if (sc->sc_poll)
374 			printf(": polling");
375 	}
376 
377 	printf("\n");
378 
379 	/* Attach I2C bus */
380 	rw_init(&sc->sc_i2c_lock, "iiclk");
381 	sc->sc_i2c_tag.ic_cookie = sc;
382 	sc->sc_i2c_tag.ic_acquire_bus = viapm_i2c_acquire_bus;
383 	sc->sc_i2c_tag.ic_release_bus = viapm_i2c_release_bus;
384 	sc->sc_i2c_tag.ic_exec = viapm_i2c_exec;
385 
386 	bzero(&iba, sizeof iba);
387 	iba.iba_name = "iic";
388 	iba.iba_tag = &sc->sc_i2c_tag;
389 	config_found(self, &iba, iicbus_print);
390 
391 nosmb:
392 
393 	/* Power management */
394 	switch (PCI_PRODUCT(pa->pa_id)) {
395 	case PCI_PRODUCT_VIATECH_VT82C596:
396 	case PCI_PRODUCT_VIATECH_VT82C596B_PM:
397 	case PCI_PRODUCT_VIATECH_VT82C686A_SMB:
398 	case PCI_PRODUCT_VIATECH_VT8231_PWR:
399 		basereg = VIAPM_PM_BASE1;
400 		cfgreg = VIAPM_PM_CFG1;
401 		break;
402 	default:
403 		basereg = VIAPM_PM_BASE2;
404 		cfgreg = VIAPM_PM_CFG2;
405 	}
406 
407 	/* Check if power management I/O space is enabled */
408 	conf = pci_conf_read(pa->pa_pc, pa->pa_tag, cfgreg);
409 	if ((conf & VIAPM_PM_CFG_PMEN) == 0) {
410 		printf("%s: PM disabled\n", DEVNAME(sc));
411 		goto nopm;
412 	}
413 
414 	/* Map power management I/O space */
415 	iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, basereg);
416 	iobase &= VIAPM_PM_BASE_MASK;
417 	if (iobase == 0 || bus_space_map(sc->sc_iot, iobase,
418 	    VIAPM_PM_SIZE, 0, &sc->sc_pm_ioh)) {
419 		/* XXX can't map PM i/o space if ACPI mode */
420 		DPRINTF("%s: can't map PM i/o space\n", DEVNAME(sc));
421 		goto nopm;
422 	}
423 
424 	/* Check for 32-bit PM timer */
425 	if (conf & VIAPM_PM_CFG_TMR32)
426 		viapm_timecounter.tc_counter_mask = 0xffffffff;
427 
428 	/* Register new timecounter */
429 	viapm_timecounter.tc_priv = sc;
430 	tc_init(&viapm_timecounter);
431 
432 	printf("%s: %s-bit timer at %lluHz\n", DEVNAME(sc),
433 	    (viapm_timecounter.tc_counter_mask == 0xffffffff ? "32" : "24"),
434 	    (unsigned long long)viapm_timecounter.tc_frequency);
435 
436 nopm:
437 
438 	/* HWMon */
439 	switch (PCI_PRODUCT(pa->pa_id)) {
440 	case PCI_PRODUCT_VIATECH_VT82C686A_SMB:
441 	case PCI_PRODUCT_VIATECH_VT8231_PWR:
442 		break;
443 	default:
444 		return;
445 	}
446 
447 	/* Check if HWMon I/O space is enabled */
448 	conf = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_HWMON_CFG);
449 	if ((conf & VIAPM_HWMON_CFG_HWEN) == 0) {
450 		printf("%s: HWM disabled\n", DEVNAME(sc));
451 		return;
452 	}
453 
454 	/* Map HWMon I/O space */
455 	iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_HWMON_BASE);
456 	iobase &= VIAPM_HWMON_BASE_MASK;
457 	if (iobase == 0 || bus_space_map(sc->sc_iot, iobase,
458 	    VIAPM_HWMON_SIZE, 0, &sc->sc_hwmon_ioh)) {
459 		printf("%s: can't map HWM i/o space\n", DEVNAME(sc));
460 		return;
461 	}
462 
463 	v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_FANCONF);
464 
465 	sc->sc_fan_div[0] = 1 << ((v >> 4) & 0x3);
466 	sc->sc_fan_div[1] = 1 << ((v >> 6) & 0x3);
467 
468 	for (i = 0; i <= 2; i++)
469 		sc->sc_data[i].type = SENSOR_TEMP;
470 	for (i = 3; i <= 4; i++)
471 		sc->sc_data[i].type = SENSOR_FANRPM;
472 	for (i = 5; i <= 9; ++i)
473 		sc->sc_data[i].type = SENSOR_VOLTS_DC;
474 
475 	strlcpy(sc->sc_data[5].desc, "VSENS1",
476 	    sizeof(sc->sc_data[5].desc));	/* CPU core (2V) */
477 	strlcpy(sc->sc_data[6].desc, "VSENS2",
478 	    sizeof(sc->sc_data[6].desc));	/* NB core? (2.5V) */
479 	strlcpy(sc->sc_data[7].desc, "Vcore",
480 	    sizeof(sc->sc_data[7].desc));	/* Vcore (3.3V) */
481 	strlcpy(sc->sc_data[8].desc, "VSENS3",
482 	    sizeof(sc->sc_data[8].desc));	/* VSENS3 (5V) */
483 	strlcpy(sc->sc_data[9].desc, "VSENS4",
484 	    sizeof(sc->sc_data[9].desc));	/* VSENS4 (12V) */
485 
486 	/* Get initial set of sensor values. */
487 	viapm_refresh_sensor_data(sc);
488 
489 	/* Register sensors with sysctl */
490 	strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
491 	    sizeof(sc->sc_sensordev.xname));
492 	for (i = 0; i < VIAPM_NUM_SENSORS; ++i)
493 		sensor_attach(&sc->sc_sensordev, &sc->sc_data[i]);
494 	sensordev_install(&sc->sc_sensordev);
495 
496 	/* Refresh sensors data every 1.5 seconds */
497 	timeout_set(&viapm_timeout, viapm_refresh, sc);
498 	timeout_add_msec(&viapm_timeout, 1500);
499 }
500 
501 int
502 viapm_i2c_acquire_bus(void *cookie, int flags)
503 {
504 	struct viapm_softc *sc = cookie;
505 
506 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
507 		return (0);
508 
509 	return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
510 }
511 
512 void
513 viapm_i2c_release_bus(void *cookie, int flags)
514 {
515 	struct viapm_softc *sc = cookie;
516 
517 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
518 		return;
519 
520 	rw_exit(&sc->sc_i2c_lock);
521 }
522 
523 int
524 viapm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
525     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
526 {
527 	struct viapm_softc *sc = cookie;
528 	u_int8_t *b;
529 	u_int8_t ctl, st;
530 	int retries;
531 
532 	/* Check if there's a transfer already running */
533 	st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS);
534 	DPRINTF("%s: exec op %d, addr 0x%x, cmdlen %d, len %d, "
535 	    "flags 0x%x, status 0x%b\n", DEVNAME(sc), op, addr,
536 	    cmdlen, len, flags, st, VIAPM_SMB_HS_BITS);
537 	if (st & VIAPM_SMB_HS_BUSY)
538 		return (1);
539 
540 	if (cold || sc->sc_poll)
541 		flags |= I2C_F_POLL;
542 
543 	if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
544 		return (1);
545 
546 	/* Setup transfer */
547 	sc->sc_i2c_xfer.op = op;
548 	sc->sc_i2c_xfer.buf = buf;
549 	sc->sc_i2c_xfer.len = len;
550 	sc->sc_i2c_xfer.flags = flags;
551 	sc->sc_i2c_xfer.error = 0;
552 
553 	/* Set slave address and transfer direction */
554 	bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_TXSLVA,
555 	    VIAPM_SMB_TXSLVA_ADDR(addr) |
556 	    (I2C_OP_READ_P(op) ? VIAPM_SMB_TXSLVA_READ : 0));
557 
558 	b = (void *)cmdbuf;
559 	if (cmdlen > 0)
560 		/* Set command byte */
561 		bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh,
562 		    VIAPM_SMB_HCMD, b[0]);
563 
564 	if (I2C_OP_WRITE_P(op)) {
565 		/* Write data */
566 		b = buf;
567 		if (len > 0)
568 			bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh,
569 			    VIAPM_SMB_HD0, b[0]);
570 		if (len > 1)
571 			bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh,
572 			    VIAPM_SMB_HD1, b[1]);
573 	}
574 
575 	/* Set SMBus command */
576 	if (len == 0)
577 		ctl = VIAPM_SMB_HC_CMD_BYTE;
578 	else if (len == 1)
579 		ctl = VIAPM_SMB_HC_CMD_BDATA;
580 	else if (len == 2)
581 		ctl = VIAPM_SMB_HC_CMD_WDATA;
582 	else
583 		panic("%s: unexpected len %zd", __func__, len);
584 
585 	if ((flags & I2C_F_POLL) == 0)
586 		ctl |= VIAPM_SMB_HC_INTREN;
587 
588 	/* Start transaction */
589 	ctl |= VIAPM_SMB_HC_START;
590 	bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HC, ctl);
591 
592 	if (flags & I2C_F_POLL) {
593 		/* Poll for completion */
594 		DELAY(VIAPM_SMBUS_DELAY);
595 		for (retries = 1000; retries > 0; retries--) {
596 			st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh,
597 			    VIAPM_SMB_HS);
598 			if ((st & VIAPM_SMB_HS_BUSY) == 0)
599 				break;
600 			DELAY(VIAPM_SMBUS_DELAY);
601 		}
602 		if (st & VIAPM_SMB_HS_BUSY)
603 			goto timeout;
604 		viapm_intr(sc);
605 	} else {
606 		/* Wait for interrupt */
607 		if (tsleep_nsec(sc, PRIBIO, "iicexec",
608 		    SEC_TO_NSEC(VIAPM_SMBUS_TIMEOUT)))
609 			goto timeout;
610 	}
611 
612 	if (sc->sc_i2c_xfer.error)
613 		return (1);
614 
615 	return (0);
616 
617 timeout:
618 	/*
619 	 * Transfer timeout. Kill the transaction and clear status bits.
620 	 */
621 	printf("%s: timeout, status 0x%b\n", DEVNAME(sc), st,
622 	    VIAPM_SMB_HS_BITS);
623 	bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HC,
624 	    VIAPM_SMB_HC_KILL);
625 	DELAY(VIAPM_SMBUS_DELAY);
626 	st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS);
627 	if ((st & VIAPM_SMB_HS_FAILED) == 0)
628 		printf("%s: transaction abort failed, status 0x%b\n",
629 		    DEVNAME(sc), st, VIAPM_SMB_HS_BITS);
630 	bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS, st);
631 	return (1);
632 }
633 
634 int
635 viapm_intr(void *arg)
636 {
637 	struct viapm_softc *sc = arg;
638 	u_int8_t st;
639 	u_int8_t *b;
640 	size_t len;
641 
642 	/* Read status */
643 	st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS);
644 	if ((st & VIAPM_SMB_HS_BUSY) != 0 || (st & (VIAPM_SMB_HS_INTR |
645 	    VIAPM_SMB_HS_DEVERR | VIAPM_SMB_HS_BUSERR |
646 	    VIAPM_SMB_HS_FAILED)) == 0)
647 		/* Interrupt was not for us */
648 		return (0);
649 
650 	DPRINTF("%s: intr st 0x%b\n", DEVNAME(sc), st, VIAPM_SMB_HS_BITS);
651 
652 	/* Clear status bits */
653 	bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS, st);
654 
655 	/* Check for errors */
656 	if (st & (VIAPM_SMB_HS_DEVERR | VIAPM_SMB_HS_BUSERR |
657 	    VIAPM_SMB_HS_FAILED)) {
658 		sc->sc_i2c_xfer.error = 1;
659 		goto done;
660 	}
661 
662 	if (st & VIAPM_SMB_HS_INTR) {
663 		if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
664 			goto done;
665 
666 		/* Read data */
667 		b = sc->sc_i2c_xfer.buf;
668 		len = sc->sc_i2c_xfer.len;
669 		if (len > 0)
670 			b[0] = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh,
671 			    VIAPM_SMB_HD0);
672 		if (len > 1)
673 			b[1] = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh,
674 			    VIAPM_SMB_HD1);
675 	}
676 
677 done:
678 	if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
679 		wakeup(sc);
680 	return (1);
681 }
682 
683 int
684 val_to_uK(unsigned int val)
685 {
686 	int i = val / 4;
687 	int j = val % 4;
688 
689 	KASSERT(i >= 0 && i <= 255);
690 
691 	if (j == 0 || i == 255)
692 		return val_to_temp[i] * 10000;
693 
694 	/* is linear interpolation ok? */
695 	return (val_to_temp[i] * (4 - j) +
696 	    val_to_temp[i + 1] * j) * 2500 /* really: / 4 * 10000 */ ;
697 }
698 
699 int
700 val_to_rpm(unsigned int val, int div)
701 {
702 	if (val == 0)
703 		return 0;
704 
705 	return 1350000 / val / div;
706 }
707 
708 long
709 val_to_uV(unsigned int val, int index)
710 {
711 	static const long mult[] =
712 	    {1250000, 1250000, 1670000, 2600000, 6300000};
713 
714 	KASSERT(index >= 0 && index <= 4);
715 
716 	return (25LL * val + 133) * mult[index] / 2628;
717 }
718 
719 void
720 viapm_refresh_sensor_data(struct viapm_softc *sc)
721 {
722 	int i;
723 	u_int8_t v, v2;
724 
725 	/* temperature */
726 	v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TIRQ);
727 	v2 = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TSENS1);
728 	DPRINTF("%s: TSENS1 = %d\n", DEVNAME(sc), (v2 << 2) | (v >> 6));
729 	sc->sc_data[0].value = val_to_uK((v2 << 2) | (v >> 6));
730 
731 	v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TLOW);
732 	v2 = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TSENS2);
733 	DPRINTF("%s: TSENS2 = %d\n", DEVNAME(sc), (v2 << 2) | ((v >> 4) & 0x3));
734 	sc->sc_data[1].value = val_to_uK((v2 << 2) | ((v >> 4) & 0x3));
735 
736 	v2 = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_TSENS3);
737 	DPRINTF("%s: TSENS3 = %d\n", DEVNAME(sc), (v2 << 2) | (v >> 6));
738 	sc->sc_data[2].value = val_to_uK((v2 << 2) | (v >> 6));
739 
740 	/* fan */
741 	for (i = 3; i <= 4; i++) {
742 		v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh,
743 		    VIAPM_HWMON_FAN1 + i - 3);
744 		DPRINTF("%s: FAN%d = %d / %d\n", DEVNAME(sc), i - 3, v,
745 		    sc->sc_fan_div[i - 3]);
746 		sc->sc_data[i].value = val_to_rpm(v, sc->sc_fan_div[i - 3]);
747 	}
748 
749 	/* voltage */
750 	for (i = 5; i <= 9; i++) {
751 		v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh,
752 		    VIAPM_HWMON_VSENS1 + i - 5);
753 		DPRINTF("%s: V%d = %d\n", DEVNAME(sc), i - 5, v);
754 		sc->sc_data[i].value = val_to_uV(v, i - 5);
755 	}
756 }
757 
758 void
759 viapm_refresh(void *arg)
760 {
761 	struct viapm_softc *sc = (struct viapm_softc *)arg;
762 
763 	viapm_refresh_sensor_data(sc);
764 	timeout_add_msec(&viapm_timeout, 1500);
765 }
766 
767 u_int
768 viapm_get_timecount(struct timecounter *tc)
769 {
770 	struct viapm_softc *sc = tc->tc_priv;
771 	u_int u1, u2, u3;
772 
773 	u2 = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, VIAPM_PM_TMR);
774 	u3 = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, VIAPM_PM_TMR);
775 	do {
776 		u1 = u2;
777 		u2 = u3;
778 		u3 = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, VIAPM_PM_TMR);
779 	} while (u1 > u2 || u2 > u3);
780 
781 	return (u2);
782 }
783