123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- /* $OpenBSD: it.c,v 1.46 2015/03/14 03:38:47 jsg Exp $ */
- /*
- * Copyright (c) 2007-2008 Oleg Safiullin <form@pdp-11.org.ru>
- * Copyright (c) 2006-2007 Juan Romero Pardines <juan@xtrarom.org>
- * Copyright (c) 2003 Julien Bordet <zejames@greyhats.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/device.h>
- #include <sys/sensors.h>
- #include <machine/bus.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
- int it_match(struct device *, void *, void *);
- void it_attach(struct device *, struct device *, void *);
- int it_activate(struct device *, int);
- 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);
- /*
- * 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))
- struct {
- enum sensor_type 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 5
- { SENSOR_FANRPM, NULL },
- { SENSOR_FANRPM, NULL },
- { SENSOR_FANRPM, NULL },
- { SENSOR_FANRPM, NULL },
- { SENSOR_FANRPM, NULL },
- #define IT_VOLT_BASE 8
- #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, "-12V" },
- { SENSOR_VOLTS_DC, "-5V" },
- { SENSOR_VOLTS_DC, "+5VSB" },
- { SENSOR_VOLTS_DC, "VBAT" }
- };
- /* rfact values for voltage sensors */
- int it_vrfact[IT_VOLT_COUNT] = {
- RFACT_NONE, /* VCORE_A */
- RFACT_NONE, /* VCORE_A */
- RFACT_NONE, /* +3.3V */
- RFACT(68, 100), /* +5V */
- RFACT(30, 10), /* +12V */
- RFACT(83, 20), /* -12V */
- RFACT(21, 10), /* -5V */
- RFACT(68, 100), /* +5VSB */
- RFACT_NONE /* VBAT */
- };
- int it_fan_regs[] = {
- IT_EC_FAN_TAC1, IT_EC_FAN_TAC2, IT_EC_FAN_TAC3,
- IT_EC_FAN_TAC4_LSB, IT_EC_FAN_TAC5_LSB
- };
- int it_fan_ext_regs[] = {
- IT_EC_FAN_EXT_TAC1, IT_EC_FAN_EXT_TAC2, IT_EC_FAN_EXT_TAC3,
- IT_EC_FAN_TAC4_MSB, IT_EC_FAN_TAC5_MSB
- };
- LIST_HEAD(, it_softc) it_softc_list = LIST_HEAD_INITIALIZER(it_softc_list);
- int
- it_match(struct device *parent, void *match, void *aux)
- {
- struct isa_attach_args *ia = aux;
- struct it_softc *sc;
- bus_space_handle_t ioh;
- int ec_iobase, found = 0;
- u_int16_t cr;
- if (ia->ipa_io[0].base != IO_IT1 && ia->ipa_io[0].base != IO_IT2)
- return (0);
- /* map i/o space */
- if (bus_space_map(ia->ia_iot, ia->ipa_io[0].base, 2, 0, &ioh) != 0) {
- DPRINTF(("it_match: can't map i/o space"));
- return (0);
- }
- /* enter MB PnP mode */
- it_enter(ia->ia_iot, ioh, ia->ipa_io[0].base);
- /*
- * SMSC or similar SuperIO chips use 0x55 magic to enter PnP mode
- * and 0xaa to exit. These chips also enter PnP mode via ITE
- * `enter MB PnP mode' sequence, so force chip to exit PnP mode
- * if this is the case.
- */
- bus_space_write_1(ia->ia_iot, ioh, IT_IO_ADDR, 0xaa);
- /* get chip id */
- cr = it_readreg(ia->ia_iot, ioh, IT_CHIPID1) << 8;
- cr |= it_readreg(ia->ia_iot, ioh, IT_CHIPID2);
- switch (cr) {
- case IT_ID_8705:
- case IT_ID_8712:
- case IT_ID_8716:
- case IT_ID_8718:
- case IT_ID_8720:
- case IT_ID_8721:
- case IT_ID_8726:
- case IT_ID_8728:
- case IT_ID_8772:
- /* get environment controller base address */
- it_writereg(ia->ia_iot, ioh, IT_LDN, IT_EC_LDN);
- ec_iobase = it_readreg(ia->ia_iot, ioh, IT_EC_MSB) << 8;
- ec_iobase |= it_readreg(ia->ia_iot, ioh, IT_EC_LSB);
- /* check if device already attached */
- LIST_FOREACH(sc, &it_softc_list, sc_list)
- if (sc->sc_ec_iobase == ec_iobase)
- break;
- if (sc == NULL) {
- ia->ipa_nio = 1;
- ia->ipa_io[0].length = 2;
- ia->ipa_nmem = ia->ipa_nirq = ia->ipa_ndrq = 0;
- found++;
- }
- break;
- }
- /* exit MB PnP mode */
- it_exit(ia->ia_iot, ioh);
- /* unmap i/o space */
- bus_space_unmap(ia->ia_iot, ioh, 2);
- return (found);
- }
- void
- it_attach(struct device *parent, struct device *self, void *aux)
- {
- struct it_softc *sc = (void *)self;
- struct isa_attach_args *ia = aux;
- int i;
- 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;
- }
- /* 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) & 0x0f;
- /* get environment controller base address */
- it_writereg(sc->sc_iot, sc->sc_ioh, IT_LDN, IT_EC_LDN);
- sc->sc_ec_iobase = it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_MSB) << 8;
- sc->sc_ec_iobase |= it_readreg(sc->sc_iot, sc->sc_ioh, IT_EC_LSB);
- /* initialize watchdog timer */
- 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, 0x00);
- wdog_register(it_wdog_cb, sc);
- }
- /* exit MB PnP mode and unmap */
- it_exit(sc->sc_iot, sc->sc_ioh);
- LIST_INSERT_HEAD(&it_softc_list, sc, sc_list);
- printf(": IT%xF rev %X", sc->sc_chipid, sc->sc_chiprev);
- if (sc->sc_ec_iobase == 0) {
- printf(", EC disabled\n");
- return;
- }
- printf(", EC port 0x%x\n", sc->sc_ec_iobase);
- /* map environment controller i/o space */
- sc->sc_ec_iot = ia->ia_iot;
- if (bus_space_map(sc->sc_ec_iot, sc->sc_ec_iobase, 8, 0,
- &sc->sc_ec_ioh) != 0) {
- printf("%s: can't map EC i/o space\n", sc->sc_dev.dv_xname);
- return;
- }
- /* initialize sensor structures */
- for (i = 0; i < IT_EC_NUMSENSORS; i++) {
- sc->sc_sensors[i].type = it_sensors[i].type;
- if (it_sensors[i].desc != NULL)
- strlcpy(sc->sc_sensors[i].desc, it_sensors[i].desc,
- sizeof(sc->sc_sensors[i].desc));
- }
- /* register sensor update task */
- if (sensor_task_register(sc, it_ec_refresh, IT_EC_INTERVAL) == NULL) {
- printf("%s: unable to register update task\n",
- sc->sc_dev.dv_xname);
- bus_space_unmap(sc->sc_ec_iot, sc->sc_ec_ioh, 8);
- return;
- }
- /* use 16-bit FAN tachometer registers for newer chips */
- if (sc->sc_chipid != IT_ID_8705 && sc->sc_chipid != IT_ID_8712)
- it_ec_writereg(sc, IT_EC_FAN_ECER,
- it_ec_readreg(sc, IT_EC_FAN_ECER) | 0x07);
- /* activate monitoring */
- it_ec_writereg(sc, IT_EC_CFG,
- it_ec_readreg(sc, IT_EC_CFG) | IT_EC_CFG_START | IT_EC_CFG_INTCLR);
- /* 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);
- }
- int
- it_activate(struct device *self, int act)
- {
- switch (act) {
- case DVACT_POWERDOWN:
- wdog_shutdown(self);
- break;
- }
- return (0);
- }
- u_int8_t
- it_readreg(bus_space_tag_t iot, bus_space_handle_t ioh, int r)
- {
- bus_space_write_1(iot, ioh, IT_IO_ADDR, r);
- return (bus_space_read_1(iot, ioh, IT_IO_DATA));
- }
- void
- it_writereg(bus_space_tag_t iot, bus_space_handle_t ioh, int r, u_int8_t v)
- {
- bus_space_write_1(iot, ioh, IT_IO_ADDR, r);
- bus_space_write_1(iot, ioh, IT_IO_DATA, v);
- }
- void
- it_enter(bus_space_tag_t iot, bus_space_handle_t ioh, int iobase)
- {
- 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_exit(bus_space_tag_t iot, bus_space_handle_t ioh)
- {
- bus_space_write_1(iot, ioh, IT_IO_ADDR, IT_CCR);
- bus_space_write_1(iot, ioh, IT_IO_DATA, 0x02);
- }
- u_int8_t
- it_ec_readreg(struct it_softc *sc, int r)
- {
- 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_ec_writereg(struct it_softc *sc, int r, u_int8_t v)
- {
- 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_ec_refresh(void *arg)
- {
- struct it_softc *sc = arg;
- int i, sdata, divisor, odivisor, ndivisor;
- u_int8_t cr, ecr;
- /* refresh temp sensors */
- cr = it_ec_readreg(sc, IT_EC_ADC_TEMPER);
- for (i = 0; i < IT_TEMP_COUNT; i++) {
- sc->sc_sensors[IT_TEMP_BASE + i].flags &=
- SENSOR_FINVALID;
- if (!(cr & (1 << i)) && !(cr & (1 << (i + 3)))) {
- sc->sc_sensors[IT_TEMP_BASE + i].flags |=
- SENSOR_FINVALID;
- continue;
- }
- sdata = it_ec_readreg(sc, IT_EC_TEMPBASE + i);
- /* convert to degF */
- sc->sc_sensors[IT_TEMP_BASE + i].value =
- sdata * 1000000 + 273150000;
- }
- /* refresh volt sensors */
- cr = it_ec_readreg(sc, IT_EC_ADC_VINER);
- for (i = 0; i < IT_VOLT_COUNT; i++) {
- sc->sc_sensors[IT_VOLT_BASE + i].flags &=
- SENSOR_FINVALID;
- if ((i < 8) && !(cr & (1 << i))) {
- sc->sc_sensors[IT_VOLT_BASE + i].flags |=
- SENSOR_FINVALID;
- continue;
- }
- sdata = it_ec_readreg(sc, IT_EC_VOLTBASE + i);
- /* voltage returned as (mV >> 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)
- sc->sc_sensors[IT_VOLT_BASE + i].value -= IT_EC_VREF;
- /* rfact is (factor * 10^4) */
- sc->sc_sensors[IT_VOLT_BASE + i].value *= it_vrfact[i];
- /* division by 10 gets us back to uVDC */
- sc->sc_sensors[IT_VOLT_BASE + i].value /= 10;
- if (i == 5 || i == 6)
- sc->sc_sensors[IT_VOLT_BASE + i].value +=
- IT_EC_VREF * 1000;
- }
- /* refresh fan sensors */
- cr = it_ec_readreg(sc, IT_EC_FAN_MCR);
- if (sc->sc_chipid != IT_ID_8705 && sc->sc_chipid != IT_ID_8712) {
- /* use 16-bit FAN tachometer registers */
- ecr = it_ec_readreg(sc, IT_EC_FAN_ECER);
- for (i = 0; i < IT_FAN_COUNT; i++) {
- sc->sc_sensors[IT_FAN_BASE + i].flags &=
- ~SENSOR_FINVALID;
- if (i < 3 && !(cr & (1 << (i + 4)))) {
- sc->sc_sensors[IT_FAN_BASE + i].flags |=
- SENSOR_FINVALID;
- continue;
- } else if (i > 2 && !(ecr & (1 << (i + 1)))) {
- sc->sc_sensors[IT_FAN_BASE + i].flags |=
- SENSOR_FINVALID;
- continue;
- }
- sdata = it_ec_readreg(sc, it_fan_regs[i]);
- sdata |= it_ec_readreg(sc, it_fan_ext_regs[i]) << 8;
- if (sdata == 0 || sdata == 0xffff)
- sc->sc_sensors[IT_FAN_BASE + i].value = 0;
- else
- sc->sc_sensors[IT_FAN_BASE + i].value =
- 675000 / sdata;
- }
- } else {
- /* use 8-bit FAN tachometer & FAN divisor registers */
- odivisor = ndivisor = divisor =
- it_ec_readreg(sc, IT_EC_FAN_DIV);
- for (i = 0; i < IT_FAN_COUNT; i++) {
- if (i > 2 || !(cr & (1 << (i + 4)))) {
- sc->sc_sensors[IT_FAN_BASE + i].flags |=
- SENSOR_FINVALID;
- continue;
- }
- sc->sc_sensors[IT_FAN_BASE + i].flags &=
- ~SENSOR_FINVALID;
- sdata = it_ec_readreg(sc, it_fan_regs[i]);
- if (sdata == 0xff) {
- sc->sc_sensors[IT_FAN_BASE + i].value = 0;
- 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);
- }
- }
- int
- it_wdog_cb(void *arg, int period)
- {
- struct it_softc *sc = arg;
- int minutes = 0;
- /* 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 timer */
- it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR, 0x00);
- /* 1000s should be enough for everyone */
- if (period > 1000)
- period = 1000;
- else if (period < 0)
- period = 0;
- if (period > 0) {
- /*
- * Older IT8712F chips have 8-bit timeout counter.
- * Use minutes for 16-bit values for these chips.
- */
- if (sc->sc_chipid == IT_ID_8712 && sc->sc_chiprev < 0x8 &&
- period > 0xff) {
- if (period % 60 >= 30)
- period += 60;
- period /= 60;
- minutes++;
- }
- /* set watchdog timeout (low byte) */
- it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TMO_LSB,
- period & 0xff);
- if (minutes) {
- /* enable watchdog timer */
- it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR,
- IT_WDT_TCR_KRST | IT_WDT_TCR_PWROK);
- period *= 60;
- } else {
- /* set watchdog timeout (high byte) */
- it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TMO_MSB,
- period >> 8);
- /* enable watchdog timer */
- it_writereg(sc->sc_iot, sc->sc_ioh, IT_WDT_TCR,
- IT_WDT_TCR_SECS | IT_WDT_TCR_KRST |
- IT_WDT_TCR_PWROK);
- }
- }
- /* 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,
- NULL,
- it_activate
- };
- struct cfdriver it_cd = {
- NULL, "it", DV_DULL
- };
|