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>
This commit is contained in:
Duncan Laurie 2013-08-08 15:31:51 -07:00 committed by Patrick Georgi
parent 2017b4a44f
commit 0dc0d1383d
3 changed files with 78 additions and 1 deletions

View File

@ -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;

View File

@ -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

View File

@ -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.
*/