From 1ba62015184c5e8cb750f4f39de9dd382d869cb8 Mon Sep 17 00:00:00 2001 From: Jingle Hsu Date: Thu, 2 Jul 2020 09:35:06 +0800 Subject: mb/ocp/deltalake: Send OEM IPMI command for CMOS clear on RTC failure When RTC failure is detected, send IPMI OEM command to issue CMOS clear. This is to let the payload (LinuxBoot) handle the IPMI OEM CMOS clear command by resetting RTC data, erasing RW_VPD (TODO) and add a SEL, then reboot the system. Tested=on OCP Delta Lake, after removing RTC battery we can see the above flow can be executed correctly. Signed-off-by: Jingle Hsu Change-Id: I27428c02e99040754e15e07782ec1ad8524def2f Reviewed-on: https://review.coreboot.org/c/coreboot/+/43005 Reviewed-by: Angel Pons Tested-by: build bot (Jenkins) --- src/mainboard/ocp/deltalake/ipmi.c | 48 ++++++++++++++++++++++++++++++++++ src/mainboard/ocp/deltalake/ipmi.h | 18 +++++++++++++ src/mainboard/ocp/deltalake/romstage.c | 8 ++++++ 3 files changed, 74 insertions(+) (limited to 'src/mainboard/ocp') diff --git a/src/mainboard/ocp/deltalake/ipmi.c b/src/mainboard/ocp/deltalake/ipmi.c index 9c5a0c0cfe..790038f380 100644 --- a/src/mainboard/ocp/deltalake/ipmi.c +++ b/src/mainboard/ocp/deltalake/ipmi.c @@ -129,3 +129,51 @@ void init_frb2_wdt(void) ipmi_stop_bmc_wdt(CONFIG_BMC_KCS_BASE); } } + +enum cb_err ipmi_set_cmos_clear(void) +{ + int ret; + + struct ipmi_oem_rsp { + struct ipmi_rsp resp; + struct boot_order data; + } __packed; + + struct ipmi_oem_rsp rsp; + struct boot_order req; + + /* IPMI OEM get bios boot order command to check if the valid bit and + the CMOS clear bit are both set from the response BootMode byte. */ + + ret = ipmi_kcs_message(CONFIG_BMC_KCS_BASE, IPMI_NETFN_OEM, 0x0, + IPMI_OEM_GET_BIOS_BOOT_ORDER, + NULL, 0, + (unsigned char *) &rsp, sizeof(rsp)); + + if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) { + printk(BIOS_ERR, "IPMI: %s command failed (read ret=%d resp=0x%x)\n", + __func__, ret, rsp.resp.completion_code); + return CB_ERR; + } + + if (!IS_CMOS_AND_VALID_BIT(rsp.data.boot_mode)) { + req = rsp.data; + SET_CMOS_AND_VALID_BIT(req.boot_mode); + ret = ipmi_kcs_message(CONFIG_BMC_KCS_BASE, IPMI_NETFN_OEM, 0x0, + IPMI_OEM_SET_BIOS_BOOT_ORDER, + (const unsigned char *) &req, sizeof(req), + (unsigned char *) &rsp, sizeof(rsp)); + + if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) { + printk(BIOS_ERR, "IPMI: %s command failed (sent ret=%d resp=0x%x)\n", + __func__, ret, rsp.resp.completion_code); + return CB_ERR; + } + + printk(BIOS_INFO, "IPMI CMOS clear requested because CMOS data is invalid.\n"); + + return CB_SUCCESS; + } + + return CB_SUCCESS; +} diff --git a/src/mainboard/ocp/deltalake/ipmi.h b/src/mainboard/ocp/deltalake/ipmi.h index bb0b4a6e04..440a5056ba 100644 --- a/src/mainboard/ocp/deltalake/ipmi.h +++ b/src/mainboard/ocp/deltalake/ipmi.h @@ -10,6 +10,14 @@ #define IPMI_OEM_GET_PCIE_CONFIG 0xf4 #define IPMI_OEM_GET_BOARD_ID 0x37 #define IPMI_BMC_SET_POST_START 0x73 +#define IPMI_OEM_SET_BIOS_BOOT_ORDER 0x52 +#define IPMI_OEM_GET_BIOS_BOOT_ORDER 0x53 + +#define CMOS_BIT (1 << 1) +#define VALID_BIT (1 << 7) +#define CLEAR_CMOS_AND_VALID_BIT(x) ((x) &= ~(CMOS_BIT | VALID_BIT)) +#define SET_CMOS_AND_VALID_BIT(x) ((x) |= (CMOS_BIT | VALID_BIT)) +#define IS_CMOS_AND_VALID_BIT(x) ((x)&CMOS_BIT && (x)&VALID_BIT) enum config_type { PCIE_CONFIG_UNKNOWN = 0x0, @@ -26,9 +34,19 @@ struct ppin_req { uint32_t cpu1_hi; } __packed; +struct boot_order { + uint8_t boot_mode; + uint8_t boot_dev0; + uint8_t boot_dev1; + uint8_t boot_dev2; + uint8_t boot_dev3; + uint8_t boot_dev4; +} __packed; + enum cb_err ipmi_set_ppin(struct ppin_req *req); enum cb_err ipmi_get_pcie_config(uint8_t *config); enum cb_err ipmi_get_slot_id(uint8_t *slot_id); enum cb_err ipmi_set_post_start(const int port); void init_frb2_wdt(void); +enum cb_err ipmi_set_cmos_clear(void); #endif diff --git a/src/mainboard/ocp/deltalake/romstage.c b/src/mainboard/ocp/deltalake/romstage.c index b366fd9cde..f69ec60c73 100644 --- a/src/mainboard/ocp/deltalake/romstage.c +++ b/src/mainboard/ocp/deltalake/romstage.c @@ -126,3 +126,11 @@ void mainboard_memory_init_params(FSPM_UPD *mupd) mainboard_config_iio(mupd); mainboard_config_upd(mupd); } + +void mainboard_rtc_failed(void) +{ + if (ipmi_set_cmos_clear() == CB_SUCCESS) + printk(BIOS_DEBUG, "%s: IPMI set cmos clear successful\n", __func__); + else + printk(BIOS_ERR, "%s: IPMI set cmos clear failed\n", __func__); +} -- cgit v1.2.3