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