diff options
Diffstat (limited to 'src/southbridge/intel/bd82x6x/me_common.c')
-rw-r--r-- | src/southbridge/intel/bd82x6x/me_common.c | 100 |
1 files changed, 100 insertions, 0 deletions
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 +} |