[PATCH 5/9] misc: Add HPE GSC memory-mapped EEPROM driver

Jorge Cisneros jorge.cisneros at hpe.com
Wed Apr 8 21:24:17 CEST 2026


Add a driver for the HPE GSC memory-mapped virtual EEPROM. This
device provides access to system VPD (Vital Product Data) including
MAC addresses, serial numbers, and part numbers through a simple
memory-mapped interface.

The driver registers as UCLASS_I2C_EEPROM for compatibility with
the standard EEPROM read/write API and includes checksum validation
to detect data corruption.

Signed-off-by: Jorge Cisneros <jorge.cisneros at hpe.com>
---
 drivers/misc/Kconfig          |   7 +++
 drivers/misc/Makefile         |   1 +
 drivers/misc/gsc_mem_eeprom.c | 118 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 126 insertions(+)

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a0aa290480e..5d316b03ec7 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -573,6 +573,13 @@ config SPL_I2C_EEPROM
 	  This option is an SPL-variant of the I2C_EEPROM option.
 	  See the help of I2C_EEPROM for details.
 
+config GSC_MEMEEPROM
+	bool "HPE GSC memory-mapped EEPROM driver"
+	depends on MISC
+	help
+	  Support for HPE GSC memory-mapped EEPROM used for storing
+	  VPD (Vital Product Data) in HPE Gen12 server BMCs.
+
 config SYS_I2C_EEPROM_ADDR
 	hex "Chip address of the EEPROM device"
 	depends on ID_EEPROM || I2C_EEPROM || SPL_I2C_EEPROM || CMD_EEPROM || ENV_IS_IN_EEPROM
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 1d950f7a0ab..e616b9f67d2 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o
 obj-$(CONFIG_IRQ) += irq-uclass.o
 obj-$(CONFIG_SANDBOX) += irq_sandbox.o irq_sandbox_test.o
 obj-$(CONFIG_$(PHASE_)I2C_EEPROM) += i2c_eeprom.o
+obj-$(CONFIG_GSC_MEMEEPROM) += gsc_mem_eeprom.o
 obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o
 obj-$(CONFIG_IMX8) += imx8/
 obj-$(CONFIG_IMX_ELE) += imx_ele/
diff --git a/drivers/misc/gsc_mem_eeprom.c b/drivers/misc/gsc_mem_eeprom.c
new file mode 100644
index 00000000000..f67662fe40b
--- /dev/null
+++ b/drivers/misc/gsc_mem_eeprom.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * HPE GSC memory-mapped EEPROM driver
+ *
+ * (C) Copyright 2025 Hewlett Packard Enterprise Development LP.
+ */
+
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <i2c_eeprom.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+struct memory_eeprom_priv {
+	u64 mem_offset;
+	int size;
+};
+
+static int validate_checksum(u8 *data)
+{
+	u16 sum = 0;
+	u16 word;
+	u8 rev;
+	int i;
+
+	rev = readb(data);
+	switch (rev) {
+	case 2:
+	case 3:
+		for (i = 0; i < 64; i++) {
+			memcpy(&word, data, sizeof(word));
+			data += sizeof(word);
+			sum += word;
+		}
+		if (sum == 0)
+			return 1;
+		debug("%s - Computed checksum fails 0x%04x\n", __func__, sum);
+		break;
+	default:
+		debug("%s - Version byte 0x%02x unsupported.\n", __func__, rev);
+	}
+	return 0;
+}
+
+static int mem_eeprom_read(struct udevice *dev, int offset, u8 *buf,
+			   int size)
+{
+	struct memory_eeprom_priv *priv = dev_get_priv(dev);
+	u8 *ptr;
+
+	ptr = map_physmem(priv->mem_offset, priv->size, MAP_NOCACHE);
+	if (!ptr) {
+		printf("%s - failed to map physical memory.\n", __func__);
+		return -ENODEV;
+	}
+
+	if (size + offset > priv->size) {
+		unmap_physmem(ptr, MAP_NOCACHE);
+		return -ENOSYS;
+	}
+
+	memcpy(buf, &ptr[offset], size);
+	unmap_physmem(ptr, MAP_NOCACHE);
+
+	return 0;
+}
+
+static const struct i2c_eeprom_ops i2c_mem_eeprom_ops = {
+	.read = mem_eeprom_read,
+};
+
+static const struct udevice_id i2c_mem_eeprom_ids[] = {
+	{ .compatible = "i2c_gsc_mem_eeprom" },
+	{ }
+};
+
+static int i2c_mem_eeprom_probe(struct udevice *dev)
+{
+	struct memory_eeprom_priv *priv = dev_get_priv(dev);
+	u8 *ptr;
+	u8 crc1, crc2;
+	u32 reg[2];
+	int ret;
+
+	ret = dev_read_u32_array(dev, "reg", reg, 2);
+	if (ret) {
+		printf("Error reading reg from DT: %d\n", ret);
+		return ret;
+	}
+	priv->mem_offset = reg[0];
+	priv->size = reg[1];
+
+	ptr = map_physmem(priv->mem_offset, priv->size, MAP_NOCACHE);
+	if (!ptr) {
+		printf("%s failed to map physical memory.\n", __func__);
+		return -ENODEV;
+	}
+
+	crc1 = validate_checksum(ptr);
+	crc2 = validate_checksum(ptr + 128);
+	unmap_physmem(ptr, MAP_NOCACHE);
+
+	if (crc1 != 1 || crc2 != 1) {
+		printf("%s - Warning: Invalid checksum\n", __func__);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+U_BOOT_DRIVER(i2c_gsc_memeeprom) = {
+	.name = "gsc_mem_eeprom",
+	.id = UCLASS_I2C_EEPROM,
+	.of_match = i2c_mem_eeprom_ids,
+	.probe = i2c_mem_eeprom_probe,
+	.ops = &i2c_mem_eeprom_ops,
+	.priv_auto = sizeof(struct memory_eeprom_priv),
+};

-- 
2.43.0



More information about the U-Boot mailing list