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