diff --git a/src/southbridge/intel/lynxpoint/chip.h b/src/southbridge/intel/lynxpoint/chip.h index 70f3e63a63..a0e2232788 100644 --- a/src/southbridge/intel/lynxpoint/chip.h +++ b/src/southbridge/intel/lynxpoint/chip.h @@ -92,6 +92,13 @@ struct southbridge_intel_lynxpoint_config { /* I2C voltage select: 0=3.3V 1=1.8V */ uint8_t sio_i2c0_voltage; uint8_t sio_i2c1_voltage; + + /* + * Clock Disable Map: + * [21:16] = CLKOUT_PCIE# 5-0 + * [24] = CLKOUT_ITPXDP + */ + uint32_t icc_clock_disable; }; extern struct chip_operations southbridge_intel_lynxpoint_ops; diff --git a/src/southbridge/intel/lynxpoint/me.h b/src/southbridge/intel/lynxpoint/me.h index d919107609..a72778b88f 100644 --- a/src/southbridge/intel/lynxpoint/me.h +++ b/src/southbridge/intel/lynxpoint/me.h @@ -286,6 +286,24 @@ struct me_fw_version { u16 recovery_hot_fix; } __attribute__ ((packed)); +/* ICC Messages */ +#define ICC_SET_CLOCK_ENABLES 0x3 +#define ICC_API_VERSION_LYNXPOINT 0x00030000 + +struct icc_header { + u32 api_version; + u32 icc_command; + u32 icc_status; + u32 length; + u32 reserved; +} __attribute__ ((packed)); + +struct icc_clock_enables_msg { + u32 clock_enables; + u32 clock_mask; + u32 no_response: 1; + u32 reserved: 31; +} __attribute__ ((packed)); #define HECI_EOP_STATUS_SUCCESS 0x0 #define HECI_EOP_PERFORM_GLOBAL_RESET 0x1 diff --git a/src/southbridge/intel/lynxpoint/me_9.x.c b/src/southbridge/intel/lynxpoint/me_9.x.c index d1a692c287..e01316f28e 100644 --- a/src/southbridge/intel/lynxpoint/me_9.x.c +++ b/src/southbridge/intel/lynxpoint/me_9.x.c @@ -412,6 +412,30 @@ static inline int mei_sendrecv_mkhi(struct mkhi_header *mkhi, return 0; } +static inline int mei_sendrecv_icc(struct icc_header *icc, + void *req_data, int req_bytes, + void *rsp_data, int rsp_bytes) +{ + struct icc_header icc_rsp; + + /* Send header */ + if (mei_send_header(MEI_ADDRESS_ICC, MEI_HOST_ADDRESS, + icc, sizeof(*icc), req_bytes ? 0 : 1) < 0) + return -1; + + /* Send data if available */ + if (req_bytes && mei_send_data(MEI_ADDRESS_ICC, MEI_HOST_ADDRESS, + req_data, req_bytes) < 0) + return -1; + + /* Read header and data, if needed */ + if (rsp_bytes && mei_recv_msg(&icc_rsp, sizeof(icc_rsp), + rsp_data, rsp_bytes) < 0) + return -1; + + return 0; +} + /* * mbp give up routine. This path is taken if hfs.mpb_rdy is 0 or the read * state machine on the BIOS end doesn't match the ME's state machine. @@ -610,6 +634,30 @@ void intel_me_finalize_smm(void) #else /* !__SMM__ */ +static int me_icc_set_clock_enables(u32 mask) +{ + struct icc_clock_enables_msg clk = { + .clock_enables = 0, /* Turn off specified clocks */ + .clock_mask = mask, + .no_response = 1, /* Do not expect response */ + }; + struct icc_header icc = { + .api_version = ICC_API_VERSION_LYNXPOINT, + .icc_command = ICC_SET_CLOCK_ENABLES, + .length = sizeof(clk), + }; + + /* Send request and wait for response */ + if (mei_sendrecv_icc(&icc, &clk, sizeof(clk), NULL, 0) < 0) { + printk(BIOS_ERR, "ME: ICC SET CLOCK ENABLES message failed\n"); + return -1; + } else { + printk(BIOS_INFO, "ME: ICC SET CLOCK ENABLES 0x%08x\n", mask); + } + + return 0; +} + /* Determine the path that we should take based on ME status */ static me_bios_path intel_me_path(device_t dev) { @@ -760,6 +808,7 @@ static int intel_me_extend_valid(device_t dev) /* Check whether ME is present and do basic init */ static void intel_me_init(device_t dev) { + struct southbridge_intel_lynxpoint_config *config = dev->chip_info; me_bios_path path = intel_me_path(dev); me_bios_payload mbp_data; @@ -768,7 +817,6 @@ static void intel_me_init(device_t dev) if (path == ME_NORMAL_BIOS_PATH) { /* Validate the extend register */ - /* FIXME: force recovery mode on failure. */ intel_me_extend_valid(dev); } @@ -800,6 +848,10 @@ static void intel_me_init(device_t dev) } #endif + /* Set clock enables according to devicetree */ + if (config && config->icc_clock_disable) + me_icc_set_clock_enables(config->icc_clock_disable); + /* * Leave the ME unlocked. It will be locked via SMI command later. */