From b65fd3e305eba74d0a7f1b5466b4910710d5e2f3 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Kollasch" Date: Tue, 3 Nov 2015 12:19:35 -0600 Subject: [PATCH] sunw/ultra40m2: initialize hardware monitor and fan control Change-Id: I3fbb897feb68d899e5dec075a09d0dd605eca5ce Signed-off-by: Jonathan A. Kollasch Reviewed-on: http://review.coreboot.org/12309 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi --- src/mainboard/sunw/ultra40m2/devicetree.cb | 12 +- src/mainboard/sunw/ultra40m2/mainboard.c | 151 ++++++++++++++++++++- 2 files changed, 154 insertions(+), 9 deletions(-) diff --git a/src/mainboard/sunw/ultra40m2/devicetree.cb b/src/mainboard/sunw/ultra40m2/devicetree.cb index 9928d456fd..998245950c 100644 --- a/src/mainboard/sunw/ultra40m2/devicetree.cb +++ b/src/mainboard/sunw/ultra40m2/devicetree.cb @@ -75,12 +75,12 @@ chip northbridge/amd/amdk8/root_complex # Root complex #chip drivers/generic/generic # PCA9556 GPIO on HDD backplanes (address conflict!) # device i2c 18 on end #end - #chip drivers/generic/generic # EMC6D103 HWM (for CPUs) - # device i2c 2d on end - #end - #chip drivers/generic/generic # DME1737 HWM - # device i2c 2e on end - #end + chip drivers/generic/generic # EMC6D103 HWM (for CPUs) + device i2c 2d on end + end + chip drivers/generic/generic # DME1737 HWM + device i2c 2e on end + end #chip drivers/generic/generic # HDD 4-7 backplane FRU 24C64 EEPROM # device i2c 51 on end #end diff --git a/src/mainboard/sunw/ultra40m2/mainboard.c b/src/mainboard/sunw/ultra40m2/mainboard.c index 1f269953a1..3e2bbf004a 100644 --- a/src/mainboard/sunw/ultra40m2/mainboard.c +++ b/src/mainboard/sunw/ultra40m2/mainboard.c @@ -15,15 +15,160 @@ * GNU General Public License for more details. */ +#include #include #include -#include -#include -#include +#include +#include +#include +#include +static void emc6d103_init(void) +{ + size_t i; + int reg; + + static const struct { uint8_t idx; uint8_t msk; uint8_t set; } script[] = { + { 0x7f, 0x7f, 0x80 }, // INIT + { 0x4f, 0x00, 0x64 }, // Diode 1 High 100°C + { 0x53, 0x00, 0x64 }, // Diode 2 High 100°C (Sun firmware didn't set this) + { 0x54, 0x00, 0x30 }, // Tach1 Minimum LSB + { 0x55, 0x00, 0x2a }, // Tach1 Minimum MSB + { 0x56, 0x00, 0x30 }, // Tach2 Minimum LSB + { 0x57, 0x00, 0x2a }, // Tach2 Minimum MSB + { 0x5c, 0x00, 0x02 }, // PWM 1 Config + { 0x5d, 0x00, 0x42 }, // PWM 2 Config + { 0x5f, 0x00, 0x8a }, // Zone 1 range, Fan 1 freq + { 0x60, 0x00, 0xca }, // Zone 2 range, Fan 2 freq + { 0x61, 0x00, 0x8a }, // Zone 3 range, Fan 3 freq + { 0x62, 0x00, 0x67 }, // Min/Off, PWM 1 ramp rate + { 0x63, 0x00, 0x70 }, // PWM 2, PWM 3 ramp rate + { 0x64, 0x00, 0x59 }, // PWM1 Minimum Duty Cycle + { 0x65, 0x00, 0x59 }, // PWM2 Minimum Duty Cycle + { 0x67, 0x00, 0x47 }, // Zone 1 Low Temp Limit + { 0x69, 0x00, 0x47 }, // Zone 3 Low Temp Limit + { 0x80, 0x00, 0x07 }, // Interrupt Enable 2 + { 0x40, 0xfe, 0x01 }, // START + }; + + struct device * const dev = dev_find_slot_on_smbus(2, 0x2d); + if (dev == NULL) + printk(BIOS_WARNING, "EMC6D103 not found\n"); + + printk(BIOS_SPEW, "%s EMC6D103 id: %x %x\n", __func__, smbus_read_byte(dev, 0x3e), smbus_read_byte(dev, 0x3f)); + + for (i = 0; i < ARRAY_SIZE(script); i++) { + reg = smbus_read_byte(dev, script[i].idx); + if (reg < 0) + goto fail; + reg &= script[i].msk; + reg |= script[i].set; + reg = smbus_write_byte(dev, script[i].idx, reg & 0xff); + if (reg < 0) + goto fail; + } + + return; + +fail: + printk(BIOS_WARNING, "failed to initialize EMC6D103\n"); +} + +/* set up DME1737 runtime registers for FAN/PWM 5/6 */ +static void dme1737_runtime_init(void) +{ + size_t i; + uint8_t reg; + + static const struct { uint8_t idx; uint8_t msk; uint8_t set; } rttab[] = { + { 0x43, 0xf3, 0x08 }, + { 0x44, 0xf0, 0x08 }, + { 0x45, 0xf3, 0x08 }, + { 0x46, 0xf0, 0x08 }, + }; + + /* find DME1737 runtime device (LDN 10) */ + struct device * const dev = dev_find_slot_pnp(0x2e, DME1737_RT); + if (dev == NULL) + return; + + struct resource * const res = find_resource(dev, PNP_IDX_IO0); + if (res == NULL) + return; + + for (i = 0; i < ARRAY_SIZE(rttab); i++) { + reg = inb(res->base + rttab[i].idx); + reg &= rttab[i].msk; + reg |= rttab[i].set; + outb(reg, res->base + rttab[i].idx); + } +} + +static void dme1737_hwm_init(void) +{ + size_t i; + int reg; + + static const struct { uint8_t idx; uint8_t msk; uint8_t set; } script[] = { + //{ 0x7f, 0x7f, 0x80 }, // INIT + { 0x4f, 0x00, 0x32 }, // High + { 0x54, 0x00, 0x30 }, // Tach0 Minimum LSB + { 0x55, 0x00, 0x2a }, // Tach0 Minimum MSB + { 0x56, 0x00, 0x30 }, // Tach1 Minimum LSB + { 0x57, 0x00, 0x2a }, // Tach1 Minimum MSB + { 0x5a, 0x00, 0x30 }, // Tach3 Minimum LSB + { 0x5b, 0x00, 0x2a }, // Tach3 Minimum MSB + { 0x5d, 0x00, 0x07 }, // PWM 1 Config: Zone 0 + { 0x5f, 0x0f, 0x50 }, // Zone 0 range, PWM freq + { 0x62, 0x00, 0x67 }, // Ramp Rate + { 0x63, 0x00, 0x80 }, // Ramp Rate + { 0x65, 0x00, 0x0d }, // PWM 1 Minimum + { 0x67, 0x00, 0x23 }, // Zone 0 Low + { 0x6a, 0x00, 0x32 }, // Zone 0 High + { 0x6c, 0x00, 0x5a }, // Zone 2 Abs + { 0x80, 0x00, 0x17 }, // Interrupt Enable 2? + { 0xa5, 0x00, 0x40 }, // PMW 4: 25% duty + { 0xa6, 0x00, 0x40 }, // PWM 5: 25% duty + { 0x40, 0xfe, 0x01 }, // START + }; + + struct device * const dev = dev_find_slot_on_smbus(2, 0x2e); + if (dev == NULL) { + printk(BIOS_INFO, "SMBus DME1737 not found\n"); + return; + } + + printk(BIOS_SPEW, "%s DME1737 id: %x %x\n", __func__, smbus_read_byte(dev, 0x3e), smbus_read_byte(dev, 0x3f)); + + for (i = 0; i < ARRAY_SIZE(script); i++) { + reg = smbus_read_byte(dev, script[i].idx); + if (reg < 0) + goto fail; + reg &= script[i].msk; + reg |= script[i].set; + reg = smbus_write_byte(dev, script[i].idx, reg & 0xff); + if (reg < 0) + goto fail; + } + + return; + +fail: + printk(BIOS_WARNING, "failed to initialize EMC6D103\n"); +} + +static void mainboard_init(device_t dev) +{ + emc6d103_init(); + dme1737_runtime_init(); + dme1737_hwm_init(); + + printk(BIOS_DEBUG, "%s done\n", __func__); +} static void mainboard_enable(device_t dev) { + dev->ops->init = mainboard_init; } struct chip_operations mainboard_ops = {