1 /* $OpenBSD: it.c,v 1.32 2008/04/07 17:50:37 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 u_int8_t cr; 193 194 sc->sc_iot = ia->ia_iot; 195 sc->sc_iobase = ia->ipa_io[0].base; 196 if (bus_space_map(sc->sc_iot, sc->sc_iobase, 2, 0, &sc->sc_ioh) != 0) { 197 printf(": can't map i/o space\n"); 198 return; 199 } 200 201 /* enter MB PnP mode */ 202 it_enter(sc->sc_iot, sc->sc_ioh, sc->sc_iobase); 203 204 /* get chip id and rev */ 205 sc->sc_chipid = it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPID1) << 8; 206 sc->sc_chipid |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPID2); 207 sc->sc_chiprev = it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPREV); 208 209 /* get environment controller base address */ 210 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_EC_LDN); 211 sc->sc_ec_iobase = it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_MSB) << 8; 212 sc->sc_ec_iobase |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_LSB); 213 214 /* initialize watchdog */ 215 if (sc->sc_chipid != IT_ID_8705) { 216 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_WDT_LDN); 217 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_CSR, 0x00); 218 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 219 IT_WDT_TCR_SECS); 220 wdog_register(sc, it_wdog_cb); 221 } 222 223 /* exit MB PnP mode and unmap */ 224 it_exit(sc->sc_iot, sc->sc_ioh); 225 226 LIST_INSERT_HEAD(&it_softc_list, sc, sc_list); 227 228 printf(": IT%xF rev 0x%02x", sc->sc_chipid, sc->sc_chiprev); 229 230 if (sc->sc_ec_iobase == 0) { 231 printf(", EC disabled\n"); 232 return; 233 } 234 235 printf(", EC port 0x%x\n", sc->sc_ec_iobase); 236 237 /* map environment controller i/o space */ 238 sc->sc_ec_iot = ia->ia_iot; 239 if (bus_space_map(sc->sc_ec_iot, sc->sc_ec_iobase, 8, 0, 240 &sc->sc_ec_ioh) != 0) { 241 printf("%s: can't map EC i/o space\n", sc->sc_dev.dv_xname); 242 return; 243 } 244 245 /* initialize sensor structures */ 246 for (i = 0; i < IT_EC_NUMSENSORS; i++) { 247 sc->sc_sensors[i].type = it_sensors[i].type; 248 249 if (it_sensors[i].desc != NULL) 250 strlcpy(sc->sc_sensors[i].desc, it_sensors[i].desc, 251 sizeof(sc->sc_sensors[i].desc)); 252 } 253 254 /* register update task */ 255 if (sensor_task_register(sc, it_ec_refresh, IT_EC_INTERVAL) == NULL) { 256 printf(": unable to register update task\n", 257 sc->sc_dev.dv_xname); 258 bus_space_unmap(sc->sc_ec_iot, sc->sc_ec_ioh, 8); 259 return; 260 } 261 262 /* activate monitoring */ 263 cr = it_ec_readreg(sc, IT_EC_CFG); 264 it_ec_writereg(sc, IT_EC_CFG, cr | 0x09); 265 266 /* initialize sensors */ 267 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 268 sizeof(sc->sc_sensordev.xname)); 269 for (i = 0; i < IT_EC_NUMSENSORS; i++) 270 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); 271 sensordev_install(&sc->sc_sensordev); 272 } 273 274 u_int8_t 275 it_readreg(bus_space_tag_t iot, bus_space_handle_t ioh, int r) 276 { 277 bus_space_write_1(iot, ioh, IT_IO_ADDR, r); 278 return (bus_space_read_1(iot, ioh, IT_IO_DATA)); 279 } 280 281 void 282 it_writereg(bus_space_tag_t iot, bus_space_handle_t ioh, int r, u_int8_t v) 283 { 284 bus_space_write_1(iot, ioh, IT_IO_ADDR, r); 285 bus_space_write_1(iot, ioh, IT_IO_DATA, v); 286 } 287 288 void 289 it_enter(bus_space_tag_t iot, bus_space_handle_t ioh, int iobase) 290 { 291 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x87); 292 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x01); 293 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x55); 294 if (iobase == IO_IT1) 295 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x55); 296 else 297 bus_space_write_1(iot, ioh, IT_IO_ADDR, 0xaa); 298 } 299 300 void 301 it_exit(bus_space_tag_t iot, bus_space_handle_t ioh) 302 { 303 bus_space_write_1(iot, ioh, IT_IO_ADDR, IT_CCR); 304 bus_space_write_1(iot, ioh, IT_IO_DATA, 0x02); 305 } 306 307 u_int8_t 308 it_ec_readreg(struct it_softc *sc, int r) 309 { 310 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_ADDR, r); 311 return (bus_space_read_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_DATA)); 312 } 313 314 void 315 it_ec_writereg(struct it_softc *sc, int r, u_int8_t v) 316 { 317 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_ADDR, r); 318 bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_DATA, v); 319 } 320 321 void 322 it_ec_refresh(void *arg) 323 { 324 struct it_softc *sc = arg; 325 int i, sdata, mode, divisor, odivisor, ndivisor; 326 327 /* refresh temp sensors */ 328 for (i = 0; i < IT_TEMP_COUNT; i++) { 329 sdata = it_ec_readreg(sc, IT_EC_TEMPBASE + i); 330 /* convert to degF */ 331 sc->sc_sensors[IT_TEMP_BASE + i].value = 332 sdata * 1000000 + 273150000; 333 } 334 335 /* refresh volt sensors */ 336 for (i = 0; i < IT_VOLT_COUNT; i++) { 337 sdata = it_ec_readreg(sc, IT_EC_VOLTBASE + i); 338 /* voltage returned as (mV >> 4) */ 339 sc->sc_sensors[IT_VOLT_BASE + i].value = sdata << 4; 340 /* these two values are negative and formula is different */ 341 if (i == 5 || i == 6) 342 sc->sc_sensors[IT_VOLT_BASE + i].value -= IT_EC_VREF; 343 /* rfact is (factor * 10^4) */ 344 sc->sc_sensors[IT_VOLT_BASE + i].value *= it_vrfact[i]; 345 /* division by 10 gets us back to uVDC */ 346 sc->sc_sensors[IT_VOLT_BASE + i].value /= 10; 347 if (i == 5 || i == 6) 348 sc->sc_sensors[IT_VOLT_BASE + i].value += 349 IT_EC_VREF * 1000; 350 } 351 352 /* refresh fan sensors */ 353 if (sc->sc_chipid == IT_ID_8705 || sc->sc_chipid == IT_ID_8712) 354 odivisor = ndivisor = divisor = 355 it_ec_readreg(sc, IT_EC_FAN_DIV); 356 else { 357 mode = it_ec_readreg(sc, IT_EC_FAN_ECR); 358 divisor = -1; 359 } 360 361 for (i = 0; i < IT_FAN_COUNT; i++) { 362 sc->sc_sensors[IT_FAN_BASE + i].flags &= ~SENSOR_FINVALID; 363 sdata = it_ec_readreg(sc, IT_EC_FANBASE + i); 364 365 if (divisor != -1) { 366 /* 367 * Use 8-bit FAN Tachometer & FAN Divisor registers 368 */ 369 if (sdata == 0xff) { 370 sc->sc_sensors[IT_FAN_BASE + i].flags |= 371 SENSOR_FINVALID; 372 if (i == 2) 373 ndivisor ^= 0x40; 374 else { 375 ndivisor &= ~(7 << (i * 3)); 376 ndivisor |= ((divisor + 1) & 7) << 377 (i * 3); 378 } 379 } else if (sdata != 0) { 380 if (i == 2) 381 divisor = divisor & 1 ? 3 : 1; 382 sc->sc_sensors[IT_FAN_BASE + i].value = 383 1350000 / (sdata << (divisor & 7)); 384 } else 385 sc->sc_sensors[IT_FAN_BASE + i].value = 0; 386 387 if (ndivisor != odivisor) 388 it_ec_writereg(sc, IT_EC_FAN_DIV, ndivisor); 389 } else { 390 /* 391 * Use 16-bit FAN tachometer register 392 */ 393 if (mode & (1 << i)) 394 sdata |= it_ec_readreg(sc, 395 IT_EC_FANEXTBASE + i) << 8; 396 if (sdata == ((mode & (1 << i)) ? 0xffff : 0xff)) 397 sc->sc_sensors[IT_FAN_BASE + i].flags |= 398 SENSOR_FINVALID; 399 else if (sdata != 0) 400 sc->sc_sensors[IT_FAN_BASE + i].value = 401 675000 / sdata; 402 else 403 sc->sc_sensors[IT_FAN_BASE + i].value = 0; 404 } 405 } 406 } 407 408 int 409 it_wdog_cb(void *arg, int period) 410 { 411 struct it_softc *sc = arg; 412 413 /* enter MB PnP mode and select WDT device */ 414 it_enter(sc->sc_iot, sc->sc_ioh, sc->sc_iobase); 415 it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_WDT_LDN); 416 417 /* disable watchdog timeout */ 418 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, IT_WDT_TCR_SECS); 419 420 /* 1000s should be enough for everyone */ 421 if (period > 1000) 422 period = 1000; 423 else if (period < 0) 424 period = 0; 425 426 /* set watchdog timeout */ 427 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TMO_MSB, period >> 8); 428 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TMO_LSB, period & 0xff); 429 430 if (period > 0) 431 /* enable watchdog timeout */ 432 it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 433 IT_WDT_TCR_SECS | IT_WDT_TCR_KRST); 434 435 /* exit MB PnP mode */ 436 it_exit(sc->sc_iot, sc->sc_ioh); 437 438 return (period); 439 } 440 441 442 struct cfattach it_ca = { 443 sizeof(struct it_softc), 444 it_match, 445 it_attach 446 }; 447 448 struct cfdriver it_cd = { 449 NULL, "it", DV_DULL 450 }; 451