drivers/ipmi: prepare for adding more interfaces

De-duplicate common initialization code (self-test and device
identification) and put it in a new ipmi_if.c unit, which is
supposed to work with any underlying IPMI interface.

Change-Id: Ia99da6fb63adb7bf556d3d6f7964b34831be8a2f
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/67056
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Krystian Hebel <krystian.hebel@3mdeb.com>
diff --git a/src/drivers/ipmi/Makefile.inc b/src/drivers/ipmi/Makefile.inc
index e4bcf31..85f3dde 100644
--- a/src/drivers/ipmi/Makefile.inc
+++ b/src/drivers/ipmi/Makefile.inc
@@ -1,8 +1,10 @@
+ramstage-$(CONFIG_IPMI_KCS) += ipmi_if.c
 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_if.c
+romstage-$(CONFIG_IPMI_KCS_ROMSTAGE) += ipmi_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/chip.h b/src/drivers/ipmi/chip.h
index 4e9d9e1..3b970c9 100644
--- a/src/drivers/ipmi/chip.h
+++ b/src/drivers/ipmi/chip.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 struct drivers_ipmi_config {
+#if CONFIG(IPMI_KCS)
 	u8 bmc_i2c_address;
 	u8 have_nv_storage;
 	u8 nv_storage_device_address;
@@ -25,6 +26,9 @@
 	/* "POST complete" GPIO and polarity */
 	u32 post_complete_gpio;
 	bool post_complete_invert;
+	unsigned int uid; /* Auto-filled by ipmi_ssdt() */
+#endif
+
 	/*
 	 * Wait for BMC to boot.
 	 * This can be used if the BMC takes a long time to boot after PoR:
@@ -36,7 +40,6 @@
 	 * Will be used if wait_for_bmc is true.
 	 */
 	u16 bmc_boot_timeout;
-	unsigned int uid; /* Auto-filled by ipmi_ssdt() */
 };
 
 #endif /* _IMPI_CHIP_H_ */
diff --git a/src/drivers/ipmi/ipmi_fru.c b/src/drivers/ipmi/ipmi_fru.c
index 822e5bf..f165307 100644
--- a/src/drivers/ipmi/ipmi_fru.c
+++ b/src/drivers/ipmi/ipmi_fru.c
@@ -5,6 +5,7 @@
 #include <delay.h>
 #include <stdlib.h>
 
+#include "ipmi_if.h"
 #include "ipmi_ops.h"
 
 #define MAX_FRU_BUSY_RETRY 5
@@ -34,7 +35,7 @@
 			req->count = CONFIG_IPMI_FRU_SINGLE_RW_SZ;
 
 		while (retry_count <= MAX_FRU_BUSY_RETRY) {
-			ret = ipmi_kcs_message(port, IPMI_NETFN_STORAGE, 0x0,
+			ret = ipmi_message(port, IPMI_NETFN_STORAGE, 0x0,
 					IPMI_READ_FRU_DATA, (const unsigned char *) req,
 					sizeof(*req), (unsigned char *) &rsp, sizeof(rsp));
 			if (rsp.resp.completion_code == 0x81) {
diff --git a/src/drivers/ipmi/ipmi_if.c b/src/drivers/ipmi/ipmi_if.c
new file mode 100644
index 0000000..4ff9004
--- /dev/null
+++ b/src/drivers/ipmi/ipmi_if.c
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include "ipmi_if.h"
+
+#include <console/console.h>
+#include <delay.h>
+
+#include "chip.h"
+
+int ipmi_get_device_id(const struct device *dev, struct ipmi_devid_rsp *rsp)
+{
+	int ret;
+
+	ret = ipmi_message(dev->path.pnp.port, IPMI_NETFN_APPLICATION, 0,
+			   IPMI_BMC_GET_DEVICE_ID, NULL, 0, (u8 *)rsp,
+			   sizeof(*rsp));
+	if (ret < sizeof(struct ipmi_rsp) || rsp->resp.completion_code) {
+		printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
+		       __func__, ret, rsp->resp.completion_code);
+		return 1;
+	}
+	if (ret != sizeof(*rsp)) {
+		printk(BIOS_ERR, "IPMI: %s response truncated\n", __func__);
+		return 1;
+	}
+	return 0;
+}
+
+static int ipmi_get_bmc_self_test_result(const struct device *dev,
+					 struct ipmi_selftest_rsp *rsp)
+{
+	int ret;
+
+	ret = ipmi_message(dev->path.pnp.port, IPMI_NETFN_APPLICATION, 0,
+			   IPMI_BMC_GET_SELFTEST_RESULTS, NULL, 0, (u8 *)rsp,
+			   sizeof(*rsp));
+
+	if (ret < sizeof(struct ipmi_rsp) || rsp->resp.completion_code) {
+		printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
+		       __func__, ret, rsp->resp.completion_code);
+		return 1;
+	}
+	if (ret != sizeof(*rsp)) {
+		printk(BIOS_ERR, "IPMI: %s response truncated\n", __func__);
+		return 1;
+	}
+
+	return 0;
+}
+
+int ipmi_process_self_test_result(const struct device *dev)
+{
+	int failure = 0;
+	uint8_t retry_count = 0;
+	struct ipmi_selftest_rsp selftestrsp = {0};
+
+	const struct drivers_ipmi_config *conf = dev->chip_info;
+	uint8_t retry_limit = 0;
+
+	if (conf && conf->wait_for_bmc)
+		retry_limit = conf->bmc_boot_timeout;
+
+	if (retry_limit == 0)
+		/* Try to get self-test results at least once */
+		retry_limit = 1;
+
+	printk(BIOS_INFO, "Get BMC self test result...");
+	for (retry_count = 0; retry_count < retry_limit; retry_count++) {
+		if (!ipmi_get_bmc_self_test_result(dev, &selftestrsp))
+			break;
+
+		mdelay(1000);
+	}
+
+	switch (selftestrsp.result) {
+	case IPMI_APP_SELFTEST_NO_ERROR: /* 0x55 */
+		printk(BIOS_DEBUG, "No Error\n");
+		break;
+	case IPMI_APP_SELFTEST_NOT_IMPLEMENTED: /* 0x56 */
+		printk(BIOS_DEBUG, "Function Not Implemented\n");
+		break;
+	case IPMI_APP_SELFTEST_ERROR: /* 0x57 */
+		printk(BIOS_ERR, "BMC: Corrupted or inaccessible data or device\n");
+		failure = 1;
+		break;
+	case IPMI_APP_SELFTEST_FATAL_HW_ERROR: /* 0x58 */
+		printk(BIOS_ERR, "BMC: Fatal Hardware Error\n");
+		failure = 1;
+		break;
+	case IPMI_APP_SELFTEST_RESERVED: /* 0xFF */
+		printk(BIOS_DEBUG, "Reserved\n");
+		break;
+
+	default: /* Other Device Specific Hardware Error */
+		printk(BIOS_ERR, "BMC: Device Specific Error: 0x%02x\n", selftestrsp.result);
+		failure = 1;
+		break;
+	}
+
+	return failure;
+}
diff --git a/src/drivers/ipmi/ipmi_kcs.h b/src/drivers/ipmi/ipmi_if.h
similarity index 68%
rename from src/drivers/ipmi/ipmi_kcs.h
rename to src/drivers/ipmi/ipmi_if.h
index 33ddd5f..984b469 100644
--- a/src/drivers/ipmi/ipmi_kcs.h
+++ b/src/drivers/ipmi/ipmi_if.h
@@ -1,7 +1,11 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 
-#ifndef __IPMI_KCS_H
-#define __IPMI_KCS_H
+#ifndef __IPMI_IF_H
+#define __IPMI_IF_H
+
+/* Common API and code for different IPMI interfaces in different stages */
+
+#include <stdint.h>
 
 #define IPMI_NETFN_CHASSIS 0x00
 #define IPMI_NETFN_BRIDGE 0x02
@@ -25,16 +29,6 @@
 
 #define IPMI_CMD_ACPI_POWERON 0x06
 
-extern int ipmi_kcs_message(int port, int netfn, int lun, int cmd,
-			    const unsigned char *inmsg, int inlen,
-			    unsigned char *outmsg, int outlen);
-
-/* Run basic IPMI init functions in romstage from the provided PnP device,
- * returns CB_SUCCESS on success and CB_ERR if an error occurred. */
-enum cb_err ipmi_kcs_premem_init(const u16 port, const u16 device);
-
-void ipmi_bmc_version(uint8_t *ipmi_bmc_major_revision, uint8_t *ipmi_bmc_minor_revision);
-
 struct ipmi_rsp {
 	uint8_t lun;
 	uint8_t cmd;
@@ -61,4 +55,25 @@
 	uint8_t param;
 } __packed;
 
-#endif
+struct device;
+
+/*
+ * Sends a command and reads its response. Input buffer is for payload, but
+ * output includes `struct ipmi_rsp` as a header. Returns number of bytes copied
+ * into the buffer or -1.
+ */
+int ipmi_message(int port, int netfn, int lun, int cmd,
+		 const unsigned char *inmsg, int inlen,
+		 unsigned char *outmsg, int outlen);
+
+/* Run basic IPMI init functions in romstage from the provided PnP device,
+ * returns CB_SUCCESS on success and CB_ERR if an error occurred. */
+enum cb_err ipmi_premem_init(const uint16_t port, const uint16_t device);
+
+int ipmi_get_device_id(const struct device *dev, struct ipmi_devid_rsp *rsp);
+
+int ipmi_process_self_test_result(const struct device *dev);
+
+void ipmi_bmc_version(uint8_t *ipmi_bmc_major_revision, uint8_t *ipmi_bmc_minor_revision);
+
+#endif /* __IPMI_IF_H */
diff --git a/src/drivers/ipmi/ipmi_kcs.c b/src/drivers/ipmi/ipmi_kcs.c
index 12cbe82f1..6678272 100644
--- a/src/drivers/ipmi/ipmi_kcs.c
+++ b/src/drivers/ipmi/ipmi_kcs.c
@@ -4,7 +4,7 @@
 #include <device/device.h>
 #include <arch/io.h>
 #include <timer.h>
-#include "ipmi_kcs.h"
+#include "ipmi_if.h"
 
 #define IPMI_KCS_STATE(_x)	((_x) >> 6)
 
@@ -219,9 +219,9 @@
 	return ret;
 }
 
-int ipmi_kcs_message(int port, int netfn, int lun, int cmd,
-			const unsigned char *inmsg, int inlen,
-			unsigned char *outmsg, int outlen)
+int ipmi_message(int port, int netfn, int lun, int cmd,
+		 const unsigned char *inmsg, int inlen,
+		 unsigned char *outmsg, int outlen)
 {
 	if (ipmi_kcs_send_message(port, netfn, lun, cmd, inmsg, inlen)) {
 		printk(BIOS_ERR, "ipmi_kcs_send_message failed\n");
diff --git a/src/drivers/ipmi/ipmi_kcs_ops.c b/src/drivers/ipmi/ipmi_kcs_ops.c
index 4ffa91f..a2ad7ab 100644
--- a/src/drivers/ipmi/ipmi_kcs_ops.c
+++ b/src/drivers/ipmi/ipmi_kcs_ops.c
@@ -24,7 +24,7 @@
 #include <version.h>
 #include <delay.h>
 #include <timer.h>
-#include "ipmi_kcs.h"
+#include "ipmi_if.h"
 #include "ipmi_supermicro_oem.h"
 #include "chip.h"
 
@@ -37,46 +37,6 @@
 
 static struct boot_state_callback bscb_post_complete;
 
-static int ipmi_get_device_id(struct device *dev, struct ipmi_devid_rsp *rsp)
-{
-	int ret;
-
-	ret = ipmi_kcs_message(dev->path.pnp.port, IPMI_NETFN_APPLICATION, 0,
-			     IPMI_BMC_GET_DEVICE_ID, NULL, 0, (u8 *)rsp,
-			     sizeof(*rsp));
-	if (ret < sizeof(struct ipmi_rsp) || rsp->resp.completion_code) {
-		printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
-		       __func__, ret, rsp->resp.completion_code);
-		return 1;
-	}
-	if (ret != sizeof(*rsp)) {
-		printk(BIOS_ERR, "IPMI: %s response truncated\n", __func__);
-		return 1;
-	}
-	return 0;
-}
-
-static int ipmi_get_bmc_self_test_result(struct device *dev, struct ipmi_selftest_rsp *rsp)
-{
-	int ret;
-
-	ret = ipmi_kcs_message(dev->path.pnp.port, IPMI_NETFN_APPLICATION, 0,
-				 IPMI_BMC_GET_SELFTEST_RESULTS, NULL, 0, (u8 *)rsp,
-				 sizeof(*rsp));
-
-	if (ret < sizeof(struct ipmi_rsp) || rsp->resp.completion_code) {
-		printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
-		       __func__, ret, rsp->resp.completion_code);
-		return 1;
-	}
-	if (ret != sizeof(*rsp)) {
-		printk(BIOS_ERR, "IPMI: %s response truncated\n", __func__);
-		return 1;
-	}
-
-	return 0;
-}
-
 static void bmc_set_post_complete_gpio_callback(void *arg)
 {
 	struct drivers_ipmi_config *conf = arg;
@@ -103,8 +63,6 @@
 	uint32_t man_id = 0, prod_id = 0;
 	struct drivers_ipmi_config *conf = dev->chip_info;
 	const struct gpio_operations *gpio_ops;
-	struct ipmi_selftest_rsp selftestrsp = {0};
-	uint8_t retry_count;
 
 	if (!conf) {
 		printk(BIOS_WARNING, "IPMI: chip_info is missing! Skip init.\n");
@@ -154,41 +112,9 @@
 		}
 	}
 
-	printk(BIOS_INFO, "Get BMC self test result...");
-	for (retry_count = 0; retry_count < conf->bmc_boot_timeout; retry_count++) {
-		if (!ipmi_get_bmc_self_test_result(dev, &selftestrsp))
-			break;
-
-		mdelay(1000);
-	}
-
-	switch (selftestrsp.result) {
-	case IPMI_APP_SELFTEST_NO_ERROR: /* 0x55 */
-		printk(BIOS_DEBUG, "No Error\n");
-		break;
-	case IPMI_APP_SELFTEST_NOT_IMPLEMENTED: /* 0x56 */
-		printk(BIOS_DEBUG, "Function Not Implemented\n");
-		break;
-	case IPMI_APP_SELFTEST_ERROR: /* 0x57 */
-		printk(BIOS_ERR, "BMC: Corrupted or inaccessible data or device\n");
+	if (ipmi_process_self_test_result(dev))
 		/* Don't write tables if communication failed */
 		dev->enabled = 0;
-		break;
-	case IPMI_APP_SELFTEST_FATAL_HW_ERROR: /* 0x58 */
-		printk(BIOS_ERR, "BMC: Fatal Hardware Error\n");
-		/* Don't write tables if communication failed */
-		dev->enabled = 0;
-		break;
-	case IPMI_APP_SELFTEST_RESERVED: /* 0xFF */
-		printk(BIOS_DEBUG, "Reserved\n");
-		break;
-
-	default: /* Other Device Specific Hardware Error */
-		printk(BIOS_ERR, "BMC: Device Specific Error\n");
-		/* Don't write tables if communication failed */
-		dev->enabled = 0;
-		break;
-	}
 
 	if (!ipmi_get_device_id(dev, &rsp)) {
 		/* Queried the IPMI revision from BMC */
diff --git a/src/drivers/ipmi/ipmi_kcs_ops_premem.c b/src/drivers/ipmi/ipmi_kcs_ops_premem.c
deleted file mode 100644
index e1ae0dc..0000000
--- a/src/drivers/ipmi/ipmi_kcs_ops_premem.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#include <arch/io.h>
-#include <console/console.h>
-#include <device/pnp.h>
-#include <delay.h>
-#include <timer.h>
-
-#include "ipmi_kcs.h"
-#include "chip.h"
-
-static int ipmi_get_bmc_self_test_result(const struct device *dev,
-	struct ipmi_selftest_rsp *rsp)
-{
-	int ret;
-
-	ret = ipmi_kcs_message(dev->path.pnp.port, IPMI_NETFN_APPLICATION, 0,
-				 IPMI_BMC_GET_SELFTEST_RESULTS, NULL, 0, (u8 *)rsp,
-				 sizeof(*rsp));
-
-	if (ret < sizeof(struct ipmi_rsp) || rsp->resp.completion_code) {
-		printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
-		       __func__, ret, rsp->resp.completion_code);
-		return 1;
-	}
-	if (ret != sizeof(*rsp)) {
-		printk(BIOS_ERR, "IPMI: %s response truncated\n", __func__);
-		return 1;
-	}
-
-	return 0;
-}
-
-enum cb_err ipmi_kcs_premem_init(const u16 port, const u16 device)
-{
-	const struct drivers_ipmi_config *conf = NULL;
-	struct ipmi_selftest_rsp selftestrsp = {0};
-	uint8_t retry_count;
-	const struct device *dev;
-
-	/* Find IPMI PNP device from devicetree in romstage */
-	dev = dev_find_slot_pnp(port, device);
-
-	if (!dev) {
-		printk(BIOS_ERR, "IPMI: Cannot find PNP device port: %x, device %x\n",
-			port, device);
-		return CB_ERR;
-	}
-	if (!dev->enabled) {
-		printk(BIOS_ERR, "IPMI: device is not enabled\n");
-		return CB_ERR;
-	}
-	printk(BIOS_DEBUG, "IPMI: romstage PNP KCS 0x%x\n", dev->path.pnp.port);
-	if (dev->chip_info)
-		conf = dev->chip_info;
-
-	if (conf && conf->wait_for_bmc && conf->bmc_boot_timeout) {
-		struct stopwatch sw;
-		stopwatch_init_msecs_expire(&sw, conf->bmc_boot_timeout * 1000);
-		printk(BIOS_DEBUG, "IPMI: Waiting for BMC...\n");
-
-		while (!stopwatch_expired(&sw)) {
-			if (inb(dev->path.pnp.port) != 0xff)
-				break;
-			mdelay(100);
-		}
-		if (stopwatch_expired(&sw)) {
-			printk(BIOS_INFO, "IPMI: Waiting for BMC timed out\n");
-			return CB_ERR;
-		}
-	}
-
-	printk(BIOS_INFO, "Get BMC self test result...");
-	if (conf && conf->bmc_boot_timeout) {
-		for (retry_count = 0; retry_count < conf->bmc_boot_timeout; retry_count++) {
-			if (!ipmi_get_bmc_self_test_result(dev, &selftestrsp))
-				break;
-
-			mdelay(1000);
-		}
-	} else {
-		/* At least run once */
-		ipmi_get_bmc_self_test_result(dev, &selftestrsp);
-	}
-
-	int ret = CB_ERR;
-	switch (selftestrsp.result) {
-	case IPMI_APP_SELFTEST_NO_ERROR: /* 0x55 */
-		printk(BIOS_DEBUG, "No Error\n");
-		ret = CB_SUCCESS;
-		break;
-	case IPMI_APP_SELFTEST_NOT_IMPLEMENTED: /* 0x56 */
-		printk(BIOS_DEBUG, "Function Not Implemented\n");
-		ret = CB_SUCCESS;
-		break;
-	case IPMI_APP_SELFTEST_ERROR: /* 0x57 */
-		printk(BIOS_ERR, "Corrupted or inaccessible data or device\n");
-		break;
-	case IPMI_APP_SELFTEST_FATAL_HW_ERROR: /* 0x58 */
-		printk(BIOS_ERR, "Fatal Hardware Error\n");
-		break;
-	case IPMI_APP_SELFTEST_RESERVED: /* 0xFF */
-		printk(BIOS_DEBUG, "Reserved\n");
-		ret = CB_SUCCESS;
-		break;
-
-	default: /* Other Device Specific Hardware Error */
-		printk(BIOS_ERR, "Device Specific Error 0x%x 0x%x\n", selftestrsp.result,
-			selftestrsp.param);
-		break;
-	}
-	return ret;
-}
diff --git a/src/drivers/ipmi/ipmi_ops.c b/src/drivers/ipmi/ipmi_ops.c
index 73a02e1..d9b3256 100644
--- a/src/drivers/ipmi/ipmi_ops.c
+++ b/src/drivers/ipmi/ipmi_ops.c
@@ -2,6 +2,7 @@
 
 #include <console/console.h>
 #include "ipmi_ops.h"
+#include "ipmi_if.h"
 #include <string.h>
 #include <types.h>
 
@@ -18,7 +19,7 @@
 	/* clear BIOS FRB2 expiration flag */
 	req.timer_use_expiration_flags_clr = 2;
 	req.initial_countdown_val = countdown;
-	ret = ipmi_kcs_message(port, IPMI_NETFN_APPLICATION, 0x0,
+	ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0,
 			IPMI_BMC_SET_WDG_TIMER,
 			(const unsigned char *) &req, sizeof(req),
 			(unsigned char *) &rsp, sizeof(rsp));
@@ -32,7 +33,7 @@
 	}
 
 	/* Reset command to start timer */
-	ret = ipmi_kcs_message(port, IPMI_NETFN_APPLICATION, 0x0,
+	ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0,
 			IPMI_BMC_RESET_WDG_TIMER, NULL, 0,
 			(unsigned char *) &rsp, sizeof(rsp));
 
@@ -56,7 +57,7 @@
 	struct ipmi_rsp resp;
 
 	/* Get current timer first */
-	ret = ipmi_kcs_message(port, IPMI_NETFN_APPLICATION, 0x0,
+	ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0,
 			IPMI_BMC_GET_WDG_TIMER, NULL, 0,
 			(unsigned char *) &rsp, sizeof(rsp));
 
@@ -76,7 +77,7 @@
 	rsp.data.timer_use &= ~(1 << 6);
 	rsp.data.initial_countdown_val = 0;
 	req = rsp.data;
-	ret = ipmi_kcs_message(port, IPMI_NETFN_APPLICATION, 0x0,
+	ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0,
 			IPMI_BMC_SET_WDG_TIMER,
 			(const unsigned char *) &req, sizeof(req),
 			(unsigned char *) &resp, sizeof(resp));
@@ -104,7 +105,7 @@
 		return CB_ERR;
 	}
 
-	ret = ipmi_kcs_message(port, IPMI_NETFN_APPLICATION, 0x0,
+	ret = ipmi_message(port, IPMI_NETFN_APPLICATION, 0x0,
 			IPMI_BMC_GET_SYSTEM_GUID, NULL, 0,
 			(unsigned char *) &rsp, sizeof(rsp));
 
@@ -128,7 +129,7 @@
 		return CB_ERR;
 	}
 
-	ret = ipmi_kcs_message(port, IPMI_NETFN_STORAGE, 0x0,
+	ret = ipmi_message(port, IPMI_NETFN_STORAGE, 0x0,
 			IPMI_ADD_SEL_ENTRY, (const unsigned char *) sel,
 			16, (unsigned char *) &rsp, sizeof(rsp));
 
diff --git a/src/drivers/ipmi/ipmi_ops.h b/src/drivers/ipmi/ipmi_ops.h
index d900272..7a92a28 100644
--- a/src/drivers/ipmi/ipmi_ops.h
+++ b/src/drivers/ipmi/ipmi_ops.h
@@ -4,7 +4,7 @@
 #define __IPMI_OPS_H
 
 #include <types.h>
-#include "ipmi_kcs.h"
+#include "ipmi_if.h"
 #define IPMI_BMC_RESET_WDG_TIMER 0x22
 #define IPMI_BMC_SET_WDG_TIMER 0x24
 #define IPMI_BMC_GET_WDG_TIMER 0x25
diff --git a/src/drivers/ipmi/ipmi_ops_premem.c b/src/drivers/ipmi/ipmi_ops_premem.c
new file mode 100644
index 0000000..99c5842
--- /dev/null
+++ b/src/drivers/ipmi/ipmi_ops_premem.c
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <device/pnp.h>
+#include <delay.h>
+#include <timer.h>
+
+#include "ipmi_if.h"
+#include "chip.h"
+
+enum cb_err ipmi_premem_init(const u16 port, const u16 device)
+{
+	const struct drivers_ipmi_config *conf = NULL;
+	const struct device *dev;
+
+	/* Find IPMI PNP device from devicetree in romstage */
+	dev = dev_find_slot_pnp(port, device);
+
+	if (!dev) {
+		printk(BIOS_ERR, "IPMI: Cannot find PNP device port: %x, device %x\n",
+			port, device);
+		return CB_ERR;
+	}
+	if (!dev->enabled) {
+		printk(BIOS_ERR, "IPMI: device is not enabled\n");
+		return CB_ERR;
+	}
+	printk(BIOS_DEBUG, "IPMI: romstage PNP KCS 0x%x\n", dev->path.pnp.port);
+	if (dev->chip_info)
+		conf = dev->chip_info;
+
+	if (conf && conf->wait_for_bmc && conf->bmc_boot_timeout) {
+		struct stopwatch sw;
+		stopwatch_init_msecs_expire(&sw, conf->bmc_boot_timeout * 1000);
+		printk(BIOS_DEBUG, "IPMI: Waiting for BMC...\n");
+
+		while (!stopwatch_expired(&sw)) {
+			if (inb(dev->path.pnp.port) != 0xff)
+				break;
+			mdelay(100);
+		}
+		if (stopwatch_expired(&sw)) {
+			printk(BIOS_INFO, "IPMI: Waiting for BMC timed out\n");
+			return CB_ERR;
+		}
+	}
+
+	if (ipmi_process_self_test_result(dev))
+		return CB_ERR;
+
+	return CB_SUCCESS;
+}
diff --git a/src/drivers/ipmi/ocp/ipmi_ocp.c b/src/drivers/ipmi/ocp/ipmi_ocp.c
index 11161a8..9f583be 100644
--- a/src/drivers/ipmi/ocp/ipmi_ocp.c
+++ b/src/drivers/ipmi/ocp/ipmi_ocp.c
@@ -10,7 +10,7 @@
 #include <console/console.h>
 #include <device/device.h>
 #include <device/pnp.h>
-#include <drivers/ipmi/ipmi_kcs.h>
+#include <drivers/ipmi/ipmi_if.h>
 #include <drivers/ocp/dmi/ocp_dmi.h>
 #include <types.h>
 
@@ -28,8 +28,9 @@
 		req.cpu1_lo = xeon_sp_ppin[1].lo;
 		req.cpu1_hi = xeon_sp_ppin[1].hi;
 	}
-	ret = ipmi_kcs_message(dev->path.pnp.port, IPMI_NETFN_OEM, 0x0, IPMI_OEM_SET_PPIN,
-		(const unsigned char *) &req, sizeof(req), (unsigned char *) &rsp, sizeof(rsp));
+	ret = ipmi_message(dev->path.pnp.port, IPMI_NETFN_OEM, 0x0, IPMI_OEM_SET_PPIN,
+			   (const unsigned char *) &req, sizeof(req),
+			   (unsigned char *) &rsp, sizeof(rsp));
 
 	if (ret < sizeof(struct ipmi_rsp) || rsp.completion_code) {
 		printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
diff --git a/src/drivers/ipmi/ocp/ipmi_ocp_romstage.c b/src/drivers/ipmi/ocp/ipmi_ocp_romstage.c
index 8e43d8d..7b0b9ea 100644
--- a/src/drivers/ipmi/ocp/ipmi_ocp_romstage.c
+++ b/src/drivers/ipmi/ocp/ipmi_ocp_romstage.c
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-or-later */
 
 #include <console/console.h>
-#include <drivers/ipmi/ipmi_kcs.h>
+#include <drivers/ipmi/ipmi_if.h>
 
 #include "ipmi_ocp.h"
 
@@ -10,9 +10,9 @@
 	int ret;
 	struct ipmi_rsp rsp;
 
-	ret = ipmi_kcs_message(port, IPMI_NETFN_OEM, 0x0,
-				 IPMI_BMC_SET_POST_START, NULL, 0, (u8 *) &rsp,
-				 sizeof(rsp));
+	ret = ipmi_message(port, IPMI_NETFN_OEM, 0x0,
+			   IPMI_BMC_SET_POST_START, NULL, 0, (u8 *) &rsp,
+			   sizeof(rsp));
 
 	if (ret < sizeof(struct ipmi_rsp) || rsp.completion_code) {
 		printk(BIOS_ERR, "IPMI: %s command failed (ret=%d rsp=0x%x)\n",
@@ -42,10 +42,10 @@
 
 	/* 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));
+	ret = ipmi_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",
@@ -56,10 +56,10 @@
 	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));
+		ret = ipmi_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",
diff --git a/src/drivers/ipmi/supermicro_oem.c b/src/drivers/ipmi/supermicro_oem.c
index 9d5ffc7..7af4e3b 100644
--- a/src/drivers/ipmi/supermicro_oem.c
+++ b/src/drivers/ipmi/supermicro_oem.c
@@ -3,7 +3,7 @@
 #include <types.h>
 
 #include <console/console.h>
-#include <drivers/ipmi/ipmi_kcs.h>
+#include <drivers/ipmi/ipmi_if.h>
 #include <string.h>
 #include <build.h>
 #include "ipmi_supermicro_oem.h"
@@ -35,9 +35,9 @@
 	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));
+	ret = ipmi_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);
@@ -54,9 +54,9 @@
 	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));
+	ret = ipmi_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);