lynxpoint: me: Support ICC clock enables message
This message allows unused clocks to be disabled based on a
devicetree setting in each mainboard.
Change-Id: Ib1988cab3748490cf24028752562c64ccbce2054
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/65250
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/4450
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
diff --git a/src/southbridge/intel/lynxpoint/chip.h b/src/southbridge/intel/lynxpoint/chip.h
index 70f3e63..a0e2232 100644
--- a/src/southbridge/intel/lynxpoint/chip.h
+++ b/src/southbridge/intel/lynxpoint/chip.h
@@ -92,6 +92,13 @@
/* 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 d919107..a72778b 100644
--- a/src/southbridge/intel/lynxpoint/me.h
+++ b/src/southbridge/intel/lynxpoint/me.h
@@ -286,6 +286,24 @@
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 d1a692c..e01316f 100644
--- a/src/southbridge/intel/lynxpoint/me_9.x.c
+++ b/src/southbridge/intel/lynxpoint/me_9.x.c
@@ -412,6 +412,30 @@
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 @@
#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 @@
/* 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 @@
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 @@
}
#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.
*/