diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
index c108441882ccde34311729361afc7f2876e5f182..94719fc6ff9d3dc2a9c1cc0fc4d399c08128683f 100644
--- a/drivers/char/ipmi/Kconfig
+++ b/drivers/char/ipmi/Kconfig
@@ -18,6 +18,10 @@ menuconfig IPMI_HANDLER
 	 If unsure, say N.
 
 config IPMI_DMI_DECODE
+       select IPMI_PLAT_DATA
+       bool
+
+config IPMI_PLAT_DATA
        bool
 
 if IPMI_HANDLER
@@ -56,6 +60,7 @@ config IPMI_DEVICE_INTERFACE
 
 config IPMI_SI
        tristate 'IPMI System Interface handler'
+       select IPMI_PLAT_DATA
        help
          Provides a driver for System Interfaces (KCS, SMIC, BT).
 	 Currently, only KCS and SMIC are supported.  If
diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile
index 7a3baf301a8f7a15ff442fe84ba045dd209c0d84..3f06b206247516e23cbe2065ec77289855201a55 100644
--- a/drivers/char/ipmi/Makefile
+++ b/drivers/char/ipmi/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
 obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
 obj-$(CONFIG_IPMI_SI) += ipmi_si.o
 obj-$(CONFIG_IPMI_DMI_DECODE) += ipmi_dmi.o
+obj-$(CONFIG_IPMI_PLAT_DATA) += ipmi_plat_data.o
 obj-$(CONFIG_IPMI_SSIF) += ipmi_ssif.o
 obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o
 obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
diff --git a/drivers/char/ipmi/ipmi_dmi.c b/drivers/char/ipmi/ipmi_dmi.c
index 249880457b17798a091b218fe4e33469f62f1144..ff0b199be4729757743bbd72bff2fc61a842d291 100644
--- a/drivers/char/ipmi/ipmi_dmi.c
+++ b/drivers/char/ipmi/ipmi_dmi.c
@@ -14,6 +14,7 @@
 #include <linux/property.h>
 #include "ipmi_si_sm.h"
 #include "ipmi_dmi.h"
+#include "ipmi_plat_data.h"
 
 #define IPMI_DMI_TYPE_KCS	0x01
 #define IPMI_DMI_TYPE_SMIC	0x02
@@ -22,7 +23,7 @@
 
 struct ipmi_dmi_info {
 	enum si_type si_type;
-	u32 flags;
+	unsigned int space; /* addr space for si, intf# for ssif */
 	unsigned long addr;
 	u8 slave_addr;
 	struct ipmi_dmi_info *next;
@@ -33,133 +34,60 @@ static struct ipmi_dmi_info *ipmi_dmi_infos;
 static int ipmi_dmi_nr __initdata;
 
 static void __init dmi_add_platform_ipmi(unsigned long base_addr,
-					 u32 flags,
+					 unsigned int space,
 					 u8 slave_addr,
 					 int irq,
 					 int offset,
 					 int type)
 {
-	struct platform_device *pdev;
-	struct resource r[4];
-	unsigned int num_r = 1, size;
-	struct property_entry p[5];
-	unsigned int pidx = 0;
-	char *name;
-	int rv;
-	enum si_type si_type;
+	const char *name;
 	struct ipmi_dmi_info *info;
+	struct ipmi_plat_data p;
 
-	memset(p, 0, sizeof(p));
+	memset(&p, 0, sizeof(p));
 
 	name = "dmi-ipmi-si";
 	switch (type) {
 	case IPMI_DMI_TYPE_SSIF:
 		name = "dmi-ipmi-ssif";
-		offset = 1;
-		size = 1;
-		si_type = SI_TYPE_INVALID;
+		p.type = SI_TYPE_INVALID;
 		break;
 	case IPMI_DMI_TYPE_BT:
-		size = 3;
-		si_type = SI_BT;
+		p.type = SI_BT;
 		break;
 	case IPMI_DMI_TYPE_KCS:
-		size = 2;
-		si_type = SI_KCS;
+		p.type = SI_KCS;
 		break;
 	case IPMI_DMI_TYPE_SMIC:
-		size = 2;
-		si_type = SI_SMIC;
+		p.type = SI_SMIC;
 		break;
 	default:
 		pr_err("Invalid IPMI type: %d\n", type);
 		return;
 	}
 
-	if (si_type != SI_TYPE_INVALID)
-		p[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", si_type);
-
-	p[pidx++] = PROPERTY_ENTRY_U8("slave-addr", slave_addr);
-	p[pidx++] = PROPERTY_ENTRY_U8("addr-source", SI_SMBIOS);
+	memset(&p, 0, sizeof(p));
+	p.addr = base_addr;
+	p.space = space;
+	p.regspacing = offset;
+	p.irq = irq;
+	p.slave_addr = slave_addr;
+	p.addr_source = SI_SMBIOS;
 
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
 	if (!info) {
 		pr_warn("Could not allocate dmi info\n");
 	} else {
-		info->si_type = si_type;
-		info->flags = flags;
+		info->si_type = p.type;
+		info->space = space;
 		info->addr = base_addr;
 		info->slave_addr = slave_addr;
 		info->next = ipmi_dmi_infos;
 		ipmi_dmi_infos = info;
 	}
 
-	pdev = platform_device_alloc(name, ipmi_dmi_nr);
-	if (!pdev) {
-		pr_err("Error allocation IPMI platform device\n");
-		return;
-	}
-
-	if (type == IPMI_DMI_TYPE_SSIF) {
-		p[pidx++] = PROPERTY_ENTRY_U16("i2c-addr", base_addr);
-		goto add_properties;
-	}
-
-	memset(r, 0, sizeof(r));
-
-	r[0].start = base_addr;
-	r[0].end = r[0].start + offset - 1;
-	r[0].name = "IPMI Address 1";
-	r[0].flags = flags;
-
-	if (size > 1) {
-		r[1].start = r[0].start + offset;
-		r[1].end = r[1].start + offset - 1;
-		r[1].name = "IPMI Address 2";
-		r[1].flags = flags;
-		num_r++;
-	}
-
-	if (size > 2) {
-		r[2].start = r[1].start + offset;
-		r[2].end = r[2].start + offset - 1;
-		r[2].name = "IPMI Address 3";
-		r[2].flags = flags;
-		num_r++;
-	}
-
-	if (irq) {
-		r[num_r].start = irq;
-		r[num_r].end = irq;
-		r[num_r].name = "IPMI IRQ";
-		r[num_r].flags = IORESOURCE_IRQ;
-		num_r++;
-	}
-
-	rv = platform_device_add_resources(pdev, r, num_r);
-	if (rv) {
-		dev_err(&pdev->dev, "Unable to add resources: %d\n", rv);
-		goto err;
-	}
-
-add_properties:
-	rv = platform_device_add_properties(pdev, p);
-	if (rv) {
-		dev_err(&pdev->dev, "Unable to add properties: %d\n", rv);
-		goto err;
-	}
-
-	rv = platform_device_add(pdev);
-	if (rv) {
-		dev_err(&pdev->dev, "Unable to add device: %d\n", rv);
-		goto err;
-	}
-
-	ipmi_dmi_nr++;
-	return;
-
-err:
-	platform_device_put(pdev);
+	if (ipmi_platform_add(name, ipmi_dmi_nr, &p))
+		ipmi_dmi_nr++;
 }
 
 /*
@@ -169,14 +97,14 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
  * This function allows an ACPI-specified IPMI device to look up the
  * slave address from the DMI table.
  */
-int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags,
+int ipmi_dmi_get_slave_addr(enum si_type si_type, unsigned int space,
 			    unsigned long base_addr)
 {
 	struct ipmi_dmi_info *info = ipmi_dmi_infos;
 
 	while (info) {
 		if (info->si_type == si_type &&
-		    info->flags == flags &&
+		    info->space == space &&
 		    info->addr == base_addr)
 			return info->slave_addr;
 		info = info->next;
@@ -197,13 +125,13 @@ EXPORT_SYMBOL(ipmi_dmi_get_slave_addr);
 
 static void __init dmi_decode_ipmi(const struct dmi_header *dm)
 {
-	const u8	*data = (const u8 *) dm;
-	u32             flags = IORESOURCE_IO;
-	unsigned long	base_addr;
-	u8              len = dm->length;
-	u8              slave_addr;
-	int             irq = 0, offset;
-	int             type;
+	const u8 *data = (const u8 *) dm;
+	int space = IPMI_IO_ADDR_SPACE;
+	unsigned long base_addr;
+	u8 len = dm->length;
+	u8 slave_addr;
+	int irq = 0, offset = 0;
+	int type;
 
 	if (len < DMI_IPMI_MIN_LENGTH)
 		return;
@@ -218,8 +146,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm)
 	}
 	if (len >= DMI_IPMI_VER2_LENGTH) {
 		if (type == IPMI_DMI_TYPE_SSIF) {
-			offset = 0;
-			flags = 0;
+			space = 0; /* Match I2C interface 0. */
 			base_addr = data[DMI_IPMI_ADDR] >> 1;
 			if (base_addr == 0) {
 				/*
@@ -236,7 +163,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm)
 				base_addr &= DMI_IPMI_IO_MASK;
 			} else {
 				/* Memory */
-				flags = IORESOURCE_MEM;
+				space = IPMI_MEM_ADDR_SPACE;
 			}
 
 			/*
@@ -280,7 +207,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm)
 		offset = 1;
 	}
 
-	dmi_add_platform_ipmi(base_addr, flags, slave_addr, irq,
+	dmi_add_platform_ipmi(base_addr, space, slave_addr, irq,
 			      offset, type);
 }
 
diff --git a/drivers/char/ipmi/ipmi_dmi.h b/drivers/char/ipmi/ipmi_dmi.h
index 8d2b094db8e63b1fb6f090315bd278ffa5d870e8..2dbec0461d0c4373b52531792ab8e1162ab95e2e 100644
--- a/drivers/char/ipmi/ipmi_dmi.h
+++ b/drivers/char/ipmi/ipmi_dmi.h
@@ -4,6 +4,6 @@
  */
 
 #ifdef CONFIG_IPMI_DMI_DECODE
-int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags,
+int ipmi_dmi_get_slave_addr(enum si_type si_type, unsigned int space,
 			    unsigned long base_addr);
 #endif
diff --git a/drivers/char/ipmi/ipmi_plat_data.c b/drivers/char/ipmi/ipmi_plat_data.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f0ca2a848eb4ea61763fbd2ea96fc4dfef39b99
--- /dev/null
+++ b/drivers/char/ipmi/ipmi_plat_data.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Add an IPMI platform device.
+ */
+
+#include <linux/platform_device.h>
+#include "ipmi_plat_data.h"
+#include "ipmi_si.h"
+
+struct platform_device *ipmi_platform_add(const char *name, unsigned int inst,
+					  struct ipmi_plat_data *p)
+{
+	struct platform_device *pdev;
+	unsigned int num_r = 1, size, pidx = 0;
+	struct resource r[4];
+	struct property_entry pr[6];
+	u32 flags;
+	int rv;
+
+	memset(pr, 0, sizeof(pr));
+	memset(r, 0, sizeof(r));
+
+	if (p->type == SI_BT)
+		size = 3;
+	else if (p->type == SI_TYPE_INVALID)
+		size = 0;
+	else
+		size = 2;
+
+	if (p->regsize == 0)
+		p->regsize = DEFAULT_REGSIZE;
+	if (p->regspacing == 0)
+		p->regspacing = p->regsize;
+
+	pr[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", p->type);
+	if (p->slave_addr)
+		pr[pidx++] = PROPERTY_ENTRY_U8("slave-addr", p->slave_addr);
+	pr[pidx++] = PROPERTY_ENTRY_U8("addr-source", p->addr_source);
+	if (p->regshift)
+		pr[pidx++] = PROPERTY_ENTRY_U8("reg-shift", p->regshift);
+	pr[pidx++] = PROPERTY_ENTRY_U8("reg-size", p->regsize);
+	/* Last entry must be left NULL to terminate it. */
+
+	pdev = platform_device_alloc(name, inst);
+	if (!pdev) {
+		pr_err("Error allocating IPMI platform device %s.%d\n",
+		       name, inst);
+		return NULL;
+	}
+
+	if (size == 0)
+		/* An invalid or SSIF interface, no resources. */
+		goto add_properties;
+
+	/*
+	 * Register spacing is derived from the resources in
+	 * the IPMI platform code.
+	 */
+
+	if (p->space == IPMI_IO_ADDR_SPACE)
+		flags = IORESOURCE_IO;
+	else
+		flags = IORESOURCE_MEM;
+
+	r[0].start = p->addr;
+	r[0].end = r[0].start + p->regsize - 1;
+	r[0].name = "IPMI Address 1";
+	r[0].flags = flags;
+
+	if (size > 1) {
+		r[1].start = r[0].start + p->regspacing;
+		r[1].end = r[1].start + p->regsize - 1;
+		r[1].name = "IPMI Address 2";
+		r[1].flags = flags;
+		num_r++;
+	}
+
+	if (size > 2) {
+		r[2].start = r[1].start + p->regspacing;
+		r[2].end = r[2].start + p->regsize - 1;
+		r[2].name = "IPMI Address 3";
+		r[2].flags = flags;
+		num_r++;
+	}
+
+	if (p->irq) {
+		r[num_r].start = p->irq;
+		r[num_r].end = p->irq;
+		r[num_r].name = "IPMI IRQ";
+		r[num_r].flags = IORESOURCE_IRQ;
+		num_r++;
+	}
+
+	rv = platform_device_add_resources(pdev, r, num_r);
+	if (rv) {
+		dev_err(&pdev->dev,
+			"Unable to add hard-code resources: %d\n", rv);
+		goto err;
+	}
+ add_properties:
+	rv = platform_device_add_properties(pdev, pr);
+	if (rv) {
+		dev_err(&pdev->dev,
+			"Unable to add hard-code properties: %d\n", rv);
+		goto err;
+	}
+
+	rv = platform_device_add(pdev);
+	if (rv) {
+		dev_err(&pdev->dev,
+			"Unable to add hard-code device: %d\n", rv);
+		goto err;
+	}
+	return pdev;
+
+err:
+	platform_device_put(pdev);
+	return NULL;
+}
+EXPORT_SYMBOL(ipmi_platform_add);
diff --git a/drivers/char/ipmi/ipmi_plat_data.h b/drivers/char/ipmi/ipmi_plat_data.h
new file mode 100644
index 0000000000000000000000000000000000000000..567cfcec8ada399c81c643a0e58185286a47a229
--- /dev/null
+++ b/drivers/char/ipmi/ipmi_plat_data.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+/*
+ * Generic code to add IPMI platform devices.
+ */
+
+#include <linux/ipmi.h>
+
+struct ipmi_plat_data {
+	unsigned int type; /* si_type for si, SI_INVALID for others */
+	unsigned int space; /* addr_space for si, intf# for ssif. */
+	unsigned long addr;
+	unsigned int regspacing;
+	unsigned int regsize;
+	unsigned int regshift;
+	unsigned int irq;
+	unsigned int slave_addr;
+	enum ipmi_addr_src addr_source;
+};
+
+struct platform_device *ipmi_platform_add(const char *name, unsigned int inst,
+					  struct ipmi_plat_data *p);
diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h
index 3efc8a71aab4ec59fbd17af19547cdc5720c542a..49b211bf9ad769c3d8a45e154f9f7496737835a5 100644
--- a/drivers/char/ipmi/ipmi_si.h
+++ b/drivers/char/ipmi/ipmi_si.h
@@ -7,6 +7,7 @@
  */
 
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
 #include "ipmi_si_sm.h"
 
 #define DEFAULT_REGSPACING	1
diff --git a/drivers/char/ipmi/ipmi_si_hardcode.c b/drivers/char/ipmi/ipmi_si_hardcode.c
index 86ac9b8a3219af54810874d30d299ac660b0b070..cb58298d80f59aa12d14feaf2b38b41dc8dd476a 100644
--- a/drivers/char/ipmi/ipmi_si_hardcode.c
+++ b/drivers/char/ipmi/ipmi_si_hardcode.c
@@ -5,6 +5,7 @@
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include "ipmi_si.h"
+#include "ipmi_plat_data.h"
 
 /*
  * There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
@@ -78,121 +79,39 @@ static struct platform_device *ipmi_hc_pdevs[SI_MAX_PARMS];
 static void __init ipmi_hardcode_init_one(const char *si_type_str,
 					  unsigned int i,
 					  unsigned long addr,
-					  unsigned int flags)
+					  enum ipmi_addr_space addr_space)
 {
-	struct platform_device *pdev;
-	unsigned int num_r = 1, size;
-	struct resource r[4];
-	struct property_entry p[6];
-	enum si_type si_type;
-	unsigned int regspacing, regsize;
-	int rv;
+	struct ipmi_plat_data p;
 
-	memset(p, 0, sizeof(p));
-	memset(r, 0, sizeof(r));
+	memset(&p, 0, sizeof(p));
 
 	if (!si_type_str || !*si_type_str || strcmp(si_type_str, "kcs") == 0) {
-		size = 2;
-		si_type = SI_KCS;
+		p.type = SI_KCS;
 	} else if (strcmp(si_type_str, "smic") == 0) {
-		size = 2;
-		si_type = SI_SMIC;
+		p.type = SI_SMIC;
 	} else if (strcmp(si_type_str, "bt") == 0) {
-		size = 3;
-		si_type = SI_BT;
+		p.type = SI_BT;
 	} else if (strcmp(si_type_str, "invalid") == 0) {
 		/*
 		 * Allow a firmware-specified interface to be
 		 * disabled.
 		 */
-		size = 1;
-		si_type = SI_TYPE_INVALID;
+		p.type = SI_TYPE_INVALID;
 	} else {
 		pr_warn("Interface type specified for interface %d, was invalid: %s\n",
 			i, si_type_str);
 		return;
 	}
 
-	regsize = regsizes[i];
-	if (regsize == 0)
-		regsize = DEFAULT_REGSIZE;
+	p.regsize = regsizes[i];
+	p.slave_addr = slave_addrs[i];
+	p.addr_source = SI_HARDCODED;
+	p.regshift = regshifts[i];
+	p.regsize = regsizes[i];
+	p.addr = addr;
+	p.space = addr_space;
 
-	p[0] = PROPERTY_ENTRY_U8("ipmi-type", si_type);
-	p[1] = PROPERTY_ENTRY_U8("slave-addr", slave_addrs[i]);
-	p[2] = PROPERTY_ENTRY_U8("addr-source", SI_HARDCODED);
-	p[3] = PROPERTY_ENTRY_U8("reg-shift", regshifts[i]);
-	p[4] = PROPERTY_ENTRY_U8("reg-size", regsize);
-	/* Last entry must be left NULL to terminate it. */
-
-	/*
-	 * Register spacing is derived from the resources in
-	 * the IPMI platform code.
-	 */
-	regspacing = regspacings[i];
-	if (regspacing == 0)
-		regspacing = regsize;
-
-	r[0].start = addr;
-	r[0].end = r[0].start + regsize - 1;
-	r[0].name = "IPMI Address 1";
-	r[0].flags = flags;
-
-	if (size > 1) {
-		r[1].start = r[0].start + regspacing;
-		r[1].end = r[1].start + regsize - 1;
-		r[1].name = "IPMI Address 2";
-		r[1].flags = flags;
-		num_r++;
-	}
-
-	if (size > 2) {
-		r[2].start = r[1].start + regspacing;
-		r[2].end = r[2].start + regsize - 1;
-		r[2].name = "IPMI Address 3";
-		r[2].flags = flags;
-		num_r++;
-	}
-
-	if (irqs[i]) {
-		r[num_r].start = irqs[i];
-		r[num_r].end = irqs[i];
-		r[num_r].name = "IPMI IRQ";
-		r[num_r].flags = IORESOURCE_IRQ;
-		num_r++;
-	}
-
-	pdev = platform_device_alloc("hardcode-ipmi-si", i);
-	if (!pdev) {
-		pr_err("Error allocating IPMI platform device %d\n", i);
-		return;
-	}
-
-	rv = platform_device_add_resources(pdev, r, num_r);
-	if (rv) {
-		dev_err(&pdev->dev,
-			"Unable to add hard-code resources: %d\n", rv);
-		goto err;
-	}
-
-	rv = platform_device_add_properties(pdev, p);
-	if (rv) {
-		dev_err(&pdev->dev,
-			"Unable to add hard-code properties: %d\n", rv);
-		goto err;
-	}
-
-	rv = platform_device_add(pdev);
-	if (rv) {
-		dev_err(&pdev->dev,
-			"Unable to add hard-code device: %d\n", rv);
-		goto err;
-	}
-
-	ipmi_hc_pdevs[i] = pdev;
-	return;
-
-err:
-	platform_device_put(pdev);
+	ipmi_hc_pdevs[i] = ipmi_platform_add("hardcode-ipmi-si", i, &p);
 }
 
 void __init ipmi_hardcode_init(void)
@@ -219,10 +138,10 @@ void __init ipmi_hardcode_init(void)
 	for (i = 0; i < SI_MAX_PARMS; i++) {
 		if (i < num_ports && ports[i])
 			ipmi_hardcode_init_one(si_type[i], i, ports[i],
-					       IORESOURCE_IO);
+					       IPMI_IO_ADDR_SPACE);
 		if (i < num_addrs && addrs[i])
 			ipmi_hardcode_init_one(si_type[i], i, addrs[i],
-					       IORESOURCE_MEM);
+					       IPMI_MEM_ADDR_SPACE);
 	}
 }
 
diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c
index f690e9edb08c1aec97daf64f92ef4424c1010bc9..f2b5ac0986f257aebb3ca9495f5e52bff5d589b7 100644
--- a/drivers/char/ipmi/ipmi_si_platform.c
+++ b/drivers/char/ipmi/ipmi_si_platform.c
@@ -307,15 +307,10 @@ static int of_ipmi_probe(struct platform_device *dev)
 static int find_slave_address(struct si_sm_io *io, int slave_addr)
 {
 #ifdef CONFIG_IPMI_DMI_DECODE
-	if (!slave_addr) {
-		u32 flags = IORESOURCE_IO;
-
-		if (io->addr_space == IPMI_MEM_ADDR_SPACE)
-			flags = IORESOURCE_MEM;
-
-		slave_addr = ipmi_dmi_get_slave_addr(io->si_type, flags,
+	if (!slave_addr)
+		slave_addr = ipmi_dmi_get_slave_addr(io->si_type,
+						     io->addr_space,
 						     io->addr_data);
-	}
 #endif
 
 	return slave_addr;