1 /* $OpenBSD: it.c,v 1.34 2008/10/08 17:17:39 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 int 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 3 85 { SENSOR_FANRPM, NULL }, 86 { SENSOR_FANRPM, NULL }, 87 { SENSOR_FANRPM, NULL }, 88 89 #define IT_VOLT_BASE 6 90 #define IT_VOLT_COUNT 9 91 { SENSOR_VOLTS_DC, "VCORE_A" }, 92 { SENSOR_VOLTS_DC, "VCORE_B" }, 93 { SENSOR_VOLTS_DC, "+3.3V" }, 94 { SENSOR_VOLTS_DC, "+5V" }, 95 { SENSOR_VOLTS_DC, "+12V" }, 96 { SENSOR_VOLTS_DC, "-5V" }, 97 { SENSOR_VOLTS_DC, "-12V" }, 98 { SENSOR_VOLTS_DC, "+5VSB" }, 99 { SENSOR_VOLTS_DC, "VBAT" } 100 }; 101 102 /* rfact values for voltage sensors */ 103 int it_vrfact[IT_VOLT_COUNT] = { 104 RFACT_NONE, /* VCORE_A */ 105 RFACT_NONE, /* VCORE_A */ 106 RFACT_NONE, /* +3.3V */ 107 RFACT(68, 100), /* +5V */ 108 RFACT(30, 10), /* +12V */ 109 RFACT(21, 10), /* -5V */ 110 RFACT(83, 20), /* -12V */ 111 RFACT(68, 100), /* +5VSB */ 112 RFACT_NONE /* VBAT */ 113 }; 114 115 LIST_HEAD(, it_softc) it_softc_list = LIST_HEAD_INITIALIZER(&it_softc_list); 116 117 118 int 119 it_match(struct device *parent, void *match, void *aux) 120 { 121 struct isa_attach_args *ia = aux; 122 struct it_softc *sc; 123 bus_space_handle_t ioh; 124 int ec_iobase, found = 0; 125 u_int16_t cr; 126 127 if (ia->ipa_io[0].base != IO_IT1 && ia->ipa_io[0].base != IO_IT2) 128 return (0); 129 130 /* map i/o space */ 131 if (bus_space_map(ia->ia_iot, ia->ipa_io[0].base, 2, 0, &ioh) != 0) { 132 DPRINTF(("it_match: can't map i/o space")); 133 return (0); 134 } 135 136 /* enter MB PnP mode */ 137 it_enter(ia->ia_iot, ioh, ia->ipa_io[0].base); 138 139 /* 140 * SMSC or similar SuperIO chips use 0x55 magic to enter PnP mode 141 * and 0xaa to exit. These chips also enter PnP mode via ITE 142 * `enter MB PnP mode' sequence, so force chip to exit PnP mode 143 * if this is the case. 144 */ 145 bus_space_write_1(ia->ia_iot, ioh, IT_IO_ADDR, 0xaa); 146 147 /* get chip id */ 148 cr = it_readreg(ia->ia_iot, ioh, IT_CHIPID1) << 8; 149 cr |= it_readreg(ia->ia_iot, ioh, IT_CHIPID2); 150 151 switch (cr) { 152 case IT_ID_8705: 153 case IT_ID_8712: 154 case IT_ID_8716: 155 case IT_ID_8718: 156 case IT_ID_8726: 157 /* get environment controller base address */ 158 it_writereg(ia->ia_iot, ioh, IT_LDN, IT_EC_LDN); 159 ec_iobase = it_readreg(ia->ia_iot, ioh, IT_EC_MSB) << 8; 160 ec_iobase |= it_readreg(ia->ia_iot, ioh, IT_EC_LSB); 161 162 /* check if device already attached */ 163 LIST_FOREACH(sc, &it_softc_list, sc_list) 164 if (sc->sc_ec_iobase == ec_iobase) 165 break; 166 167 if (sc == NULL) { 168 ia->ipa_nio = 1; 169 ia->ipa_io[0].length = 2; 170 ia->ipa_nmem = ia->ipa_nirq = ia->ipa_ndrq = 0; 171 found++; 172 } 173 174 break; 175 } 176 177 /* exit MB PnP mode */ 178 it_exit(ia->ia_iot, ioh); 179 180 /* unmap i/o space */ 181 bus_space_unmap(ia->ia_iot, ioh, 2); 182 183 return (found); 184 } 185 186 void 187 it_attach(struct device *parent, struct device *self, void *aux) 188 { 189 struct it_softc *sc = (void *)self; 190 struct isa_attach_args *ia = aux; 191 int i; 192 193 sc->sc_iot = ia->ia_iot; 194 sc->sc_iobase = ia->ipa_io[0].base; 195 if (bus_space_map(sc->sc_iot, sc->sc_iobase, 2, 0, &sc->sc_ioh) != 0) { 196 printf(": can't map i/o space\n"); 197 return; 198 } 199 200 /* enter MB PnP mode */ 201 it_enter(sc->sc_iot, sc->sc_ioh, sc->sc_iobase); 202 203 /* get chip id and rev */ 204 sc->sc_chipid = it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPID1) << 8; 205 sc->sc_chipid |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPID2); 206 sc->sc_chiprev = it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPREV) & 0x0f; 207 208 /* get environment controller base address */ 209 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_EC_LDN); 210 sc->sc_ec_iobase = it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_MSB) << 8; 211 sc->sc_ec_iobase |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_LSB); 212 213 /* initialize watchdog */ 214 if (sc->sc_chipid != IT_ID_8705) { 215 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_WDT_LDN); 216 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_CSR, 0x00); 217 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 0x00); 218 wdog_register(sc, it_wdog_cb); 219 } 220 221 /* exit MB PnP mode and unmap */ 222 it_exit(sc->sc_iot, sc->sc_ioh); 223 224 LIST_INSERT_HEAD(&it_softc_list, sc, sc_list); 225 printf(": IT%xF rev 0x%x", sc->sc_chipid, sc->sc_chiprev); 226 227 if (sc->sc_ec_iobase == 0) { 228 printf(", EC disabled\n"); 229 return; 230 } 231 232 printf(", EC port 0x%x\n", sc->sc_ec_iobase); 233 234 /* map environment controller i/o space */ 235 sc->sc_ec_iot = ia->ia_iot; 236 if (bus_space_map(sc->sc_ec_iot, sc->sc_ec_iobase, 8, 0, 237 &sc->sc_ec_ioh) != 0) { 238 printf("%s: can't map EC i/o space\n", sc->sc_dev.dv_xname); 239 return; 240 } 241 242 /* initialize sensor structures */ 243 for (i = 0; i < IT_EC_NUMSENSORS; i++) { 244 sc->sc_sensors[i].type = it_sensors[i].type; 245 246 if (it_sensors[i].desc != NULL) 247 strlcpy(sc->sc_sensors[i].desc, it_sensors[i].desc, 248 sizeof(sc->sc_sensors[i].desc)); 249 } 250 251 /* register update task */ 252 if (sensor_task_register(sc, it_ec_refresh, IT_EC_INTERVAL) == NULL) { 253 printf(": unable to register update task\n", 254 sc->sc_dev.dv_xname); 255 bus_space_unmap(sc->sc_ec_iot, sc->sc_ec_ioh, 8); 256 return; 257 } 258 259 /* activate monitoring */ 260 it_ec_writereg(sc, IT_EC_CFG, 261 it_ec_readreg(sc, IT_EC_CFG) | IT_EC_CFG_START | IT_EC_INT_CLEAR); 262 263 /* initialize sensors */ 264 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 265 sizeof(sc->sc_sensordev.xname)); 266 for (i = 0; i < IT_EC_NUMSENSORS; i++) 267 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); 268 sensordev_install(&sc->sc_sensordev); 269 } 270 271 u_int8_t 272 it_readreg(bus_space_tag_t iot, bus_space_handle_t ioh, int r) 273 { 274 bus_space_write_1(iot, ioh, IT_IO_ADDR, r); 275 return (bus_space_read_1(iot, ioh, IT_IO_DATA)); 276 } 277 278 void 279 it_writereg(bus_space_tag_t iot, bus_space_handle_t ioh, int r, u_int8_t v) 280 { 281 bus_space_write_1(iot, ioh, IT_IO_ADDR, r); 282 bus_space_write_1(iot, ioh, IT_IO_DATA, v); 283 } 284 285 void 286 it_enter(bus_space_tag_t iot, bus_space_handle_t ioh, int iobase) 287 { 288 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x87); 289 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x01); 290 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x55); 291 if (iobase == IO_IT1) 292 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x55); 293 else 294 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0xaa); 295 } 296 297 void 298 it_exit(bus_space_tag_t iot, bus_space_handle_t ioh) 299 { 300 bus_space_write_1(iot, ioh, IT_IO_ADDR, IT_CCR); 301 bus_space_write_1(iot, ioh, IT_IO_DATA, 0x02); 302 } 303 304 u_int8_t 305 it_ec_readreg(struct it_softc *sc, int r) 306 { 307 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_ADDR, r); 308 return (bus_space_read_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_DATA)); 309 } 310 311 void 312 it_ec_writereg(struct it_softc *sc, int r, u_int8_t v) 313 { 314 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_ADDR, r); 315 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_DATA, v); 316 } 317 318 void 319 it_ec_refresh(void *arg) 320 { 321 struct it_softc *sc = arg; 322 int i, sdata, mode, divisor, odivisor, ndivisor; 323 324 /* refresh temp sensors */ 325 for (i = 0; i < IT_TEMP_COUNT; i++) { 326 sdata = it_ec_readreg(sc, IT_EC_TEMPBASE + i); 327 /* convert to degF */ 328 sc->sc_sensors[IT_TEMP_BASE + i].value = 329 sdata * 1000000 + 273150000; 330 } 331 332 /* refresh volt sensors */ 333 for (i = 0; i < IT_VOLT_COUNT; i++) { 334 sdata = it_ec_readreg(sc, IT_EC_VOLTBASE + i); 335 /* voltage returned as (mV >> 4) */ 336 sc->sc_sensors[IT_VOLT_BASE + i].value = sdata << 4; 337 /* these two values are negative and formula is different */ 338 if (i == 5 || i == 6) 339 sc->sc_sensors[IT_VOLT_BASE + i].value -= IT_EC_VREF; 340 /* rfact is (factor * 10^4) */ 341 sc->sc_sensors[IT_VOLT_BASE + i].value *= it_vrfact[i]; 342 /* division by 10 gets us back to uVDC */ 343 sc->sc_sensors[IT_VOLT_BASE + i].value /= 10; 344 if (i == 5 || i == 6) 345 sc->sc_sensors[IT_VOLT_BASE + i].value += 346 IT_EC_VREF * 1000; 347 } 348 349 /* refresh fan sensors */ 350 if (sc->sc_chipid == IT_ID_8705 || sc->sc_chipid == IT_ID_8712) 351 odivisor = ndivisor = divisor = 352 it_ec_readreg(sc, IT_EC_FAN_DIV); 353 else { 354 mode = it_ec_readreg(sc, IT_EC_FAN_ECR); 355 divisor = -1; 356 } 357 358 for (i = 0; i < IT_FAN_COUNT; i++) { 359 sc->sc_sensors[IT_FAN_BASE + i].flags &= ~SENSOR_FINVALID; 360 sdata = it_ec_readreg(sc, IT_EC_FANBASE + i); 361 362 if (divisor != -1) { 363 /* 364 * Use 8-bit FAN Tachometer & FAN Divisor registers 365 */ 366 if (sdata == 0xff) { 367 sc->sc_sensors[IT_FAN_BASE + i].flags |= 368 SENSOR_FINVALID; 369 if (i == 2) 370 ndivisor ^= 0x40; 371 else { 372 ndivisor &= ~(7 << (i * 3)); 373 ndivisor |= ((divisor + 1) & 7) << 374 (i * 3); 375 } 376 } else if (sdata != 0) { 377 if (i == 2) 378 divisor = divisor & 1 ? 3 : 1; 379 sc->sc_sensors[IT_FAN_BASE + i].value = 380 1350000 / (sdata << (divisor & 7)); 381 } else 382 sc->sc_sensors[IT_FAN_BASE + i].value = 0; 383 384 if (ndivisor != odivisor) 385 it_ec_writereg(sc, IT_EC_FAN_DIV, ndivisor); 386 } else { 387 /* 388 * Use 16-bit FAN tachometer register 389 */ 390 if (mode & (1 << i)) 391 sdata |= it_ec_readreg(sc, 392 IT_EC_FANEXTBASE + i) << 8; 393 if (sdata == ((mode & (1 << i)) ? 0xffff : 0xff)) 394 sc->sc_sensors[IT_FAN_BASE + i].flags |= 395 SENSOR_FINVALID; 396 else if (sdata != 0) 397 sc->sc_sensors[IT_FAN_BASE + i].value = 398 675000 / sdata; 399 else 400 sc->sc_sensors[IT_FAN_BASE + i].value = 0; 401 } 402 } 403 } 404 405 int 406 it_wdog_cb(void *arg, int period) 407 { 408 struct it_softc *sc = arg; 409 int minutes = 0; 410 411 /* enter MB PnP mode and select WDT device */ 412 it_enter(sc->sc_iot, sc->sc_ioh, sc->sc_iobase); 413 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_WDT_LDN); 414 415 /* disable watchdog timer */ 416 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 0x00); 417 418 /* 1000s should be enough for everyone */ 419 if (period > 1000) 420 period = 1000; 421 else if (period < 0) 422 period = 0; 423 424 if (period > 0) { 425 /* 426 * Older IT8712F chips have 8-bit timeout counter. 427 * Use minutes for 16-bit values. 428 */ 429 if (sc->sc_chipid == IT_ID_8712 && sc->sc_chiprev < 0x8 && 430 period > 0xff) { 431 period /= 60; 432 minutes++; 433 } 434 435 /* set watchdog timeout (low byte) */ 436 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TMO_LSB, 437 period & 0xff); 438 439 if (minutes) { 440 /* enable watchdog timer */ 441 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 442 IT_WDT_TCR_KRST | IT_WDT_TCR_PWROK); 443 444 period *= 60; 445 } else { 446 /* set watchdog timeout (high byte) */ 447 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TMO_MSB, 448 period >> 8); 449 450 /* enable watchdog timer */ 451 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 452 IT_WDT_TCR_SECS | IT_WDT_TCR_KRST | 453 IT_WDT_TCR_PWROK); 454 } 455 } 456 457 /* exit MB PnP mode */ 458 it_exit(sc->sc_iot, sc->sc_ioh); 459 460 return (period); 461 } 462 463 464 struct cfattach it_ca = { 465 sizeof(struct it_softc), 466 it_match, 467 it_attach 468 }; 469 470 struct cfdriver it_cd = { 471 NULL, "it", DV_DULL 472 }; 473