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