diff --git a/src/drivers/ipmi/Kconfig b/src/drivers/ipmi/Kconfig index 1137dcf8d5..012f67887c 100644 --- a/src/drivers/ipmi/Kconfig +++ b/src/drivers/ipmi/Kconfig @@ -42,3 +42,14 @@ config IPMI_KCS_TIMEOUT_MS The time unit is millisecond for each IPMI KCS transfer. IPMI spec v2.0 rev 1.1 Sec. 9.15, a five-second timeout or greater is recommended. + +config DRIVERS_IPMI_SUPERMICRO_OEM + bool "Supermicro IPMI OEM BMC support" + depends on IPMI_KCS + default n + help + Tested on X11SSH only. Different BMCs might not support these OEM + commands. + The following features are implemented: + * Communicates the BIOS version to the BMC + * Communicates the BIOS date to the BMC diff --git a/src/drivers/ipmi/Makefile.inc b/src/drivers/ipmi/Makefile.inc index 06a3433ae0..e4bcf313eb 100644 --- a/src/drivers/ipmi/Makefile.inc +++ b/src/drivers/ipmi/Makefile.inc @@ -2,6 +2,7 @@ ramstage-$(CONFIG_IPMI_KCS) += ipmi_kcs.c ramstage-$(CONFIG_IPMI_KCS) += ipmi_kcs_ops.c ramstage-$(CONFIG_IPMI_KCS) += ipmi_ops.c ramstage-$(CONFIG_IPMI_KCS) += ipmi_fru.c +ramstage-$(CONFIG_DRIVERS_IPMI_SUPERMICRO_OEM) += supermicro_oem.c romstage-$(CONFIG_IPMI_KCS_ROMSTAGE) += ipmi_kcs_ops_premem.c romstage-$(CONFIG_IPMI_KCS_ROMSTAGE) += ipmi_kcs.c romstage-$(CONFIG_IPMI_KCS_ROMSTAGE) += ipmi_ops.c diff --git a/src/drivers/ipmi/ipmi_kcs_ops.c b/src/drivers/ipmi/ipmi_kcs_ops.c index 640bfa1c17..38311ee7eb 100644 --- a/src/drivers/ipmi/ipmi_kcs_ops.c +++ b/src/drivers/ipmi/ipmi_kcs_ops.c @@ -23,6 +23,7 @@ #include #include #include "ipmi_kcs.h" +#include "ipmi_supermicro_oem.h" #include "chip.h" /* 4 bit encoding */ @@ -167,6 +168,12 @@ static void ipmi_kcs_init(struct device *dev) /* Don't write tables if communication failed */ dev->enabled = 0; } + + if (!dev->enabled) + return; + + if (CONFIG(DRIVERS_IPMI_SUPERMICRO_OEM)) + supermicro_ipmi_oem(dev->path.pnp.port); } #if CONFIG(HAVE_ACPI_TABLES) diff --git a/src/drivers/ipmi/ipmi_supermicro_oem.h b/src/drivers/ipmi/ipmi_supermicro_oem.h new file mode 100644 index 0000000000..5babadb13f --- /dev/null +++ b/src/drivers/ipmi/ipmi_supermicro_oem.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __IPMI_SUPERMICRO_OEM_H +#define __IPMI_SUPERMICRO_OEM_H + +#include + +void supermicro_ipmi_oem(const uint16_t kcs_port); + +#endif /* __IPMI_SUPERMICRO_OEM_H */ diff --git a/src/drivers/ipmi/supermicro_oem.c b/src/drivers/ipmi/supermicro_oem.c new file mode 100644 index 0000000000..87b7fe243a --- /dev/null +++ b/src/drivers/ipmi/supermicro_oem.c @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include + +#include +#include +#include +#include +#include "ipmi_supermicro_oem.h" + +#define IPMI_NETFN_OEM 0x30 +#define IPMI_LUN0_AC_SET_BIOS_VER 0x100 +#define IPMI_LUN0_AC_SET_BIOS_DATE 0x101 +#define IPMI_LUN0_SET_BIOS_STRING 0xac + +struct ipmi_oem_set_bios_str { + uint16_t ver; + char str[16]; // NULL terminated string +} __packed; + +static void set_coreboot_ver(const uint16_t kcs_port) +{ + const char *coreboot_ver = COREBOOT_VERSION; + struct ipmi_oem_set_bios_str bios_ver; + struct ipmi_rsp rsp; + int ret; + size_t i; + + /* Only 8 charactars are visible in UI. Cut of on first dash */ + for (i = 0; i < 15; i++) { + if (coreboot_ver[i] == '-') + break; + bios_ver.str[i] = coreboot_ver[i]; + } + bios_ver.str[i] = 0; + bios_ver.ver = IPMI_LUN0_AC_SET_BIOS_VER; + + ret = ipmi_kcs_message(kcs_port, IPMI_NETFN_OEM, 0, IPMI_LUN0_SET_BIOS_STRING, + (const unsigned char *) &bios_ver, sizeof(bios_ver), + (unsigned char *) &rsp, sizeof(rsp)); + if (ret < sizeof(rsp) || rsp.completion_code) { + printk(BIOS_ERR, "BMC_IPMI: %s command failed (ret=%d resp=0x%x)\n", + __func__, ret, rsp.completion_code); + } +} + +static void set_coreboot_date(const uint16_t kcs_port) +{ + struct ipmi_oem_set_bios_str bios_ver; + struct ipmi_rsp rsp; + int ret; + + strncpy(bios_ver.str, COREBOOT_DMI_DATE, 15); + bios_ver.str[15] = 0; + bios_ver.ver = IPMI_LUN0_AC_SET_BIOS_DATE; + + ret = ipmi_kcs_message(kcs_port, IPMI_NETFN_OEM, 0, IPMI_LUN0_SET_BIOS_STRING, + (const unsigned char *) &bios_ver, sizeof(bios_ver), + (unsigned char *) &rsp, sizeof(rsp)); + if (ret < sizeof(rsp) || rsp.completion_code) { + printk(BIOS_ERR, "BMC_IPMI: %s command failed (ret=%d resp=0x%x)\n", + __func__, ret, rsp.completion_code); + } +} + +void supermicro_ipmi_oem(const uint16_t kcs_port) +{ + set_coreboot_ver(kcs_port); + set_coreboot_date(kcs_port); +} diff --git a/src/mainboard/supermicro/x11-lga1151-series/Kconfig b/src/mainboard/supermicro/x11-lga1151-series/Kconfig index 5e9b6457e5..533899dbde 100644 --- a/src/mainboard/supermicro/x11-lga1151-series/Kconfig +++ b/src/mainboard/supermicro/x11-lga1151-series/Kconfig @@ -63,6 +63,10 @@ config FMDFILE string default "src/mainboard/\$(CONFIG_MAINBOARD_DIR)/vboot-ro-rwab.fmd" if VBOOT_SLOTS_RW_AB +config DRIVERS_IPMI_SUPERMICRO_OEM + bool + default y + config CBFS_SIZE hex default 0xb00000