1 /* $OpenBSD: it.c,v 1.42 2012/12/14 13:17:29 mikeb Exp $ */ 2 3 /* 4 * Copyright (c) 2007-2008 Oleg Safiullin <form@pdp-11.org.ru> 5 * Copyright (c) 2006-2007 Juan Romero Pardines <juan@xtrarom.org> 6 * Copyright (c) 2003 Julien Bordet <zejames@greyhats.org> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/device.h> 33 #include <sys/sensors.h> 34 35 #include <machine/bus.h> 36 37 #include <dev/isa/isareg.h> 38 #include <dev/isa/isavar.h> 39 #include <dev/isa/itvar.h> 40 41 42 #if defined(ITDEBUG) 43 #define DPRINTF(x) do { printf x; } while (0) 44 #else 45 #define DPRINTF(x) 46 #endif 47 48 49 int it_match(struct device *, void *, void *); 50 void it_attach(struct device *, struct device *, void *); 51 u_int8_t it_readreg(bus_space_tag_t, bus_space_handle_t, int); 52 void it_writereg(bus_space_tag_t, bus_space_handle_t, int, u_int8_t); 53 void it_enter(bus_space_tag_t, bus_space_handle_t, int); 54 void it_exit(bus_space_tag_t, bus_space_handle_t); 55 56 u_int8_t it_ec_readreg(struct it_softc *, int); 57 void it_ec_writereg(struct it_softc *, int, u_int8_t); 58 void it_ec_refresh(void *arg); 59 60 int it_wdog_cb(void *, int); 61 62 /* 63 * IT87-compatible chips can typically measure voltages up to 4.096 V. 64 * To measure higher voltages the input is attenuated with (external) 65 * resistors. Negative voltages are measured using a reference 66 * voltage. So we have to convert the sensor values back to real 67 * voltages by applying the appropriate resistor factor. 68 */ 69 #define RFACT_NONE 10000 70 #define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y)) 71 72 73 struct { 74 enum sensor_type type; 75 const char *desc; 76 } it_sensors[IT_EC_NUMSENSORS] = { 77 #define IT_TEMP_BASE 0 78 #define IT_TEMP_COUNT 3 79 { SENSOR_TEMP, NULL }, 80 { SENSOR_TEMP, NULL }, 81 { SENSOR_TEMP, NULL }, 82 83 #define IT_FAN_BASE 3 84 #define IT_FAN_COUNT 5 85 { SENSOR_FANRPM, NULL }, 86 { SENSOR_FANRPM, NULL }, 87 { SENSOR_FANRPM, NULL }, 88 { SENSOR_FANRPM, NULL }, 89 { SENSOR_FANRPM, NULL }, 90 91 #define IT_VOLT_BASE 8 92 #define IT_VOLT_COUNT 9 93 { SENSOR_VOLTS_DC, "VCORE_A" }, 94 { SENSOR_VOLTS_DC, "VCORE_B" }, 95 { SENSOR_VOLTS_DC, "+3.3V" }, 96 { SENSOR_VOLTS_DC, "+5V" }, 97 { SENSOR_VOLTS_DC, "+12V" }, 98 { SENSOR_VOLTS_DC, "-12V" }, 99 { SENSOR_VOLTS_DC, "-5V" }, 100 { SENSOR_VOLTS_DC, "+5VSB" }, 101 { SENSOR_VOLTS_DC, "VBAT" } 102 }; 103 104 /* rfact values for voltage sensors */ 105 int it_vrfact[IT_VOLT_COUNT] = { 106 RFACT_NONE, /* VCORE_A */ 107 RFACT_NONE, /* VCORE_A */ 108 RFACT_NONE, /* +3.3V */ 109 RFACT(68, 100), /* +5V */ 110 RFACT(30, 10), /* +12V */ 111 RFACT(83, 20), /* -12V */ 112 RFACT(21, 10), /* -5V */ 113 RFACT(68, 100), /* +5VSB */ 114 RFACT_NONE /* VBAT */ 115 }; 116 117 int it_fan_regs[] = { 118 IT_EC_FAN_TAC1, IT_EC_FAN_TAC2, IT_EC_FAN_TAC3, 119 IT_EC_FAN_TAC4_LSB, IT_EC_FAN_TAC5_LSB 120 }; 121 122 int it_fan_ext_regs[] = { 123 IT_EC_FAN_EXT_TAC1, IT_EC_FAN_EXT_TAC2, IT_EC_FAN_EXT_TAC3, 124 IT_EC_FAN_TAC4_MSB, IT_EC_FAN_TAC5_MSB 125 }; 126 127 LIST_HEAD(, it_softc) it_softc_list = LIST_HEAD_INITIALIZER(&it_softc_list); 128 129 130 int 131 it_match(struct device *parent, void *match, void *aux) 132 { 133 struct isa_attach_args *ia = aux; 134 struct it_softc *sc; 135 bus_space_handle_t ioh; 136 int ec_iobase, found = 0; 137 u_int16_t cr; 138 139 if (ia->ipa_io[0].base != IO_IT1 && ia->ipa_io[0].base != IO_IT2) 140 return (0); 141 142 /* map i/o space */ 143 if (bus_space_map(ia->ia_iot, ia->ipa_io[0].base, 2, 0, &ioh) != 0) { 144 DPRINTF(("it_match: can't map i/o space")); 145 return (0); 146 } 147 148 /* enter MB PnP mode */ 149 it_enter(ia->ia_iot, ioh, ia->ipa_io[0].base); 150 151 /* 152 * SMSC or similar SuperIO chips use 0x55 magic to enter PnP mode 153 * and 0xaa to exit. These chips also enter PnP mode via ITE 154 * `enter MB PnP mode' sequence, so force chip to exit PnP mode 155 * if this is the case. 156 */ 157 bus_space_write_1(ia->ia_iot, ioh, IT_IO_ADDR, 0xaa); 158 159 /* get chip id */ 160 cr = it_readreg(ia->ia_iot, ioh, IT_CHIPID1) << 8; 161 cr |= it_readreg(ia->ia_iot, ioh, IT_CHIPID2); 162 163 switch (cr) { 164 case IT_ID_8705: 165 case IT_ID_8712: 166 case IT_ID_8716: 167 case IT_ID_8718: 168 case IT_ID_8720: 169 case IT_ID_8721: 170 case IT_ID_8726: 171 case IT_ID_8772: 172 /* get environment controller base address */ 173 it_writereg(ia->ia_iot, ioh, IT_LDN, IT_EC_LDN); 174 ec_iobase = it_readreg(ia->ia_iot, ioh, IT_EC_MSB) << 8; 175 ec_iobase |= it_readreg(ia->ia_iot, ioh, IT_EC_LSB); 176 177 /* check if device already attached */ 178 LIST_FOREACH(sc, &it_softc_list, sc_list) 179 if (sc->sc_ec_iobase == ec_iobase) 180 break; 181 182 if (sc == NULL) { 183 ia->ipa_nio = 1; 184 ia->ipa_io[0].length = 2; 185 ia->ipa_nmem = ia->ipa_nirq = ia->ipa_ndrq = 0; 186 found++; 187 } 188 189 break; 190 } 191 192 /* exit MB PnP mode */ 193 it_exit(ia->ia_iot, ioh); 194 195 /* unmap i/o space */ 196 bus_space_unmap(ia->ia_iot, ioh, 2); 197 198 return (found); 199 } 200 201 void 202 it_attach(struct device *parent, struct device *self, void *aux) 203 { 204 struct it_softc *sc = (void *)self; 205 struct isa_attach_args *ia = aux; 206 int i; 207 208 sc->sc_iot = ia->ia_iot; 209 sc->sc_iobase = ia->ipa_io[0].base; 210 if (bus_space_map(sc->sc_iot, sc->sc_iobase, 2, 0, &sc->sc_ioh) != 0) { 211 printf(": can't map i/o space\n"); 212 return; 213 } 214 215 /* enter MB PnP mode */ 216 it_enter(sc->sc_iot, sc->sc_ioh, sc->sc_iobase); 217 218 /* get chip id and rev */ 219 sc->sc_chipid = it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPID1) << 8; 220 sc->sc_chipid |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPID2); 221 sc->sc_chiprev = it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPREV) & 0x0f; 222 223 /* get environment controller base address */ 224 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_EC_LDN); 225 sc->sc_ec_iobase = it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_MSB) << 8; 226 sc->sc_ec_iobase |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_LSB); 227 228 /* initialize watchdog timer */ 229 if (sc->sc_chipid != IT_ID_8705) { 230 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_WDT_LDN); 231 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_CSR, 0x00); 232 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 0x00); 233 wdog_register(it_wdog_cb, sc); 234 } 235 236 /* exit MB PnP mode and unmap */ 237 it_exit(sc->sc_iot, sc->sc_ioh); 238 239 LIST_INSERT_HEAD(&it_softc_list, sc, sc_list); 240 printf(": IT%xF rev %X", sc->sc_chipid, sc->sc_chiprev); 241 242 if (sc->sc_ec_iobase == 0) { 243 printf(", EC disabled\n"); 244 return; 245 } 246 247 printf(", EC port 0x%x\n", sc->sc_ec_iobase); 248 249 /* map environment controller i/o space */ 250 sc->sc_ec_iot = ia->ia_iot; 251 if (bus_space_map(sc->sc_ec_iot, sc->sc_ec_iobase, 8, 0, 252 &sc->sc_ec_ioh) != 0) { 253 printf("%s: can't map EC i/o space\n", sc->sc_dev.dv_xname); 254 return; 255 } 256 257 /* initialize sensor structures */ 258 for (i = 0; i < IT_EC_NUMSENSORS; i++) { 259 sc->sc_sensors[i].type = it_sensors[i].type; 260 261 if (it_sensors[i].desc != NULL) 262 strlcpy(sc->sc_sensors[i].desc, it_sensors[i].desc, 263 sizeof(sc->sc_sensors[i].desc)); 264 } 265 266 /* register sensor update task */ 267 if (sensor_task_register(sc, it_ec_refresh, IT_EC_INTERVAL) == NULL) { 268 printf("%s: unable to register update task\n", 269 sc->sc_dev.dv_xname); 270 bus_space_unmap(sc->sc_ec_iot, sc->sc_ec_ioh, 8); 271 return; 272 } 273 274 /* use 16-bit FAN tachometer registers for newer chips */ 275 if (sc->sc_chipid != IT_ID_8705 && sc->sc_chipid != IT_ID_8712) 276 it_ec_writereg(sc, IT_EC_FAN_ECER, 277 it_ec_readreg(sc, IT_EC_FAN_ECER) | 0x07); 278 279 /* activate monitoring */ 280 it_ec_writereg(sc, IT_EC_CFG, 281 it_ec_readreg(sc, IT_EC_CFG) | IT_EC_CFG_START | IT_EC_CFG_INTCLR); 282 283 /* initialize sensors */ 284 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 285 sizeof(sc->sc_sensordev.xname)); 286 for (i = 0; i < IT_EC_NUMSENSORS; i++) 287 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); 288 sensordev_install(&sc->sc_sensordev); 289 } 290 291 u_int8_t 292 it_readreg(bus_space_tag_t iot, bus_space_handle_t ioh, int r) 293 { 294 bus_space_write_1(iot, ioh, IT_IO_ADDR, r); 295 return (bus_space_read_1(iot, ioh, IT_IO_DATA)); 296 } 297 298 void 299 it_writereg(bus_space_tag_t iot, bus_space_handle_t ioh, int r, u_int8_t v) 300 { 301 bus_space_write_1(iot, ioh, IT_IO_ADDR, r); 302 bus_space_write_1(iot, ioh, IT_IO_DATA, v); 303 } 304 305 void 306 it_enter(bus_space_tag_t iot, bus_space_handle_t ioh, int iobase) 307 { 308 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x87); 309 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x01); 310 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x55); 311 if (iobase == IO_IT1) 312 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x55); 313 else 314 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0xaa); 315 } 316 317 void 318 it_exit(bus_space_tag_t iot, bus_space_handle_t ioh) 319 { 320 bus_space_write_1(iot, ioh, IT_IO_ADDR, IT_CCR); 321 bus_space_write_1(iot, ioh, IT_IO_DATA, 0x02); 322 } 323 324 u_int8_t 325 it_ec_readreg(struct it_softc *sc, int r) 326 { 327 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_ADDR, r); 328 return (bus_space_read_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_DATA)); 329 } 330 331 void 332 it_ec_writereg(struct it_softc *sc, int r, u_int8_t v) 333 { 334 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_ADDR, r); 335 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_DATA, v); 336 } 337 338 void 339 it_ec_refresh(void *arg) 340 { 341 struct it_softc *sc = arg; 342 int i, sdata, divisor, odivisor, ndivisor; 343 u_int8_t cr, ecr; 344 345 /* refresh temp sensors */ 346 cr = it_ec_readreg(sc, IT_EC_ADC_TEMPER); 347 348 for (i = 0; i < IT_TEMP_COUNT; i++) { 349 sc->sc_sensors[IT_TEMP_BASE + i].flags &= 350 SENSOR_FINVALID; 351 352 if (!(cr & (1 << i)) && !(cr & (1 << (i + 3)))) { 353 sc->sc_sensors[IT_TEMP_BASE + i].flags |= 354 SENSOR_FINVALID; 355 continue; 356 } 357 358 sdata = it_ec_readreg(sc, IT_EC_TEMPBASE + i); 359 /* convert to degF */ 360 sc->sc_sensors[IT_TEMP_BASE + i].value = 361 sdata * 1000000 + 273150000; 362 } 363 364 /* refresh volt sensors */ 365 cr = it_ec_readreg(sc, IT_EC_ADC_VINER); 366 367 for (i = 0; i < IT_VOLT_COUNT; i++) { 368 sc->sc_sensors[IT_VOLT_BASE + i].flags &= 369 SENSOR_FINVALID; 370 371 if ((i < 8) && !(cr & (1 << i))) { 372 sc->sc_sensors[IT_VOLT_BASE + i].flags |= 373 SENSOR_FINVALID; 374 continue; 375 } 376 377 sdata = it_ec_readreg(sc, IT_EC_VOLTBASE + i); 378 /* voltage returned as (mV >> 4) */ 379 sc->sc_sensors[IT_VOLT_BASE + i].value = sdata << 4; 380 /* these two values are negative and formula is different */ 381 if (i == 5 || i == 6) 382 sc->sc_sensors[IT_VOLT_BASE + i].value -= IT_EC_VREF; 383 /* rfact is (factor * 10^4) */ 384 sc->sc_sensors[IT_VOLT_BASE + i].value *= it_vrfact[i]; 385 /* division by 10 gets us back to uVDC */ 386 sc->sc_sensors[IT_VOLT_BASE + i].value /= 10; 387 if (i == 5 || i == 6) 388 sc->sc_sensors[IT_VOLT_BASE + i].value += 389 IT_EC_VREF * 1000; 390 } 391 392 /* refresh fan sensors */ 393 cr = it_ec_readreg(sc, IT_EC_FAN_MCR); 394 395 if (sc->sc_chipid != IT_ID_8705 && sc->sc_chipid != IT_ID_8712) { 396 /* use 16-bit FAN tachometer registers */ 397 ecr = it_ec_readreg(sc, IT_EC_FAN_ECER); 398 399 for (i = 0; i < IT_FAN_COUNT; i++) { 400 sc->sc_sensors[IT_FAN_BASE + i].flags &= 401 ~SENSOR_FINVALID; 402 403 if (i < 3 && !(cr & (1 << (i + 4)))) { 404 sc->sc_sensors[IT_FAN_BASE + i].flags |= 405 SENSOR_FINVALID; 406 continue; 407 } else if (i > 2 && !(ecr & (1 << (i + 1)))) { 408 sc->sc_sensors[IT_FAN_BASE + i].flags |= 409 SENSOR_FINVALID; 410 continue; 411 } 412 413 sdata = it_ec_readreg(sc, it_fan_regs[i]); 414 sdata |= it_ec_readreg(sc, it_fan_ext_regs[i]) << 8; 415 416 if (sdata == 0 || sdata == 0xffff) 417 sc->sc_sensors[IT_FAN_BASE + i].value = 0; 418 else 419 sc->sc_sensors[IT_FAN_BASE + i].value = 420 675000 / sdata; 421 } 422 } else { 423 /* use 8-bit FAN tachometer & FAN divisor registers */ 424 odivisor = ndivisor = divisor = 425 it_ec_readreg(sc, IT_EC_FAN_DIV); 426 427 for (i = 0; i < IT_FAN_COUNT; i++) { 428 if (i > 2 || !(cr & (1 << (i + 4)))) { 429 sc->sc_sensors[IT_FAN_BASE + i].flags |= 430 SENSOR_FINVALID; 431 continue; 432 } 433 434 sc->sc_sensors[IT_FAN_BASE + i].flags &= 435 ~SENSOR_FINVALID; 436 437 sdata = it_ec_readreg(sc, it_fan_regs[i]); 438 439 if (sdata == 0xff) { 440 sc->sc_sensors[IT_FAN_BASE + i].value = 0; 441 442 if (i == 2) 443 ndivisor ^= 0x40; 444 else { 445 ndivisor &= ~(7 << (i * 3)); 446 ndivisor |= ((divisor + 1) & 7) << 447 (i * 3); 448 } 449 } else if (sdata != 0) { 450 if (i == 2) 451 divisor = divisor & 1 ? 3 : 1; 452 sc->sc_sensors[IT_FAN_BASE + i].value = 453 1350000 / (sdata << (divisor & 7)); 454 } else 455 sc->sc_sensors[IT_FAN_BASE + i].value = 0; 456 } 457 458 if (ndivisor != odivisor) 459 it_ec_writereg(sc, IT_EC_FAN_DIV, ndivisor); 460 } 461 } 462 463 int 464 it_wdog_cb(void *arg, int period) 465 { 466 struct it_softc *sc = arg; 467 int minutes = 0; 468 469 /* enter MB PnP mode and select WDT device */ 470 it_enter(sc->sc_iot, sc->sc_ioh, sc->sc_iobase); 471 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_WDT_LDN); 472 473 /* disable watchdog timer */ 474 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 0x00); 475 476 /* 1000s should be enough for everyone */ 477 if (period > 1000) 478 period = 1000; 479 else if (period < 0) 480 period = 0; 481 482 if (period > 0) { 483 /* 484 * Older IT8712F chips have 8-bit timeout counter. 485 * Use minutes for 16-bit values for these chips. 486 */ 487 if (sc->sc_chipid == IT_ID_8712 && sc->sc_chiprev < 0x8 && 488 period > 0xff) { 489 if (period % 60 >= 30) 490 period += 60; 491 period /= 60; 492 minutes++; 493 } 494 495 /* set watchdog timeout (low byte) */ 496 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TMO_LSB, 497 period & 0xff); 498 499 if (minutes) { 500 /* enable watchdog timer */ 501 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 502 IT_WDT_TCR_KRST | IT_WDT_TCR_PWROK); 503 504 period *= 60; 505 } else { 506 /* set watchdog timeout (high byte) */ 507 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TMO_MSB, 508 period >> 8); 509 510 /* enable watchdog timer */ 511 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 512 IT_WDT_TCR_SECS | IT_WDT_TCR_KRST | 513 IT_WDT_TCR_PWROK); 514 } 515 } 516 517 /* exit MB PnP mode */ 518 it_exit(sc->sc_iot, sc->sc_ioh); 519 520 return (period); 521 } 522 523 524 struct cfattach it_ca = { 525 sizeof(struct it_softc), 526 it_match, 527 it_attach 528 }; 529 530 struct cfdriver it_cd = { 531 NULL, "it", DV_DULL 532 }; 533