[coreboot] Patch set updated for coreboot: 4533033 SB800: Add IMC ROM and fan control.

Martin Roth (martin@se-eng.com) gerrit at coreboot.org
Tue Dec 11 02:57:24 CET 2012


Martin Roth (martin at se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1977

-gerrit

commit 4533033a0acbfe174f5e7a644ec7a61dd03d6c13
Author: Martin Roth <martin at se-eng.com>
Date:   Wed Dec 5 16:07:11 2012 -0700

    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 <martin at se-eng.com>
---
 src/mainboard/amd/persimmon/devicetree.cb   |  49 +++++
 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 +
 src/vendorcode/amd/cimx/sb800/OEM.h         |  10 +
 10 files changed, 866 insertions(+), 1 deletion(-)

diff --git a/src/mainboard/amd/persimmon/devicetree.cb b/src/mainboard/amd/persimmon/devicetree.cb
index 178fd76..bd40a43 100644
--- a/src/mainboard/amd/persimmon/devicetree.cb
+++ b/src/mainboard/amd/persimmon/devicetree.cb
@@ -91,6 +91,55 @@ chip northbridge/amd/agesa/family14/root_complex
 				device pci 16.2 off end # EHCI USB3
 				register "gpp_configuration" = "0" #4:0:0:0 (really need to disable all 4 somehow)
 				register "boot_switch_sata_ide" = "0"	# 0: boot from SATA. 1: IDE
+
+				#set up SB800 Fan control registers and IMC fan controls
+				register "imc_port_address" = "0x6E"	# 0x2E and 0x6E are common
+				register "fan0_enabled" = "1"
+				register "fan1_enabled" = "1"
+				register "imc_fan_zone0_enabled" = "1"
+				register "imc_fan_zone1_enabled" = "1"
+
+				register "fan0_config_vals" = "{ \
+					FAN_INPUT_INTERNAL_DIODE, FAN_POLARITY_HIGH, \
+					FREQ_25KHZ, 0x08, 0x00, 0x00, 0x00, 0x00,\
+					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }"
+				register "fan1_config_vals" = "{ \
+					FAN_INPUT_INTERNAL_DIODE, FAN_POLARITY_HIGH, \
+					FREQ_25KHZ, 0x10, 0x00, 0x00, 0x00, 0x00, \
+					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }"
+
+				register "imc_zone0_mode1" = " \
+					IMC_MODE1_FAN_ENABLED | IMC_MODE1_FAN_IMC_CONTROLLED | \
+					IMC_MODE1_FAN_STEP_MODE | IMC_MODE1_FANOUT0"
+				register "imc_zone0_mode2" = " IMC_MODE2_TEMPIN_SB_TSI | \
+					IMC_MODE2_FANIN0 | IMC_MODE2_TEMP_AVERAGING_DISABLED"
+				register "imc_zone0_temp_offset" = "0x00"	# No temp offset
+				register "imc_zone0_hysteresis" = "0x05"	# Degrees C Hysteresis
+				register "imc_zone0_smbus_addr" = "0x98"	# Temp Sensor SMBus address
+				register "imc_zone0_smbus_num" = "IMC_TEMP_SENSOR_ON_SMBUS_3"	# SMBUS number
+				register "imc_zone0_pwm_step" = "0x01"		# Fan PWM stepping rate
+				register "imc_zone0_ramping" = "0x00"		# Disable Fan PWM ramping and stepping
+
+				register "imc_zone1_mode1" = " \
+					IMC_MODE1_FAN_ENABLED | IMC_MODE1_FAN_IMC_CONTROLLED | \
+					IMC_MODE1_FAN_STEP_MODE | IMC_MODE1_FANOUT1"
+				register "imc_zone1_mode2" = " IMC_MODE2_TEMPIN_SB_TSI | \
+					IMC_MODE2_FANIN1 | IMC_MODE2_TEMP_AVERAGING_DISABLED"
+				register "imc_zone1_temp_offset" = "0x00"	# No temp offset
+				register "imc_zone1_hysteresis" = "0x05"	# Degrees C Hysteresis
+				register "imc_zone1_smbus_addr" = "0x98"	# Temp Sensor SMBus address
+				register "imc_zone1_smbus_num" = "IMC_TEMP_SENSOR_ON_SMBUS_3"	# SMBUS number
+				register "imc_zone1_pwm_step" = "0x01"		# Fan PWM stepping rate
+				register "imc_zone1_ramping" = "0x00"		# Disable Fan PWM ramping and stepping
+
+				# T56N has a Maximum operating temperature  of 90C
+				# ZONEX_THRESHOLDS - _AC0 - _AC7, _CRT - Temp Threshold in degrees C
+				# ZONEX_FANSPEEDS - Fan speeds as a "percentage"
+				register "imc_zone0_thresholds" = "{ 87, 82, 77, 72, 65, 1, 0, 0, 90 }"
+				register "imc_zone0_fanspeeds"  = "{100,  7,  5,  4,  3, 2, 0, 0 }"
+				register "imc_zone1_thresholds" = "{ 85, 80, 75, 65,  1, 0, 0, 0, 90 }"
+				register "imc_zone1_fanspeeds"  = "{100, 10,  6,  4,  3, 0, 0, 0 }"
+
 			end	#southbridge/amd/cimx/sb800
 #			end #  device pci 18.0
 # These seem unnecessary
diff --git a/src/southbridge/amd/cimx/sb800/Kconfig b/src/southbridge/amd/cimx/sb800/Kconfig
index 4ac2094..2461d97 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 bea9763..064cbc7 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 22d7724..1966eb4 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 <console/console.h>
 #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 71fea67..ebc9918 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 7fc7b88..4742c6f 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 0000000..115da65
--- /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 <southbridge/amd/cimx/cimx_util.h>
+#include <device/device.h>	/* device_t */
+#include <device/pci.h>		/* 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 0000000..a0fc04e
--- /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 6067e39..ef3a34b 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 */
diff --git a/src/vendorcode/amd/cimx/sb800/OEM.h b/src/vendorcode/amd/cimx/sb800/OEM.h
index c2d8670..640f740 100644
--- a/src/vendorcode/amd/cimx/sb800/OEM.h
+++ b/src/vendorcode/amd/cimx/sb800/OEM.h
@@ -293,3 +293,13 @@
 #ifndef Spread_Spectrum_Type
   #define Spread_Spectrum_Type         0x00
 #endif
+
+/**
+ *    Imc Enable OverWrite
+ *    2 - by default strapping
+ *    1 - On
+ *    0 - Off
+ */
+#ifndef IMC_ENABLE_OVER_WRITE
+  #define IMC_ENABLE_OVER_WRITE        0x02
+#endif



More information about the coreboot mailing list