Module Name: src Committed By: martin Date: Sun Feb 28 11:49:44 UTC 2010
Modified Files: src/sys/arch/sparc64/conf: GENERIC SCHIZO files.sparc64 Added Files: src/sys/arch/sparc64/dev: pcf8591_envctrl.c pcfiic_ebus.c tda.c Removed Files: src/sys/arch/sparc64/dev: envctrl.c envctrlreg.h Log Message: Remove the envctrl driver, it is superseeded by the more general pcfiic @ ebus. Add the SB1000/SB2000 fan controll driver (tda). From OpenBSD. Move config files over to direct configuration of i2c devices. To generate a diff of this commit: cvs rdiff -u -r1.117 -r1.118 src/sys/arch/sparc64/conf/GENERIC cvs rdiff -u -r1.6 -r1.7 src/sys/arch/sparc64/conf/SCHIZO cvs rdiff -u -r1.124 -r1.125 src/sys/arch/sparc64/conf/files.sparc64 cvs rdiff -u -r1.11 -r0 src/sys/arch/sparc64/dev/envctrl.c cvs rdiff -u -r1.5 -r0 src/sys/arch/sparc64/dev/envctrlreg.h cvs rdiff -u -r0 -r1.1 src/sys/arch/sparc64/dev/pcf8591_envctrl.c \ src/sys/arch/sparc64/dev/pcfiic_ebus.c src/sys/arch/sparc64/dev/tda.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/sparc64/conf/GENERIC diff -u src/sys/arch/sparc64/conf/GENERIC:1.117 src/sys/arch/sparc64/conf/GENERIC:1.118 --- src/sys/arch/sparc64/conf/GENERIC:1.117 Sat Feb 13 08:54:58 2010 +++ src/sys/arch/sparc64/conf/GENERIC Sun Feb 28 11:49:44 2010 @@ -1,4 +1,4 @@ -# $NetBSD: GENERIC,v 1.117 2010/02/13 08:54:58 mrg Exp $ +# $NetBSD: GENERIC,v 1.118 2010/02/28 11:49:44 martin Exp $ # # GENERIC machine description file # @@ -22,7 +22,7 @@ options INCLUDE_CONFIG_FILE # embed config file in kernel binary -#ident "GENERIC-$Revision: 1.117 $" +#ident "GENERIC-$Revision: 1.118 $" maxusers 64 @@ -906,17 +906,20 @@ #### Other device configuration psm* at ebus? # Ultrabook IIi microcontroller -envctrl* at ebus? # Ultra E450 environmental monitoring +pcfiic* at ebus? # various environmental monitoring +iic* at pcfiic? lom* at ebus? # LOMlite lights out management # Netra X1 / T1 style environmental monitoring alipm* at pci? iic* at alipm? -spdmem* at iic? addr 0x54 -spdmem* at iic? addr 0x55 -spdmem* at iic? addr 0x56 -spdmem* at iic? addr 0x57 -admtemp* at iic? addr 0x18 + +# I2C devices +spdmem* at iic? addr? +admtemp* at iic? addr? +ecadc* at iic? addr? # envctrl/envctrltwo on E250/E450 +lmtemp* at iic? addr? +tda* at iic? addr? # fan controll on SB1000/2000 ### Other pseudo-devices Index: src/sys/arch/sparc64/conf/SCHIZO diff -u src/sys/arch/sparc64/conf/SCHIZO:1.6 src/sys/arch/sparc64/conf/SCHIZO:1.7 --- src/sys/arch/sparc64/conf/SCHIZO:1.6 Sat Feb 13 22:24:09 2010 +++ src/sys/arch/sparc64/conf/SCHIZO Sun Feb 28 11:49:44 2010 @@ -1,4 +1,4 @@ -# $NetBSD: SCHIZO,v 1.6 2010/02/13 22:24:09 mrg Exp $ +# $NetBSD: SCHIZO,v 1.7 2010/02/28 11:49:44 martin Exp $ # # GENERIC with schizo support enabled, with the annoying schizo interupt # option @@ -7,7 +7,7 @@ include "arch/sparc64/conf/GENERIC.MP" #include "arch/sparc64/conf/GENERIC" -#ident "SCHIZO.$Revision: 1.6 $" +#ident "SCHIZO.$Revision: 1.7 $" options CHEETAH @@ -20,6 +20,3 @@ # this crashes when attaching. #no machfb - -# this matches when it isn't present. ugh. -no admtemp Index: src/sys/arch/sparc64/conf/files.sparc64 diff -u src/sys/arch/sparc64/conf/files.sparc64:1.124 src/sys/arch/sparc64/conf/files.sparc64:1.125 --- src/sys/arch/sparc64/conf/files.sparc64:1.124 Mon Feb 22 22:28:58 2010 +++ src/sys/arch/sparc64/conf/files.sparc64 Sun Feb 28 11:49:44 2010 @@ -1,4 +1,4 @@ -# $NetBSD: files.sparc64,v 1.124 2010/02/22 22:28:58 mrg Exp $ +# $NetBSD: files.sparc64,v 1.125 2010/02/28 11:49:44 martin Exp $ # @(#)files.sparc64 8.1 (Berkeley) 7/19/93 # sparc64-specific configuration info @@ -68,9 +68,17 @@ attach power at sbus, ebus file arch/sparc64/dev/power.c power -device envctrl: sysmon_envsys, pcf8584, i2cbus -attach envctrl at ebus -file arch/sparc64/dev/envctrl.c envctrl +device tda +attach tda at iic +file arch/sparc64/dev/tda.c tda + +device pcfiic: sysmon_envsys, pcf8584, i2cbus +attach pcfiic at ebus +file arch/sparc64/dev/pcfiic_ebus.c pcfiic + +device ecadc +attach ecadc at iic +file arch/sparc64/dev/pcf8591_envctrl.c device lom: sysmon_envsys, sysmon_wdog attach lom at ebus Added files: Index: src/sys/arch/sparc64/dev/pcf8591_envctrl.c diff -u /dev/null src/sys/arch/sparc64/dev/pcf8591_envctrl.c:1.1 --- /dev/null Sun Feb 28 11:49:44 2010 +++ src/sys/arch/sparc64/dev/pcf8591_envctrl.c Sun Feb 28 11:49:44 2010 @@ -0,0 +1,255 @@ +/* $NetBSD: pcf8591_envctrl.c,v 1.1 2010/02/28 11:49:44 martin Exp $ */ +/* $OpenBSD: pcf8591_envctrl.c,v 1.6 2007/10/25 21:17:20 kettenis Exp $ */ + +/* + * Copyright (c) 2006 Damien Miller <d...@openbsd.org> + * Copyright (c) 2007 Mark Kettenis <kette...@openbsd.org> + * + * 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 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <dev/sysmon/sysmonvar.h> + +#include <dev/ofw/openfirm.h> +#include <dev/i2c/i2cvar.h> + +#define PCF8591_CHANNELS 4 + +#define PCF8591_CTRL_CH0 0x00 +#define PCF8591_CTRL_CH1 0x01 +#define PCF8591_CTRL_CH2 0x02 +#define PCF8591_CTRL_CH3 0x03 +#define PCF8591_CTRL_AUTOINC 0x04 +#define PCF8591_CTRL_OSCILLATOR 0x40 + +struct ecadc_channel { + u_int chan_num; + envsys_data_t chan_sensor; + u_char *chan_xlate; + int64_t chan_factor; + int64_t chan_min; + int64_t chan_warn; + int64_t chan_crit; +}; + +struct ecadc_softc { + device_t sc_dev; + i2c_tag_t sc_tag; + i2c_addr_t sc_addr; + u_char sc_ps_xlate[256]; + u_char sc_cpu_xlate[256]; + u_int sc_nchan; + struct ecadc_channel sc_channels[PCF8591_CHANNELS]; + struct sysmon_envsys *sc_sme; +}; + +static int ecadc_match(device_t, cfdata_t, void *); +static void ecadc_attach(device_t, device_t, void *); +static void ecadc_refresh(struct sysmon_envsys *, envsys_data_t *); +static void ecadc_get_limits(struct sysmon_envsys *, envsys_data_t *, + sysmon_envsys_lim_t *, uint32_t *); + +CFATTACH_DECL_NEW(ecadc, sizeof(struct ecadc_softc), + ecadc_match, ecadc_attach, NULL, NULL); + +static const char * ecadc_compats[] = { + "ecadc", + NULL +}; + +static int +ecadc_match(device_t parent, cfdata_t cf, void *aux) +{ + struct i2c_attach_args *ia = aux; + + if (iic_compat_match(ia, ecadc_compats)) + return 1; + + return 0; +} + +static void +ecadc_attach(device_t parent, device_t self, void *aux) +{ + struct i2c_attach_args *ia = aux; + struct ecadc_softc *sc = device_private(self); + u_char term[256]; + u_char *cp, *desc; + int64_t minv, warnv, crit, num, den; + u_int8_t junk[PCF8591_CHANNELS + 1]; + envsys_data_t *sensor; + int len, error, addr, chan, node = (int)ia->ia_cookie; + u_int i; + + sc->sc_dev = self; + if ((len = OF_getprop(node, "thermisters", term, + sizeof(term))) < 0) { + aprint_error(": couldn't find \"thermisters\" property\n"); + return; + } + + if (OF_getprop(node, "cpu-temp-factors", &sc->sc_cpu_xlate[2], + sizeof(sc->sc_cpu_xlate) - 2) < 0) { + aprint_error(": couldn't find \"cpu-temp-factors\" property\n"); + return; + } + sc->sc_cpu_xlate[0] = sc->sc_cpu_xlate[1] = sc->sc_cpu_xlate[2]; + + /* Only the Sun Enterprise 450 has these. */ + OF_getprop(node, "ps-temp-factors", &sc->sc_ps_xlate[2], + sizeof(sc->sc_ps_xlate) - 2); + sc->sc_ps_xlate[0] = sc->sc_ps_xlate[1] = sc->sc_ps_xlate[2]; + + cp = term; + while (cp < term + len) { + addr = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4; + chan = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4; + minv = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4; + warnv = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4; + crit = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4; + num = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4; + den = cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; cp += 4; + desc = cp; + while (cp < term + len && *cp++); + + if (addr != (ia->ia_addr << 1)) + continue; + + if (num == 0 || den == 0) + num = den = 1; + + sc->sc_channels[sc->sc_nchan].chan_num = chan; + + sensor = &sc->sc_channels[sc->sc_nchan].chan_sensor; + sensor->units = ENVSYS_STEMP; + strlcpy(sensor->desc, desc, sizeof(sensor->desc)); + + if (strncmp(desc, "CPU", 3) == 0) + sc->sc_channels[sc->sc_nchan].chan_xlate = + sc->sc_cpu_xlate; + else if (strncmp(desc, "PS", 2) == 0) + sc->sc_channels[sc->sc_nchan].chan_xlate = + sc->sc_ps_xlate; + else + sc->sc_channels[sc->sc_nchan].chan_factor = + (1000000 * num) / den; + sc->sc_channels[sc->sc_nchan].chan_min = + 273150000 + 1000000 * minv; + sc->sc_channels[sc->sc_nchan].chan_warn = + 273150000 + 1000000 * warnv; + sc->sc_channels[sc->sc_nchan].chan_crit = + 273150000 + 1000000 * crit; + sc->sc_nchan++; + } + + sc->sc_tag = ia->ia_tag; + sc->sc_addr = ia->ia_addr; + + iic_acquire_bus(sc->sc_tag, 0); + + /* Try a read now, so we can fail if it doesn't work */ + if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, + NULL, 0, junk, sc->sc_nchan + 1, 0)) { + aprint_error(": read failed\n"); + iic_release_bus(sc->sc_tag, 0); + return; + } + + iic_release_bus(sc->sc_tag, 0); + + /* Hook us into the sysmon_envsys subsystem */ + sc->sc_sme = sysmon_envsys_create(); + sc->sc_sme->sme_name = device_xname(self); + sc->sc_sme->sme_cookie = sc; + sc->sc_sme->sme_flags |= ENVSYS_FMONNOTSUPP; + sc->sc_sme->sme_refresh = ecadc_refresh; + sc->sc_sme->sme_get_limits = ecadc_get_limits; + + /* Initialize sensor data. */ + for (i = 0; i < sc->sc_nchan; i++) + sysmon_envsys_sensor_attach(sc->sc_sme, + &sc->sc_channels[i].chan_sensor); + + error = sysmon_envsys_register(sc->sc_sme); + if (error) { + aprint_error_dev(self, "error %d registering with sysmon\n", + error); + sysmon_envsys_destroy(sc->sc_sme); + return; + } + + aprint_naive(": Temp Sensors\n"); + aprint_normal("%s Temp Sensors\n", ia->ia_name); +} + +static void +ecadc_refresh(struct sysmon_envsys *sme, envsys_data_t *sensor) +{ + struct ecadc_softc *sc = sme->sme_cookie; + u_int i; + u_int8_t data[PCF8591_CHANNELS + 1]; + u_int8_t ctrl = PCF8591_CTRL_CH0 | PCF8591_CTRL_AUTOINC | + PCF8591_CTRL_OSCILLATOR; + + iic_acquire_bus(sc->sc_tag, 0); + if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, + &ctrl, 1, NULL, 0, 0)) { + iic_release_bus(sc->sc_tag, 0); + return; + } + /* NB: first byte out is stale, so read num_channels + 1 */ + if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, + NULL, 0, data, PCF8591_CHANNELS + 1, 0)) { + iic_release_bus(sc->sc_tag, 0); + return; + } + iic_release_bus(sc->sc_tag, 0); + + /* We only support temperature channels. */ + for (i = 0; i < sc->sc_nchan; i++) { + struct ecadc_channel *chp = &sc->sc_channels[i]; + + if (chp->chan_xlate) + chp->chan_sensor.value_cur = 273150000 + 1000000 * + chp->chan_xlate[data[1 + chp->chan_num]]; + else + chp->chan_sensor.value_cur = 273150000 + + chp->chan_factor * data[1 + chp->chan_num]; + + chp->chan_sensor.state = ENVSYS_SVALID; + chp->chan_sensor.flags &= ~ENVSYS_FNEED_REFRESH; + chp->chan_sensor.flags |= ENVSYS_FMONLIMITS; + } +} + +static void +ecadc_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata, + sysmon_envsys_lim_t *limits, uint32_t *props) +{ + struct ecadc_softc *sc = sme->sme_cookie; + int i; + + for (i = 0; i < sc->sc_nchan; i++) { + if (edata != &sc->sc_channels[i].chan_sensor) + continue; + *props |= PROP_WARNMIN|PROP_WARNMAX|PROP_CRITMAX; + limits->sel_warnmin = sc->sc_channels[i].chan_min; + limits->sel_warnmax = sc->sc_channels[i].chan_warn; + limits->sel_critmax = sc->sc_channels[i].chan_crit; + return; + } +} Index: src/sys/arch/sparc64/dev/pcfiic_ebus.c diff -u /dev/null src/sys/arch/sparc64/dev/pcfiic_ebus.c:1.1 --- /dev/null Sun Feb 28 11:49:44 2010 +++ src/sys/arch/sparc64/dev/pcfiic_ebus.c Sun Feb 28 11:49:44 2010 @@ -0,0 +1,222 @@ +/* $NetBSD: pcfiic_ebus.c,v 1.1 2010/02/28 11:49:44 martin Exp $ */ +/* $OpenBSD: pcfiic_ebus.c,v 1.13 2008/06/08 03:07:40 deraadt Exp $ */ + +/* + * Copyright (c) 2006 David Gwynne <d...@openbsd.org> + * + * 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 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Device specific driver for the EBus i2c devices found on some sun4u + * systems. On systems not having a boot-bus controller the i2c devices + * are PCF8584. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/rwlock.h> + +#include <machine/bus.h> +#include <machine/openfirm.h> +#include <machine/autoconf.h> + +#include <dev/ebus/ebusreg.h> +#include <dev/ebus/ebusvar.h> + +#include <dev/i2c/i2cvar.h> + +#include <dev/ic/pcf8584var.h> + +int pcfiic_ebus_match(device_t, struct cfdata *, void *); +void pcfiic_ebus_attach(device_t, device_t, void *); + +struct pcfiic_ebus_softc { + struct pcfiic_softc esc_sc; + + int esc_node; + void *esc_ih; +}; + +CFATTACH_DECL_NEW(pcfiic, sizeof(struct pcfiic_ebus_softc), + pcfiic_ebus_match, pcfiic_ebus_attach, NULL, NULL); + +static prop_array_t create_dict(device_t); +static void add_prop(prop_array_t, const char *, const char *, u_int, int); +static void envctrl_props(prop_array_t, int); +static void envctrltwo_props(prop_array_t, int); + +int +pcfiic_ebus_match(device_t parent, struct cfdata *match, void *aux) +{ + struct ebus_attach_args *ea = aux; + char compat[32]; + + if (strcmp(ea->ea_name, "SUNW,envctrl") == 0 || + strcmp(ea->ea_name, "SUNW,envctrltwo") == 0) + return (1); + + if (strcmp(ea->ea_name, "i2c") != 0) + return (0); + + if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) == -1) + return (0); + + if (strcmp(compat, "pcf8584") == 0 || + strcmp(compat, "i2cpcf,8584") == 0 || + strcmp(compat, "SUNW,i2c-pic16f747") == 0 || + strcmp(compat, "SUNW,bbc-i2c") == 0) + return (1); + + return (0); +} + +void +pcfiic_ebus_attach(device_t parent, device_t self, void *aux) +{ + struct pcfiic_ebus_softc *esc = device_private(self); + struct pcfiic_softc *sc = &esc->esc_sc; + struct ebus_attach_args *ea = aux; + char compat[32]; + u_int64_t addr; + u_int8_t clock = PCF_CLOCK_12 | PCF_FREQ_90; + int swapregs = 0; + + if (ea->ea_nreg < 1 || ea->ea_nreg > 2) { + printf(": expected 1 or 2 registers, got %d\n", ea->ea_nreg); + return; + } + + sc->sc_dev = self; + if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) > 0 && + strcmp(compat, "SUNW,bbc-i2c") == 0) { + /* + * On BBC-based machines, Sun swapped the order of + * the registers on their clone pcf, plus they feed + * it a non-standard clock. + */ + int clk = prom_getpropint(findroot(), "clock-frequency", 0); + + if (clk < 105000000) + clock = PCF_CLOCK_3 | PCF_FREQ_90; + else if (clk < 160000000) + clock = PCF_CLOCK_4_43 | PCF_FREQ_90; + swapregs = 1; + } + + if (OF_getprop(ea->ea_node, "own-address", &addr, sizeof(addr)) == -1) { + addr = 0xaa; + } else if (addr == 0x00 || addr > 0xff) { + printf(": invalid address on I2C bus"); + return; + } + + if (bus_space_map(ea->ea_bustag, + EBUS_ADDR_FROM_REG(&ea->ea_reg[0]), + ea->ea_reg[0].size, 0, &sc->sc_ioh) == 0) { + sc->sc_iot = ea->ea_bustag; + } else { + printf(": can't map register space\n"); + return; + } + + if (ea->ea_nreg == 2) { + /* + * Second register only occurs on BBC-based machines, + * and is likely not prom mapped + */ + if (bus_space_map(sc->sc_iot, EBUS_ADDR_FROM_REG(&ea->ea_reg[1]), + ea->ea_reg[1].size, 0, &sc->sc_ioh2) != 0) { + printf(": can't map 2nd register space\n"); + return; + } + sc->sc_master = 1; + } + + if (ea->ea_nintr >= 1) + esc->esc_ih = bus_intr_establish(sc->sc_iot, ea->ea_intr[0], + IPL_BIO, pcfiic_intr, sc); + else + esc->esc_ih = NULL; + + + if (esc->esc_ih == NULL) + sc->sc_poll = 1; + + if (strcmp(ea->ea_name, "SUNW,envctrl") == 0) { + envctrl_props(create_dict(self), ea->ea_node); + pcfiic_attach(sc, 0x55, PCF_CLOCK_12 | PCF_FREQ_45, 0); + } else if (strcmp(ea->ea_name, "SUNW,envctrltwo") == 0) { + envctrltwo_props(create_dict(self), ea->ea_node); + pcfiic_attach(sc, 0x55, PCF_CLOCK_12 | PCF_FREQ_45, 0); + } else + pcfiic_attach(sc, (i2c_addr_t)(addr >> 1), clock, swapregs); +} + +static prop_array_t +create_dict(device_t parent) +{ + prop_dictionary_t props = device_properties(parent); + prop_array_t cfg = prop_dictionary_get(props, "i2c-child-devices"); + if (cfg) return cfg; + cfg = prop_array_create(); + prop_dictionary_set(props, "i2c-child-devices", cfg); + prop_object_release(cfg); + return cfg; +} + +static void +add_prop(prop_array_t c, const char *name, const char *compat, u_int addr, + int node) +{ + prop_dictionary_t dev; + prop_data_t data; + + dev = prop_dictionary_create(); + prop_dictionary_set_cstring(dev, "name", name); + data = prop_data_create_data(compat, strlen(compat)+1); + prop_dictionary_set(dev, "compatible", data); + prop_object_release(data); + prop_dictionary_set_uint32(dev, "addr", addr); + prop_dictionary_set_uint64(dev, "cookie", node); + prop_array_add(c, dev); + prop_object_release(dev); +} + +static void +envctrl_props(prop_array_t c, int node) +{ + /* Power supply 1 temperature. */ + add_prop(c, "PSU-1", "ecadc", 0x48, node); + + /* Power supply 2 termperature. */ + add_prop(c, "PSU-2", "ecadc", 0x49, node); + + /* Power supply 3 tempterature. */ + add_prop(c, "PSU-3", "ecadc", 0x4a, node); + + /* Ambient tempterature. */ + add_prop(c, "ambient", "i2c-lm75", 0x4d, node); + + /* CPU temperatures. */ + add_prop(c, "CPU", "ecadc", 0x4f, node); +} + +static void +envctrltwo_props(prop_array_t c, int node) +{ + add_prop(c, "PSU", "ecadc", 0x4a, node); + add_prop(c, "CPU", "ecadc", 0x4f, node); +} Index: src/sys/arch/sparc64/dev/tda.c diff -u /dev/null src/sys/arch/sparc64/dev/tda.c:1.1 --- /dev/null Sun Feb 28 11:49:44 2010 +++ src/sys/arch/sparc64/dev/tda.c Sun Feb 28 11:49:44 2010 @@ -0,0 +1,228 @@ +/* $NetBSD: tda.c,v 1.1 2010/02/28 11:49:44 martin Exp $ */ +/* $OpenBSD: tda.c,v 1.4 2008/02/27 17:25:00 robert Exp $ */ + +/* + * Copyright (c) 2008 Robert Nagy <rob...@openbsd.org> + * Copyright (c) 2008 Mark Kettenis <kette...@openbsd.org> + * + * 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 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <dev/sysmon/sysmonvar.h> +#include <dev/sysmon/sysmon_taskq.h> + +#include <machine/autoconf.h> +#include <machine/openfirm.h> + +#include <dev/i2c/i2cvar.h> + +/* fan control registers */ +#define TDA_SYSFAN_REG 0xf0 +#define TDA_CPUFAN_REG 0xf2 +#define TDA_PSFAN_REG 0xf4 + +#define TDA_FANSPEED_MIN 0x0c +#define TDA_FANSPEED_MAX 0x3f + +#define TDA_PSFAN_ON 0x1f +#define TDA_PSFAN_OFF 0x00 + +/* Internal and External temperature senor numbers */ +#define SENSOR_TEMP_EXT 0 +#define SENSOR_TEMP_INT 1 + +#define CPU_TEMP_MAX (67 * 1000000 + 273150000) +#define CPU_TEMP_MIN (57 * 1000000 + 273150000) +#define SYS_TEMP_MAX (30 * 1000000 + 273150000) +#define SYS_TEMP_MIN (20 * 1000000 + 273150000) + +struct tda_softc { + device_t sc_dev; + i2c_tag_t sc_tag; + i2c_addr_t sc_addr; + + u_int16_t sc_cfan_speed; /* current CPU fan speed */ + u_int16_t sc_sfan_speed; /* current SYS fan speed */ + + callout_t sc_timer; +}; + +int tda_match(struct device *, struct cfdata *, void *); +void tda_attach(struct device *, struct device *, void *); + +void tda_setspeed(struct tda_softc *); +static void tda_adjust(void *); +static void tda_timeout(void *); + + +CFATTACH_DECL_NEW(tda, sizeof(struct tda_softc), + tda_match, tda_attach, NULL, NULL); + +int +tda_match(struct device *parent, struct cfdata *match, void *aux) +{ + struct i2c_attach_args *ia = aux; + char name[32]; + + /* Only attach on the Sun Blade 1000/2000. */ + if (OF_getprop(findroot(), "name", name, sizeof(name)) <= 0) + return (0); + if (strcmp(name, "SUNW,Sun-Blade-1000") != 0) + return (0); + + /* + * No need for "compatible" matching, we know exactly what + * firmware calls us. + */ + return strcmp(ia->ia_name, "fan-control") == 0; +} + +void +tda_attach(struct device *parent, struct device *self, void *aux) +{ + struct tda_softc *sc = device_private(self); + struct i2c_attach_args *ia = aux; + + sc->sc_dev = self; + sc->sc_tag = ia->ia_tag; + sc->sc_addr = ia->ia_addr; + + aprint_normal(": %s\n", ia->ia_name); + + /* + * Set the fans to maximum speed and save the power levels; + * the controller is write-only. + */ + sc->sc_cfan_speed = sc->sc_sfan_speed = (TDA_FANSPEED_MAX+TDA_FANSPEED_MIN)/2; + tda_setspeed(sc); + + callout_init(&sc->sc_timer, CALLOUT_MPSAFE); + callout_reset(&sc->sc_timer, hz*20, tda_timeout, sc); +} + +static void +tda_timeout(void *v) +{ + struct tda_softc *sc = v; + + sysmon_task_queue_sched(0, tda_adjust, sc); + callout_reset(&sc->sc_timer, hz*60, tda_timeout, sc); +} + +void +tda_setspeed(struct tda_softc *sc) +{ + u_int8_t cmd[2]; + + if (sc->sc_cfan_speed < TDA_FANSPEED_MIN) + sc->sc_cfan_speed = TDA_FANSPEED_MIN; + if (sc->sc_sfan_speed < TDA_FANSPEED_MIN) + sc->sc_sfan_speed = TDA_FANSPEED_MIN; + if (sc->sc_cfan_speed > TDA_FANSPEED_MAX) + sc->sc_cfan_speed = TDA_FANSPEED_MAX; + if (sc->sc_sfan_speed > TDA_FANSPEED_MAX) + sc->sc_sfan_speed = TDA_FANSPEED_MAX; + + iic_acquire_bus(sc->sc_tag, 0); + + cmd[0] = TDA_CPUFAN_REG; + cmd[1] = sc->sc_cfan_speed; + if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, + sc->sc_addr, &cmd, sizeof(cmd), NULL, 0, 0)) { + aprint_error_dev(sc->sc_dev, "cannot write cpu-fan register\n"); + iic_release_bus(sc->sc_tag, 0); + return; + } + + cmd[0] = TDA_SYSFAN_REG; + cmd[1] = sc->sc_sfan_speed; + if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, + sc->sc_addr, &cmd, sizeof(cmd), NULL, 0, 0)) { + aprint_error_dev(sc->sc_dev, "cannot write system-fan register\n"); + iic_release_bus(sc->sc_tag, 0); + return; + } + + iic_release_bus(sc->sc_tag, 0); + + aprint_debug_dev(sc->sc_dev, "changed fan speed to cpu=%d system=%d\n", + sc->sc_cfan_speed, sc->sc_sfan_speed); +} + +static bool +is_cpu_sensor(const envsys_data_t *edata) +{ + if (edata->units != ENVSYS_STEMP) + return false; + return strcmp(edata->desc, "external") == 0; +} + +static bool +is_system_sensor(const envsys_data_t *edata) +{ + if (edata->units != ENVSYS_STEMP) + return false; + return strcmp(edata->desc, "internal") == 0; +} + +static void +tda_adjust(void *v) +{ + struct tda_softc *sc = v; + u_int64_t ctemp, stemp; + u_int16_t cspeed, sspeed; + + /* Default to running the fans at maximum speed. */ + sspeed = cspeed = TDA_FANSPEED_MAX; + + /* fetch maximum current temperature */ + ctemp = sysmon_envsys_get_max_value(is_cpu_sensor, true); + stemp = sysmon_envsys_get_max_value(is_system_sensor, true); + + /* the predicates for selecting sensors must have gone wrong */ + if (ctemp == 0 || stemp == 0) { + aprint_error_dev(sc->sc_dev, "skipping temp adjustment" + " - no sensor values\n"); + return; + } + + aprint_debug_dev(sc->sc_dev, "current temperature: cpu %lu system %lu\n", + ctemp, stemp); + + if (ctemp < CPU_TEMP_MIN) + cspeed = TDA_FANSPEED_MIN; + else if (ctemp < CPU_TEMP_MAX) + cspeed = TDA_FANSPEED_MIN + + (ctemp - CPU_TEMP_MIN) * + (TDA_FANSPEED_MAX - TDA_FANSPEED_MIN) / + (CPU_TEMP_MAX - CPU_TEMP_MIN); + + if (stemp < SYS_TEMP_MIN) + sspeed = TDA_FANSPEED_MIN; + else if (stemp < SYS_TEMP_MAX) + sc->sc_sfan_speed = TDA_FANSPEED_MIN + + (stemp - SYS_TEMP_MIN) * + (TDA_FANSPEED_MAX - TDA_FANSPEED_MIN) / + (SYS_TEMP_MAX - SYS_TEMP_MIN); + + if (sspeed == sc->sc_sfan_speed && cspeed == sc->sc_cfan_speed) + return; + + sc->sc_sfan_speed = sspeed; + sc->sc_cfan_speed = cspeed; + tda_setspeed(sc); +}