diff options
26 files changed, 306 insertions, 52 deletions
diff --git a/src/mainboard/lenovo/l520/cmos.default b/src/mainboard/lenovo/l520/cmos.default index 979f132863..681c40e78b 100644 --- a/src/mainboard/lenovo/l520/cmos.default +++ b/src/mainboard/lenovo/l520/cmos.default @@ -14,3 +14,4 @@ sticky_fn=Disable trackpoint=Enable backlight=Both usb_always_on=Disable +me_state=Normal diff --git a/src/mainboard/lenovo/l520/cmos.layout b/src/mainboard/lenovo/l520/cmos.layout index e96915d2d1..a3f5308aa4 100644 --- a/src/mainboard/lenovo/l520/cmos.layout +++ b/src/mainboard/lenovo/l520/cmos.layout @@ -34,7 +34,9 @@ entries 421 1 e 9 sata_mode 422 2 e 10 backlight -# coreboot config options: cpu +# coreboot config options: ME +424 1 e 13 me_state +425 2 h 0 me_state_prev # coreboot config options: northbridge 432 3 e 11 gfx_uma_size @@ -89,6 +91,8 @@ enumerations 12 0 Disable 12 1 AC and battery 12 2 AC only +13 0 Normal +13 1 Disabled # ----------------------------------------------------------------- checksums diff --git a/src/mainboard/lenovo/t420/cmos.default b/src/mainboard/lenovo/t420/cmos.default index 467f965829..8244071b8a 100644 --- a/src/mainboard/lenovo/t420/cmos.default +++ b/src/mainboard/lenovo/t420/cmos.default @@ -14,3 +14,4 @@ sticky_fn=Disable trackpoint=Enable hybrid_graphics_mode=Integrated Only usb_always_on=Disable +me_state=Normal diff --git a/src/mainboard/lenovo/t420/cmos.layout b/src/mainboard/lenovo/t420/cmos.layout index e1d15be56b..daf569c0af 100644 --- a/src/mainboard/lenovo/t420/cmos.layout +++ b/src/mainboard/lenovo/t420/cmos.layout @@ -34,7 +34,9 @@ entries 421 1 e 9 sata_mode 422 2 e 13 usb_always_on -# coreboot config options: cpu +# coreboot config options: ME +424 1 e 14 me_state +425 2 h 0 me_state_prev # coreboot config options: northbridge 432 3 e 11 gfx_uma_size @@ -97,6 +99,8 @@ enumerations 13 0 Disable 13 1 AC and battery 13 2 AC only +14 0 Normal +14 1 Disabled # ----------------------------------------------------------------- checksums diff --git a/src/mainboard/lenovo/t420s/cmos.default b/src/mainboard/lenovo/t420s/cmos.default index 467f965829..8244071b8a 100644 --- a/src/mainboard/lenovo/t420s/cmos.default +++ b/src/mainboard/lenovo/t420s/cmos.default @@ -14,3 +14,4 @@ sticky_fn=Disable trackpoint=Enable hybrid_graphics_mode=Integrated Only usb_always_on=Disable +me_state=Normal diff --git a/src/mainboard/lenovo/t420s/cmos.layout b/src/mainboard/lenovo/t420s/cmos.layout index e1d15be56b..daf569c0af 100644 --- a/src/mainboard/lenovo/t420s/cmos.layout +++ b/src/mainboard/lenovo/t420s/cmos.layout @@ -34,7 +34,9 @@ entries 421 1 e 9 sata_mode 422 2 e 13 usb_always_on -# coreboot config options: cpu +# coreboot config options: ME +424 1 e 14 me_state +425 2 h 0 me_state_prev # coreboot config options: northbridge 432 3 e 11 gfx_uma_size @@ -97,6 +99,8 @@ enumerations 13 0 Disable 13 1 AC and battery 13 2 AC only +14 0 Normal +14 1 Disabled # ----------------------------------------------------------------- checksums diff --git a/src/mainboard/lenovo/t430/cmos.default b/src/mainboard/lenovo/t430/cmos.default index e65869b332..26795fe5cf 100644 --- a/src/mainboard/lenovo/t430/cmos.default +++ b/src/mainboard/lenovo/t430/cmos.default @@ -15,3 +15,4 @@ trackpoint=Enable backlight=Both usb_always_on=Disable hybrid_graphics_mode=Integrated Only +me_state=Normal diff --git a/src/mainboard/lenovo/t430/cmos.layout b/src/mainboard/lenovo/t430/cmos.layout index dd51c36854..3e48df5584 100644 --- a/src/mainboard/lenovo/t430/cmos.layout +++ b/src/mainboard/lenovo/t430/cmos.layout @@ -34,7 +34,9 @@ entries 421 1 e 9 sata_mode 422 2 e 10 backlight -# coreboot config options: cpu +# coreboot config options: ME +424 1 e 14 me_state +425 2 h 0 me_state_prev # coreboot config options: northbridge 432 3 e 11 gfx_uma_size @@ -96,6 +98,8 @@ enumerations 13 0 Disable 13 1 AC and battery 13 2 AC only +14 0 Normal +14 1 Disabled # ----------------------------------------------------------------- checksums diff --git a/src/mainboard/lenovo/t430s/cmos.default b/src/mainboard/lenovo/t430s/cmos.default index a30c90dc1f..52dbf70377 100644 --- a/src/mainboard/lenovo/t430s/cmos.default +++ b/src/mainboard/lenovo/t430s/cmos.default @@ -16,3 +16,4 @@ backlight=Both enable_dual_graphics=Disable usb_always_on=Disable f1_to_f12_as_primary=Enable +me_state=Normal diff --git a/src/mainboard/lenovo/t430s/cmos.layout b/src/mainboard/lenovo/t430s/cmos.layout index 02c1ea78df..14a21eb84e 100644 --- a/src/mainboard/lenovo/t430s/cmos.layout +++ b/src/mainboard/lenovo/t430s/cmos.layout @@ -35,7 +35,9 @@ entries 422 2 e 10 backlight 424 1 e 1 f1_to_f12_as_primary -# coreboot config options: cpu +# coreboot config options: ME +425 1 e 13 me_state +426 2 h 0 me_state_prev # coreboot config options: northbridge 432 3 e 11 gfx_uma_size @@ -94,6 +96,8 @@ enumerations 12 0 Disable 12 1 AC and battery 12 2 AC only +13 0 Normal +13 1 Disabled # ----------------------------------------------------------------- checksums diff --git a/src/mainboard/lenovo/t520/cmos.default b/src/mainboard/lenovo/t520/cmos.default index 6e61dae340..cf79b391e2 100644 --- a/src/mainboard/lenovo/t520/cmos.default +++ b/src/mainboard/lenovo/t520/cmos.default @@ -15,3 +15,4 @@ trackpoint=Enable backlight=Both hybrid_graphics_mode=Integrated Only usb_always_on=Disable +me_state=Normal diff --git a/src/mainboard/lenovo/t520/cmos.layout b/src/mainboard/lenovo/t520/cmos.layout index dd51c36854..3e48df5584 100644 --- a/src/mainboard/lenovo/t520/cmos.layout +++ b/src/mainboard/lenovo/t520/cmos.layout @@ -34,7 +34,9 @@ entries 421 1 e 9 sata_mode 422 2 e 10 backlight -# coreboot config options: cpu +# coreboot config options: ME +424 1 e 14 me_state +425 2 h 0 me_state_prev # coreboot config options: northbridge 432 3 e 11 gfx_uma_size @@ -96,6 +98,8 @@ enumerations 13 0 Disable 13 1 AC and battery 13 2 AC only +14 0 Normal +14 1 Disabled # ----------------------------------------------------------------- checksums diff --git a/src/mainboard/lenovo/t530/cmos.default b/src/mainboard/lenovo/t530/cmos.default index 6e61dae340..cf79b391e2 100644 --- a/src/mainboard/lenovo/t530/cmos.default +++ b/src/mainboard/lenovo/t530/cmos.default @@ -15,3 +15,4 @@ trackpoint=Enable backlight=Both hybrid_graphics_mode=Integrated Only usb_always_on=Disable +me_state=Normal diff --git a/src/mainboard/lenovo/t530/cmos.layout b/src/mainboard/lenovo/t530/cmos.layout index 6cd8ac066b..d109a61b4e 100644 --- a/src/mainboard/lenovo/t530/cmos.layout +++ b/src/mainboard/lenovo/t530/cmos.layout @@ -34,7 +34,9 @@ entries 421 1 e 9 sata_mode 422 2 e 10 backlight -# coreboot config options: cpu +# coreboot config options: ME +424 1 e 14 me_state +425 2 h 0 me_state_prev # coreboot config options: northbridge 432 3 e 11 gfx_uma_size @@ -97,6 +99,8 @@ enumerations 13 0 Disable 13 1 AC and battery 13 2 AC only +14 0 Normal +14 1 Disabled # ----------------------------------------------------------------- checksums diff --git a/src/mainboard/lenovo/x220/cmos.default b/src/mainboard/lenovo/x220/cmos.default index 42720a27bd..6d1d57a795 100644 --- a/src/mainboard/lenovo/x220/cmos.default +++ b/src/mainboard/lenovo/x220/cmos.default @@ -13,3 +13,4 @@ usb_always_on=Disable fn_ctrl_swap=Disable sticky_fn=Disable trackpoint=Enable +me_state=Normal diff --git a/src/mainboard/lenovo/x220/cmos.layout b/src/mainboard/lenovo/x220/cmos.layout index f152b2982a..c63ed8c22c 100644 --- a/src/mainboard/lenovo/x220/cmos.layout +++ b/src/mainboard/lenovo/x220/cmos.layout @@ -34,7 +34,9 @@ entries 421 1 e 9 sata_mode 422 2 e 12 usb_always_on -# coreboot config options: cpu +# coreboot config options: ME +424 1 e 13 me_state +425 2 h 0 me_state_prev # coreboot config options: northbridge 432 3 e 11 gfx_uma_size @@ -92,6 +94,8 @@ enumerations 12 0 Disable 12 1 AC and battery 12 2 AC only +13 0 Normal +13 1 Disabled # ----------------------------------------------------------------- checksums diff --git a/src/mainboard/lenovo/x230/cmos.default b/src/mainboard/lenovo/x230/cmos.default index 5c19d0f4a5..7314066c2b 100644 --- a/src/mainboard/lenovo/x230/cmos.default +++ b/src/mainboard/lenovo/x230/cmos.default @@ -15,3 +15,4 @@ trackpoint=Enable backlight=Both usb_always_on=Disable f1_to_f12_as_primary=Enable +me_state=Normal diff --git a/src/mainboard/lenovo/x230/cmos.layout b/src/mainboard/lenovo/x230/cmos.layout index 89891bf0b0..914e8ff5f6 100644 --- a/src/mainboard/lenovo/x230/cmos.layout +++ b/src/mainboard/lenovo/x230/cmos.layout @@ -35,7 +35,9 @@ entries 422 2 e 10 backlight 424 1 e 1 f1_to_f12_as_primary -# coreboot config options: cpu +# coreboot config options: ME +425 1 e 13 me_state +426 2 h 0 me_state_prev # coreboot config options: northbridge 432 3 e 11 gfx_uma_size @@ -94,6 +96,8 @@ enumerations 12 0 Disable 12 1 AC and battery 12 2 AC only +13 0 Normal +13 1 Disabled # ----------------------------------------------------------------- checksums diff --git a/src/southbridge/intel/bd82x6x/Makefile.inc b/src/southbridge/intel/bd82x6x/Makefile.inc index a591aabea0..fdf9b87e64 100644 --- a/src/southbridge/intel/bd82x6x/Makefile.inc +++ b/src/southbridge/intel/bd82x6x/Makefile.inc @@ -31,6 +31,7 @@ smm-y += smihandler.c me.c me_8.x.c pch.c me_common.c romstage-y += me_status.c romstage-y += early_rcba.c romstage-y += early_pch.c +romstage-y += me_common.c ifeq ($(CONFIG_USE_NATIVE_RAMINIT),y) romstage-y += early_thermal.c early_me.c early_usb.c diff --git a/src/southbridge/intel/bd82x6x/early_me.c b/src/southbridge/intel/bd82x6x/early_me.c index 6320d2ea9f..b7a3b44d06 100644 --- a/src/southbridge/intel/bd82x6x/early_me.c +++ b/src/southbridge/intel/bd82x6x/early_me.c @@ -91,22 +91,6 @@ int intel_early_me_uma_size(void) return 0; } -static inline void set_global_reset(int enable) -{ - u32 etr3 = pci_read_config32(PCH_LPC_DEV, ETR3); - - /* Clear CF9 Without Resume Well Reset Enable */ - etr3 &= ~ETR3_CWORWRE; - - /* CF9GR indicates a Global Reset */ - if (enable) - etr3 |= ETR3_CF9GR; - else - etr3 &= ~ETR3_CF9GR; - - pci_write_config32(PCH_LPC_DEV, ETR3, etr3); -} - int intel_early_me_init_done(u8 status) { u8 reset, errorcode, opmode; @@ -163,7 +147,7 @@ int intel_early_me_init_done(u8 status) if ((me_fws2 & 0x80) == 0x80) { printk(BIOS_NOTICE, "CPU was replaced & warm reset required...\n"); pci_and_config16(PCI_DEV(0, 31, 0), 0xa2, ~0x80); - set_global_reset(0); + set_global_reset(false); system_reset(); } @@ -232,17 +216,17 @@ int intel_early_me_init_done(u8 status) return 0; case ME_HFS_ACK_RESET: /* Non-power cycle reset */ - set_global_reset(0); + set_global_reset(false); reset |= 0x06; break; case ME_HFS_ACK_PWR_CYCLE: /* Power cycle reset */ - set_global_reset(0); + set_global_reset(false); reset |= 0x0e; break; case ME_HFS_ACK_GBL_RESET: /* Global reset */ - set_global_reset(1); + set_global_reset(true); reset |= 0x0e; break; case ME_HFS_ACK_S3: diff --git a/src/southbridge/intel/bd82x6x/early_me_mrc.c b/src/southbridge/intel/bd82x6x/early_me_mrc.c index 0b11fd0e81..847c708f42 100644 --- a/src/southbridge/intel/bd82x6x/early_me_mrc.c +++ b/src/southbridge/intel/bd82x6x/early_me_mrc.c @@ -96,22 +96,6 @@ int intel_early_me_uma_size(void) return 0; } -static inline void set_global_reset(int enable) -{ - u32 etr3 = pci_read_config32(PCH_LPC_DEV, ETR3); - - /* Clear CF9 Without Resume Well Reset Enable */ - etr3 &= ~ETR3_CWORWRE; - - /* CF9GR indicates a Global Reset */ - if (enable) - etr3 |= ETR3_CF9GR; - else - etr3 &= ~ETR3_CF9GR; - - pci_write_config32(PCH_LPC_DEV, ETR3, etr3); -} - int intel_early_me_init_done(u8 status) { u8 reset; @@ -160,17 +144,17 @@ int intel_early_me_init_done(u8 status) return 0; case ME_HFS_ACK_RESET: /* Non-power cycle reset */ - set_global_reset(0); + set_global_reset(false); reset = 0x06; break; case ME_HFS_ACK_PWR_CYCLE: /* Power cycle reset */ - set_global_reset(0); + set_global_reset(false); reset = 0x0e; break; case ME_HFS_ACK_GBL_RESET: /* Global reset */ - set_global_reset(1); + set_global_reset(true); reset = 0x0e; break; case ME_HFS_ACK_S3: diff --git a/src/southbridge/intel/bd82x6x/me.c b/src/southbridge/intel/bd82x6x/me.c index fe2a37c849..558ee91e6a 100644 --- a/src/southbridge/intel/bd82x6x/me.c +++ b/src/southbridge/intel/bd82x6x/me.c @@ -9,6 +9,7 @@ */ #include <acpi/acpi.h> +#include <cf9_reset.h> #include <device/mmio.h> #include <device/device.h> #include <device/pci.h> @@ -19,6 +20,8 @@ #include <string.h> #include <delay.h> #include <elog.h> +#include <halt.h> +#include <option.h> #include "me.h" #include "pch.h" @@ -248,13 +251,20 @@ static me_bios_path intel_me_path(struct device *dev) static void intel_me_init(struct device *dev) { me_bios_path path = intel_me_path(dev); + u8 me_state = 0, me_state_prev = 0; + bool need_reset = false; + struct me_hfs hfs; /* Do initial setup and determine the BIOS path */ printk(BIOS_NOTICE, "ME: BIOS path: %s\n", me_get_bios_path_string(path)); + get_option(&me_state, "me_state"); + get_option(&me_state_prev, "me_state_prev"); + + printk(BIOS_DEBUG, "ME: me_state=%u, me_state_prev=%u\n", me_state, me_state_prev); + switch (path) { case ME_S3WAKE_BIOS_PATH: - case ME_DISABLE_BIOS_PATH: #if CONFIG(HIDE_MEI_ON_ERROR) case ME_ERROR_BIOS_PATH: #endif @@ -277,12 +287,49 @@ static void intel_me_init(struct device *dev) mkhi_get_fwcaps(); } + /* Put ME in Software Temporary Disable Mode, if needed */ + if (me_state == CMOS_ME_STATE_DISABLED + && CMOS_ME_STATE(me_state_prev) == CMOS_ME_STATE_NORMAL) { + printk(BIOS_INFO, "ME: disabling ME\n"); + if (enter_soft_temp_disable()) { + enter_soft_temp_disable_wait(); + need_reset = true; + } else { + printk(BIOS_ERR, "ME: failed to enter Soft Temporary Disable mode\n"); + } + + break; + } + /* * Leave the ME unlocked in this path. * It will be locked via SMI command later. */ break; + case ME_DISABLE_BIOS_PATH: + /* Bring ME out of Soft Temporary Disable mode, if needed */ + pci_read_dword_ptr(dev, &hfs, PCI_ME_HFS); + if (hfs.operation_mode == ME_HFS_MODE_DIS + && me_state == CMOS_ME_STATE_NORMAL + && (CMOS_ME_STATE(me_state_prev) == CMOS_ME_STATE_DISABLED + || !CMOS_ME_CHANGED(me_state_prev))) { + printk(BIOS_INFO, "ME: re-enabling ME\n"); + + exit_soft_temp_disable(dev); + exit_soft_temp_disable_wait(dev); + + /* + * ME starts loading firmware immediately after writing to H_GS, + * but Lenovo BIOS performs a reboot after bringing ME back to + * Normal mode. Assume that global reset is needed. + */ + need_reset = true; + } else { + intel_me_hide(dev); + } + break; + #if !CONFIG(HIDE_MEI_ON_ERROR) case ME_ERROR_BIOS_PATH: #endif @@ -290,6 +337,18 @@ static void intel_me_init(struct device *dev) case ME_FIRMWARE_UPDATE_BIOS_PATH: break; } + + /* To avoid boot loops if ME fails to get back from disabled mode, + set the 'changed' bit here. */ + if (me_state != CMOS_ME_STATE(me_state_prev) || need_reset) { + u8 new_state = me_state | CMOS_ME_STATE_CHANGED; + set_option("me_state_prev", &new_state); + } + + if (need_reset) { + set_global_reset(true); + full_reset(); + } } static struct device_operations device_ops = { diff --git a/src/southbridge/intel/bd82x6x/me.h b/src/southbridge/intel/bd82x6x/me.h index 014fc1d9ea..dfe2eb0bbf 100644 --- a/src/southbridge/intel/bd82x6x/me.h +++ b/src/southbridge/intel/bd82x6x/me.h @@ -171,6 +171,22 @@ struct mei_header { #define MKHI_GLOBAL_RESET 0x0b #define MKHI_FWCAPS_GET_RULE 0x02 +#define MKHI_FWCAPS_SET_RULE 0x03 + +#define MKHI_DISABLE_RULE_ID 0x06 + +#define CMOS_ME_STATE(state) ((state) & 0x1) +#define CMOS_ME_CHANGED(state) (((state) & 0x2) >> 1) +#define CMOS_ME_STATE_NORMAL 0 +#define CMOS_ME_STATE_DISABLED 1 +#define CMOS_ME_STATE_CHANGED 2 + +#define ME_ENABLE_TIMEOUT 20000 + +struct me_disable { + u32 rule_id; + u32 data; +} __packed; #define MKHI_MDES_ENABLE 0x09 @@ -228,6 +244,10 @@ void mei_write_dword_ptr(void *ptr, int offset); #ifndef __SIMPLE_DEVICE__ void pci_read_dword_ptr(struct device *dev, void *ptr, int offset); +bool enter_soft_temp_disable(void); +void enter_soft_temp_disable_wait(void); +void exit_soft_temp_disable(struct device *dev); +void exit_soft_temp_disable_wait(struct device *dev); #endif void read_host_csr(struct mei_csr *csr); @@ -247,6 +267,8 @@ int intel_mei_setup(struct device *dev); int intel_me_extend_valid(struct device *dev); void intel_me_hide(struct device *dev); +void set_global_reset(bool enable); + /* Defined in me_status.c for both romstage and ramstage */ void intel_me_status(struct me_hfs *hfs, struct me_gmes *gmes); diff --git a/src/southbridge/intel/bd82x6x/me_8.x.c b/src/southbridge/intel/bd82x6x/me_8.x.c index f5a39ecfa6..3d9ebd6026 100644 --- a/src/southbridge/intel/bd82x6x/me_8.x.c +++ b/src/southbridge/intel/bd82x6x/me_8.x.c @@ -9,6 +9,7 @@ */ #include <acpi/acpi.h> +#include <cf9_reset.h> #include <device/mmio.h> #include <device/device.h> #include <device/pci.h> @@ -19,6 +20,8 @@ #include <string.h> #include <delay.h> #include <elog.h> +#include <halt.h> +#include <option.h> #include "me.h" #include "pch.h" @@ -206,8 +209,7 @@ static me_bios_path intel_me_path(struct device *dev) /* Check if the MBP is ready */ if (!gmes.mbp_rdy) { - printk(BIOS_CRIT, "%s: mbp is not ready!\n", - __func__); + printk(BIOS_CRIT, "%s: mbp is not ready!\n", __func__); path = ME_ERROR_BIOS_PATH; } @@ -236,13 +238,20 @@ static void intel_me_init(struct device *dev) { me_bios_path path = intel_me_path(dev); me_bios_payload mbp_data; + u8 me_state = 0, me_state_prev = 0; + bool need_reset = false; + struct me_hfs hfs; /* Do initial setup and determine the BIOS path */ printk(BIOS_NOTICE, "ME: BIOS path: %s\n", me_get_bios_path_string(path)); + get_option(&me_state, "me_state"); + get_option(&me_state_prev, "me_state_prev"); + + printk(BIOS_DEBUG, "ME: me_state=%u, me_state_prev=%u\n", me_state, me_state_prev); + switch (path) { case ME_S3WAKE_BIOS_PATH: - case ME_DISABLE_BIOS_PATH: #if CONFIG(HIDE_MEI_ON_ERROR) case ME_ERROR_BIOS_PATH: #endif @@ -266,12 +275,49 @@ static void intel_me_init(struct device *dev) me_print_fwcaps(&mbp_data.fw_caps_sku); } + /* Put ME in Software Temporary Disable Mode, if needed */ + if (me_state == CMOS_ME_STATE_DISABLED + && CMOS_ME_STATE(me_state_prev) == CMOS_ME_STATE_NORMAL) { + printk(BIOS_INFO, "ME: disabling ME\n"); + if (enter_soft_temp_disable()) { + enter_soft_temp_disable_wait(); + need_reset = true; + } else { + printk(BIOS_ERR, "ME: failed to enter Soft Temporary Disable mode\n"); + } + + break; + } + /* * Leave the ME unlocked in this path. * It will be locked via SMI command later. */ break; + case ME_DISABLE_BIOS_PATH: + /* Bring ME out of Soft Temporary Disable mode, if needed */ + pci_read_dword_ptr(dev, &hfs, PCI_ME_HFS); + if (hfs.operation_mode == ME_HFS_MODE_DIS + && me_state == CMOS_ME_STATE_NORMAL + && (CMOS_ME_STATE(me_state_prev) == CMOS_ME_STATE_DISABLED + || !CMOS_ME_CHANGED(me_state_prev))) { + printk(BIOS_INFO, "ME: re-enabling ME\n"); + + exit_soft_temp_disable(dev); + exit_soft_temp_disable_wait(dev); + + /* + * ME starts loading firmware immediately after writing to H_GS, + * but Lenovo BIOS performs a reboot after bringing ME back to + * Normal mode. Assume that global reset is needed. + */ + need_reset = true; + } else { + intel_me_hide(dev); + } + break; + #if !CONFIG(HIDE_MEI_ON_ERROR) case ME_ERROR_BIOS_PATH: #endif @@ -279,6 +325,18 @@ static void intel_me_init(struct device *dev) case ME_FIRMWARE_UPDATE_BIOS_PATH: break; } + + /* To avoid boot loops if ME fails to get back from disabled mode, + set the 'changed' bit here. */ + if (me_state != CMOS_ME_STATE(me_state_prev) || need_reset) { + u8 new_state = me_state | CMOS_ME_STATE_CHANGED; + set_option("me_state_prev", &new_state); + } + + if (need_reset) { + set_global_reset(true); + full_reset(); + } } static struct device_operations device_ops = { diff --git a/src/southbridge/intel/bd82x6x/me_common.c b/src/southbridge/intel/bd82x6x/me_common.c index 422c091001..1b25d146be 100644 --- a/src/southbridge/intel/bd82x6x/me_common.c +++ b/src/southbridge/intel/bd82x6x/me_common.c @@ -11,6 +11,7 @@ #include <string.h> #include <delay.h> #include <halt.h> +#include <timer.h> #include "me.h" #include "pch.h" @@ -417,4 +418,103 @@ void intel_me_hide(struct device *dev) pch_enable(dev); } +bool enter_soft_temp_disable(void) +{ + /* The binary sequence for the disable command was found by PT in some vendor BIOS */ + struct me_disable message = { + .rule_id = MKHI_DISABLE_RULE_ID, + .data = 0x01, + }; + struct mkhi_header mkhi = { + .group_id = MKHI_GROUP_ID_FWCAPS, + .command = MKHI_FWCAPS_SET_RULE, + }; + struct mei_header mei = { + .is_complete = 1, + .length = sizeof(mkhi) + sizeof(message), + .host_address = MEI_HOST_ADDRESS, + .client_address = MEI_ADDRESS_MKHI, + }; + u32 resp; + + if (mei_sendrecv(&mei, &mkhi, &message, &resp, sizeof(resp)) < 0 + || resp != MKHI_DISABLE_RULE_ID) { + printk(BIOS_WARNING, "ME: disable command failed\n"); + return false; + } + + return true; +} + +void enter_soft_temp_disable_wait(void) +{ + /* + * TODO: Find smarter way to determine when we're ready to reboot. + * + * There has to be some bit in some register, or something, that indicates that ME has + * finished doing its thing and we're ready to reboot. + * + * It was not found yet, though, and waiting for a response after the disable command is + * not enough. If we reboot too early, ME will not be disabled on next boot. For now, + * let's just wait for 1 second here. + */ + mdelay(1000); +} + +void exit_soft_temp_disable(struct device *dev) +{ + /* To bring ME out of Soft Temporary Disable Mode, host writes 0x20000000 to H_GS */ + pci_write_config32(dev, PCI_ME_H_GS, 0x2 << 28); +} + +void exit_soft_temp_disable_wait(struct device *dev) +{ + struct me_hfs hfs; + struct stopwatch sw; + + stopwatch_init_msecs_expire(&sw, ME_ENABLE_TIMEOUT); + + /** + * Wait for fw_init_complete. Check every 50 ms, give up after 20 sec. + * This is what vendor BIOS does. Usually it takes 1.5 seconds or so. + */ + do { + mdelay(50); + pci_read_dword_ptr(dev, &hfs, PCI_ME_HFS); + if (hfs.fw_init_complete) + break; + } while (!stopwatch_expired(&sw)); + + if (!hfs.fw_init_complete) + printk(BIOS_ERR, "ME: giving up on waiting for fw_init_complete\n"); + else + printk(BIOS_NOTICE, "ME: took %lums to complete initialization\n", + stopwatch_duration_msecs(&sw)); +} + +#endif + +void set_global_reset(bool enable) +{ +#ifdef __SIMPLE_DEVICE__ + u32 etr3 = pci_read_config32(PCH_LPC_DEV, ETR3); +#else + struct device *lpc = pcidev_on_root(0x1f, 0); + u32 etr3 = pci_read_config32(lpc, ETR3); +#endif + + /* Clear CF9 Without Resume Well Reset Enable */ + etr3 &= ~ETR3_CWORWRE; + + /* CF9GR indicates a Global Reset */ + if (enable) + etr3 |= ETR3_CF9GR; + else + etr3 &= ~ETR3_CF9GR; + +#ifdef __SIMPLE_DEVICE__ + pci_write_config32(PCH_LPC_DEV, ETR3, etr3); +#else + pci_write_config32(lpc, ETR3, etr3); #endif +} diff --git a/src/southbridge/intel/ibexpeak/Makefile.inc b/src/southbridge/intel/ibexpeak/Makefile.inc index c745b0a552..da33778454 100644 --- a/src/southbridge/intel/ibexpeak/Makefile.inc +++ b/src/southbridge/intel/ibexpeak/Makefile.inc @@ -30,6 +30,7 @@ smm-y += smihandler.c romstage-y += early_pch.c romstage-y +=../bd82x6x/early_me.c romstage-y +=../bd82x6x/me_status.c +romstage-y +=../bd82x6x/me_common.c romstage-y += early_thermal.c romstage-y += ../bd82x6x/early_rcba.c romstage-y += early_cir.c |