diff options
Diffstat (limited to 'sys/dev/isa/it.c')
-rw-r--r-- | sys/dev/isa/it.c | 492 |
1 files changed, 298 insertions, 194 deletions
diff --git a/sys/dev/isa/it.c b/sys/dev/isa/it.c index 79c51ac1baa..9d36c0ed997 100644 --- a/sys/dev/isa/it.c +++ b/sys/dev/isa/it.c @@ -1,7 +1,7 @@ -/* $OpenBSD: it.c,v 1.23 2007/06/24 05:34:35 dlg Exp $ */ +/* $OpenBSD: it.c,v 1.24 2007/12/18 21:17:54 form Exp $ */ /* - * Copyright (c) 2003 Julien Bordet <zejames@greyhats.org> + * Copyright (c) 2007 Oleg Safiullin <form@pdp-11.org.ru> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,292 +28,396 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/device.h> -#include <sys/kernel.h> #include <sys/sensors.h> + #include <machine/bus.h> #include <dev/isa/isareg.h> #include <dev/isa/isavar.h> - #include <dev/isa/itvar.h> + #if defined(ITDEBUG) #define DPRINTF(x) do { printf x; } while (0) #else #define DPRINTF(x) #endif -/* - * IT87-compatible chips can typically measure voltages up to 4.096 V. - * To measure higher voltages the input is attenuated with (external) - * resistors. Negative voltages are measured using a reference - * voltage. So we have to convert the sensor values back to real - * voltages by applying the appropriate resistor factor. - */ -#define RFACT_NONE 10000 -#define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y)) -int it_match(struct device *, void *, void *); +int it_probe(struct isa_attach_args *, bus_addr_t); +int it_match(struct device *, void *, void *); void it_attach(struct device *, struct device *, void *); -u_int8_t it_readreg(struct it_softc *, int); -void it_writereg(struct it_softc *, int, int); -void it_setup_volt(struct it_softc *, int, int); -void it_setup_temp(struct it_softc *, int, int); -void it_setup_fan(struct it_softc *, int, int); - -void it_generic_stemp(struct it_softc *, struct ksensor *); -void it_generic_svolt(struct it_softc *, struct ksensor *); -void it_generic_fanrpm(struct it_softc *, struct ksensor *); +u_int8_t it_readreg(bus_space_tag_t, bus_space_handle_t, int); +void it_writereg(bus_space_tag_t, bus_space_handle_t, int, u_int8_t); +void it_enter(bus_space_tag_t, bus_space_handle_t, int); +void it_exit(bus_space_tag_t, bus_space_handle_t); + +u_int8_t it_ec_readreg(struct it_softc *, int); +void it_ec_writereg(struct it_softc *, int, u_int8_t); +void it_ec_refresh(void *arg); + +int it_wdog_cb(void *, int); + + +struct { + int type; + const char *desc; +} it_sensors[IT_EC_NUMSENSORS] = { +#define IT_TEMP_BASE 0 +#define IT_TEMP_COUNT 3 + { SENSOR_TEMP, NULL }, + { SENSOR_TEMP, NULL }, + { SENSOR_TEMP, NULL }, + +#define IT_FAN_BASE 3 +#define IT_FAN_COUNT 3 + { SENSOR_FANRPM, NULL }, + { SENSOR_FANRPM, NULL }, + { SENSOR_FANRPM, NULL }, + +#define IT_VOLT_BASE 6 +#define IT_VOLT_COUNT 9 + { SENSOR_VOLTS_DC, "VCORE_A" }, + { SENSOR_VOLTS_DC, "VCORE_B" }, + { SENSOR_VOLTS_DC, "+3.3V" }, + { SENSOR_VOLTS_DC, "+5V" }, + { SENSOR_VOLTS_DC, "+12V" }, + { SENSOR_VOLTS_DC, "-5V" }, + { SENSOR_VOLTS_DC, "-12V" }, + { SENSOR_VOLTS_DC, "+5VSB" }, + { SENSOR_VOLTS_DC, "VBAT" } +}; -void it_refresh_sensor_data(struct it_softc *); -void it_refresh(void *); +#define RFACT_NONE 10000 +#define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y)) -struct cfattach it_ca = { - sizeof(struct it_softc), - it_match, - it_attach +int it_vrfact[IT_VOLT_COUNT] = { + RFACT_NONE, RFACT_NONE, RFACT_NONE, RFACT(68, 100), RFACT(30, 10), + RFACT(21, 10), RFACT(83, 20), + RFACT(68, 100), RFACT_NONE }; -struct cfdriver it_cd = { - NULL, "it", DV_DULL -}; +int it_found; -const int it_vrfact[] = { - RFACT_NONE, - RFACT_NONE, - RFACT_NONE, - RFACT(68, 100), - RFACT(30, 10), - RFACT(21, 10), - RFACT(83, 20), - RFACT(68, 100), - RFACT_NONE -}; int -it_match(struct device *parent, void *match, void *aux) +it_probe(struct isa_attach_args *ia, bus_addr_t iobase) { - bus_space_tag_t iot; bus_space_handle_t ioh; - struct isa_attach_args *ia = aux; - int iobase; - u_int8_t cr; - - iot = ia->ia_iot; - iobase = ia->ipa_io[0].base; + u_int16_t cr; - if (bus_space_map(iot, iobase, 8, 0, &ioh)) { - DPRINTF(("it: can't map i/o space\n")); + /* map i/o space */ + if (bus_space_map(ia->ia_iot, iobase, 2, 0, &ioh) != 0) { + DPRINTF(("it_probe: can't map i/o space")); return (0); } - /* Check Vendor ID */ - bus_space_write_1(iot, ioh, ITC_ADDR, ITD_CHIPID); - cr = bus_space_read_1(iot, ioh, ITC_DATA); - bus_space_unmap(iot, ioh, 8); - DPRINTF(("it: vendor id 0x%x\n", cr)); - if (cr != IT_ID_IT87) + /* enter MB PnP mode */ + it_enter(ia->ia_iot, ioh, iobase); + + /* get chip id */ + cr = it_readreg(ia->ia_iot, ioh, IT_CHIPID1) << 8; + cr |= it_readreg(ia->ia_iot, ioh, IT_CHIPID2); + + /* exit MB PnP mode and unmap */ + it_exit(ia->ia_iot, ioh); + bus_space_unmap(ia->ia_iot, ioh, 2); + + switch (cr) { + case IT_ID_8705: + case IT_ID_8712: + case IT_ID_8716: + case IT_ID_8718: + case IT_ID_8726: + ia->ipa_io[0].base = iobase; + ia->ipa_nio = 1; + ia->ipa_io[0].length = 2; + ia->ipa_nmem = ia->ipa_nirq = ia->ipa_ndrq = 0; + break; + default: return (0); - - ia->ipa_nio = 1; - ia->ipa_io[0].length = 8; - ia->ipa_nmem = 0; - ia->ipa_nirq = 0; - ia->ipa_ndrq = 0; + } return (1); } +int +it_match(struct device *parent, void *match, void *aux) +{ + struct isa_attach_args *ia = aux; + + if (!it_found) { + if (ia->ipa_io[0].base == IOBASEUNK) { + if (it_probe(ia, IO_IT1) || it_probe(ia, IO_IT2)) + return (1); + } else if (ia->ipa_io[0].base == IO_IT1 || + ia->ipa_io[0].base == IO_IT2) + return (it_probe(ia, ia->ipa_io[0].base)); + } + + return (0); +} + void it_attach(struct device *parent, struct device *self, void *aux) { struct it_softc *sc = (void *)self; - int iobase; - bus_space_tag_t iot; struct isa_attach_args *ia = aux; - int i; + int i, iobase; u_int8_t cr; - iobase = ia->ipa_io[0].base; - iot = sc->it_iot = ia->ia_iot; - - if (bus_space_map(iot, iobase, 8, 0, &sc->it_ioh)) { + sc->sc_iot = ia->ia_iot; + sc->sc_iobase = ia->ipa_io[0].base; + if (bus_space_map(sc->sc_iot, sc->sc_iobase, 2, 0, &sc->sc_ioh) != 0) { printf(": can't map i/o space\n"); return; } - i = it_readreg(sc, ITD_CHIPID); - switch (i) { - case IT_ID_IT87: - printf(": IT87\n"); - break; + it_found++; + + /* enter MB PnP mode */ + it_enter(sc->sc_iot, sc->sc_ioh, sc->sc_iobase); + + /* get chip id and rev */ + sc->sc_chipid = it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPID1) << 8; + sc->sc_chipid |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPID2); + sc->sc_chiprev = it_readreg(sc->sc_iot, sc->sc_ioh, IT_CHIPREV); + + /* get environment controller base address */ + it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_EC_LDN); + iobase = it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_MSB) << 8; + iobase |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_LSB); + + /* initialize watchdog */ + if (sc->sc_chipid != IT_ID_8705) { + it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_WDT_LDN); + it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_CSR, 0x00); + it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 0x80); + wdog_register(sc, it_wdog_cb); + } + + /* exit MB PnP mode and unmap */ + it_exit(sc->sc_iot, sc->sc_ioh); + + printf(": IT%xF rev 0x%02x", sc->sc_chipid, sc->sc_chiprev); + + if (iobase == 0) { + printf(", EC disabled\n"); + return; + } + + printf(", EC port 0x%x\n", iobase); + + /* map environment controller i/o space */ + sc->sc_ec_iot = ia->ia_iot; + if (bus_space_map(sc->sc_ec_iot, iobase, 8, 0, &sc->sc_ec_ioh) != 0) { + printf("%s: can't map EC i/o space\n", sc->sc_dev.dv_xname); + return; } - sc->numsensors = IT_NUM_SENSORS; + /* initialize sensor structures */ + for (i = 0; i < IT_EC_NUMSENSORS; i++) { + sc->sc_sensors[i].type = it_sensors[i].type; - it_setup_fan(sc, 0, 3); - it_setup_volt(sc, 3, 9); - it_setup_temp(sc, 12, 3); + if (it_sensors[i].desc != NULL) + snprintf(sc->sc_sensors[i].desc, + sizeof(sc->sc_sensors[i].desc), + it_sensors[i].desc); + } - if (sensor_task_register(sc, it_refresh, 5) == NULL) { - printf("%s: unable to register update task\n", + /* register update task */ + if (sensor_task_register(sc, it_ec_refresh, IT_EC_INTERVAL) == NULL) { + printf(": unable to register update task\n", sc->sc_dev.dv_xname); + bus_space_unmap(sc->sc_ec_iot, sc->sc_ec_ioh, 8); return; } - /* Activate monitoring */ - cr = it_readreg(sc, ITD_CONFIG); - cr |= 0x01 | 0x08; - it_writereg(sc, ITD_CONFIG, cr); - - /* Initialize sensors */ - strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname, - sizeof(sc->sensordev.xname)); - for (i = 0; i < sc->numsensors; ++i) - sensor_attach(&sc->sensordev, &sc->sensors[i]); - sensordev_install(&sc->sensordev); + /* activate monitoring */ + cr = it_ec_readreg(sc, IT_EC_CFG); + it_ec_writereg(sc, IT_EC_CFG, cr | 0x09); + + /* initialize sensors */ + strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, + sizeof(sc->sc_sensordev.xname)); + for (i = 0; i < IT_EC_NUMSENSORS; i++) + sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); + sensordev_install(&sc->sc_sensordev); } u_int8_t -it_readreg(struct it_softc *sc, int reg) +it_readreg(bus_space_tag_t iot, bus_space_handle_t ioh, int r) { - bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_ADDR, reg); - return (bus_space_read_1(sc->it_iot, sc->it_ioh, ITC_DATA)); + bus_space_write_1(iot, ioh, IT_IO_ADDR, r); + return (bus_space_read_1(iot, ioh, IT_IO_DATA)); } void -it_writereg(struct it_softc *sc, int reg, int val) +it_writereg(bus_space_tag_t iot, bus_space_handle_t ioh, int r, u_int8_t v) { - bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_ADDR, reg); - bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_DATA, val); + bus_space_write_1(iot, ioh, IT_IO_ADDR, r); + bus_space_write_1(iot, ioh, IT_IO_DATA, v); } void -it_setup_volt(struct it_softc *sc, int start, int n) +it_enter(bus_space_tag_t iot, bus_space_handle_t ioh, int iobase) { - int i; - - for (i = 0; i < n; ++i) { - sc->sensors[start + i].type = SENSOR_VOLTS_DC; - } - - snprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc), - "VCORE_A"); - snprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc), - "VCORE_B"); - snprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc), - "+3.3V"); - snprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc), - "+5V"); - snprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc), - "+12V"); - snprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc), - "Unused"); - snprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc), - "-12V"); - snprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc), - "+5VSB"); - snprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc), - "VBAT"); + bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x87); + bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x01); + bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x55); + if (iobase == IO_IT1) + bus_space_write_1(iot, ioh, IT_IO_ADDR, 0x55); + else + bus_space_write_1(iot, ioh, IT_IO_ADDR, 0xaa); } void -it_setup_temp(struct it_softc *sc, int start, int n) +it_exit(bus_space_tag_t iot, bus_space_handle_t ioh) { - int i; - - for (i = 0; i < n; ++i) - sc->sensors[start + i].type = SENSOR_TEMP; + bus_space_write_1(iot, ioh, IT_IO_ADDR, IT_CCR); + bus_space_write_1(iot, ioh, IT_IO_DATA, 0x02); } -void -it_setup_fan(struct it_softc *sc, int start, int n) +u_int8_t +it_ec_readreg(struct it_softc *sc, int r) { - int i; - - for (i = 0; i < n; ++i) - sc->sensors[start + i].type = SENSOR_FANRPM; + bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_ADDR, r); + return (bus_space_read_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_DATA)); } void -it_generic_stemp(struct it_softc *sc, struct ksensor *sensors) +it_ec_writereg(struct it_softc *sc, int r, u_int8_t v) { - int i, sdata; - - for (i = 0; i < 3; i++) { - sdata = it_readreg(sc, ITD_SENSORTEMPBASE + i); - /* Convert temperature to Fahrenheit degres */ - sensors[i].value = sdata * 1000000 + 273150000; - } + bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_ADDR, r); + bus_space_write_1(sc->sc_ec_iot, sc->sc_ec_ioh, IT_EC_DATA, v); } void -it_generic_svolt(struct it_softc *sc, struct ksensor *sensors) +it_ec_refresh(void *arg) { - int i, sdata; + struct it_softc *sc = arg; + int i, sdata, mode, divisor, odivisor, ndivisor; + + /* refresh temp sensors */ + for (i = 0; i < IT_TEMP_COUNT; i++) { + sdata = it_ec_readreg(sc, IT_EC_TEMPBASE + i); + /* convert to degF */ + sc->sc_sensors[IT_TEMP_BASE + i].value = + sdata * 1000000 + 273150000; + } - for (i = 0; i < 9; i++) { - sdata = it_readreg(sc, ITD_SENSORVOLTBASE + i); - DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); + /* refresh volt sensors */ + for (i = 0; i < IT_VOLT_COUNT; i++) { + sdata = it_ec_readreg(sc, IT_EC_VOLTBASE + i); /* voltage returned as (mV >> 4) */ - sensors[i].value = (sdata << 4); + sc->sc_sensors[IT_VOLT_BASE + i].value = sdata << 4; /* these two values are negative and formula is different */ if (i == 5 || i == 6) - sensors[i].value = ((sdata << 4) - IT_VREF); + sc->sc_sensors[IT_VOLT_BASE + i].value -= IT_EC_VREF; /* rfact is (factor * 10^4) */ - sensors[i].value *= it_vrfact[i]; + sc->sc_sensors[IT_VOLT_BASE + i].value *= it_vrfact[i]; /* division by 10 gets us back to uVDC */ - sensors[i].value /= 10; + sc->sc_sensors[IT_VOLT_BASE + i].value /= 10; if (i == 5 || i == 6) - sensors[i].value += IT_VREF * 1000; + sc->sc_sensors[IT_VOLT_BASE + i].value += + IT_EC_VREF * 1000; } -} -void -it_generic_fanrpm(struct it_softc *sc, struct ksensor *sensors) -{ - int i, sdata, divisor, odivisor, ndivisor; - - odivisor = ndivisor = divisor = it_readreg(sc, ITD_FAN); - for (i = 0; i < 3; i++, divisor >>= 3) { - sensors[i].flags &= ~SENSOR_FINVALID; - if ((sdata = it_readreg(sc, ITD_SENSORFANBASE + i)) == 0xff) { - sensors[i].flags |= SENSOR_FINVALID; - if (i == 2) - ndivisor ^= 0x40; - else { - ndivisor &= ~(7 << (i * 3)); - ndivisor |= ((divisor + 1) & 7) << (i * 3); - } - } else if (sdata == 0) { - sensors[i].value = 0; + /* refresh fan sensors */ + if (sc->sc_chipid == IT_ID_8705 || sc->sc_chipid == IT_ID_8712) + odivisor = ndivisor = divisor = + it_ec_readreg(sc, IT_EC_FAN_DIV); + else { + mode = it_ec_readreg(sc, IT_EC_FAN_ECR); + divisor = -1; + } + + for (i = 0; i < IT_FAN_COUNT; i++) { + sc->sc_sensors[IT_FAN_BASE + i].flags &= ~SENSOR_FINVALID; + sdata = it_ec_readreg(sc, IT_EC_FANBASE + i); + + if (divisor != -1) { + /* + * Use 8-bit FAN Tachometer & FAN Divisor registers + */ + if (sdata == 0xff) { + sc->sc_sensors[IT_FAN_BASE + i].flags |= + SENSOR_FINVALID; + if (i == 2) + ndivisor ^= 0x40; + else { + ndivisor &= ~(7 << (i * 3)); + ndivisor |= ((divisor + 1) & 7) << + (i * 3); + } + } else if (sdata != 0) { + if (i == 2) + divisor = divisor & 1 ? 3 : 1; + sc->sc_sensors[IT_FAN_BASE + i].value = + 1350000 / (sdata << (divisor & 7)); + } else + sc->sc_sensors[IT_FAN_BASE + i].value = 0; + + if (ndivisor != odivisor) + it_ec_writereg(sc, IT_EC_FAN_DIV, ndivisor); } else { - if (i == 2) - divisor = divisor & 1 ? 3 : 1; - sensors[i].value = 1350000 / (sdata << (divisor & 7)); + /* + * Use 16-bit FAN tachometer register + */ + if (mode & (1 << i)) + sdata |= it_ec_readreg(sc, + IT_EC_FANEXTBASE + i) << 8; + if (sdata == ((mode & (1 << i)) ? 0xffff : 0xff)) + sc->sc_sensors[IT_FAN_BASE + i].flags |= + SENSOR_FINVALID; + else if (sdata != 0) + sc->sc_sensors[IT_FAN_BASE + i].value = + 675000 / sdata; + else + sc->sc_sensors[IT_FAN_BASE + i].value = 0; } } - if (ndivisor != odivisor) - it_writereg(sc, ITD_FAN, ndivisor); } -/* - * pre: last read occurred >= 1.5 seconds ago - * post: sensors[] current data are the latest from the chip - */ -void -it_refresh_sensor_data(struct it_softc *sc) +int +it_wdog_cb(void *arg, int period) { - /* Refresh our stored data for every sensor */ - it_generic_stemp(sc, &sc->sensors[12]); - it_generic_svolt(sc, &sc->sensors[3]); - it_generic_fanrpm(sc, &sc->sensors[0]); -} + struct it_softc *sc = arg; -void -it_refresh(void *arg) -{ - struct it_softc *sc = (struct it_softc *)arg; + /* enter MB PnP mode and select WDT device */ + it_enter(sc->sc_iot, sc->sc_ioh, sc->sc_iobase); + it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_WDT_LDN); + + /* disable watchdog timeout */ + it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 0x80); - it_refresh_sensor_data(sc); + /* 1000s should be enough for everyone */ + if (period > 1000) + period = 1000; + else if (period < 0) + period = 0; + + /* set watchdog timeout */ + it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_MSB, period >> 8); + it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_LSB, period & 0xff); + + if (period > 0) + /* enable watchdog timeout */ + it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 0xc0); + + /* exit MB PnP mode */ + it_exit(sc->sc_iot, sc->sc_ioh); + + return (period); } + + +struct cfattach it_ca = { + sizeof(struct it_softc), + it_match, + it_attach +}; + +struct cfdriver it_cd = { + NULL, "it", DV_DULL +}; |