| /* |
| * This file is part of the coreboot project. |
| * |
| * Copyright (C) 2007 AMD |
| * Written by Yinghai Lu <yinghailu@amd.com> for AMD. |
| * Copyright (C) 2010 coresystems GmbH |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; version 2 of the License. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include <arch/io.h> |
| #include <console/console.h> |
| #include <device/device.h> |
| #include <device/pnp_def.h> |
| #include <device/smbus.h> |
| #include <stdlib.h> |
| #include <superio/smsc/dme1737/dme1737.h> |
| |
| 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 = { |
| .enable_dev = mainboard_enable, |
| }; |