1 /* $OpenBSD: it.c,v 1.40 2011/01/20 16:59:55 form 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 /* get environment controller base address */ 172 it_writereg(ia->ia_iot, ioh, IT_LDN, IT_EC_LDN); 173 ec_iobase = it_readreg(ia->ia_iot, ioh, IT_EC_MSB) << 8; 174 ec_iobase |= it_readreg(ia->ia_iot, ioh, IT_EC_LSB); 175 176 /* check if device already attached */ 177 LIST_FOREACH(sc, &it_softc_list, sc_list) 178 if (sc->sc_ec_iobase == ec_iobase) 179 break; 180 181 if (sc == NULL) { 182 ia->ipa_nio = 1; 183 ia->ipa_io[0].length = 2; 184 ia->ipa_nmem = ia->ipa_nirq = ia->ipa_ndrq = 0; 185 found++; 186 } 187 188 break; 189 } 190 191 /* exit MB PnP mode */ 192 it_exit(ia->ia_iot, ioh); 193 194 /* unmap i/o space */ 195 bus_space_unmap(ia->ia_iot, ioh, 2); 196 197 return (found); 198 } 199 200 void 201 it_attach(struct device *parent, struct device *self, void *aux) 202 { 203 struct it_softc *sc = (void *)self; 204 struct isa_attach_args *ia = aux; 205 int i; 206 207 sc->sc_iot = ia->ia_iot; 208 sc->sc_iobase = ia->ipa_io[0].base; 209 if (bus_space_map(sc->sc_iot, sc->sc_iobase, 2, 0, &sc->sc_ioh) != 0) { 210 printf(": can't map i/o space\n"); 211 return; 212 } 213 214 /* enter MB PnP mode */ 215 it_enter(sc->sc_iot, sc->sc_ioh, sc->sc_iobase); 216 217 /* get chip id and rev */ 218 sc->sc_chipid = it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPID1) << 8; 219 sc->sc_chipid |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPID2); 220 sc->sc_chiprev = it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPREV) & 0x0f; 221 222 /* get environment controller base address */ 223 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_EC_LDN); 224 sc->sc_ec_iobase = it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_MSB) << 8; 225 sc->sc_ec_iobase |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_LSB); 226 227 /* initialize watchdog timer */ 228 if (sc->sc_chipid != IT_ID_8705) { 229 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_WDT_LDN); 230 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_CSR, 0x00); 231 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 0x00); 232 wdog_register(sc, it_wdog_cb); 233 } 234 235 /* exit MB PnP mode and unmap */ 236 it_exit(sc->sc_iot, sc->sc_ioh); 237 238 LIST_INSERT_HEAD(&it_softc_list, sc, sc_list); 239 printf(": IT%xF rev %X", sc->sc_chipid, sc->sc_chiprev); 240 241 if (sc->sc_ec_iobase == 0) { 242 printf(", EC disabled\n"); 243 return; 244 } 245 246 printf(", EC port 0x%x\n", sc->sc_ec_iobase); 247 248 /* map environment controller i/o space */ 249 sc->sc_ec_iot = ia->ia_iot; 250 if (bus_space_map(sc->sc_ec_iot, sc->sc_ec_iobase, 8, 0, 251 &sc->sc_ec_ioh) != 0) { 252 printf("%s: can't map EC i/o space\n", sc->sc_dev.dv_xname); 253 return; 254 } 255 256 /* initialize sensor structures */ 257 for (i = 0; i < IT_EC_NUMSENSORS; i++) { 258 sc->sc_sensors[i].type = it_sensors[i].type; 259 260 if (it_sensors[i].desc != NULL) 261 strlcpy(sc->sc_sensors[i].desc, it_sensors[i].desc, 262 sizeof(sc->sc_sensors[i].desc)); 263 } 264 265 /* register sensor update task */ 266 if (sensor_task_register(sc, it_ec_refresh, IT_EC_INTERVAL) == NULL) { 267 printf("%s: unable to register update task\n", 268 sc->sc_dev.dv_xname); 269 bus_space_unmap(sc->sc_ec_iot, sc->sc_ec_ioh, 8); 270 return; 271 } 272 273 /* use 16-bit FAN tachometer registers for newer chips */ 274 if (sc->sc_chipid != IT_ID_8705 && sc->sc_chipid != IT_ID_8712) 275 it_ec_writereg(sc, IT_EC_FAN_ECER, 276 it_ec_readreg(sc, IT_EC_FAN_ECER) | 0x07); 277 278 /* activate monitoring */ 279 it_ec_writereg(sc, IT_EC_CFG, 280 it_ec_readreg(sc, IT_EC_CFG) | IT_EC_CFG_START | IT_EC_CFG_INTCLR); 281 282 /* initialize sensors */ 283 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 284 sizeof(sc->sc_sensordev.xname)); 285 for (i = 0; i < IT_EC_NUMSENSORS; i++) 286 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); 287 sensordev_install(&sc->sc_sensordev); 288 } 289 290 u_int8_t 291 it_readreg(bus_space_tag_t iot, bus_space_handle_t ioh, int r) 292 { 293 bus_space_write_1(iot, ioh, IT_IO_ADDR, r); 294 return (bus_space_read_1(iot, ioh, IT_IO_DATA)); 295 } 296 297 void 298 it_writereg(bus_space_tag_t iot, bus_space_handle_t ioh, int r, u_int8_t v) 299 { 300 bus_space_write_1(iot, ioh, IT_IO_ADDR, r); 301 bus_space_write_1(iot, ioh, IT_IO_DATA, v); 302 } 303 304 void 305 it_enter(bus_space_tag_t iot, bus_space_handle_t ioh, int iobase) 306 { 307 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x87); 308 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x01); 309 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x55); 310 if (iobase == IO_IT1) 311 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x55); 312 else 313 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0xaa); 314 } 315 316 void 317 it_exit(bus_space_tag_t iot, bus_space_handle_t ioh) 318 { 319 bus_space_write_1(iot, ioh, IT_IO_ADDR, IT_CCR); 320 bus_space_write_1(iot, ioh, IT_IO_DATA, 0x02); 321 } 322 323 u_int8_t 324 it_ec_readreg(struct it_softc *sc, int r) 325 { 326 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_ADDR, r); 327 return (bus_space_read_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_DATA)); 328 } 329 330 void 331 it_ec_writereg(struct it_softc *sc, int r, u_int8_t v) 332 { 333 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_ADDR, r); 334 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_DATA, v); 335 } 336 337 void 338 it_ec_refresh(void *arg) 339 { 340 struct it_softc *sc = arg; 341 int i, sdata, divisor, odivisor, ndivisor; 342 u_int8_t cr, ecr; 343 344 /* refresh temp sensors */ 345 cr = it_ec_readreg(sc, IT_EC_ADC_TEMPER); 346 347 for (i = 0; i < IT_TEMP_COUNT; i++) { 348 sc->sc_sensors[IT_TEMP_BASE + i].flags &= 349 SENSOR_FINVALID; 350 351 if (!(cr & (1 << i)) && !(cr & (1 << (i + 3)))) { 352 sc->sc_sensors[IT_TEMP_BASE + i].flags |= 353 SENSOR_FINVALID; 354 continue; 355 } 356 357 sdata = it_ec_readreg(sc, IT_EC_TEMPBASE + i); 358 /* convert to degF */ 359 sc->sc_sensors[IT_TEMP_BASE + i].value = 360 sdata * 1000000 + 273150000; 361 } 362 363 /* refresh volt sensors */ 364 cr = it_ec_readreg(sc, IT_EC_ADC_VINER); 365 366 for (i = 0; i < IT_VOLT_COUNT; i++) { 367 sc->sc_sensors[IT_VOLT_BASE + i].flags &= 368 SENSOR_FINVALID; 369 370 if ((i < 8) && !(cr & (1 << i))) { 371 sc->sc_sensors[IT_VOLT_BASE + i].flags |= 372 SENSOR_FINVALID; 373 continue; 374 } 375 376 sdata = it_ec_readreg(sc, IT_EC_VOLTBASE + i); 377 /* voltage returned as (mV >> 4) */ 378 sc->sc_sensors[IT_VOLT_BASE + i].value = sdata << 4; 379 /* these two values are negative and formula is different */ 380 if (i == 5 || i == 6) 381 sc->sc_sensors[IT_VOLT_BASE + i].value -= IT_EC_VREF; 382 /* rfact is (factor * 10^4) */ 383 sc->sc_sensors[IT_VOLT_BASE + i].value *= it_vrfact[i]; 384 /* division by 10 gets us back to uVDC */ 385 sc->sc_sensors[IT_VOLT_BASE + i].value /= 10; 386 if (i == 5 || i == 6) 387 sc->sc_sensors[IT_VOLT_BASE + i].value += 388 IT_EC_VREF * 1000; 389 } 390 391 /* refresh fan sensors */ 392 cr = it_ec_readreg(sc, IT_EC_FAN_MCR); 393 394 if (sc->sc_chipid != IT_ID_8705 && sc->sc_chipid != IT_ID_8712) { 395 /* use 16-bit FAN tachometer registers */ 396 ecr = it_ec_readreg(sc, IT_EC_FAN_ECER); 397 398 for (i = 0; i < IT_FAN_COUNT; i++) { 399 sc->sc_sensors[IT_FAN_BASE + i].flags &= 400 ~SENSOR_FINVALID; 401 402 if (i < 3 && !(cr & (1 << (i + 4)))) { 403 sc->sc_sensors[IT_FAN_BASE + i].flags |= 404 SENSOR_FINVALID; 405 continue; 406 } else if (i > 2 && !(ecr & (1 << (i + 1)))) { 407 sc->sc_sensors[IT_FAN_BASE + i].flags |= 408 SENSOR_FINVALID; 409 continue; 410 } 411 412 sdata = it_ec_readreg(sc, it_fan_regs[i]); 413 sdata |= it_ec_readreg(sc, it_fan_ext_regs[i]) << 8; 414 415 if (sdata == 0 || sdata == 0xffff) 416 sc->sc_sensors[IT_FAN_BASE + i].value = 0; 417 else 418 sc->sc_sensors[IT_FAN_BASE + i].value = 419 675000 / sdata; 420 } 421 } else { 422 /* use 8-bit FAN tachometer & FAN divisor registers */ 423 odivisor = ndivisor = divisor = 424 it_ec_readreg(sc, IT_EC_FAN_DIV); 425 426 for (i = 0; i < IT_FAN_COUNT; i++) { 427 if (i > 2 || !(cr & (1 << (i + 4)))) { 428 sc->sc_sensors[IT_FAN_BASE + i].flags |= 429 SENSOR_FINVALID; 430 continue; 431 } 432 433 sc->sc_sensors[IT_FAN_BASE + i].flags &= 434 ~SENSOR_FINVALID; 435 436 sdata = it_ec_readreg(sc, it_fan_regs[i]); 437 438 if (sdata == 0xff) { 439 sc->sc_sensors[IT_FAN_BASE + i].value = 0; 440 441 if (i == 2) 442 ndivisor ^= 0x40; 443 else { 444 ndivisor &= ~(7 << (i * 3)); 445 ndivisor |= ((divisor + 1) & 7) << 446 (i * 3); 447 } 448 } else if (sdata != 0) { 449 if (i == 2) 450 divisor = divisor & 1 ? 3 : 1; 451 sc->sc_sensors[IT_FAN_BASE + i].value = 452 1350000 / (sdata << (divisor & 7)); 453 } else 454 sc->sc_sensors[IT_FAN_BASE + i].value = 0; 455 } 456 457 if (ndivisor != odivisor) 458 it_ec_writereg(sc, IT_EC_FAN_DIV, ndivisor); 459 } 460 } 461 462 int 463 it_wdog_cb(void *arg, int period) 464 { 465 struct it_softc *sc = arg; 466 int minutes = 0; 467 468 /* enter MB PnP mode and select WDT device */ 469 it_enter(sc->sc_iot, sc->sc_ioh, sc->sc_iobase); 470 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_WDT_LDN); 471 472 /* disable watchdog timer */ 473 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 0x00); 474 475 /* 1000s should be enough for everyone */ 476 if (period > 1000) 477 period = 1000; 478 else if (period < 0) 479 period = 0; 480 481 if (period > 0) { 482 /* 483 * Older IT8712F chips have 8-bit timeout counter. 484 * Use minutes for 16-bit values for these chips. 485 */ 486 if (sc->sc_chipid == IT_ID_8712 && sc->sc_chiprev < 0x8 && 487 period > 0xff) { 488 if (period % 60 >= 30) 489 period += 60; 490 period /= 60; 491 minutes++; 492 } 493 494 /* set watchdog timeout (low byte) */ 495 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TMO_LSB, 496 period & 0xff); 497 498 if (minutes) { 499 /* enable watchdog timer */ 500 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 501 IT_WDT_TCR_KRST | IT_WDT_TCR_PWROK); 502 503 period *= 60; 504 } else { 505 /* set watchdog timeout (high byte) */ 506 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TMO_MSB, 507 period >> 8); 508 509 /* enable watchdog timer */ 510 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 511 IT_WDT_TCR_SECS | IT_WDT_TCR_KRST | 512 IT_WDT_TCR_PWROK); 513 } 514 } 515 516 /* exit MB PnP mode */ 517 it_exit(sc->sc_iot, sc->sc_ioh); 518 519 return (period); 520 } 521 522 523 struct cfattach it_ca = { 524 sizeof(struct it_softc), 525 it_match, 526 it_attach 527 }; 528 529 struct cfdriver it_cd = { 530 NULL, "it", DV_DULL 531 }; 532