From e899e518d88f2f48927fba9006d02ea9e1e5a797 Mon Sep 17 00:00:00 2001 From: Martin Roth Date: Wed, 5 Dec 2012 16:07:11 -0700 Subject: SB800: Add IMC ROM and fan control. Add configuration for AMD's IMC ROM and fan registers for cimx/sb800 platforms. - Allows user to add the IMC rom to the build and to configure the location of the "signature" between the allowed positions. - Allows for no fan control, manual setup of SB800 Fan registers, or setup of the IMC fan configuration registers. - Register configuration is done through devicetree.cb. No files need to be added for new platform configuration. - Initial setup is for Persimmon, but may be extended to any cimx/sb800 platform. Change-Id: Ib06408d794988cbb29eed6adbeeadea8b2629bae Signed-off-by: Martin Roth Reviewed-on: http://review.coreboot.org/1977 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi Reviewed-by: Marc Jones --- src/southbridge/amd/cimx/sb800/Kconfig | 95 +++++++++ src/southbridge/amd/cimx/sb800/Makefile.inc | 40 ++++ src/southbridge/amd/cimx/sb800/SBPLATFORM.h | 4 + src/southbridge/amd/cimx/sb800/cfg.c | 1 + src/southbridge/amd/cimx/sb800/chip.h | 198 +++++++++++++++++- src/southbridge/amd/cimx/sb800/fan.c | 311 ++++++++++++++++++++++++++++ src/southbridge/amd/cimx/sb800/fan.h | 152 ++++++++++++++ src/southbridge/amd/cimx/sb800/late.c | 7 + 8 files changed, 807 insertions(+), 1 deletion(-) create mode 100644 src/southbridge/amd/cimx/sb800/fan.c create mode 100644 src/southbridge/amd/cimx/sb800/fan.h (limited to 'src/southbridge/amd/cimx') diff --git a/src/southbridge/amd/cimx/sb800/Kconfig b/src/southbridge/amd/cimx/sb800/Kconfig index 4ac2094d4d..2461d97fa4 100644 --- a/src/southbridge/amd/cimx/sb800/Kconfig +++ b/src/southbridge/amd/cimx/sb800/Kconfig @@ -130,5 +130,100 @@ config S3_VOLATILE_POS For a system with S3 feature, the BIOS needs to save some data to non-volitile storage at cold boot stage. +config SB800_IMC_FWM + bool "Add IMC firmware" + default n + help + Add SB800 / Hudson 1 IMC Firmware to support the onboard fan control. + Please contact AMD to obtain the related firmware. + +if SB800_IMC_FWM + +config SB800_IMC_FWM_FILE + string "IMC firmware path and filename" + default "3rdparty/southbridge/amd/sb800/imc.bin" + +choice + prompt "SB800 Firmware ROM Position" + +config SB800_FWM_AT_FFFA0000 + bool "0xFFFA0000" + help + The IMC and GEC ROMs requires a 'signature' located at one of several + fixed locations in memory. The location used shouldn't matter, just + select an area that doesn't conflict with anything else. + +config SB800_FWM_AT_FFF20000 + bool "0xFFF20000" + help + The IMC and GEC ROMs requires a 'signature' located at one of several + fixed locations in memory. The location used shouldn't matter, just + select an area that doesn't conflict with anything else. + +config SB800_FWM_AT_FFE20000 + depends on BOARD_ROMSIZE_KB_8192 || BOARD_ROMSIZE_KB_4096 || BOARD_ROMSIZE_KB_2048 + bool "0xFFE20000" + help + The IMC and GEC ROMs requires a 'signature' located at one of several + fixed locations in memory. The location used shouldn't matter, just + select an area that doesn't conflict with anything else. + +config SB800_FWM_AT_FFC20000 + depends on BOARD_ROMSIZE_KB_8192 || BOARD_ROMSIZE_KB_4096 + bool "0xFFC20000" + help + The IMC and GEC ROMs requires a 'signature' located at one of several + fixed locations in memory. The location used shouldn't matter, just + select an area that doesn't conflict with anything else. + +config SB800_FWM_AT_FF820000 + depends on BOARD_ROMSIZE_KB_8192 + bool "0xFF820000" + help + The IMC and GEC ROMs requires a 'signature' located at one of several + fixed locations in memory. The location used shouldn't matter, just + select an area that doesn't conflict with anything else. + +endchoice + +config SB800_FWM_POSITION + hex + default 0xFFFA0000 if SB800_FWM_AT_FFFA0000 + default 0xFFF20000 if SB800_FWM_AT_FFF20000 + default 0xFFE20000 if SB800_FWM_AT_FFE20000 + default 0xFFC20000 if SB800_FWM_AT_FFC20000 + default 0xFF820000 if SB800_FWM_AT_FFE20000 + +endif #SB800_IMC_FWM + +choice + prompt "Fan Control" + default SB800_NO_FAN_CONTROL + help + Select the method of SB800 fan control to be used. None would be + for either fixed maximum speed fans connected to the SB800 or for + an external chip controlling the fan speeds. Manual control sets + up the SB800 fan control registers. IMC fan control uses the SB800 + IMC to actively control the fan speeds. + +config SB800_NO_FAN_CONTROL + bool "None" + help + No SB800 Fan control - Do not set up the SB800 fan control registers. + +config SB800_MANUAL_FAN_CONTROL + bool "Manual" + help + Configure the SB800 fan control registers in devicetree.cb. + +config SB800_IMC_FAN_CONTROL + bool "IMC Based" + depends on SB800_IMC_FWM + help + Set up the SB800 to use the IMC based Fan controller. This requires + the IMC rom from AMD. Configure the registers in devicetree.cb. + +endchoice + endif #SOUTHBRIDGE_AMD_CIMX_SB800 diff --git a/src/southbridge/amd/cimx/sb800/Makefile.inc b/src/southbridge/amd/cimx/sb800/Makefile.inc index bea976356a..064cbc7122 100644 --- a/src/southbridge/amd/cimx/sb800/Makefile.inc +++ b/src/southbridge/amd/cimx/sb800/Makefile.inc @@ -27,6 +27,8 @@ romstage-y += smbus.c ramstage-y += cfg.c ramstage-y += late.c +ramstage-$(CONFIG_SB800_MANUAL_FAN_CONTROL) += fan.c +ramstage-$(CONFIG_SB800_IMC_FAN_CONTROL) += fan.c ramstage-$(CONFIG_HAVE_ACPI_RESUME) += spi.c ramstage-$(CONFIG_GENERATE_ACPI_TABLES) += fadt.c @@ -53,3 +55,41 @@ ifeq ($(CONFIG_SB800_SATA_RAID), y) raid/misc.bin-position := $(CONFIG_RAID_MISC_ROM_POSITION) raid/misc.bin-type := raw endif + +ifeq ($(CONFIG_SB800_IMC_FWM), y) + +# ROMSIG At ROMBASE + 0x20000: +# +-----------+---------------+----------------+------------+ +# |0x55AA55AA |EC ROM Address |GEC ROM Address | | +# +-----------+---------------+----------------+------------+ +# EC ROM should be 64K aligned. +SB800_FWM_POSITION=$(shell printf %u $(CONFIG_SB800_FWM_POSITION)) +#assume the cbfs header is less than 128 bytes. +ROMSIG_SIZE=16 + +SB800_IMC_POSITION_UNALIGN=$(shell echo $(SB800_FWM_POSITION) $(ROMSIG_SIZE) 128 65535 | awk '{print $$1 + $$2 + $$3 + $$4}') +SB800_IMC_POSITION=$(shell echo $(SB800_IMC_POSITION_UNALIGN) | awk '{print $$1 - $$1 % 65536}') + +$(obj)/coreboot_SB800_romsig.bin: \ + $(call strip_quotes, $(CONFIG_SB800_IMC_FWM_FILE)) \ + $(obj)/config.h \ + $(obj)/mainboard/$(MAINBOARDDIR)/static.c + echo " SB800 FW $@" + for fwm in 1437226410 \ + $(SB800_IMC_POSITION) \ + 0 \ + 0 ; do \ + echo $$fwm | LC_ALL=C awk '{printf ("%c%c%c%c", $$1 % 256, int($$1/256) % 256, int($$1/65536) % 256, int($$1/16777216));}'; \ + done > $@ + +cbfs-files-y += SB800/fwm +SB800/fwm-file := $(obj)/coreboot_SB800_romsig.bin +SB800/fwm-position := $(SB800_FWM_POSITION) +SB800/fwm-type := raw + +cbfs-files-y += SB800/imc +SB800/imc-file := $(call strip_quotes, $(CONFIG_SB800_IMC_FWM_FILE)) +SB800/imc-position := $(SB800_IMC_POSITION) +SB800/imc-type := raw + +endif diff --git a/src/southbridge/amd/cimx/sb800/SBPLATFORM.h b/src/southbridge/amd/cimx/sb800/SBPLATFORM.h index 22d7724890..1966eb469c 100644 --- a/src/southbridge/amd/cimx/sb800/SBPLATFORM.h +++ b/src/southbridge/amd/cimx/sb800/SBPLATFORM.h @@ -57,6 +57,10 @@ typedef union _PCI_ADDR { #endif #define FIXUP_PTR(ptr) ptr +#if CONFIG_SB800_IMC_FWM + #define IMC_ENABLE_OVER_WRITE 0x01 +#endif + #include #include "AmdSbLib.h" #include "Amd.h" diff --git a/src/southbridge/amd/cimx/sb800/cfg.c b/src/southbridge/amd/cimx/sb800/cfg.c index 71fea672d5..ebc9918890 100644 --- a/src/southbridge/amd/cimx/sb800/cfg.c +++ b/src/southbridge/amd/cimx/sb800/cfg.c @@ -112,6 +112,7 @@ void sb800_cimx_config(AMDSBCFG *sb_config) sb_config->BuildParameters.PCIBSsid = PCIB_SSID; sb_config->BuildParameters.SpreadSpectrumType = Spread_Spectrum_Type; sb_config->BuildParameters.HpetBase = HPET_BASE_ADDRESS; + sb_config->BuildParameters.ImcEnableOverWrite = IMC_ENABLE_OVER_WRITE; /* General */ sb_config->SpreadSpectrum = SPREAD_SPECTRUM; diff --git a/src/southbridge/amd/cimx/sb800/chip.h b/src/southbridge/amd/cimx/sb800/chip.h index 7fc7b88c76..4742c6fa0c 100644 --- a/src/southbridge/amd/cimx/sb800/chip.h +++ b/src/southbridge/amd/cimx/sb800/chip.h @@ -19,6 +19,7 @@ #ifndef _CIMX_SB800_CHIP_H_ #define _CIMX_SB800_CHIP_H_ +#include "fan.h" /* include for #defines used in devicetree.cb */ /* * configuration set in mainboard/devicetree.cb @@ -35,6 +36,201 @@ struct southbridge_amd_cimx_sb800_config { u32 boot_switch_sata_ide : 1; u8 gpp_configuration; -}; + /* + * SB800 IMC and fan control + */ + + u16 imc_port_address; + + u32 fan0_enabled : 1; + u32 fan1_enabled : 1; + u32 fan2_enabled : 1; + u32 fan3_enabled : 1; + u32 fan4_enabled : 1; + u32 imc_fan_zone0_enabled : 1; + u32 imc_fan_zone1_enabled : 1; + u32 imc_fan_zone2_enabled : 1; + u32 imc_fan_zone3_enabled : 1; + u32 imc_tempin0_enabled : 1; + u32 imc_tempin1_enabled : 1; + u32 imc_tempin2_enabled : 1; + u32 imc_tempin3_enabled : 1; + + union { + struct { + u8 fan0_control_reg_value; + u8 fan0_frequency_reg_value; + u8 fan0_low_duty_reg_value; + u8 fan0_med_duty_reg_value; + u8 fan0_multiplier_reg_value; + u8 fan0_low_temp_lo_reg_value; + u8 fan0_low_temp_hi_reg_value; + u8 fan0_med_temp_lo_reg_value; + u8 fan0_med_temp_hi_reg_value; + u8 fan0_high_temp_lo_reg_value; + u8 fan0_high_temp_hi_reg_value; + u8 fan0_linear_range_reg_value; + u8 fan0_linear_hold_reg_value; + }; + u8 fan0_config_vals[FAN_REGISTER_COUNT]; + }; + + union { + struct { + u8 fan1_control_reg_value; + u8 fan1_frequency_reg_value; + u8 fan1_low_duty_reg_value; + u8 fan1_med_duty_reg_value; + u8 fan1_multiplier_reg_value; + u8 fan1_low_temp_lo_reg_value; + u8 fan1_low_temp_hi_reg_value; + u8 fan1_med_temp_lo_reg_value; + u8 fan1_med_temp_hi_reg_value; + u8 fan1_high_temp_lo_reg_value; + u8 fan1_high_temp_hi_reg_value; + u8 fan1_linear_range_reg_value; + u8 fan1_linear_hold_reg_value; + }; + u8 fan1_config_vals[FAN_REGISTER_COUNT]; + }; + + union { + struct { + u8 fan2_control_reg_value; + u8 fan2_frequency_reg_value; + u8 fan2_low_duty_reg_value; + u8 fan2_med_duty_reg_value; + u8 fan2_multiplier_reg_value; + u8 fan2_low_temp_lo_reg_value; + u8 fan2_low_temp_hi_reg_value; + u8 fan2_med_temp_lo_reg_value; + u8 fan2_med_temp_hi_reg_value; + u8 fan2_high_temp_lo_reg_value; + u8 fan2_high_temp_hi_reg_value; + u8 fan2_linear_range_reg_value; + u8 fan2_linear_hold_reg_value; + }; + u8 fan2_config_vals[FAN_REGISTER_COUNT]; + }; + + union { + struct { + u8 fan3_control_reg_value; + u8 fan3_frequency_reg_value; + u8 fan3_low_duty_reg_value; + u8 fan3_med_duty_reg_value; + u8 fan3_multiplier_reg_value; + u8 fan3_low_temp_lo_reg_value; + u8 fan3_low_temp_hi_reg_value; + u8 fan3_med_temp_lo_reg_value; + u8 fan3_med_temp_hi_reg_value; + u8 fan3_high_temp_lo_reg_value; + u8 fan3_high_temp_hi_reg_value; + u8 fan3_linear_range_reg_value; + u8 fan3_linear_hold_reg_value; + }; + u8 fan3_config_vals[FAN_REGISTER_COUNT]; + }; + + union { + struct { + u8 fan4_control_reg_value; + u8 fan4_frequency_reg_value; + u8 fan4_low_duty_reg_value; + u8 fan4_med_duty_reg_value; + u8 fan4_multiplier_reg_value; + u8 fan4_low_temp_lo_reg_value; + u8 fan4_low_temp_hi_reg_value; + u8 fan4_med_temp_lo_reg_value; + u8 fan4_med_temp_hi_reg_value; + u8 fan4_high_temp_lo_reg_value; + u8 fan4_high_temp_hi_reg_value; + u8 fan4_linear_range_reg_value; + u8 fan4_linear_hold_reg_value; + }; + u8 fan4_config_vals[FAN_REGISTER_COUNT]; + }; + + union { + struct { + u8 imc_zone0_mode1; + u8 imc_zone0_mode2; + u8 imc_zone0_temp_offset; + u8 imc_zone0_hysteresis; + u8 imc_zone0_smbus_addr; + u8 imc_zone0_smbus_num; + u8 imc_zone0_pwm_step; + u8 imc_zone0_ramping; + }; + u8 imc_zone0_config_vals[IMC_FAN_CONFIG_COUNT]; + }; + u8 imc_zone0_thresholds[IMC_FAN_THRESHOLD_COUNT]; + u8 imc_zone0_fanspeeds[IMC_FAN_SPEED_COUNT]; + + union { + struct { + u8 imc_zone1_mode1; + u8 imc_zone1_mode2; + u8 imc_zone1_temp_offset; + u8 imc_zone1_hysteresis; + u8 imc_zone1_smbus_addr; + u8 imc_zone1_smbus_num; + u8 imc_zone1_pwm_step; + u8 imc_zone1_ramping; + }; + u8 imc_zone1_config_vals[IMC_FAN_CONFIG_COUNT]; + }; + u8 imc_zone1_thresholds[IMC_FAN_THRESHOLD_COUNT]; + u8 imc_zone1_fanspeeds[IMC_FAN_SPEED_COUNT]; + + union { + struct { + u8 imc_zone2_mode1; + u8 imc_zone2_mode2; + u8 imc_zone2_temp_offset; + u8 imc_zone2_hysteresis; + u8 imc_zone2_smbus_addr; + u8 imc_zone2_smbus_num; + u8 imc_zone2_pwm_step; + u8 imc_zone2_ramping; + }; + u8 imc_zone2_config_vals[IMC_FAN_CONFIG_COUNT]; + }; + u8 imc_zone2_thresholds[IMC_FAN_THRESHOLD_COUNT]; + u8 imc_zone2_fanspeeds[IMC_FAN_SPEED_COUNT]; + + union { + struct { + u8 imc_zone3_mode1; + u8 imc_zone3_mode2; + u8 imc_zone3_temp_offset; + u8 imc_zone3_hysteresis; + u8 imc_zone3_smbus_addr; + u8 imc_zone3_smbus_num; + u8 imc_zone3_pwm_step; + u8 imc_zone3_ramping; + }; + u8 imc_zone3_config_vals[IMC_FAN_CONFIG_COUNT]; + }; + u8 imc_zone3_thresholds[IMC_FAN_THRESHOLD_COUNT]; + u8 imc_zone3_fanspeeds[IMC_FAN_SPEED_COUNT]; + + u32 imc_tempin0_at; + u32 imc_tempin0_ct; + u8 imc_tempin0_tuning_param; + + u32 imc_tempin1_at; + u32 imc_tempin1_ct; + u8 imc_tempin1_tuning_param; + + u32 imc_tempin2_at; + u32 imc_tempin2_ct; + u8 imc_tempin2_tuning_param; + + u32 imc_tempin3_at; + u32 imc_tempin3_ct; + u8 imc_tempin3_tuning_param; + +}; #endif /* _CIMX_SB800_CHIP_H_ */ diff --git a/src/southbridge/amd/cimx/sb800/fan.c b/src/southbridge/amd/cimx/sb800/fan.c new file mode 100644 index 0000000000..115da6541a --- /dev/null +++ b/src/southbridge/amd/cimx/sb800/fan.c @@ -0,0 +1,311 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Sage Electronic Engineering, LLC + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include /* device_t */ +#include /* device_operations */ +#include "SBPLATFORM.h" +#include "sb_cimx.h" +#include "chip.h" /* struct southbridge_amd_cimx_sb800_config */ +#include "fan.h" + +void init_sb800_MANUAL_fans(device_t dev) +{ + int i; + struct southbridge_amd_cimx_sb800_config *sb_chip = + (struct southbridge_amd_cimx_sb800_config *)(dev->chip_info); + + /* Init Fan 0 */ + if (sb_chip->fan0_enabled) + for (i = 0; i < FAN_REGISTER_COUNT; i++) + pm2_iowrite(FAN_0_OFFSET + i, sb_chip->fan0_config_vals[i]); + + /* Init Fan 1 */ + if (sb_chip->fan1_enabled) + for (i = 0; i < FAN_REGISTER_COUNT; i++) + pm2_iowrite(FAN_1_OFFSET + i, sb_chip->fan1_config_vals[i]); + + /* Init Fan 2 */ + if (sb_chip->fan2_enabled) + for (i = 0; i < FAN_REGISTER_COUNT; i++) + pm2_iowrite(FAN_2_OFFSET + i, sb_chip->fan2_config_vals[i]); + + /* Init Fan 3 */ + if (sb_chip->fan3_enabled) + for (i = 0; i < FAN_REGISTER_COUNT; i++) + pm2_iowrite(FAN_3_OFFSET + i, sb_chip->fan3_config_vals[i]); + + /* Init Fan 4 */ + if (sb_chip->fan4_enabled) + for (i = 0; i < FAN_REGISTER_COUNT; i++) + pm2_iowrite(FAN_4_OFFSET + i, sb_chip->fan4_config_vals[i]); + +} + +void init_sb800_IMC_fans(device_t dev) +{ + + AMDSBCFG sb_config; + unsigned char *message_ptr; + int i; + struct southbridge_amd_cimx_sb800_config *sb_chip = + (struct southbridge_amd_cimx_sb800_config *)(dev->chip_info); + + /* + * The default I/O address of the IMC configuration register index + * port is 0x6E. Change the IMC Config port I/O Address if it + * conflicts with other components in the system. + * + * Device 20, Function 3, Reg 0xA4 + * [0]: if 1, the address specified in IMC_PortAddress is used. + * [15:1] IMC_PortAddress bits 15:1 (0x17 - address 0x2E ) + */ + + pci_write_config16(dev, 0xA4, sb_chip->imc_port_address | 0x01); + + + /* + * Do an initial manual setup of the fans for things like polarity + * and frequency. + */ + init_sb800_MANUAL_fans(dev); + + /* + * FLAG for Func 81/83/85/89 support (1=On,0=Off) + * Bit0-3 = Func 81 Zone0-Zone3 + * Bit4-7 = Func 83 Zone0-Zone3 + * Bit8-11 = Func 85 Zone0-Zone3 + * Bit12-15 = Func 89 Tempin Channel0-Channel3 + */ + sb_config.Pecstruct.IMCFUNSupportBitMap = 0; + +/* + ********** Zone 0 ********** + */ +if (sb_chip->imc_fan_zone0_enabled) { + + sb_config.Pecstruct.IMCFUNSupportBitMap |= IMC_ENABLE_ZONE0; + + /* EC LDN9 function 81 zone 0 */ + sb_config.Pecstruct.MSGFun81zone0MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun81zone0MSGREG1 = IMC_ZONE0; + message_ptr = &sb_config.Pecstruct.MSGFun81zone0MSGREG2; + for (i = 0; i < IMC_FAN_CONFIG_COUNT ; i++ ) + *(message_ptr + i) = sb_chip->imc_zone0_config_vals[i]; + + /* EC LDN9 function 83 zone 0 - Temperature Thresholds */ + sb_config.Pecstruct.MSGFun83zone0MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun83zone0MSGREG1 = IMC_ZONE0; + sb_config.Pecstruct.MSGFun83zone0MSGREGB = 0x00; + message_ptr = &sb_config.Pecstruct.MSGFun83zone0MSGREG2; + for (i = 0; i < IMC_FAN_THRESHOLD_COUNT ; i++ ) + *(message_ptr + i) = sb_chip->imc_zone0_thresholds[i]; + + /*EC LDN9 function 85 zone 0 - Fan Speeds */ + sb_config.Pecstruct.MSGFun85zone0MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun85zone0MSGREG1 = IMC_ZONE0; + message_ptr = &sb_config.Pecstruct.MSGFun85zone0MSGREG2; + for (i = 0; i < IMC_FAN_SPEED_COUNT ; i++ ) + *(message_ptr + i) = sb_chip->imc_zone0_fanspeeds[i]; + +} + +/* + ********** Zone 1 ********** + */ +if (sb_chip->imc_fan_zone1_enabled) { + + sb_config.Pecstruct.IMCFUNSupportBitMap |= IMC_ENABLE_ZONE1; + + /* EC LDN9 function 81 zone 1 */ + sb_config.Pecstruct.MSGFun81zone1MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun81zone1MSGREG1 = IMC_ZONE1; + message_ptr = &sb_config.Pecstruct.MSGFun81zone1MSGREG2; + for (i = 0; i < IMC_FAN_CONFIG_COUNT ; i++ ) + *(message_ptr + i) = sb_chip->imc_zone1_config_vals[i]; + + /* EC LDN9 function 83 zone 1 - Temperature Thresholds */ + sb_config.Pecstruct.MSGFun83zone1MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun83zone1MSGREG1 = IMC_ZONE1; + sb_config.Pecstruct.MSGFun83zone1MSGREGB = 0x00; + message_ptr = &sb_config.Pecstruct.MSGFun83zone1MSGREG2; + for (i = 0; i < IMC_FAN_THRESHOLD_COUNT ; i++ ) + *(message_ptr + i) = sb_chip->imc_zone1_thresholds[i]; + + /* EC LDN9 function 85 zone 1 - Fan Speeds */ + sb_config.Pecstruct.MSGFun85zone1MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun85zone1MSGREG1 = IMC_ZONE1; + message_ptr = &sb_config.Pecstruct.MSGFun85zone1MSGREG2; + for (i = 0; i < IMC_FAN_SPEED_COUNT ; i++ ) + *(message_ptr + i) = sb_chip->imc_zone1_fanspeeds[i]; + +} + + +/* + ********** Zone 2 ********** + */ +if (sb_chip->imc_fan_zone2_enabled) { + + sb_config.Pecstruct.IMCFUNSupportBitMap |= IMC_ENABLE_ZONE2; + + /* EC LDN9 function 81 zone 2 */ + sb_config.Pecstruct.MSGFun81zone2MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun81zone2MSGREG1 = IMC_ZONE2; + message_ptr = &sb_config.Pecstruct.MSGFun81zone2MSGREG2; + for (i = 0; i < IMC_FAN_CONFIG_COUNT ; i++ ) + *(message_ptr + i) = sb_chip->imc_zone2_config_vals[i]; + + /* EC LDN9 function 83 zone 2 */ + sb_config.Pecstruct.MSGFun83zone2MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun83zone2MSGREG1 = IMC_ZONE2; + sb_config.Pecstruct.MSGFun83zone2MSGREGB = 0x00; + message_ptr = &sb_config.Pecstruct.MSGFun83zone2MSGREG2; + for (i = 0; i < IMC_FAN_THRESHOLD_COUNT ; i++ ) + *(message_ptr + i) = sb_chip->imc_zone2_thresholds[i]; + + /* EC LDN9 function 85 zone 2 */ + sb_config.Pecstruct.MSGFun85zone2MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun85zone2MSGREG1 = IMC_ZONE2; + message_ptr = &sb_config.Pecstruct.MSGFun85zone2MSGREG2; + for (i = 0; i < IMC_FAN_SPEED_COUNT ; i++ ) + *(message_ptr + i) = sb_chip->imc_zone2_fanspeeds[i]; + +} + +/* + ********** Zone 3 ********** + */ + +if (sb_chip->imc_fan_zone3_enabled) { + + sb_config.Pecstruct.IMCFUNSupportBitMap |= IMC_ENABLE_ZONE3; + + /* EC LDN9 function 81 zone 3 */ + sb_config.Pecstruct.MSGFun81zone3MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun81zone3MSGREG1 = IMC_ZONE3; + message_ptr = &sb_config.Pecstruct.MSGFun81zone3MSGREG2; + for (i = 0; i < IMC_FAN_CONFIG_COUNT ; i++ ) + *(message_ptr + i) = sb_chip->imc_zone3_config_vals[i]; + + /* EC LDN9 function 83 zone 3 */ + sb_config.Pecstruct.MSGFun83zone3MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun83zone3MSGREG1 = IMC_ZONE3; + sb_config.Pecstruct.MSGFun83zone3MSGREGB = 0x00; + message_ptr = &sb_config.Pecstruct.MSGFun83zone3MSGREG2; + for (i = 0; i < IMC_FAN_THRESHOLD_COUNT ; i++ ) + *(message_ptr + i) = sb_chip->imc_zone3_thresholds[i]; + + /* EC LDN9 function 85 zone 3 */ + sb_config.Pecstruct.MSGFun85zone3MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun85zone3MSGREG1 = IMC_ZONE3; + message_ptr = &sb_config.Pecstruct.MSGFun85zone3MSGREG2; + for (i = 0; i < IMC_FAN_SPEED_COUNT ; i++ ) + *(message_ptr + i) = sb_chip->imc_zone3_fanspeeds[i]; + +} + + /* + * EC LDN9 funtion 89 - Set HWM TEMPIN Temperature Calculation Parameters + * This function provides the critical parameters of the HWM TempIn + * sensors, IMC would not perform temperature measurement using those + * sensors until the parameters are provided. + */ + +if (sb_chip->imc_tempin0_enabled) { + + sb_config.Pecstruct.IMCFUNSupportBitMap |= IMC_ENABLE_TEMPIN0; + + /* EC LDN9 funtion 89 TEMPIN channel 0 */ + sb_config.Pecstruct.MSGFun89zone0MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun89zone0MSGREG1 = 0x00; + sb_config.Pecstruct.MSGFun89zone0MSGREG2 = ( sb_chip->imc_tempin0_at & 0xff); + sb_config.Pecstruct.MSGFun89zone0MSGREG3 = ((sb_chip->imc_tempin0_at >> 8) & 0xff); + sb_config.Pecstruct.MSGFun89zone0MSGREG4 = ((sb_chip->imc_tempin0_at >> 16) & 0xff); + sb_config.Pecstruct.MSGFun89zone0MSGREG5 = ((sb_chip->imc_tempin0_at >> 24) & 0xff); + sb_config.Pecstruct.MSGFun89zone0MSGREG6 = ( sb_chip->imc_tempin0_ct & 0xff); + sb_config.Pecstruct.MSGFun89zone0MSGREG7 = ((sb_chip->imc_tempin0_ct >> 8) & 0xff); + sb_config.Pecstruct.MSGFun89zone0MSGREG8 = ((sb_chip->imc_tempin0_ct >> 16) & 0xff); + sb_config.Pecstruct.MSGFun89zone0MSGREG9 = ((sb_chip->imc_tempin0_ct >> 24) & 0xff); + sb_config.Pecstruct.MSGFun89zone0MSGREGA = sb_chip->imc_tempin0_tuning_param; +} + +if (sb_chip->imc_tempin1_enabled) { + + sb_config.Pecstruct.IMCFUNSupportBitMap |= IMC_ENABLE_TEMPIN1; + + /* EC LDN9 funtion 89 TEMPIN channel 1 */ + sb_config.Pecstruct.MSGFun89zone1MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun89zone1MSGREG1 = 0x01; + sb_config.Pecstruct.MSGFun89zone1MSGREG2 = ( sb_chip->imc_tempin1_at & 0xff); + sb_config.Pecstruct.MSGFun89zone1MSGREG3 = ((sb_chip->imc_tempin1_at >> 8) & 0xff); + sb_config.Pecstruct.MSGFun89zone1MSGREG4 = ((sb_chip->imc_tempin1_at >> 16) & 0xff); + sb_config.Pecstruct.MSGFun89zone1MSGREG5 = ((sb_chip->imc_tempin1_at >> 24) & 0xff); + sb_config.Pecstruct.MSGFun89zone1MSGREG6 = ( sb_chip->imc_tempin1_ct & 0xff); + sb_config.Pecstruct.MSGFun89zone1MSGREG7 = ((sb_chip->imc_tempin1_ct >> 8) & 0xff); + sb_config.Pecstruct.MSGFun89zone1MSGREG8 = ((sb_chip->imc_tempin1_ct >> 16) & 0xff); + sb_config.Pecstruct.MSGFun89zone1MSGREG9 = ((sb_chip->imc_tempin1_ct >> 24) & 0xff); + sb_config.Pecstruct.MSGFun89zone1MSGREGA = sb_chip->imc_tempin1_tuning_param; +} + +if (sb_chip->imc_tempin2_enabled) { + + sb_config.Pecstruct.IMCFUNSupportBitMap |= IMC_ENABLE_TEMPIN2; + + /* EC LDN9 funtion 89 TEMPIN channel 2 */ + sb_config.Pecstruct.MSGFun89zone2MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun89zone2MSGREG1 = 0x02; + sb_config.Pecstruct.MSGFun89zone2MSGREG2 = ( sb_chip->imc_tempin2_at & 0xff); + sb_config.Pecstruct.MSGFun89zone2MSGREG3 = ((sb_chip->imc_tempin2_at >> 8) & 0xff); + sb_config.Pecstruct.MSGFun89zone2MSGREG4 = ((sb_chip->imc_tempin2_at >> 16) & 0xff); + sb_config.Pecstruct.MSGFun89zone2MSGREG5 = ((sb_chip->imc_tempin2_at >> 24) & 0xff); + sb_config.Pecstruct.MSGFun89zone2MSGREG6 = ( sb_chip->imc_tempin2_ct & 0xff); + sb_config.Pecstruct.MSGFun89zone2MSGREG7 = ((sb_chip->imc_tempin2_ct >> 8) & 0xff); + sb_config.Pecstruct.MSGFun89zone2MSGREG8 = ((sb_chip->imc_tempin2_ct >> 16) & 0xff); + sb_config.Pecstruct.MSGFun89zone2MSGREG9 = ((sb_chip->imc_tempin2_ct >> 24) & 0xff); + sb_config.Pecstruct.MSGFun89zone2MSGREGA = sb_chip->imc_tempin2_tuning_param; +} + +if (sb_chip->imc_tempin3_enabled) { + + sb_config.Pecstruct.IMCFUNSupportBitMap |= IMC_ENABLE_TEMPIN3; + + /* EC LDN9 funtion 89 TEMPIN channel 3 */ + sb_config.Pecstruct.MSGFun89zone3MSGREG0 = 0x00; + sb_config.Pecstruct.MSGFun89zone3MSGREG1 = 0x03; + sb_config.Pecstruct.MSGFun89zone3MSGREG2 = ( sb_chip->imc_tempin3_at & 0xff); + sb_config.Pecstruct.MSGFun89zone3MSGREG3 = ((sb_chip->imc_tempin3_at >> 8) & 0xff); + sb_config.Pecstruct.MSGFun89zone3MSGREG4 = ((sb_chip->imc_tempin3_at >> 16) & 0xff); + sb_config.Pecstruct.MSGFun89zone3MSGREG5 = ((sb_chip->imc_tempin3_at >> 24) & 0xff); + sb_config.Pecstruct.MSGFun89zone3MSGREG6 = ( sb_chip->imc_tempin3_ct & 0xff); + sb_config.Pecstruct.MSGFun89zone3MSGREG7 = ((sb_chip->imc_tempin3_ct >> 8) & 0xff); + sb_config.Pecstruct.MSGFun89zone3MSGREG8 = ((sb_chip->imc_tempin3_ct >> 16) & 0xff); + sb_config.Pecstruct.MSGFun89zone3MSGREG9 = ((sb_chip->imc_tempin3_ct >> 24) & 0xff); + sb_config.Pecstruct.MSGFun89zone3MSGREGA = sb_chip->imc_tempin3_tuning_param; +} + + /* Set up the sb_config structure for the fan control initialization */ + sb_config.StdHeader.Func = SB_EC_FANCONTROL; + + AmdSbDispatcher(&sb_config); + + return; +} + + diff --git a/src/southbridge/amd/cimx/sb800/fan.h b/src/southbridge/amd/cimx/sb800/fan.h new file mode 100644 index 0000000000..a0fc04ee25 --- /dev/null +++ b/src/southbridge/amd/cimx/sb800/fan.h @@ -0,0 +1,152 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Sage Electronic Engineering, LLC + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SB800_FAN_H_ +#define _SB800_FAN_H_ + +#ifndef __PRE_RAM__ +void init_sb800_IMC_fans(device_t dev); +void init_sb800_MANUAL_fans(device_t dev); +#endif + +/* Fan Register Definitions */ +#define FAN_0_OFFSET 0x00 +#define FAN_1_OFFSET 0x10 +#define FAN_2_OFFSET 0x20 +#define FAN_3_OFFSET 0x30 +#define FAN_4_OFFSET 0x40 + +#define FAN_INPUT_CONTROL_REG 0x00 +#define FAN_CONTROL_REG 0x01 +#define FAN_FREQUENCY_REG 0x02 +#define FAN_LOW_DUTY_REG 0x03 +#define FAN_MED_DUTY_REG 0x04 +#define FAN_MULTIPLIER_REG 0x05 +#define FAN_LOW_TEMP_LO_REG 0x06 +#define FAN_LOW_TEMP_HI_REG 0x07 +#define FAN_MED_TEMP_LO_REG 0x08 +#define FAN_MED_TEMP_HI_REG 0x09 +#define FAN_HIGH_TEMP_LO_REG 0x0A +#define FAN_HIGH_TEMP_HI_REG 0x0B +#define FAN_LINEAR_RANGE_REG 0x0C +#define FAN_LINEAR_HOLD_REG 0x0D + +/* FanXInputControl Definitions */ +#define FAN_INPUT_INTERNAL_DIODE 0 +#define FAN_INPUT_TEMP0 1 +#define FAN_INPUT_TEMP1 2 +#define FAN_INPUT_TEMP2 3 +#define FAN_INPUT_TEMP3 4 +#define FAN_INPUT_TEMP0_FILTER 5 +#define FAN_INPUT_ZERO 6 +#define FAN_INPUT_DISABLED 7 + +/* FanXControl Definitions */ +#define FAN_AUTOMODE (1 << 0) +#define FAN_LINEARMODE (1 << 1) +#define FAN_STEPMODE 0 /* ~(1 << 1) */ +#define FAN_POLARITY_HIGH (1 << 2) +#define FAN_POLARITY_LOW 0 /*~(1 << 2) */ + +/* FanXLowDuty Definitions */ +#define FAN_POLARITY_HIGH_MAX_SPEED 0xff +#define FAN_POLARITY_LOW_MAX_SPEED 0x00 + +/* FanXFreq Definitions */ +/* Typically, fans run at 25KHz */ +#define FREQ_28KHZ 0x0 +#define FREQ_25KHZ 0x1 +#define FREQ_23KHZ 0x2 +#define FREQ_21KHZ 0x3 +#define FREQ_29KHZ 0x4 +#define FREQ_18KHZ 0x5 +/* Any value > 05h and < F7: Freq = 1/(FreqDiv * 2048 * 15ns) */ +#define FREQ_100HZ 0xF7 +#define FREQ_87HZ 0xF8 +#define FREQ_58HZ 0xF9 +#define FREQ_44HZ 0xFA +#define FREQ_35HZ 0xFB +#define FREQ_29HZ 0xFC +#define FREQ_22HZ 0xFD +#define FREQ_14HZ 0xFE +#define FREQ_11HZ 0xFF + + +/* IMC Fan Control Definitions */ +#define IMC_MODE1_FAN_ENABLED ( 1 << 0 ) +#define IMC_MODE1_FAN_IMC_CONTROLLED ( 1 << 2 ) +#define IMC_MODE1_FAN_LINEAR_MODE ( 1 << 4 ) +#define IMC_MODE1_FAN_STEP_MODE 0 /* ~( 1 << 4 ) */ +#define IMC_MODE1_NO_FANOUT 0 /* ~( 7 << 5 ) */ +#define IMC_MODE1_FANOUT0 ( 1 << 5 ) +#define IMC_MODE1_FANOUT1 ( 2 << 5 ) +#define IMC_MODE1_FANOUT2 ( 3 << 5 ) +#define IMC_MODE1_FANOUT3 ( 4 << 5 ) +#define IMC_MODE1_FANOUT4 ( 5 << 5 ) + +#define IMC_MODE2_TEMPIN_NONE 0 /* ~( 7 << 0) */ +#define IMC_MODE2_TEMPIN_0 1 +#define IMC_MODE2_TEMPIN_1 2 +#define IMC_MODE2_TEMPIN_2 3 +#define IMC_MODE2_TEMPIN_3 4 +#define IMC_MODE2_INT_TEMPIN 5 +#define IMC_MODE2_TEMPIN_SB_TSI 6 +#define IMC_MODE2_TEMPIN_OTHER 7 +#define IMC_MODE2_FANIN_NONE 0 /* ~ (7 << 3) */ +#define IMC_MODE2_FANIN0 ( 1 << 3 ) +#define IMC_MODE2_FANIN1 ( 2 << 3 ) +#define IMC_MODE2_FANIN2 ( 3 << 3 ) +#define IMC_MODE2_FANIN3 ( 4 << 3 ) +#define IMC_MODE2_FANIN4 ( 5 << 3 ) +#define IMC_MODE2_TEMP_AVERAGING_ENABLED ( 1 << 6 ) +#define IMC_MODE2_TEMP_AVERAGING_DISABLED 0 /* ~( 1 << 6 ) */ + +#define IMC_TEMP_SENSOR_ON_SMBUS_0 0 +#define IMC_TEMP_SENSOR_ON_SMBUS_2 1 +#define IMC_TEMP_SENSOR_ON_SMBUS_3 2 +#define IMC_TEMP_SENSOR_ON_SMBUS_4 3 + +#define IMC_ZONE0 0 +#define IMC_ZONE1 1 +#define IMC_ZONE2 2 +#define IMC_ZONE3 3 +#define IMC_ZONE4 4 + +#define IMC_TEMPIN_TUNING_DEFAULT_MODE 0 +#define IMC_TEMPIN_TUNING_HIGH_CURRENT_RATIO 1 +#define IMC_TEMPIN_TUNING_HIGH_CURRENT 2 +#define IMC_TEMPIN_TUNING_DISABLE_FILTERING ( 1 << 2 ) + +/* IMCFUNSupportBitMap - Zone enable values */ +#define IMC_ENABLE_ZONE0 0x111 +#define IMC_ENABLE_ZONE1 0x222 +#define IMC_ENABLE_ZONE2 0x333 +#define IMC_ENABLE_ZONE3 0x444 +#define IMC_ENABLE_TEMPIN0 ( 1 << 12 ) +#define IMC_ENABLE_TEMPIN1 ( 1 << 13 ) +#define IMC_ENABLE_TEMPIN2 ( 1 << 14 ) +#define IMC_ENABLE_TEMPIN3 ( 1 << 15 ) + +/* Array size settings */ +#define IMC_FAN_THRESHOLD_COUNT 9 +#define IMC_FAN_SPEED_COUNT 8 +#define IMC_FAN_CONFIG_COUNT 8 +#define FAN_REGISTER_COUNT 15 + +#endif diff --git a/src/southbridge/amd/cimx/sb800/late.c b/src/southbridge/amd/cimx/sb800/late.c index 6067e39471..ef3a34b796 100644 --- a/src/southbridge/amd/cimx/sb800/late.c +++ b/src/southbridge/amd/cimx/sb800/late.c @@ -32,6 +32,7 @@ #include "chip.h" /* struct southbridge_amd_cimx_sb800_config */ #include "sb_cimx.h" /* AMD CIMX wrapper entries */ #include "smbus.h" +#include "fan.h" /*implement in mainboard.c*/ void set_pcie_reset(void); @@ -418,6 +419,12 @@ static void sb800_enable(device_t dev) case (0x14 << 3) | 3: /* 0:14:3 LPC */ + /* Initialize the fans */ +#if CONFIG_SB800_IMC_FAN_CONTROL + init_sb800_IMC_fans(dev); +#elif CONFIG_SB800_MANUAL_FAN_CONTROL + init_sb800_MANUAL_fans(dev); +#endif break; case (0x14 << 3) | 4: /* 0:14:4 PCI */ -- cgit v1.2.3