1 /* $OpenBSD: viapm.c,v 1.14 2011/04/10 20:27:02 shadchin 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 #ifdef __HAVE_TIMECOUNTER 68 #include <sys/timetc.h> 69 #endif 70 71 #include <machine/bus.h> 72 73 #include <dev/pci/pcidevs.h> 74 #include <dev/pci/pcireg.h> 75 #include <dev/pci/pcivar.h> 76 77 #include <dev/i2c/i2cvar.h> 78 79 /* 80 * Register definitions. 81 */ 82 83 /* PCI configuration registers */ 84 #define VIAPM_PM_CFG1 0x40 /* general configuration */ 85 #define VIAPM_PM_CFG2 0x80 86 #define VIAPM_PM_CFG_TMR32 (1 << 11) /* 32-bit PM timer */ 87 #define VIAPM_PM_CFG_PMEN (1 << 15) /* enable PM I/O space */ 88 #define VIAPM_PM_BASE1 0x48 /* power management I/O base address */ 89 #define VIAPM_PM_BASE2 0x88 90 #define VIAPM_PM_BASE_MASK 0xff80 91 92 #define VIAPM_HWMON_BASE 0x70 /* HWMon I/O base address */ 93 #define VIAPM_HWMON_BASE_MASK 0xff80 94 #define VIAPM_HWMON_CFG 0x74 /* HWMon control register */ 95 #define VIAPM_HWMON_CFG_HWEN (1 << 0) /* enable HWMon I/O space */ 96 97 #define VIAPM_SMB_BASE1 0x90 /* SMBus I/O base address */ 98 #define VIAPM_SMB_BASE2 0x80 99 #define VIAPM_SMB_BASE3 0xd0 100 #define VIAPM_SMB_BASE_MASK 0xfff0 101 #define VIAPM_SMB_CFG1 0xd2 /* host configuration */ 102 #define VIAPM_SMB_CFG2 0x84 103 #define VIAPM_SMB_CFG_HSTEN (1 << 0) /* enable SMBus I/O space */ 104 #define VIAPM_SMB_CFG_INTEN (1 << 1) /* enable SCI/SMI */ 105 #define VIAPM_SMB_CFG_SCIEN (1 << 3) /* interrupt type (SCI/SMI) */ 106 107 #define VIAPM_PM_SIZE 256 /* Power management I/O space size */ 108 #define VIAPM_HWMON_SIZE 128 /* HWMon I/O space size */ 109 #define VIAPM_SMB_SIZE 16 /* SMBus I/O space size */ 110 111 /* HWMon I/O registers */ 112 #define VIAPM_HWMON_TSENS3 0x1f 113 #define VIAPM_HWMON_TSENS1 0x20 114 #define VIAPM_HWMON_TSENS2 0x21 115 #define VIAPM_HWMON_VSENS1 0x22 116 #define VIAPM_HWMON_VSENS2 0x23 117 #define VIAPM_HWMON_VCORE 0x24 118 #define VIAPM_HWMON_VSENS3 0x25 119 #define VIAPM_HWMON_VSENS4 0x26 120 #define VIAPM_HWMON_FAN1 0x29 121 #define VIAPM_HWMON_FAN2 0x2a 122 #define VIAPM_HWMON_FANCONF 0x47 /* fan configuration */ 123 #define VIAPM_HWMON_TLOW 0x49 /* temperature low order value */ 124 #define VIAPM_HWMON_TIRQ 0x4b /* temperature interrupt configuration */ 125 126 /* ACPI I/O registers */ 127 #define VIAPM_PM_TMR 0x08 /* PM timer */ 128 129 /* SMBus I/O registers */ 130 #define VIAPM_SMB_HS 0x00 /* host status */ 131 #define VIAPM_SMB_HS_BUSY (1 << 0) /* running a command */ 132 #define VIAPM_SMB_HS_INTR (1 << 1) /* command completed */ 133 #define VIAPM_SMB_HS_DEVERR (1 << 2) /* command error */ 134 #define VIAPM_SMB_HS_BUSERR (1 << 3) /* transaction collision */ 135 #define VIAPM_SMB_HS_FAILED (1 << 4) /* failed bus transaction */ 136 #define VIAPM_SMB_HS_INUSE (1 << 6) /* bus semaphore */ 137 #define VIAPM_SMB_HS_BITS \ 138 "\020\001BUSY\002INTR\003DEVERR\004BUSERR\005FAILED\007INUSE" 139 #define VIAPM_SMB_HC 0x02 /* host control */ 140 #define VIAPM_SMB_HC_INTREN (1 << 0) /* enable interrupts */ 141 #define VIAPM_SMB_HC_KILL (1 << 1) /* kill current transaction */ 142 #define VIAPM_SMB_HC_CMD_QUICK (0 << 2) /* QUICK command */ 143 #define VIAPM_SMB_HC_CMD_BYTE (1 << 2) /* BYTE command */ 144 #define VIAPM_SMB_HC_CMD_BDATA (2 << 2) /* BYTE DATA command */ 145 #define VIAPM_SMB_HC_CMD_WDATA (3 << 2) /* WORD DATA command */ 146 #define VIAPM_SMB_HC_CMD_PCALL (4 << 2) /* PROCESS CALL command */ 147 #define VIAPM_SMB_HC_CMD_BLOCK (5 << 2) /* BLOCK command */ 148 #define VIAPM_SMB_HC_START (1 << 6) /* start transaction */ 149 #define VIAPM_SMB_HCMD 0x03 /* host command */ 150 #define VIAPM_SMB_TXSLVA 0x04 /* transmit slave address */ 151 #define VIAPM_SMB_TXSLVA_READ (1 << 0) /* read direction */ 152 #define VIAPM_SMB_TXSLVA_ADDR(x) (((x) & 0x7f) << 1) /* 7-bit address */ 153 #define VIAPM_SMB_HD0 0x05 /* host data 0 */ 154 #define VIAPM_SMB_HD1 0x06 /* host data 1 */ 155 #define VIAPM_SMB_HBDB 0x07 /* host block data byte */ 156 157 #ifdef VIAPM_DEBUG 158 #define DPRINTF(x...) printf(x) 159 #else 160 #define DPRINTF(x...) 161 #endif 162 163 #define DEVNAME(sc) ((sc)->sc_dev.dv_xname) 164 165 #define VIAPM_SMBUS_DELAY 100 166 #define VIAPM_SMBUS_TIMEOUT 1 167 168 #define VIAPM_NUM_SENSORS 10 /* three temp, two fan, five voltage */ 169 170 #ifdef __HAVE_TIMECOUNTER 171 u_int viapm_get_timecount(struct timecounter *tc); 172 173 #ifndef VIAPM_FREQUENCY 174 #define VIAPM_FREQUENCY 3579545 175 #endif 176 177 static struct timecounter viapm_timecounter = { 178 viapm_get_timecount, /* get_timecount */ 179 0, /* no poll_pps */ 180 0xffffff, /* counter_mask */ 181 VIAPM_FREQUENCY, /* frequency */ 182 "VIAPM", /* name */ 183 1000 /* quality */ 184 }; 185 #endif /* __HAVE_TIMECOUNTER */ 186 187 struct timeout viapm_timeout; 188 189 struct viapm_softc { 190 struct device sc_dev; 191 192 bus_space_tag_t sc_iot; 193 bus_space_handle_t sc_pm_ioh; 194 bus_space_handle_t sc_smbus_ioh; 195 bus_space_handle_t sc_hwmon_ioh; 196 void * sc_ih; 197 int sc_poll; 198 199 int sc_fan_div[2]; /* fan RPM divisor */ 200 201 struct ksensor sc_data[VIAPM_NUM_SENSORS]; 202 struct ksensordev sc_sensordev; 203 204 struct i2c_controller sc_i2c_tag; 205 struct rwlock sc_i2c_lock; 206 struct { 207 i2c_op_t op; 208 void * buf; 209 size_t len; 210 int flags; 211 volatile int error; 212 } sc_i2c_xfer; 213 }; 214 215 int viapm_match(struct device *, void *, void *); 216 void viapm_attach(struct device *, struct device *, void *); 217 218 int viapm_i2c_acquire_bus(void *, int); 219 void viapm_i2c_release_bus(void *, int); 220 int viapm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, 221 void *, size_t, int); 222 223 int viapm_intr(void *); 224 225 int val_to_uK(unsigned int); 226 int val_to_rpm(unsigned int, int); 227 long val_to_uV(unsigned int, int); 228 void viapm_refresh_sensor_data(struct viapm_softc *); 229 void viapm_refresh(void *); 230 231 struct cfattach viapm_ca = { 232 sizeof(struct viapm_softc), viapm_match, viapm_attach 233 }; 234 235 struct cfdriver viapm_cd = { 236 NULL, "viapm", DV_DULL 237 }; 238 239 const struct pci_matchid viapm_ids[] = { 240 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596 }, 241 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C596B_PM }, 242 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_SMB }, 243 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8231_PWR }, 244 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_ISA }, 245 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233A_ISA }, 246 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8235_ISA }, 247 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237_ISA }, 248 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237A_ISA }, 249 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237S_ISA }, 250 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8251_ISA }, 251 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_CX700_ISA }, 252 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VX800_ISA }, 253 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VX855_ISA } 254 }; 255 256 /* 257 * XXX there doesn't seem to exist much hard documentation on how to 258 * convert the raw values to usable units, this code is more or less 259 * stolen from the Linux driver, but changed to suit our conditions 260 */ 261 262 /* 263 * lookup-table to translate raw values to uK, this is the same table 264 * used by the Linux driver (modulo units); there is a fifth degree 265 * polynomial that supposedly been used to generate this table, but I 266 * haven't been able to figure out how -- it doesn't give the same values 267 */ 268 269 static const long val_to_temp[] = { 270 20225, 20435, 20645, 20855, 21045, 21245, 21425, 21615, 21785, 21955, 271 22125, 22285, 22445, 22605, 22755, 22895, 23035, 23175, 23315, 23445, 272 23565, 23695, 23815, 23925, 24045, 24155, 24265, 24365, 24465, 24565, 273 24665, 24765, 24855, 24945, 25025, 25115, 25195, 25275, 25355, 25435, 274 25515, 25585, 25655, 25725, 25795, 25865, 25925, 25995, 26055, 26115, 275 26175, 26235, 26295, 26355, 26405, 26465, 26515, 26575, 26625, 26675, 276 26725, 26775, 26825, 26875, 26925, 26975, 27025, 27065, 27115, 27165, 277 27205, 27255, 27295, 27345, 27385, 27435, 27475, 27515, 27565, 27605, 278 27645, 27685, 27735, 27775, 27815, 27855, 27905, 27945, 27985, 28025, 279 28065, 28105, 28155, 28195, 28235, 28275, 28315, 28355, 28405, 28445, 280 28485, 28525, 28565, 28615, 28655, 28695, 28735, 28775, 28825, 28865, 281 28905, 28945, 28995, 29035, 29075, 29125, 29165, 29205, 29245, 29295, 282 29335, 29375, 29425, 29465, 29505, 29555, 29595, 29635, 29685, 29725, 283 29765, 29815, 29855, 29905, 29945, 29985, 30035, 30075, 30125, 30165, 284 30215, 30255, 30305, 30345, 30385, 30435, 30475, 30525, 30565, 30615, 285 30655, 30705, 30755, 30795, 30845, 30885, 30935, 30975, 31025, 31075, 286 31115, 31165, 31215, 31265, 31305, 31355, 31405, 31455, 31505, 31545, 287 31595, 31645, 31695, 31745, 31805, 31855, 31905, 31955, 32005, 32065, 288 32115, 32175, 32225, 32285, 32335, 32395, 32455, 32515, 32575, 32635, 289 32695, 32755, 32825, 32885, 32955, 33025, 33095, 33155, 33235, 33305, 290 33375, 33455, 33525, 33605, 33685, 33765, 33855, 33935, 34025, 34115, 291 34205, 34295, 34395, 34495, 34595, 34695, 34805, 34905, 35015, 35135, 292 35245, 35365, 35495, 35615, 35745, 35875, 36015, 36145, 36295, 36435, 293 36585, 36745, 36895, 37065, 37225, 37395, 37575, 37755, 37935, 38125, 294 38325, 38525, 38725, 38935, 39155, 39375, 39605, 39835, 40075, 40325, 295 40575, 40835, 41095, 41375, 41655, 41935, 296 }; 297 298 int 299 viapm_match(struct device *parent, void *match, void *aux) 300 { 301 return (pci_matchbyid(aux, viapm_ids, nitems(viapm_ids))); 302 } 303 304 void 305 viapm_attach(struct device *parent, struct device *self, void *aux) 306 { 307 struct viapm_softc *sc = (struct viapm_softc *)self; 308 struct pci_attach_args *pa = aux; 309 struct i2cbus_attach_args iba; 310 pcireg_t conf, iobase; 311 pci_intr_handle_t ih; 312 const char *intrstr = NULL; 313 int basereg, cfgreg; 314 int i, v; 315 316 sc->sc_iot = pa->pa_iot; 317 318 /* SMBus */ 319 switch (PCI_PRODUCT(pa->pa_id)) { 320 case PCI_PRODUCT_VIATECH_VT82C596: 321 case PCI_PRODUCT_VIATECH_VT82C596B_PM: 322 case PCI_PRODUCT_VIATECH_VT82C686A_SMB: 323 case PCI_PRODUCT_VIATECH_VT8231_PWR: 324 basereg = VIAPM_SMB_BASE1; 325 break; 326 default: 327 basereg = VIAPM_SMB_BASE3; 328 } 329 330 cfgreg = (VIAPM_SMB_CFG1 & (~0x03)); /* XXX 4-byte aligned */ 331 332 /* Check 2nd address for VT82C596 */ 333 iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, basereg); 334 if ((PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT82C596) && 335 ((iobase & 0x0001) == 0)) { 336 iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_SMB_BASE2); 337 cfgreg = VIAPM_SMB_CFG2; 338 } 339 340 /* Check if SMBus I/O space is enabled */ 341 conf = pci_conf_read(pa->pa_pc, pa->pa_tag, cfgreg); 342 if (cfgreg != VIAPM_SMB_CFG2) 343 conf >>= 16; 344 DPRINTF(": conf 0x%02x", conf & 0xff); 345 346 if ((conf & VIAPM_SMB_CFG_HSTEN) == 0) { 347 printf(": SMBus disabled\n"); 348 goto nosmb; 349 } 350 351 /* Map SMBus I/O space */ 352 iobase &= VIAPM_SMB_BASE_MASK; 353 if (iobase == 0 || bus_space_map(sc->sc_iot, iobase, 354 VIAPM_SMB_SIZE, 0, &sc->sc_smbus_ioh)) { 355 printf(": can't map SMBus i/o space\n"); 356 goto nosmb; 357 } 358 359 sc->sc_poll = 1; 360 if ((conf & VIAPM_SMB_CFG_SCIEN) == 0) { 361 /* No PCI IRQ */ 362 printf(": SMI"); 363 } else { 364 /* Install interrupt handler */ 365 if (pci_intr_map(pa, &ih) == 0) { 366 intrstr = pci_intr_string(pa->pa_pc, ih); 367 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, 368 viapm_intr, sc, DEVNAME(sc)); 369 if (sc->sc_ih != NULL) { 370 printf(": %s", intrstr); 371 sc->sc_poll = 0; 372 } 373 } 374 if (sc->sc_poll) 375 printf(": polling"); 376 } 377 378 printf("\n"); 379 380 /* Attach I2C bus */ 381 rw_init(&sc->sc_i2c_lock, "iiclk"); 382 sc->sc_i2c_tag.ic_cookie = sc; 383 sc->sc_i2c_tag.ic_acquire_bus = viapm_i2c_acquire_bus; 384 sc->sc_i2c_tag.ic_release_bus = viapm_i2c_release_bus; 385 sc->sc_i2c_tag.ic_exec = viapm_i2c_exec; 386 387 bzero(&iba, sizeof iba); 388 iba.iba_name = "iic"; 389 iba.iba_tag = &sc->sc_i2c_tag; 390 config_found(self, &iba, iicbus_print); 391 392 nosmb: 393 394 #ifdef __HAVE_TIMECOUNTER 395 /* Power management */ 396 switch (PCI_PRODUCT(pa->pa_id)) { 397 case PCI_PRODUCT_VIATECH_VT82C596: 398 case PCI_PRODUCT_VIATECH_VT82C596B_PM: 399 case PCI_PRODUCT_VIATECH_VT82C686A_SMB: 400 case PCI_PRODUCT_VIATECH_VT8231_PWR: 401 basereg = VIAPM_PM_BASE1; 402 cfgreg = VIAPM_PM_CFG1; 403 break; 404 default: 405 basereg = VIAPM_PM_BASE2; 406 cfgreg = VIAPM_PM_CFG2; 407 } 408 409 /* Check if power management I/O space is enabled */ 410 conf = pci_conf_read(pa->pa_pc, pa->pa_tag, cfgreg); 411 if ((conf & VIAPM_PM_CFG_PMEN) == 0) { 412 printf("%s: PM disabled\n", DEVNAME(sc)); 413 goto nopm; 414 } 415 416 /* Map power management I/O space */ 417 iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, basereg); 418 iobase &= VIAPM_PM_BASE_MASK; 419 if (iobase == 0 || bus_space_map(sc->sc_iot, iobase, 420 VIAPM_PM_SIZE, 0, &sc->sc_pm_ioh)) { 421 /* XXX can't map PM i/o space if ACPI mode */ 422 DPRINTF("%s: can't map PM i/o space\n", DEVNAME(sc)); 423 goto nopm; 424 } 425 426 /* Check for 32-bit PM timer */ 427 if (conf & VIAPM_PM_CFG_TMR32) 428 viapm_timecounter.tc_counter_mask = 0xffffffff; 429 430 /* Register new timecounter */ 431 viapm_timecounter.tc_priv = sc; 432 tc_init(&viapm_timecounter); 433 434 printf("%s: %s-bit timer at %lluHz\n", DEVNAME(sc), 435 (viapm_timecounter.tc_counter_mask == 0xffffffff ? "32" : "24"), 436 (unsigned long long)viapm_timecounter.tc_frequency); 437 438 nopm: 439 #endif /* __HAVE_TIMECOUNTER */ 440 441 /* HWMon */ 442 switch (PCI_PRODUCT(pa->pa_id)) { 443 case PCI_PRODUCT_VIATECH_VT82C686A_SMB: 444 case PCI_PRODUCT_VIATECH_VT8231_PWR: 445 break; 446 default: 447 return; 448 } 449 450 /* Check if HWMon I/O space is enabled */ 451 conf = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_HWMON_CFG); 452 if ((conf & VIAPM_HWMON_CFG_HWEN) == 0) { 453 printf("%s: HWM disabled\n", DEVNAME(sc)); 454 return; 455 } 456 457 /* Map HWMon I/O space */ 458 iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_HWMON_BASE); 459 iobase &= VIAPM_HWMON_BASE_MASK; 460 if (iobase == 0 || bus_space_map(sc->sc_iot, iobase, 461 VIAPM_HWMON_SIZE, 0, &sc->sc_hwmon_ioh)) { 462 printf("%s: can't map HWM i/o space\n", DEVNAME(sc)); 463 return; 464 } 465 466 v = bus_space_read_1(sc->sc_iot, sc->sc_hwmon_ioh, VIAPM_HWMON_FANCONF); 467 468 sc->sc_fan_div[0] = 1 << ((v >> 4) & 0x3); 469 sc->sc_fan_div[1] = 1 << ((v >> 6) & 0x3); 470 471 for (i = 0; i <= 2; i++) 472 sc->sc_data[i].type = SENSOR_TEMP; 473 for (i = 3; i <= 4; i++) 474 sc->sc_data[i].type = SENSOR_FANRPM; 475 for (i = 5; i <= 9; ++i) 476 sc->sc_data[i].type = SENSOR_VOLTS_DC; 477 478 strlcpy(sc->sc_data[5].desc, "VSENS1", 479 sizeof(sc->sc_data[5].desc)); /* CPU core (2V) */ 480 strlcpy(sc->sc_data[6].desc, "VSENS2", 481 sizeof(sc->sc_data[6].desc)); /* NB core? (2.5V) */ 482 strlcpy(sc->sc_data[7].desc, "Vcore", 483 sizeof(sc->sc_data[7].desc)); /* Vcore (3.3V) */ 484 strlcpy(sc->sc_data[8].desc, "VSENS3", 485 sizeof(sc->sc_data[8].desc)); /* VSENS3 (5V) */ 486 strlcpy(sc->sc_data[9].desc, "VSENS4", 487 sizeof(sc->sc_data[9].desc)); /* VSENS4 (12V) */ 488 489 /* Get initial set of sensor values. */ 490 viapm_refresh_sensor_data(sc); 491 492 /* Register sensors with sysctl */ 493 strlcpy(sc->sc_sensordev.xname, DEVNAME(sc), 494 sizeof(sc->sc_sensordev.xname)); 495 for (i = 0; i < VIAPM_NUM_SENSORS; ++i) 496 sensor_attach(&sc->sc_sensordev, &sc->sc_data[i]); 497 sensordev_install(&sc->sc_sensordev); 498 499 /* Refresh sensors data every 1.5 seconds */ 500 timeout_set(&viapm_timeout, viapm_refresh, sc); 501 timeout_add_msec(&viapm_timeout, 1500); 502 } 503 504 int 505 viapm_i2c_acquire_bus(void *cookie, int flags) 506 { 507 struct viapm_softc *sc = cookie; 508 509 if (cold || sc->sc_poll || (flags & I2C_F_POLL)) 510 return (0); 511 512 return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR)); 513 } 514 515 void 516 viapm_i2c_release_bus(void *cookie, int flags) 517 { 518 struct viapm_softc *sc = cookie; 519 520 if (cold || sc->sc_poll || (flags & I2C_F_POLL)) 521 return; 522 523 rw_exit(&sc->sc_i2c_lock); 524 } 525 526 int 527 viapm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, 528 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) 529 { 530 struct viapm_softc *sc = cookie; 531 u_int8_t *b; 532 u_int8_t ctl, st; 533 int retries; 534 535 /* Check if there's a transfer already running */ 536 st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HS); 537 DPRINTF("%s: exec op %d, addr 0x%x, cmdlen %d, len %d, " 538 "flags 0x%x, status 0x%b\n", DEVNAME(sc), op, addr, 539 cmdlen, len, flags, st, VIAPM_SMB_HS_BITS); 540 if (st & VIAPM_SMB_HS_BUSY) 541 return (1); 542 543 if (cold || sc->sc_poll) 544 flags |= I2C_F_POLL; 545 546 if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2) 547 return (1); 548 549 /* Setup transfer */ 550 sc->sc_i2c_xfer.op = op; 551 sc->sc_i2c_xfer.buf = buf; 552 sc->sc_i2c_xfer.len = len; 553 sc->sc_i2c_xfer.flags = flags; 554 sc->sc_i2c_xfer.error = 0; 555 556 /* Set slave address and transfer direction */ 557 bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_TXSLVA, 558 VIAPM_SMB_TXSLVA_ADDR(addr) | 559 (I2C_OP_READ_P(op) ? VIAPM_SMB_TXSLVA_READ : 0)); 560 561 b = (void *)cmdbuf; 562 if (cmdlen > 0) 563 /* Set command byte */ 564 bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, 565 VIAPM_SMB_HCMD, b[0]); 566 567 if (I2C_OP_WRITE_P(op)) { 568 /* Write data */ 569 b = buf; 570 if (len > 0) 571 bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, 572 VIAPM_SMB_HD0, b[0]); 573 if (len > 1) 574 bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, 575 VIAPM_SMB_HD1, b[1]); 576 } 577 578 /* Set SMBus command */ 579 if (len == 0) 580 ctl = VIAPM_SMB_HC_CMD_BYTE; 581 else if (len == 1) 582 ctl = VIAPM_SMB_HC_CMD_BDATA; 583 else if (len == 2) 584 ctl = VIAPM_SMB_HC_CMD_WDATA; 585 586 if ((flags & I2C_F_POLL) == 0) 587 ctl |= VIAPM_SMB_HC_INTREN; 588 589 /* Start transaction */ 590 ctl |= VIAPM_SMB_HC_START; 591 bus_space_write_1(sc->sc_iot, sc->sc_smbus_ioh, VIAPM_SMB_HC, ctl); 592 593 if (flags & I2C_F_POLL) { 594 /* Poll for completion */ 595 DELAY(VIAPM_SMBUS_DELAY); 596 for (retries = 1000; retries > 0; retries--) { 597 st = bus_space_read_1(sc->sc_iot, sc->sc_smbus_ioh, 598 VIAPM_SMB_HS); 599 if ((st & VIAPM_SMB_HS_BUSY) == 0) 600 break; 601 DELAY(VIAPM_SMBUS_DELAY); 602 } 603 if (st & VIAPM_SMB_HS_BUSY) 604 goto timeout; 605 viapm_intr(sc); 606 } else { 607 /* Wait for interrupt */ 608 if (tsleep(sc, PRIBIO, "iicexec", VIAPM_SMBUS_TIMEOUT * hz)) 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 #ifdef __HAVE_TIMECOUNTER 768 u_int 769 viapm_get_timecount(struct timecounter *tc) 770 { 771 struct viapm_softc *sc = tc->tc_priv; 772 u_int u1, u2, u3; 773 774 u2 = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, VIAPM_PM_TMR); 775 u3 = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, VIAPM_PM_TMR); 776 do { 777 u1 = u2; 778 u2 = u3; 779 u3 = bus_space_read_4(sc->sc_iot, sc->sc_pm_ioh, VIAPM_PM_TMR); 780 } while (u1 > u2 || u2 > u3); 781 782 return (u2); 783 } 784 #endif /* __HAVE_TIMECOUNTER */ 785