Angel Pons has submitted this change. ( https://review.coreboot.org/c/coreboot/+/43005 )
Change subject: mb/ocp/deltalake: Send OEM IPMI command for CMOS clear on RTC failure ......................................................................
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 jingle_hsu@wiwynn.com Change-Id: I27428c02e99040754e15e07782ec1ad8524def2f Reviewed-on: https://review.coreboot.org/c/coreboot/+/43005 Reviewed-by: Angel Pons th3fanbus@gmail.com Tested-by: build bot (Jenkins) no-reply@coreboot.org --- M src/mainboard/ocp/deltalake/ipmi.c M src/mainboard/ocp/deltalake/ipmi.h M src/mainboard/ocp/deltalake/romstage.c 3 files changed, 74 insertions(+), 0 deletions(-)
Approvals: build bot (Jenkins): Verified Angel Pons: Looks good to me, approved
diff --git a/src/mainboard/ocp/deltalake/ipmi.c b/src/mainboard/ocp/deltalake/ipmi.c index 9c5a0c0..790038f 100644 --- a/src/mainboard/ocp/deltalake/ipmi.c +++ b/src/mainboard/ocp/deltalake/ipmi.c @@ -129,3 +129,51 @@ 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 bb0b4a6..440a505 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 @@ 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 b366fd9..f69ec60 100644 --- a/src/mainboard/ocp/deltalake/romstage.c +++ b/src/mainboard/ocp/deltalake/romstage.c @@ -126,3 +126,11 @@ 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__); +}