[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