Subject: kern/26420: lm(4): Add support vor environment controller built into iTE 8705f
To: None <gnats-bugs@gnats.NetBSD.org>
From: None <Thilo.Manske@HEH.Uni-Oldenburg.DE>
List: netbsd-bugs
Date: 07/24/2004 18:10:54
>Number: 26420
>Category: kern
>Synopsis: lm(4): Add support vor environment controller built into iTE 8705f
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Sat Jul 24 16:43:00 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator: Thilo Manske
>Release: NetBSD 2.0G
>Organization:
>Environment:
System: NetBSD WintelKiller 2.0G NetBSD 2.0G (WintelKiller) #426: Sat Jul 10 21:50:32 MEST 2004 thilo@WintelKiller:/sys/arch/i386/compile/WintelKiller i386
Architecture: i386
Machine: i386
>Description:
This patch adds support for the environment controller built into the IT870F
super i/o chip from iTE found on some i386 motherboards.
Compared to LM or Winbond chips this environment controller has a completely
different internal register setup but otherwise works pretty much the same
way.
>How-To-Repeat:
>Fix:
Index: sys/dev/ic/nslm7x.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/nslm7x.c,v
retrieving revision 1.18
diff -c -u -r1.18 nslm7x.c
--- sys/dev/ic/nslm7x.c 22 Apr 2004 00:17:11 -0000 1.18
+++ sys/dev/ic/nslm7x.c 24 Jul 2004 16:09:44 -0000
@@ -88,6 +88,7 @@
int lm_match __P((struct lm_softc *));
int wb_match __P((struct lm_softc *));
+int itec_match __P((struct lm_softc *));
int def_match __P((struct lm_softc *));
void lm_common_match __P((struct lm_softc *));
static int lm_generic_banksel __P((struct lm_softc *, int));
@@ -108,6 +109,12 @@
void wb782_refresh_sensor_data __P((struct lm_softc *));
void wb697_refresh_sensor_data __P((struct lm_softc *));
+static void itec_svolt __P((struct lm_softc *, struct envsys_tre_data *,
+ struct envsys_basic_info *));
+static void itec_stemp __P((struct lm_softc *, struct envsys_tre_data *));
+static void itec_fanrpm __P((struct lm_softc *, struct envsys_tre_data *));
+void itec_refresh_sensor_data __P((struct lm_softc *));
+
int lm_gtredata __P((struct sysmon_envsys *, struct envsys_tre_data *));
int generic_streinfo_fan __P((struct lm_softc *, struct envsys_basic_info *,
@@ -115,12 +122,14 @@
int lm_streinfo __P((struct sysmon_envsys *, struct envsys_basic_info *));
int wb781_streinfo __P((struct sysmon_envsys *, struct envsys_basic_info *));
int wb782_streinfo __P((struct sysmon_envsys *, struct envsys_basic_info *));
+int itec_streinfo __P((struct sysmon_envsys *, struct envsys_basic_info *));
struct lm_chip {
int (*chip_match) __P((struct lm_softc *));
};
struct lm_chip lm_chips[] = {
+ { itec_match },
{ wb_match },
{ lm_match },
{ def_match } /* Must be last */
@@ -149,6 +158,23 @@
u_int8_t cr;
int rv;
+ /*
+ * Check for it8705f, bevor we do the chip reset.
+ * In case of an it8705f this might reset all the fan control
+ * parameters to defaults which would void all settings done by
+ * the BOOTROM/BIOS.
+ */
+ bus_space_write_1(iot, ioh, LMC_ADDR, ITEC_RES48);
+ cr = bus_space_read_1(iot, ioh, LMC_DATA);
+
+ if (cr==ITEC_RES48_DEFAULT)
+ {
+ bus_space_write_1(iot, ioh, LMC_ADDR, ITEC_RES52);
+ cr = bus_space_read_1(iot, ioh, LMC_DATA);
+ if (cr==ITEC_RES52_DEFAULT)
+ return 1;
+ }
+
/* Check for some power-on defaults */
bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG);
@@ -398,6 +424,47 @@
sc->info[8].rfact = 10000;
}
+int
+itec_match(sc)
+ struct lm_softc *sc;
+{
+ int vendor;
+ /* do the same thing as in lm_probe() */
+ if ((*sc->lm_readreg)(sc, ITEC_RES48)!=ITEC_RES48_DEFAULT)
+ return 0;
+
+ if ((*sc->lm_readreg)(sc, ITEC_RES52)!=ITEC_RES52_DEFAULT)
+ return 0;
+
+ vendor=(*sc->lm_readreg)(sc, ITEC_VENDID);
+
+ if (vendor==ITEC_VENDID_ITE)
+ printf(": iTE IT8705f\n");
+ else
+ printf(": unknown IT8705f compatible, vendorid 0x%02x\n",vendor);
+
+ /* XXX this is a litle bit lame...
+ * All VIN inputs work exactly the same way, it depends of the
+ * external wiring what voltages they monitor and which correction
+ * factors are needed. We assume a pretty standard setup here
+ */
+ wb_setup_volt(sc);
+ snprintf(sc->info[0].desc, sizeof(sc->info[0].desc), "CPU");
+ snprintf(sc->info[1].desc, sizeof(sc->info[1].desc), "AGP");
+ snprintf(sc->info[6].desc, sizeof(sc->info[1].desc), "+2.5V");
+ sc->info[5].rfact=51100;
+ sc->info[7].rfact=16778;
+
+ setup_temp(sc,9,3);
+ setup_fan(sc,12,3);
+ sc->numsensors = ITEC_NUM_SENSORS;
+ sc->refresh_sensor_data = itec_refresh_sensor_data;
+ sc->sc_sysmon.sme_streinfo = itec_streinfo;
+
+ return 1;
+}
+
+
static void
setup_temp(sc, start, n)
struct lm_softc *sc;
@@ -667,6 +734,65 @@
return (0);
}
+int
+itec_streinfo(sme, binfo)
+ struct sysmon_envsys *sme;
+ struct envsys_basic_info *binfo;
+{
+ struct lm_softc *sc = sme->sme_cookie;
+ int divisor;
+ u_int8_t sdata;
+ int i;
+
+ if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
+ sc->info[binfo->sensor].rfact = binfo->rfact;
+ else {
+ if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
+ if (binfo->rpms == 0) {
+ binfo->validflags = 0;
+ return (0);
+ }
+
+ /* write back the nominal FAN speed */
+ sc->info[binfo->sensor].rpms = binfo->rpms;
+
+ /* 153 is the nominal FAN speed value */
+ divisor = 1350000 / (binfo->rpms * 153);
+
+ /* ...but we need lg(divisor) */
+ for (i = 0; i < 7; i++) {
+ if (divisor <= (1 << i))
+ break;
+ }
+ divisor = i;
+
+ sdata = (*sc->lm_readreg)(sc, ITEC_FANDIV);
+ /*
+ * FAN1 div is in bits <0:2>, FAN2 is in <3:5>
+ * FAN3 is in <6>, if set divisor is 8, else 2
+ */
+ if ( binfo->sensor == 10 ) { /* FAN1 */
+ sdata = (sdata & 0xf8) | divisor;
+ } else if ( binfo->sensor == 11 ) { /* FAN2 */
+ sdata = (sdata & 0xc7) | divisor << 3;
+ } else { /* FAN3 */
+ if (divisor>2)
+ sdata = sdata & 0xbf;
+ else
+ sdata = sdata | 0x40;
+ }
+ (*sc->lm_writereg)(sc, ITEC_FANDIV, sdata);
+ }
+ memcpy(sc->info[binfo->sensor].desc, binfo->desc,
+ sizeof(sc->info[binfo->sensor].desc));
+ sc->info[binfo->sensor].desc[
+ sizeof(sc->info[binfo->sensor].desc) - 1] = '\0';
+
+ binfo->validflags = ENVSYS_FVALID;
+ }
+ return (0);
+}
+
static void
generic_stemp(sc, sensor)
struct lm_softc *sc;
@@ -899,3 +1025,88 @@
wb_stemp(sc, &sc->sensors[9], 2);
wb_fanrpm(sc, &sc->sensors[11]);
}
+
+static void
+itec_svolt(sc, sensors, infos)
+ struct lm_softc *sc;
+ struct envsys_tre_data *sensors;
+ struct envsys_basic_info *infos;
+{
+ int i, sdata;
+
+ for (i = 0; i < 9; i++) {
+ sdata = (*sc->lm_readreg)(sc, ITEC_VIN0 + i);
+ DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
+ /* voltage returned as (mV >> 4), we convert to uVDC */
+ sensors[i].cur.data_s = ( sdata << 4 );
+ /* rfact is (factor * 10^4) */
+
+ sensors[i].cur.data_s *= infos[i].rfact;
+ /*
+ * XXX We assume input 5 is wired the way iTE suggests to
+ * monitor a negative voltage. I'd prefer using negative rfacts
+ * for detecting those cases but since rfact is an u_int this
+ * isn't possible.
+ */
+ if (i==5) {
+ sensors[i].cur.data_s-= ( infos[i].rfact - 10000 )* ITEC_VREF;
+ }
+ /* division by 10 gets us back to uVDC */
+ sensors[i].cur.data_s /= 10;
+ }
+}
+
+static void
+itec_stemp(sc, sensors)
+ struct lm_softc *sc;
+ struct envsys_tre_data *sensors;
+{
+ int i, sdata;
+
+ /* temperatures. Given in dC, we convert to uK */
+ for (i = 0; i < 3; i++)
+ {
+ sdata = (*sc->lm_readreg)(sc, ITEC_TEMP1 + i );
+ DPRINTF(("sdata[temp%d] 0x%x\n",i, sdata));
+ sensors[i].cur.data_us = sdata * 1000000 + 273150000;
+ }
+}
+
+static void
+itec_fanrpm(sc, sensors)
+ struct lm_softc *sc;
+ struct envsys_tre_data *sensors;
+{
+ int i, fandiv, divisor, sdata;
+ (*sc->lm_banksel)(sc, 0);
+ fandiv=((*sc->lm_readreg)(sc, ITEC_FANDIV));
+
+ for (i = 0; i < 3; i++) {
+ sdata = (*sc->lm_readreg)(sc, ITEC_FAN1 + i);
+ DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata));
+ if (i == 0)
+ divisor = fandiv & 0x7;
+ else if (i == 1)
+ divisor = (fandiv >> 3) & 0x7;
+ else /* (i == 2) */
+ divisor = (fandiv && 0x40)?3:1;
+
+ DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor));
+ if (sdata == 0xff || sdata == 0x00) {
+ sensors[i].cur.data_us = 0;
+ } else {
+ sensors[i].cur.data_us = 1350000 /
+ (sdata << divisor);
+ }
+ }
+
+}
+
+void
+itec_refresh_sensor_data(sc)
+ struct lm_softc *sc;
+{
+ itec_svolt(sc, &sc->sensors[0], &sc->info[0]);
+ itec_stemp(sc, &sc->sensors[9]);
+ itec_fanrpm(sc, &sc->sensors[12]);
+}
Index: sys/dev/ic/nslm7xvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/nslm7xvar.h,v
retrieving revision 1.11
diff -c -u -r1.11 nslm7xvar.h
--- sys/dev/ic/nslm7xvar.h 2 Nov 2003 11:07:45 -0000 1.11
+++ sys/dev/ic/nslm7xvar.h 24 Jul 2004 16:09:45 -0000
@@ -116,6 +116,40 @@
#define WB83697_NUM_SENSORS 14
#define WB_NUM_SENSORS 15
+/*
+ * registers for the environment controller built into
+ * the IT8705F super-i/o chip
+ */
+#define ITEC_FANDIV 0x0b /* fan divisor */
+#define ITEC_FAN1 0x0d /* fan1 tachometer */
+#define ITEC_FAN2 0x0e /* fan2 tachometer */
+#define ITEC_FAN3 0x0f /* fan3 tachometer */
+#define ITEC_VIN0 0x20 /* VIN0 voltage */
+#define ITEC_VIN1 0x21 /* VIN1 voltage */
+#define ITEC_VIN2 0x22 /* VIN2 voltage */
+#define ITEC_VIN3 0x23 /* VIN3 voltage */
+#define ITEC_VIN4 0x24 /* VIN4 voltage */
+#define ITEC_VIN5 0x25 /* VIN5 voltage */
+#define ITEC_VIN6 0x26 /* VIN6 voltage */
+#define ITEC_VIN7 0x27 /* VIN7 voltage */
+#define ITEC_VBAT 0x28 /* VBAT voltage */
+#define ITEC_TEMP1 0x29 /* TMPIN1 temperature */
+#define ITEC_TEMP2 0x30 /* TMPIN1 temperature */
+#define ITEC_TEMP3 0x31 /* TMPIN1 temperature */
+#define ITEC_RES48 0x48 /* reserved, used for probing the chip */
+#define ITEC_RES52 0x52 /* reserved, used for probing the chip */
+#define ITEC_VENDID 0x58 /* vendor ID register */
+
+/*
+ * misc values
+ */
+#define ITEC_VENDID_ITE 0x90 /* iTE vendor ID */
+#define ITEC_RES48_DEFAULT 0x2d
+#define ITEC_RES52_DEFAULT 0x7f
+#define ITEC_NUM_SENSORS 15
+#define ITEC_VREF 4096 /* VREF in mV */
+
+
struct lm_softc {
struct device sc_dev;
>Release-Note:
>Audit-Trail:
>Unformatted: