From 95889133f248d52da7be4610d86d7dbd61f4577c Mon Sep 17 00:00:00 2001 From: Constantine A. Murenin Date: Fri, 12 Mar 2010 03:21:14 -0500 Subject: [PATCH] fanctl: AsiaBSDCon 2010 DragonFly sysctl hw.sensors lm(4) fan control similar to BSDCan 2009 OpenBSD * This is a ported version of the sysctl hw.sensors lm(4) fan-controlling prototype/hack as posted to the tech@openbsd.org mailing list on 2009-05-08. * DragonFly functionality regarding all aspects of fan control is the same as discussed for OpenBSD. * Details were presented at BSDCan 2009 and AsiaBSDCon 2010. * Presentation and other materials are available at http://sensors.cnst.su/fanctl/ --- sys/sys/sensors.h | 11 + sys/kern/kern_sensors.c | 14 +- sbin/sysctl/sysctl.c | 8 + sys/dev/powermng/lm/lm78var.h | 2 +- sys/dev/powermng/lm/lm78.c | 753 +++++++++++++++++++++++++++++++++++++++-- 5 files changed, 761 insertions(+), 27 deletions(-) diff --git a/sys/sys/sensors.h b/sys/sys/sensors.h index 554cfc2..ca1e46d 100644 --- a/sys/sys/sensors.h +++ b/sys/sys/sensors.h @@ -97,18 +97,28 @@ enum sensor_status { struct sensor { char desc[32]; /* sensor description, may be empty */ struct timeval tv; /* sensor value last change time */ int64_t value; /* current value */ enum sensor_type type; /* sensor type */ enum sensor_status status; /* sensor status */ int numt; /* sensor number of .type type */ int flags; /* sensor flags */ + /*int64_t upvalue;*/ /* new value */ + /* + * The upvalue is commented out from the userland structure + * to avoid increasing sizeof(struct sensor), such as to + * preserve the ABI of C/C++ sysctl(3) HW_SENSORS users, + * since otherwise recompilation of all sensor tools would + * have been required to avoid [ENOMEM] from sysctl(3). + */ #define SENSOR_FINVALID 0x0001 /* sensor is invalid */ #define SENSOR_FUNKNOWN 0x0002 /* sensor value is unknown */ +#define SENSOR_FCONTROLLABLE 0x0004 /* sensor value could be altered */ +#define SENSOR_FNEWVALUE 0x0008 /* upvalue contains update inf. */ }; /* Sensor device data: * New fields should be added at the end to encourage backwards compat */ struct sensordev { int num; /* sensordev number */ char xname[16]; /* unix device name */ @@ -129,16 +139,17 @@ struct ksensor { SLIST_ENTRY(ksensor) list; /* device-scope list */ char desc[32]; /* sensor description, may be empty */ struct timeval tv; /* sensor value last change time */ int64_t value; /* current value */ enum sensor_type type; /* sensor type */ enum sensor_status status; /* sensor status */ int numt; /* sensor number of .type type */ int flags; /* sensor flags, ie. SENSOR_FINVALID */ + int64_t upvalue; /* new value */ }; SLIST_HEAD(ksensors_head, ksensor); /* Sensor device data */ struct ksensordev { SLIST_ENTRY(ksensordev) list; int num; /* sensordev number */ char xname[16]; /* unix device name */ diff --git a/sys/kern/kern_sensors.c b/sys/kern/kern_sensors.c index b8794a1..8cb6c7a 100644 --- a/sys/kern/kern_sensors.c +++ b/sys/kern/kern_sensors.c @@ -317,17 +317,18 @@ sensor_sysctl8magic_install(struct ksensordev *sensdev) sysctl_ctx_init(cl); ol = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(cl, (&SYSCTL_NODE_CHILDREN(_hw, sensors)), sensdev->num, sensdev->xname, CTLFLAG_RD, NULL, "")); SLIST_FOREACH(s, sh, list) { char n[32]; ksnprintf(n, sizeof(n), "%s%d", sensor_type_s[s->type], s->numt); SYSCTL_ADD_PROC(cl, ol, OID_AUTO, n, CTLTYPE_STRUCT | - CTLFLAG_RD, s, 0, sysctl_handle_sensor, "S,sensor", ""); + (s->flags & SENSOR_FCONTROLLABLE ? CTLFLAG_RW : CTLFLAG_RD), + s, 0, sysctl_handle_sensor, "S,sensor", ""); } } void sensor_sysctl8magic_deinstall(struct ksensordev *sensdev) { struct sysctl_ctx_list *cl = &sensdev->clist; @@ -363,28 +364,35 @@ sysctl_handle_sensordev(SYSCTL_HANDLER_ARGS) int sysctl_handle_sensor(SYSCTL_HANDLER_ARGS) { struct ksensor *ks = arg1; struct sensor *us; int error; - if (req->newptr) - return (EPERM); + if (req->newptr) { + if (req->newlen != sizeof(int)) + return EINVAL; + if (!(ks->flags & SENSOR_FCONTROLLABLE)) + return EPERM; + ks->upvalue = *(int *)req->newptr; + ks->flags |= SENSOR_FNEWVALUE; + } /* Grab a copy, to clear the kernel pointers */ us = kmalloc(sizeof(*us), M_TEMP, M_WAITOK | M_ZERO); memcpy(us->desc, ks->desc, sizeof(ks->desc)); us->tv = ks->tv; us->value = ks->value; us->type = ks->type; us->status = ks->status; us->numt = ks->numt; us->flags = ks->flags; + /*us->upvalue = ks->upvalue;*/ error = SYSCTL_OUT(req, us, sizeof(struct sensor)); kfree(us, M_TEMP); return (error); } int diff --git a/sbin/sysctl/sysctl.c b/sbin/sysctl/sysctl.c index f26613f..18e82f5 100644 --- a/sbin/sysctl/sysctl.c +++ b/sbin/sysctl/sysctl.c @@ -245,16 +245,21 @@ parse(const char *string) break; case CTLTYPE_OPAQUE: if (strcmp(fmt, "T,dev_t") == 0 || strcmp(fmt, "T,udev_t") == 0 ) { set_T_dev_t((char*)newval, &newval, &newsize); break; + } else if (strcmp(fmt, "S,sensor") == 0) { + intval = (int)strtol(newval, NULL, 0); + newval = &intval; + newsize = sizeof(intval); + break; } /* FALLTHROUGH */ default: errx(1, "oid '%s' is type %d," " cannot set that", name, kind & CTLTYPE); } @@ -459,16 +464,19 @@ S_sensor(int l2, void *p) case SENSOR_TIMEDELTA: printf("%.6f secs", s->value / 1000000000.0); break; default: printf("unknown"); } } + if (s->flags & SENSOR_FNEWVALUE) + printf(" {updating}"); + if (s->desc[0] != '\0') printf(" (%s)", s->desc); switch (s->status) { case SENSOR_S_UNSPEC: break; case SENSOR_S_OK: printf(", OK"); diff --git a/sys/dev/powermng/lm/lm78var.h b/sys/dev/powermng/lm/lm78var.h index 67438ee..648feca 100644 --- a/sys/dev/powermng/lm/lm78var.h +++ b/sys/dev/powermng/lm/lm78var.h @@ -118,17 +118,17 @@ /* Config bits */ #define WB_CONFIG_VMR9 0x01 /* Reference voltage (mV) */ #define WB_VREF 3600 #define WB_W83627EHF_VREF 2048 -#define WB_MAX_SENSORS 19 +#define WB_MAX_SENSORS 96 struct lm_softc; struct lm_sensor { char *desc; enum sensor_type type; u_int8_t bank; u_int8_t reg; diff --git a/sys/dev/powermng/lm/lm78.c b/sys/dev/powermng/lm/lm78.c index af74d9e..dc348ba 100644 --- a/sys/dev/powermng/lm/lm78.c +++ b/sys/dev/powermng/lm/lm78.c @@ -1,11 +1,11 @@ /* * Copyright (c) 2005, 2006 Mark Kettenis - * Copyright (c) 2006, 2007 Constantine A. Murenin + * Copyright (c) 2006, 2007, 2009, 2010 Constantine A. Murenin * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -19,16 +19,20 @@ #include #include #include #include #include "lm78var.h" +//#define LMFANCTLRAW +#define LMFANDUTYHINTS +/* or use `rm lm78.o; env DEBUG="-DLMFANCTLRAW -DLMFANDUTYHINTS" make lm78.o` */ + #if defined(LMDEBUG) #define DPRINTF(x) do { printf x; } while (0) #else #define DPRINTF(x) #endif /* * LM78-compatible chips can typically measure voltages up to 4.096 V. @@ -49,16 +53,24 @@ void lm_setup_sensors(struct lm_softc *, struct lm_sensor *); void lm_refresh(void *); void lm_refresh_sensor_data(struct lm_softc *); void lm_refresh_volt(struct lm_softc *, int); void lm_refresh_temp(struct lm_softc *, int); void lm_refresh_fanrpm(struct lm_softc *, int); void wb_refresh_sensor_data(struct lm_softc *); +void wb_refresh_raw_rw(struct lm_softc *, int); +void w83627hf_refresh_pwm_rw(struct lm_softc *, int); +void w83627ehf_refresh_fanvolt_rw(struct lm_softc *, int); +void w83627ehf_refresh_fanvolt_thermal_rw(struct lm_softc *, int); +void w83627ehf_refresh_indicator_rw(struct lm_softc *, int); +void w83627ehf_refresh_temptarget_rw(struct lm_softc *, int); +void w83627ehf_refresh_temptargettol_rw(struct lm_softc *, int); +void w83627thf_refresh_fanvolt_rw(struct lm_softc *, int); void wb_w83637hf_refresh_vcore(struct lm_softc *, int); void wb_refresh_nvolt(struct lm_softc *, int); void wb_w83627ehf_refresh_nvolt(struct lm_softc *, int); void wb_refresh_temp(struct lm_softc *, int); void wb_refresh_fanrpm(struct lm_softc *, int); void wb_w83792d_refresh_fanrpm(struct lm_softc *, int); void as_refresh_temp(struct lm_softc *, int); @@ -89,17 +101,23 @@ struct lm_sensor lm78_sensors[] = { /* Fans */ { "", SENSOR_FANRPM, 0, 0x28, lm_refresh_fanrpm }, { "", SENSOR_FANRPM, 0, 0x29, lm_refresh_fanrpm }, { "", SENSOR_FANRPM, 0, 0x2a, lm_refresh_fanrpm }, { NULL } }; + struct lm_sensor w83627hf_sensors[] = { + /* The W83627HG only support the manual PWM fan speed control. */ + { "PWM", SENSOR_PERCENT, 0, 0x5a, w83627hf_refresh_pwm_rw }, + { "PWM", SENSOR_PERCENT, 0, 0x5b, w83627hf_refresh_pwm_rw }, + { "PWM 0/1 Clock Freq", SENSOR_INTEGER, 0, 0x5c, wb_refresh_raw_rw }, + /* Voltage */ { "VCore A", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, { "VCore B", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT_NONE }, { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, @@ -122,93 +140,342 @@ struct lm_sensor w83627hf_sensors[] = { /* * The W83627EHF can measure voltages up to 2.048 V instead of the * traditional 4.096 V. For measuring positive voltages, this can be * accounted for by halving the resistor factor. Negative voltages * need special treatment, also because the reference voltage is 2.048 V * instead of the traditional 3.6 V. */ struct lm_sensor w83627ehf_sensors[] = { + /* Controlling parts: Duty Cycle */ + { "Sys Fan Volt Control", SENSOR_PERCENT, 0, 0x01, w83627ehf_refresh_fanvolt_rw }, + { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x03, w83627ehf_refresh_fanvolt_rw }, + { "Aux Fan Volt Control", SENSOR_PERCENT, 0, 0x11, w83627ehf_refresh_fanvolt_rw }, + { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x61, w83627ehf_refresh_fanvolt_rw }, + /* Start-up Values */ + { "Sys Fan Start-up Value", SENSOR_PERCENT, 0, 0x0a, w83627ehf_refresh_fanvolt_thermal_rw, 0 }, + { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x0b, w83627ehf_refresh_fanvolt_thermal_rw, 0 }, + { "Aux Fan Start-up Value", SENSOR_PERCENT, 0, 0x16, w83627ehf_refresh_fanvolt_thermal_rw, 0 }, + { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x65, w83627ehf_refresh_fanvolt_thermal_rw, 0 }, + /* Stop Values */ + { "Sys Fan Stop Value", SENSOR_PERCENT, 0, 0x08, w83627ehf_refresh_fanvolt_thermal_rw, 1 }, + { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x09, w83627ehf_refresh_fanvolt_thermal_rw, 1 }, + { "Aux Fan Stop Value", SENSOR_PERCENT, 0, 0x15, w83627ehf_refresh_fanvolt_thermal_rw, 1 }, + { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x64, w83627ehf_refresh_fanvolt_thermal_rw, 1 }, + + /* Controlling parts: PWM/DC */ + { "Sys Fan Volt Control", SENSOR_INDICATOR, 0, 0x01, w83627ehf_refresh_indicator_rw }, + { "CPU Fan Volt Control", SENSOR_INDICATOR, 0, 0x03, w83627ehf_refresh_indicator_rw }, + { "Aux Fan Volt Control", SENSOR_INDICATOR, 0, 0x11, w83627ehf_refresh_indicator_rw }, + { "CPU Fan Volt Control", SENSOR_INDICATOR, 0, 0x61, w83627ehf_refresh_indicator_rw }, + +#ifdef LMFANCTLRAW + /* Smart Fan Configuration Registers, 00h--1Fh */ + { "0x00: SysFanOut PWM Output Freq", SENSOR_INTEGER, 0, 0x00, wb_refresh_raw_rw }, + { "0x01: SysFanOut", SENSOR_INTEGER, 0, 0x01, wb_refresh_raw_rw }, + { "0x02: CPUFanOut0 PWM Output Freq", SENSOR_INTEGER, 0, 0x02, wb_refresh_raw_rw }, + { "0x03: CPUFanOut0", SENSOR_INTEGER, 0, 0x03, wb_refresh_raw_rw }, + { "0x04: Fan Configuration Reg I", SENSOR_INTEGER, 0, 0x04, wb_refresh_raw_rw }, + { "0x05: Sys Target Temp/RPM", SENSOR_INTEGER, 0, 0x05, wb_refresh_raw_rw }, + { "0x06: CPU Target Temp/RPM0", SENSOR_INTEGER, 0, 0x06, wb_refresh_raw_rw }, + { "0x07: Sys/CPU Target Tolerance", SENSOR_INTEGER, 0, 0x07, wb_refresh_raw_rw }, + { "0x08: SysFanOut Stop Value", SENSOR_INTEGER, 0, 0x08, wb_refresh_raw_rw }, + { "0x09: CPUFanOut0 Stop Value", SENSOR_INTEGER, 0, 0x09, wb_refresh_raw_rw }, + { "0x0a: SysFanOut Start-up Value", SENSOR_INTEGER, 0, 0x0a, wb_refresh_raw_rw }, + { "0x0b: CPUFanOut0 Start-up Value", SENSOR_INTEGER, 0, 0x0b, wb_refresh_raw_rw }, + { "0x0c: SysFanOut Stop Time", SENSOR_INTEGER, 0, 0x0c, wb_refresh_raw_rw }, + { "0x0d: CPUFanOut0 Stop Time", SENSOR_INTEGER, 0, 0x0d, wb_refresh_raw_rw }, + { "0x0e: Fan Output Step-down Time", SENSOR_INTEGER, 0, 0x0e, wb_refresh_raw_rw }, + { "0x0f: Fan Output Step-up Time", SENSOR_INTEGER, 0, 0x0f, wb_refresh_raw_rw }, + { "0x10: AuxFanOut PWM Output Freq", SENSOR_INTEGER, 0, 0x10, wb_refresh_raw_rw }, + { "0x11: AuxFanOut", SENSOR_INTEGER, 0, 0x11, wb_refresh_raw_rw }, + { "0x12: Fan Configuration Reg II", SENSOR_INTEGER, 0, 0x12, wb_refresh_raw_rw }, + { "0x13: Aux Target Temp/RPM", SENSOR_INTEGER, 0, 0x13, wb_refresh_raw_rw }, + { "0x14: Aux Target Tolerance", SENSOR_INTEGER, 0, 0x14, wb_refresh_raw_rw }, + { "0x15: AuxFanOut Stop Value", SENSOR_INTEGER, 0, 0x15, wb_refresh_raw_rw }, + { "0x16: AuxFanOut Start-up Value", SENSOR_INTEGER, 0, 0x16, wb_refresh_raw_rw }, + { "0x17: AuxFanOut Stop Time", SENSOR_INTEGER, 0, 0x17, wb_refresh_raw_rw }, + { "0x18: OVT", SENSOR_INTEGER, 0, 0x18, wb_refresh_raw_rw }, + { "0x19: reserved", SENSOR_INTEGER, 0, 0x19, wb_refresh_raw_rw }, + { "0x1a: reserved", SENSOR_INTEGER, 0, 0x1a, wb_refresh_raw_rw }, + { "0x1b: reserved", SENSOR_INTEGER, 0, 0x1b, wb_refresh_raw_rw }, + { "0x1c: reserved", SENSOR_INTEGER, 0, 0x1c, wb_refresh_raw_rw }, + { "0x1d: reserved", SENSOR_INTEGER, 0, 0x1d, wb_refresh_raw_rw }, + { "0x1e: reserved", SENSOR_INTEGER, 0, 0x1e, wb_refresh_raw_rw }, + { "0x1f: reserved", SENSOR_INTEGER, 0, 0x1f, wb_refresh_raw_rw }, + + { "0x47: Fan Divisor Reg I", SENSOR_INTEGER, 0, 0x47, wb_refresh_raw_rw }, + { "0x4a: CPUFanOut1 Temp Source Select", SENSOR_INTEGER, 0, 0x4a, wb_refresh_raw_rw }, + { "0x4b: Fan Divisor Reg II", SENSOR_INTEGER, 0, 0x4b, wb_refresh_raw_rw }, + { "0x59: Diode Selection", SENSOR_INTEGER, 0, 0x59, wb_refresh_raw_rw }, + { "0x5d: VBat Monitor Control", SENSOR_INTEGER, 0, 0x5d, wb_refresh_raw_rw }, + + { "0x60: CPUFanOut1 PWM Output Freq", SENSOR_INTEGER, 0, 0x60, wb_refresh_raw_rw }, + { "0x61: CPUFanOut1", SENSOR_INTEGER, 0, 0x61, wb_refresh_raw_rw }, + { "0x62: Fan Configuration Reg III", SENSOR_INTEGER, 0, 0x62, wb_refresh_raw_rw }, + { "0x63: CPU Target Temp/RPM1", SENSOR_INTEGER, 0, 0x63, wb_refresh_raw_rw }, + { "0x64: CPUFanOut1 Stop Value", SENSOR_INTEGER, 0, 0x64, wb_refresh_raw_rw }, + { "0x65: CPUFanOut1 Start-up Value", SENSOR_INTEGER, 0, 0x65, wb_refresh_raw_rw }, + { "0x66: CPUFanOut1 Stop Time", SENSOR_INTEGER, 0, 0x66, wb_refresh_raw_rw }, + { "0x67: CPUFanOut0 Max Output Value", SENSOR_INTEGER, 0, 0x67, wb_refresh_raw_rw }, + { "0x68: CPUFanOut0 Output Step Value", SENSOR_INTEGER, 0, 0x68, wb_refresh_raw_rw }, + { "0x69: CPUFanOut1 Max Output Value", SENSOR_INTEGER, 0, 0x69, wb_refresh_raw_rw }, + { "0x6a: CPUFanOut1 Output Step Value", SENSOR_INTEGER, 0, 0x6a, wb_refresh_raw_rw }, +#endif /* LMFANCTLRAW */ + /* Voltage */ { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2}, { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 }, { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 }, { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 }, { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt }, { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 }, { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 }, { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 }, { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 }, { "", SENSOR_VOLTS_DC, 5, 0x52, lm_refresh_volt, RFACT_NONE / 2 }, /* Temperature */ - { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, - { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, - { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, + { "Sys", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "CPU", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, + { "Aux", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, + + /* search for Relative Registers in the datasheet for a nice table */ + /* Controlling parts: Target Temperature */ + { "Sys Target", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptarget_rw }, + { "CPU Target", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptarget_rw }, + { "Aux Target", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptarget_rw }, + { "CPU Target", SENSOR_TEMP, 0, 0x63, w83627ehf_refresh_temptarget_rw }, + /* Controlling parts: Target Temperature Tolerance */ + { "Sys Tolerance", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptargettol_rw }, + { "CPU Tolerance", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptargettol_rw }, + { "Aux Tolerance", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptargettol_rw }, + { "CPU Tolerance", SENSOR_TEMP, 0, 0x63, w83627ehf_refresh_temptargettol_rw }, /* Fans */ - { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, - { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, - { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, + { "Sys", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, + { "CPU", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, + { "Aux", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, +/* { "CPU", SENSOR_FANRPM, 0, 0x3f, w83627ehf_refresh_fanrpm }, + { "Aux", SENSOR_FANRPM, 0, 0x53, w83627ehf_refresh_fanrpm },*/ { NULL } }; /* * w83627dhg is almost identical to w83627ehf, except that * it has 9 instead of 10 voltage sensors */ struct lm_sensor w83627dhg_sensors[] = { + /* Controlling parts: Duty Cycle */ + { "Sys Fan Volt Control", SENSOR_PERCENT, 0, 0x01, w83627ehf_refresh_fanvolt_rw }, + { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x03, w83627ehf_refresh_fanvolt_rw }, + { "Aux Fan Volt Control", SENSOR_PERCENT, 0, 0x11, w83627ehf_refresh_fanvolt_rw }, + { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x61, w83627ehf_refresh_fanvolt_rw }, + /* Start-up Values */ + { "Sys Fan Start-up Value", SENSOR_PERCENT, 0, 0x0a, w83627ehf_refresh_fanvolt_thermal_rw, 0 }, + { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x0b, w83627ehf_refresh_fanvolt_thermal_rw, 0 }, + { "Aux Fan Start-up Value", SENSOR_PERCENT, 0, 0x16, w83627ehf_refresh_fanvolt_thermal_rw, 0 }, + { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x65, w83627ehf_refresh_fanvolt_thermal_rw, 0 }, + /* Stop Values */ + { "Sys Fan Stop Value", SENSOR_PERCENT, 0, 0x08, w83627ehf_refresh_fanvolt_thermal_rw, 1 }, + { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x09, w83627ehf_refresh_fanvolt_thermal_rw, 1 }, + { "Aux Fan Stop Value", SENSOR_PERCENT, 0, 0x15, w83627ehf_refresh_fanvolt_thermal_rw, 1 }, + { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x64, w83627ehf_refresh_fanvolt_thermal_rw, 1 }, + + /* Controlling parts: PWM/DC */ + { "Sys Fan Volt Control", SENSOR_INDICATOR, 0, 0x01, w83627ehf_refresh_indicator_rw }, + { "CPU Fan Volt Control", SENSOR_INDICATOR, 0, 0x03, w83627ehf_refresh_indicator_rw }, + { "Aux Fan Volt Control", SENSOR_INDICATOR, 0, 0x11, w83627ehf_refresh_indicator_rw }, + { "CPU Fan Volt Control", SENSOR_INDICATOR, 0, 0x61, w83627ehf_refresh_indicator_rw }, + +#ifdef LMFANCTLRAW + /* Smart Fan Configuration Registers, 00h--1Fh */ + { "0x00: SysFanOut PWM Output Freq", SENSOR_INTEGER, 0, 0x00, wb_refresh_raw_rw }, + { "0x01: SysFanOut", SENSOR_INTEGER, 0, 0x01, wb_refresh_raw_rw }, + { "0x02: CPUFanOut0 PWM Output Freq", SENSOR_INTEGER, 0, 0x02, wb_refresh_raw_rw }, + { "0x03: CPUFanOut0", SENSOR_INTEGER, 0, 0x03, wb_refresh_raw_rw }, + { "0x04: Fan Configuration Reg I", SENSOR_INTEGER, 0, 0x04, wb_refresh_raw_rw }, + { "0x05: Sys Target Temp/RPM", SENSOR_INTEGER, 0, 0x05, wb_refresh_raw_rw }, + { "0x06: CPU Target Temp/RPM0", SENSOR_INTEGER, 0, 0x06, wb_refresh_raw_rw }, + { "0x07: Sys/CPU Target Tolerance", SENSOR_INTEGER, 0, 0x07, wb_refresh_raw_rw }, + { "0x08: SysFanOut Stop Value", SENSOR_INTEGER, 0, 0x08, wb_refresh_raw_rw }, + { "0x09: CPUFanOut0 Stop Value", SENSOR_INTEGER, 0, 0x09, wb_refresh_raw_rw }, + { "0x0a: SysFanOut Start-up Value", SENSOR_INTEGER, 0, 0x0a, wb_refresh_raw_rw }, + { "0x0b: CPUFanOut0 Start-up Value", SENSOR_INTEGER, 0, 0x0b, wb_refresh_raw_rw }, + { "0x0c: SysFanOut Stop Time", SENSOR_INTEGER, 0, 0x0c, wb_refresh_raw_rw }, + { "0x0d: CPUFanOut0 Stop Time", SENSOR_INTEGER, 0, 0x0d, wb_refresh_raw_rw }, + { "0x0e: Fan Output Step-down Time", SENSOR_INTEGER, 0, 0x0e, wb_refresh_raw_rw }, + { "0x0f: Fan Output Step-up Time", SENSOR_INTEGER, 0, 0x0f, wb_refresh_raw_rw }, + { "0x10: AuxFanOut PWM Output Freq", SENSOR_INTEGER, 0, 0x10, wb_refresh_raw_rw }, + { "0x11: AuxFanOut", SENSOR_INTEGER, 0, 0x11, wb_refresh_raw_rw }, + { "0x12: Fan Configuration Reg II", SENSOR_INTEGER, 0, 0x12, wb_refresh_raw_rw }, + { "0x13: Aux Target Temp/RPM", SENSOR_INTEGER, 0, 0x13, wb_refresh_raw_rw }, + { "0x14: Aux Target Tolerance", SENSOR_INTEGER, 0, 0x14, wb_refresh_raw_rw }, + { "0x15: AuxFanOut Stop Value", SENSOR_INTEGER, 0, 0x15, wb_refresh_raw_rw }, + { "0x16: AuxFanOut Start-up Value", SENSOR_INTEGER, 0, 0x16, wb_refresh_raw_rw }, + { "0x17: AuxFanOut Stop Time", SENSOR_INTEGER, 0, 0x17, wb_refresh_raw_rw }, + { "0x18: OVT", SENSOR_INTEGER, 0, 0x18, wb_refresh_raw_rw }, + { "0x19: reserved", SENSOR_INTEGER, 0, 0x19, wb_refresh_raw_rw }, + { "0x1a: reserved", SENSOR_INTEGER, 0, 0x1a, wb_refresh_raw_rw }, + { "0x1b: reserved", SENSOR_INTEGER, 0, 0x1b, wb_refresh_raw_rw }, + { "0x1c: reserved", SENSOR_INTEGER, 0, 0x1c, wb_refresh_raw_rw }, + { "0x1d: reserved", SENSOR_INTEGER, 0, 0x1d, wb_refresh_raw_rw }, + { "0x1e: reserved", SENSOR_INTEGER, 0, 0x1e, wb_refresh_raw_rw }, + { "0x1f: reserved", SENSOR_INTEGER, 0, 0x1f, wb_refresh_raw_rw }, + + { "0x47: Fan Divisor Reg I", SENSOR_INTEGER, 0, 0x47, wb_refresh_raw_rw }, + { "0x49: CPUFanOut0/Aux Temp Source Select", SENSOR_INTEGER, 0, 0x49, wb_refresh_raw_rw }, /*dhg only, not on ehf*/ + { "0x4a: CPUFanOut1 Temp Source Select", SENSOR_INTEGER, 0, 0x4a, wb_refresh_raw_rw }, + { "0x4b: Fan Divisor Reg II", SENSOR_INTEGER, 0, 0x4b, wb_refresh_raw_rw }, + { "0x59: Diode Selection", SENSOR_INTEGER, 0, 0x59, wb_refresh_raw_rw }, + { "0x5d: VBat Monitor Control", SENSOR_INTEGER, 0, 0x5d, wb_refresh_raw_rw }, + + { "0x60: CPUFanOut1 PWM Output Freq", SENSOR_INTEGER, 0, 0x60, wb_refresh_raw_rw }, + { "0x61: CPUFanOut1", SENSOR_INTEGER, 0, 0x61, wb_refresh_raw_rw }, + { "0x62: Fan Configuration Reg III", SENSOR_INTEGER, 0, 0x62, wb_refresh_raw_rw }, + { "0x63: CPU Target Temp/RPM1", SENSOR_INTEGER, 0, 0x63, wb_refresh_raw_rw }, + { "0x64: CPUFanOut1 Stop Value", SENSOR_INTEGER, 0, 0x64, wb_refresh_raw_rw }, + { "0x65: CPUFanOut1 Start-up Value", SENSOR_INTEGER, 0, 0x65, wb_refresh_raw_rw }, + { "0x66: CPUFanOut1 Stop Time", SENSOR_INTEGER, 0, 0x66, wb_refresh_raw_rw }, + { "0x67: CPUFanOut0 Max Output Value", SENSOR_INTEGER, 0, 0x67, wb_refresh_raw_rw }, + { "0x68: CPUFanOut0 Output Step Value", SENSOR_INTEGER, 0, 0x68, wb_refresh_raw_rw }, + { "0x69: CPUFanOut1 Max Output Value", SENSOR_INTEGER, 0, 0x69, wb_refresh_raw_rw }, + { "0x6a: CPUFanOut1 Output Step Value", SENSOR_INTEGER, 0, 0x6a, wb_refresh_raw_rw }, +#endif /* LMFANCTLRAW */ + /* Voltage */ { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE / 2}, { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(56, 10) / 2 }, { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT(34, 34) / 2 }, { "+3.3V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 34) / 2 }, { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_w83627ehf_refresh_nvolt }, { "", SENSOR_VOLTS_DC, 0, 0x25, lm_refresh_volt, RFACT_NONE / 2 }, { "", SENSOR_VOLTS_DC, 0, 0x26, lm_refresh_volt, RFACT_NONE / 2 }, { "3.3VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 34) / 2 }, { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE / 2 }, /* Temperature */ - { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, - { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, - { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, + { "Sys", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "CPU", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, + { "Aux", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, + + /* search for Relative Registers in the datasheet for a nice table */ + /* Controlling parts: Target Temperature */ + { "Sys Target", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptarget_rw }, + { "CPU Target", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptarget_rw }, + { "Aux Target", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptarget_rw }, + { "CPU Target", SENSOR_TEMP, 0, 0x63, w83627ehf_refresh_temptarget_rw }, + /* Controlling parts: Target Temperature Tolerance */ + { "Sys Tolerance", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptargettol_rw }, + { "CPU Tolerance", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptargettol_rw }, + { "Aux Tolerance", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptargettol_rw }, + { "CPU Tolerance", SENSOR_TEMP, 0, 0x63, w83627ehf_refresh_temptargettol_rw }, /* Fans */ - { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, - { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, - { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, + { "Sys", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, + { "CPU", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, + { "Aux", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, +/* { "CPU", SENSOR_FANRPM, 0, 0x3f, w83627ehf_refresh_fanrpm },*/ { NULL } }; -struct lm_sensor w83637hf_sensors[] = { +struct lm_sensor w83627thf_sensors[] = { + /* Controlling parts: Duty Cycle */ + { "Sys Fan Volt Control", SENSOR_PERCENT, 0, 0x01, w83627thf_refresh_fanvolt_rw }, + { "CPU Fan Volt Control", SENSOR_PERCENT, 0, 0x03, w83627thf_refresh_fanvolt_rw }, + { "Aux Fan Volt Control", SENSOR_PERCENT, 0, 0x11, w83627thf_refresh_fanvolt_rw }, + /* Start-up Values */ + { "Sys Fan Start-up Value", SENSOR_PERCENT, 0, 0x0a, w83627ehf_refresh_fanvolt_thermal_rw, 0 }, + { "CPU Fan Start-up Value", SENSOR_PERCENT, 0, 0x0b, w83627ehf_refresh_fanvolt_thermal_rw, 0 }, + { "Aux Fan Start-up Value", SENSOR_PERCENT, 0, 0x16, w83627ehf_refresh_fanvolt_thermal_rw, 0 }, + /* Stop Values */ + { "Sys Fan Stop Value", SENSOR_PERCENT, 0, 0x08, w83627ehf_refresh_fanvolt_thermal_rw, 1 }, + { "CPU Fan Stop Value", SENSOR_PERCENT, 0, 0x09, w83627ehf_refresh_fanvolt_thermal_rw, 1 }, + { "Aux Fan Stop Value", SENSOR_PERCENT, 0, 0x15, w83627ehf_refresh_fanvolt_thermal_rw, 1 }, + +#ifdef LMFANCTLRAW + /* Smart Fan Configuration Registers, 00h--1Fh */ + { "0x00: reserved", SENSOR_INTEGER, 0, 0x00, wb_refresh_raw_rw }, + { "0x01: SysFanOut", SENSOR_INTEGER, 0, 0x01, wb_refresh_raw_rw }, + { "0x02: reserved", SENSOR_INTEGER, 0, 0x02, wb_refresh_raw_rw }, + { "0x03: CPUFanOut", SENSOR_INTEGER, 0, 0x03, wb_refresh_raw_rw }, + { "0x04: Fan Conguration Reg I", SENSOR_INTEGER, 0, 0x04, wb_refresh_raw_rw }, + { "0x05: Sys Target Temp/RPM", SENSOR_INTEGER, 0, 0x05, wb_refresh_raw_rw }, + { "0x06: CPU Target Temp/RPM", SENSOR_INTEGER, 0, 0x06, wb_refresh_raw_rw }, + { "0x07: Sys/CPU Target Tolerance", SENSOR_INTEGER, 0, 0x07, wb_refresh_raw_rw }, + { "0x08: SysFanOut Stop Value", SENSOR_INTEGER, 0, 0x08, wb_refresh_raw_rw }, + { "0x09: CPUFanOut Stop Value", SENSOR_INTEGER, 0, 0x09, wb_refresh_raw_rw }, + { "0x0a: SysFanOut Start-up Value", SENSOR_INTEGER, 0, 0x0a, wb_refresh_raw_rw }, + { "0x0b: CPUFanOut Start-up Value", SENSOR_INTEGER, 0, 0x0b, wb_refresh_raw_rw }, + { "0x0c: SysFanOut Stop Time", SENSOR_INTEGER, 0, 0x0c, wb_refresh_raw_rw }, + { "0x0d: CPUFanOut Stop Time", SENSOR_INTEGER, 0, 0x0d, wb_refresh_raw_rw }, + { "0x0e: Fan Output Step-down Time", SENSOR_INTEGER, 0, 0x0e, wb_refresh_raw_rw }, + { "0x0f: Fan Output Step-up Time", SENSOR_INTEGER, 0, 0x0f, wb_refresh_raw_rw }, + { "0x10: reserved", SENSOR_INTEGER, 0, 0x10, wb_refresh_raw_rw }, + { "0x11: AuxFanOut", SENSOR_INTEGER, 0, 0x11, wb_refresh_raw_rw }, + { "0x12: Fan Configuration Reg II", SENSOR_INTEGER, 0, 0x12, wb_refresh_raw_rw }, + { "0x13: Aux Target Temp/RPM", SENSOR_INTEGER, 0, 0x13, wb_refresh_raw_rw }, + { "0x14: Aux Target Tolerance", SENSOR_INTEGER, 0, 0x14, wb_refresh_raw_rw }, + { "0x15: AuxFanOut Stop Value", SENSOR_INTEGER, 0, 0x15, wb_refresh_raw_rw }, + { "0x16: AuxFanOut Start-up Value", SENSOR_INTEGER, 0, 0x16, wb_refresh_raw_rw }, + { "0x17: AuxFanOut Stop Time", SENSOR_INTEGER, 0, 0x17, wb_refresh_raw_rw }, + { "0x18: VRM and OVT", SENSOR_INTEGER, 0, 0x18, wb_refresh_raw_rw }, + { "0x19: reserved", SENSOR_INTEGER, 0, 0x19, wb_refresh_raw_rw }, + { "0x1a: user-defined", SENSOR_INTEGER, 0, 0x1a, wb_refresh_raw_rw }, + { "0x1b: user-defined", SENSOR_INTEGER, 0, 0x1b, wb_refresh_raw_rw }, + { "0x1c: reserved", SENSOR_INTEGER, 0, 0x1c, wb_refresh_raw_rw }, + { "0x1d: reserved", SENSOR_INTEGER, 0, 0x1d, wb_refresh_raw_rw }, + { "0x1e: reserved", SENSOR_INTEGER, 0, 0x1e, wb_refresh_raw_rw }, + { "0x1f: reserved", SENSOR_INTEGER, 0, 0x1f, wb_refresh_raw_rw }, + + { "0x47: Fan Divisor Reg I", SENSOR_INTEGER, 0, 0x47, wb_refresh_raw_rw }, +#endif /* LMFANCTLRAW */ + /* Voltage */ { "VCore", SENSOR_VOLTS_DC, 0, 0x20, wb_w83637hf_refresh_vcore }, { "+12V", SENSOR_VOLTS_DC, 0, 0x21, lm_refresh_volt, RFACT(28, 10) }, { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 51) }, { "-12V", SENSOR_VOLTS_DC, 0, 0x24, wb_refresh_nvolt, RFACT(232, 56) }, { "5VSB", SENSOR_VOLTS_DC, 5, 0x50, lm_refresh_volt, RFACT(34, 51) }, { "VBAT", SENSOR_VOLTS_DC, 5, 0x51, lm_refresh_volt, RFACT_NONE }, /* Temperature */ - { "", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, - { "", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, - { "", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, + { "Sys", SENSOR_TEMP, 0, 0x27, lm_refresh_temp }, + { "CPU", SENSOR_TEMP, 1, 0x50, wb_refresh_temp }, + { "Aux", SENSOR_TEMP, 2, 0x50, wb_refresh_temp }, + + /* Controlling parts: Target Temperature */ + { "Sys Target", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptarget_rw }, + { "CPU Target", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptarget_rw }, + { "Aux Target", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptarget_rw }, + /* Controlling parts: Target Temperature Tolerance */ + { "Sys Tolerance", SENSOR_TEMP, 0, 0x05, w83627ehf_refresh_temptargettol_rw }, + { "CPU Tolerance", SENSOR_TEMP, 0, 0x06, w83627ehf_refresh_temptargettol_rw }, + { "Aux Tolerance", SENSOR_TEMP, 0, 0x13, w83627ehf_refresh_temptargettol_rw }, /* Fans */ - { "", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, - { "", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, - { "", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, + { "Sys", SENSOR_FANRPM, 0, 0x28, wb_refresh_fanrpm }, + { "CPU", SENSOR_FANRPM, 0, 0x29, wb_refresh_fanrpm }, + { "Aux", SENSOR_FANRPM, 0, 0x2a, wb_refresh_fanrpm }, { NULL } }; +/* + * With regard to fan control, W83697HF documentation appears to be + * contradictory, as section 6.4.2 "Fan speed control" suggests + * using CR5A and CR5B, like in W83627HG, for PWM duty cycle, + * whereas other sections define these registers differently, + * and suggest registers similar to the other chips that implement + * the Smart Fan control system. + * Support for fan-controlling with this chip might be added later. + */ struct lm_sensor w83697hf_sensors[] = { /* Voltage */ { "VCore", SENSOR_VOLTS_DC, 0, 0x20, lm_refresh_volt, RFACT_NONE }, { "+3.3V", SENSOR_VOLTS_DC, 0, 0x22, lm_refresh_volt, RFACT_NONE }, { "+5V", SENSOR_VOLTS_DC, 0, 0x23, lm_refresh_volt, RFACT(34, 50) }, { "+12V", SENSOR_VOLTS_DC, 0, 0x24, lm_refresh_volt, RFACT(28, 10) }, { "-12V", SENSOR_VOLTS_DC, 0, 0x25, wb_refresh_nvolt, RFACT(232, 56) }, { "-5V", SENSOR_VOLTS_DC, 0, 0x26, wb_refresh_nvolt, RFACT(120, 56) }, @@ -394,17 +661,17 @@ void lm_attach(struct lm_softc *sc) { u_int i, config; /* No point in doing anything if we don't have any sensors. */ if (sc->numsensors == 0) return; - if (sensor_task_register(sc, lm_refresh, 5)) { + if (sensor_task_register(sc, lm_refresh, 3)) { device_printf(sc->sc_dev, "unable to register update task\n"); return; } /* Start the monitoring loop */ config = sc->lm_readreg(sc, LM_CONFIG); sc->lm_writereg(sc, LM_CONFIG, config | 0x01); @@ -508,33 +775,37 @@ wb_match(struct lm_softc *sc) DPRINTF((" winbond chip id 0x%x\n", sc->chipid)); switch(sc->chipid) { case WB_CHIPID_W83627HF: cdesc = "W83627HF"; lm_setup_sensors(sc, w83627hf_sensors); break; case WB_CHIPID_W83627THF: cdesc = "W83627THF"; - lm_setup_sensors(sc, w83637hf_sensors); + sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); + if (sc->lm_readreg(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9) + sc->vrm9 = 1; + sc->lm_writereg(sc, WB_BANKSEL, banksel); + lm_setup_sensors(sc, w83627thf_sensors); break; case WB_CHIPID_W83627EHF: cdesc = "W83627EHF"; lm_setup_sensors(sc, w83627ehf_sensors); break; case WB_CHIPID_W83627DHG: cdesc = "W83627DHG"; lm_setup_sensors(sc, w83627dhg_sensors); break; case WB_CHIPID_W83637HF: cdesc = "W83637HF"; sc->lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); if (sc->lm_readreg(sc, WB_BANK0_CONFIG) & WB_CONFIG_VMR9) sc->vrm9 = 1; sc->lm_writereg(sc, WB_BANKSEL, banksel); - lm_setup_sensors(sc, w83637hf_sensors); + lm_setup_sensors(sc, w83627thf_sensors); break; case WB_CHIPID_W83697HF: cdesc = "W83697HF"; lm_setup_sensors(sc, w83697hf_sensors); break; case WB_CHIPID_W83781D: case WB_CHIPID_W83781D_2: cdesc = "W83781D"; @@ -601,16 +872,22 @@ void lm_setup_sensors(struct lm_softc *sc, struct lm_sensor *sensors) { int i; for (i = 0; sensors[i].desc; i++) { sc->sensors[i].type = sensors[i].type; strlcpy(sc->sensors[i].desc, sensors[i].desc, sizeof(sc->sensors[i].desc)); + if (sc->sensors[i].type == SENSOR_PERCENT || + sc->sensors[i].type == SENSOR_INDICATOR || + sc->sensors[i].type == SENSOR_INTEGER || + (sc->sensors[i].type == SENSOR_TEMP && + sc->sensors[i].desc[4] != '\0')) + sc->sensors[i].flags = SENSOR_FCONTROLLABLE; sc->numsensors++; } sc->lm_sensors = sensors; } void lm_refresh(void *arg) { @@ -710,16 +987,446 @@ wb_refresh_sensor_data(struct lm_softc *sc) sc->lm_writereg(sc, WB_BANKSEL, bank); } sc->lm_sensors[i].refresh(sc, i); } sc->lm_writereg(sc, WB_BANKSEL, banksel); } void +wb_refresh_raw_rw(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int nv, data; + + if (sensor->flags & SENSOR_FNEWVALUE) { + sensor->flags &= ~SENSOR_FNEWVALUE; + nv = sensor->upvalue; + if (nv >= 0x00 && nv <= 0xff) + sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv); + } + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + sensor->value = data; +} + +void +w83627hf_refresh_pwm_rw(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int nv, data; + + if (sensor->flags & SENSOR_FNEWVALUE) { + sensor->flags &= ~SENSOR_FNEWVALUE; + nv = sensor->upvalue; + if (nv < 0 || nv > 100) + nv = 100; /* ramp it up! */ + nv = 255 * nv / 100; + sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv); + } + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + /* 1000 is the factor to convert from percentage to SENSOR_PERCENT */ + sensor->value = 1000 * 100 * data / 255; +} + +void +w83627ehf_refresh_fanvolt_rw(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int nv, data; + int confreg, selshift, modeshift, conf, sel, mode; + const char* const sels[2] = + { "PWM", "DC" }; + const char* const modes[4] = + { "Manual", "Thermal", "Speed", "SmartIII" }; + + /* get the right Fan Configuration Register */ + switch (sc->lm_sensors[n].reg) { + case 0x01: /* Sys */ + confreg = 0x04; selshift = 0; modeshift = 2; + break; + case 0x03: /* CPU */ + confreg = 0x04; selshift = 1; modeshift = 4; + break; + case 0x11: /* Aux */ + confreg = 0x12; selshift = 0; modeshift = 1; + break; + case 0x61: /* CPU */ + confreg = 0x5b; selshift = 6; modeshift = 4; + break; + default: + return; + } + + if (sensor->flags & SENSOR_FNEWVALUE) { + sensor->flags &= ~SENSOR_FNEWVALUE; + nv = sensor->upvalue; + if (nv < 0 || nv > 100) + nv = 100; /* ramp it up! */ + nv = 255 * nv / 100; + /* + * Since we got an explicit request to affect the speed, + * we need to go into manual mode first. + */ + conf = sc->lm_readreg(sc, confreg); + mode = (conf >> modeshift) & 0x3; + if (mode != 0) { + conf &= ~(0x3 << modeshift); + sc->lm_writereg(sc, confreg, conf); + } + sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv); + } + + /* now populate our struct ksensor */ + + conf = sc->lm_readreg(sc, confreg); + sel = (conf >> selshift) & 0x1; + mode = (conf >> modeshift) & 0x3; + ksnprintf(sensor->desc + 8, sizeof(sensor->desc) - 8, + "%s %s", sels[sel], modes[mode]); + + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + /* 1000 is the factor to convert from percentage to SENSOR_PERCENT */ + sensor->value = 1000 * 100 * data / 255; +#ifdef LMFANDUTYHINTS + if (data > 148) + sensor->status = SENSOR_S_OK; /* at least 7V */ + else if (data > 106) + sensor->status = SENSOR_S_WARN; /* at least 5V */ + else + sensor->status = SENSOR_S_CRIT; /* less than 5V */ +#endif /* LMFANDUTYHINTS */ +} + +/* + * Fan Start-up and Stop Values are only used in Thermal Cruise mode. + * The documentation is ambiguous of whether they are used in other + * modes, too. + */ +void +w83627ehf_refresh_fanvolt_thermal_rw(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int nv, data; + int confreg, selshift, modeshift, conf, mode, minfanbit, minfan; + + /* + * Get the right Fan Configuration Register. + * Register 0x12 has the "Keep Min. Fan Output Value" bools indicating + * whether the output should or should not go below the stop value. + */ + switch (sc->lm_sensors[n].reg) { + case 0x0a: + case 0x08: + /* Sys */ + confreg = 0x04; selshift = 0; modeshift = 2; + minfanbit = 5; + break; + case 0x0b: + case 0x09: + /* CPU */ + confreg = 0x04; selshift = 1; modeshift = 4; + minfanbit = 4; + break; + case 0x16: + case 0x15: + /* Aux */ + confreg = 0x12; selshift = 0; modeshift = 1; + minfanbit = 3; + break; + case 0x65: + case 0x64: + /* CPU */ + confreg = 0x5b; selshift = 6; modeshift = 4; + minfanbit = 6; + break; + default: + return; + } + + if (sensor->flags & SENSOR_FNEWVALUE) { + sensor->flags &= ~SENSOR_FNEWVALUE; + nv = sensor->upvalue; + if (!(nv < 0 || nv > 100)) { + if (sc->lm_sensors[n].rfact == 1) { + conf = sc->lm_readreg(sc, 0x12); + minfan = (conf >> minfanbit) & 0x1; + if (minfan != 1) { + conf |= (0x1 << minfanbit); + sc->lm_writereg(sc, 0x12, conf); + } + } + nv = 255 * nv / 100; + sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv); + } + } + + /* now populate our struct ksensor */ + + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + /* 1000 is the factor to convert from percentage to SENSOR_PERCENT */ + sensor->value = 1000 * 100 * data / 255; + + conf = sc->lm_readreg(sc, confreg); + mode = (conf >> modeshift) & 0x3; + if (sc->lm_sensors[n].rfact == 1) { + conf = sc->lm_readreg(sc, 0x12); + minfan = (conf >> minfanbit) & 0x1; + } else + minfan = 1; + + if (mode == 0x1 && minfan == 1) + sensor->flags &= ~SENSOR_FUNKNOWN; + else + sensor->flags |= SENSOR_FUNKNOWN; + +#ifdef LMFANDUTYHINTS + if (sensor->flags & SENSOR_FUNKNOWN) + sensor->status = SENSOR_S_UNSPEC; + else if (data > 148) + sensor->status = SENSOR_S_OK; /* at least 7V */ + else if (data > 106) + sensor->status = SENSOR_S_WARN; /* at least 5V */ + else + sensor->status = SENSOR_S_CRIT; /* less than 5V */ +#endif /* LMFANDUTYHINTS */ +} + +void +w83627ehf_refresh_indicator_rw(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int nv; + int confreg, selshift, modeshift, conf, sel; + const char* const sels[2] = + { "PWM", "DC" }; + + /* get the right Fan Configuration Register */ + switch (sc->lm_sensors[n].reg) { + case 0x01: /* Sys */ + confreg = 0x04; selshift = 0; modeshift = 2; + break; + case 0x03: /* CPU */ + confreg = 0x04; selshift = 1; modeshift = 4; + break; + case 0x11: /* Aux */ + confreg = 0x12; selshift = 0; modeshift = 1; + break; + case 0x61: /* CPU */ + confreg = 0x5b; selshift = 6; modeshift = 4; + break; + default: + return; + } + + if (sensor->flags & SENSOR_FNEWVALUE) { + sensor->flags &= ~SENSOR_FNEWVALUE; + nv = sensor->upvalue; + if (nv == 0 || nv == 1) { + conf = sc->lm_readreg(sc, confreg); + sel = (conf >> selshift) & 0x1; + if (sel != nv) { + if (nv == 0) + conf &= ~(0x1 << selshift); + else + conf |= (0x1 << selshift); + sc->lm_writereg(sc, confreg, conf); + } + } + } + + conf = sc->lm_readreg(sc, confreg); + sel = (conf >> selshift) & 0x1; + sensor->value = sel; + ksnprintf(sensor->desc + 8, sizeof(sensor->desc) - 8, + "%s/%s: %s", sels[0], sels[1], sels[sel]); +} + +void +w83627ehf_refresh_temptarget_rw(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int nv, data; + int confreg, modeshift, tolreg, tolsh, conf, mode; + + /* get the right Fan Configuration Register and Tolerance */ + /* search for Relative Registers in the datasheet for a nice table */ + /* .reg in this switch is the target cruise register */ + switch (sc->lm_sensors[n].reg) { + case 0x05: /* Sys */ + confreg = 0x04; modeshift = 2; tolreg = 0x07; tolsh = 0; + break; + case 0x06: /* CPU */ + confreg = 0x04; modeshift = 4; tolreg = 0x07; tolsh = 4; + break; + case 0x13: /* Aux */ + confreg = 0x12; modeshift = 1; tolreg = 0x14; tolsh = 0; + break; + case 0x63: /* CPU */ + confreg = 0x5b; modeshift = 4; tolreg = 0x62; tolsh = 0; + break; + default: + return; + } + + if (sensor->flags & SENSOR_FNEWVALUE) { + sensor->flags &= ~SENSOR_FNEWVALUE; + nv = sensor->upvalue; + /* + * If the new value is invalid, assume 'panic', + * and make 36 degC the new target temp. + */ + if (nv < 0 || nv > 127) + nv = 36; + /* + * Since we got an explicit request to affect the speed, + * we need to go into Temperature Cruise mode first. + */ + conf = sc->lm_readreg(sc, confreg); + mode = (conf >> modeshift) & 0x3; + if (mode != 0x1) { + conf &= ~(0x3 << modeshift); + conf |= (0x1 << modeshift); + sc->lm_writereg(sc, confreg, conf); + } + sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv); + } + + /* now populate our struct ksensor */ + + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + sensor->value = data * 1000000 + 273150000; + + conf = sc->lm_readreg(sc, confreg); + mode = (conf >> modeshift) & 0x3; + if (mode != 0x1) + sensor->flags |= SENSOR_FUNKNOWN; + else + sensor->flags &= ~SENSOR_FUNKNOWN; +} + +void +w83627ehf_refresh_temptargettol_rw(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int nv, data; + int confreg, modeshift, tolreg, tolsh, conf, mode; + + /* get the right Fan Configuration Register and Tolerance */ + /* search for Relative Registers in the datasheet for a nice table */ + /* .reg in this switch is the target cruise register */ + switch (sc->lm_sensors[n].reg) { + case 0x05: /* Sys */ + confreg = 0x04; modeshift = 2; tolreg = 0x07; tolsh = 0; + break; + case 0x06: /* CPU */ + confreg = 0x04; modeshift = 4; tolreg = 0x07; tolsh = 4; + break; + case 0x13: /* Aux */ + confreg = 0x12; modeshift = 1; tolreg = 0x14; tolsh = 0; + break; + case 0x63: /* CPU */ + confreg = 0x5b; modeshift = 4; tolreg = 0x62; tolsh = 0; + break; + default: + return; + } + + if (sensor->flags & SENSOR_FNEWVALUE) { + sensor->flags &= ~SENSOR_FNEWVALUE; + nv = sensor->upvalue; + if (!(nv < 0 || nv > 16)) { + data = sc->lm_readreg(sc, tolreg); + data &= ~(0xf << tolsh); + data |= (nv << tolsh); + sc->lm_writereg(sc, tolreg, data); + } + } + + /* now populate our struct ksensor */ + + data = sc->lm_readreg(sc, tolreg); + data &= (0xf << tolsh); + data >>= tolsh; + sensor->value = data * 1000000 + 273150000; + + conf = sc->lm_readreg(sc, confreg); + mode = (conf >> modeshift) & 0x3; + if (mode != 0x1) + sensor->flags |= SENSOR_FUNKNOWN; + else + sensor->flags &= ~SENSOR_FUNKNOWN; +} + +void +w83627thf_refresh_fanvolt_rw(struct lm_softc *sc, int n) +{ + struct ksensor *sensor = &sc->sensors[n]; + int nv, data; + int confreg, modeshift, conf, mode; + const char* const modes[4] = + { "Manual", "Thermal", "Speed", "" }; + + /* get the right Fan Configuration Register */ + switch (sc->lm_sensors[n].reg) { + case 0x01: /* Sys */ + confreg = 0x04; modeshift = 2; + break; + case 0x03: /* CPU */ + confreg = 0x04; modeshift = 4; + break; + case 0x11: /* Aux */ + confreg = 0x12; modeshift = 1; + break; + default: + return; + } + + if (sensor->flags & SENSOR_FNEWVALUE) { + sensor->flags &= ~SENSOR_FNEWVALUE; + nv = sensor->upvalue; + if (nv < 0 || nv > 100) + nv = 100; /* ramp it up! */ + /* only 4 out of 8 bits are used to control voltage */ + nv = 0xf * nv / 100; + nv <<= 4; + /* + * Since we got an explicit request to affect the speed, + * we need to go into manual mode first. + */ + conf = sc->lm_readreg(sc, confreg); + mode = (conf >> modeshift) & 0x3; + if (mode != 0) { + conf &= ~(0x3 << modeshift); + sc->lm_writereg(sc, confreg, conf); + } + sc->lm_writereg(sc, sc->lm_sensors[n].reg, nv); + } + + /* now populate our struct ksensor */ + + conf = sc->lm_readreg(sc, confreg); + mode = (conf >> modeshift) & 0x3; + ksnprintf(sensor->desc + 8, sizeof(sensor->desc) - 8, + "Ctl %s", modes[mode]); + + data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); + data >>= 4; + /* 1000 is the factor to convert from percentage to SENSOR_PERCENT */ + sensor->value = 1000 * 100 * data / 0xf; +#ifdef LMFANDUTYHINTS + if (data > 0x8) + sensor->status = SENSOR_S_OK; /* at least 7.2V */ + else if (data > 0x5) + sensor->status = SENSOR_S_WARN; /* at least 4.8V */ + else + sensor->status = SENSOR_S_CRIT; /* 4.0V and less */ +#endif /* LMFANDUTYHINTS */ +} + +void wb_w83637hf_refresh_vcore(struct lm_softc *sc, int n) { struct ksensor *sensor = &sc->sensors[n]; int data; data = sc->lm_readreg(sc, sc->lm_sensors[n].reg); /* -- 1.6.6