[PATCH v5 6/7] test: dm: add comprehensive tests for NVMEM bit field operations

Aswin Murugan aswin.murugan at oss.qualcomm.com
Thu May 21 20:05:48 CEST 2026


Add a mock I2C EEPROM device (nvmem-test at 50) to the sandbox device tree
to support NVMEM bit field operation testing.

Add test coverage for NVMEM bit field read and write operations to
validate the new bit field support in the NVMEM subsystem.

Test cases include:
- 1-byte cell with 7-bit field (Qualcomm SDAM reboot reason use case)
- 2-byte cell with 12-bit field spanning a byte boundary
- 4-byte cell without a bit field (legacy byte-level access)
- 4-byte cell with a 16-bit field in the upper 2 bytes

Error validation tests cover:
- Bit field exceeding the cell size
- Bit field exceeding the 32-bit maximum
- Invalid bit_offset and nbits combinations
- Buffer size mismatch in non-bit-field mode

The tests verify:
- Correct bit extraction during read operations
- Read-modify-write behavior preserving unrelated bits
- Proper error handling for invalid configurations

Signed-off-by: Aswin Murugan <aswin.murugan at oss.qualcomm.com>
---
Changes in v5:
1. No change in v5

Changes in v4:
1. No change in v4

Changes in v3:
1. No change in v3
---
 arch/sandbox/dts/test.dts |  12 +++
 test/dm/Makefile          |   1 +
 test/dm/nvmem.c           | 160 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 173 insertions(+)
 create mode 100644 test/dm/nvmem.c

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 0887de4333b..769f43efe4d 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -1021,6 +1021,11 @@
 				sandbox,filename = "i2c.bin";
 				sandbox,size = <256>;
 			};
+			emul_nvmem_test: emul-nvmem-test {
+				compatible = "sandbox,i2c-eeprom";
+				sandbox,filename = "nvmem-test.bin";
+				sandbox,size = <256>;
+			};
 			emul0: emul0 {
 				compatible = "sandbox,i2c-rtc-emul";
 			};
@@ -1038,6 +1043,13 @@
 			reg = <0x41>;
 			sandbox,emul = <&emul_pmic1>;
 		};
+
+		/* Mock NVMEM device for bit field testing */
+		nvmem-test at 50 {
+			reg = <0x50>;
+			compatible = "i2c-eeprom";
+			sandbox,emul = <&emul_nvmem_test>;
+		};
 	};
 
 	i3c0 {
diff --git a/test/dm/Makefile b/test/dm/Makefile
index d69b0e08d66..ca2401dabc1 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -75,6 +75,7 @@ obj-$(CONFIG_CMD_MUX) += mux-cmd.o
 obj-$(CONFIG_MULTIPLEXER) += mux-emul.o
 obj-$(CONFIG_MUX_MMIO) += mux-mmio.o
 obj-y += fdtdec.o
+obj-$(CONFIG_NVMEM) += nvmem.o
 obj-$(CONFIG_MTD_RAW_NAND) += nand.o
 obj-$(CONFIG_UT_DM) += nop.o
 obj-y += ofnode.o
diff --git a/test/dm/nvmem.c b/test/dm/nvmem.c
new file mode 100644
index 00000000000..dd8d0151d2b
--- /dev/null
+++ b/test/dm/nvmem.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test for NVMEM bit field support
+ */
+
+#include <dm.h>
+#include <i2c_eeprom.h>
+#include <nvmem.h>
+#include <dm/test.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+static int nvmem_test_write_raw(struct udevice *dev, uint offset,
+				const void *buf, uint size)
+{
+	return i2c_eeprom_write(dev, offset, buf, size);
+}
+
+static int nvmem_test_read_raw(struct udevice *dev, uint offset,
+			       void *buf, uint size)
+{
+	return i2c_eeprom_read(dev, offset, buf, size);
+}
+
+/* Test NVMEM bit field operations */
+static int dm_test_nvmem_bitfield(struct unit_test_state *uts)
+{
+	struct udevice *nvmem_dev;
+	struct nvmem_cell cell;
+	u32 value;
+	u8 hw_value_u8;
+	u32 hw_value_u32;
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_I2C_EEPROM,
+					      "nvmem-test at 50", &nvmem_dev));
+
+	cell.nvmem = nvmem_dev;
+
+	/* Test reg = <0x0 0x1>; bits = <1 7>: */
+	cell.offset = 0x0;
+	cell.size = 1;
+	cell.bit_offset = 1;
+	cell.nbits = 7;
+	hw_value_u8 = 0x01;
+	ut_assertok(nvmem_test_write_raw(nvmem_dev, cell.offset, &hw_value_u8, 1));
+	value = 0x7f;
+	ut_assertok(nvmem_cell_write(&cell, &value, sizeof(value)));
+	value = 0;
+	ut_assertok(nvmem_cell_read(&cell, &value, sizeof(value)));
+	ut_asserteq(0x7f, value);
+	ut_assertok(nvmem_test_read_raw(nvmem_dev, cell.offset, &hw_value_u8, 1));
+	ut_asserteq(0xff, hw_value_u8);
+
+	/* Test reg = <0x18 0x4>; bits = <4 12>: Spanning byte boundary */
+	cell.offset = 0x18;
+	cell.size = 4;
+	cell.bit_offset = 4;
+	cell.nbits = 12;
+	hw_value_u32 = 0x0000000f;
+	ut_assertok(nvmem_test_write_raw(nvmem_dev, cell.offset, (u8 *)&hw_value_u32, 4));
+	value = 0xfff;
+	ut_assertok(nvmem_cell_write(&cell, &value, sizeof(value)));
+	value = 0;
+	ut_assertok(nvmem_cell_read(&cell, &value, sizeof(value)));
+	ut_asserteq(0xfff, value);
+	ut_assertok(nvmem_test_read_raw(nvmem_dev, cell.offset, (u8 *)&hw_value_u32, 4));
+	ut_asserteq(0x0000ffff, hw_value_u32);
+
+	/* Test reg = <0x9 0x4>: Full 4-byte access without bit field */
+	cell.offset = 0x9;
+	cell.bit_offset = 0;
+	cell.nbits = 0;
+	value = 0x12345678;
+	ut_assertok(nvmem_cell_write(&cell, &value, sizeof(value)));
+	value = 0;
+	ut_assertok(nvmem_cell_read(&cell, &value, sizeof(value)));
+	ut_asserteq(0x12345678, value);
+
+	/* Test reg = <0xc 0x4>; bits = <16 16>: Upper 2 bytes */
+	cell.offset = 0xc;
+	cell.bit_offset = 16;
+	cell.nbits = 16;
+	hw_value_u32 = 0x0000ffff;
+	ut_assertok(nvmem_test_write_raw(nvmem_dev, cell.offset, (u8 *)&hw_value_u32, 4));
+	value = 0xffff;
+	ut_assertok(nvmem_cell_write(&cell, &value, sizeof(value)));
+	value = 0;
+	ut_assertok(nvmem_cell_read(&cell, &value, sizeof(value)));
+	ut_asserteq(0xffff, value);
+	ut_assertok(nvmem_test_read_raw(nvmem_dev, cell.offset, (u8 *)&hw_value_u32, 4));
+	ut_asserteq(0xffffffff, hw_value_u32);
+
+	return 0;
+}
+DM_TEST(dm_test_nvmem_bitfield,
+	UTF_PROBE_TEST | UTF_SCAN_FDT | UTF_FLAT_TREE);
+
+/* Test NVMEM error handling for invalid configurations */
+static int dm_test_nvmem_bitfield_errors(struct unit_test_state *uts)
+{
+	struct udevice *nvmem_dev;
+	struct nvmem_cell cell;
+	u32 value;
+	int ret;
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_I2C_EEPROM,
+					      "nvmem-test at 50", &nvmem_dev));
+
+	/* Test bit field exceeding cell size */
+	cell.nvmem = nvmem_dev;
+	cell.offset = 0xd;
+	cell.size = 1;
+	cell.bit_offset = 0;
+	cell.nbits = 9;
+
+	value = 0xff;
+	ret = nvmem_cell_write(&cell, &value, sizeof(value));
+	ut_asserteq(-EINVAL, ret);
+
+	ret = nvmem_cell_read(&cell, &value, sizeof(value));
+	ut_asserteq(-EINVAL, ret);
+
+	/* Test bit field exceeding 32 bits */
+	cell.size = 4;
+	cell.bit_offset = 0;
+	cell.nbits = 33;
+
+	ret = nvmem_cell_write(&cell, &value, sizeof(value));
+	ut_asserteq(-EINVAL, ret);
+
+	ret = nvmem_cell_read(&cell, &value, sizeof(value));
+	ut_asserteq(-EINVAL, ret);
+
+	/* Test invalid bit_offset + nbits */
+	cell.size = 1;
+	cell.bit_offset = 7;
+	cell.nbits = 2;
+
+	ret = nvmem_cell_write(&cell, &value, sizeof(value));
+	ut_asserteq(-EINVAL, ret);
+
+	ret = nvmem_cell_read(&cell, &value, sizeof(value));
+	ut_asserteq(-EINVAL, ret);
+
+	/* Test nbits=0 requires buffer size == cell size */
+	cell.size = 1;
+	cell.bit_offset = 0;
+	cell.nbits = 0;
+
+	value = 0xff;
+	ret = nvmem_cell_write(&cell, &value, sizeof(value));
+	ut_asserteq(-EINVAL, ret);
+
+	ret = nvmem_cell_read(&cell, &value, sizeof(value));
+	ut_asserteq(-EINVAL, ret);
+
+	return 0;
+}
+DM_TEST(dm_test_nvmem_bitfield_errors,
+	UTF_PROBE_TEST | UTF_SCAN_FDT | UTF_FLAT_TREE);
-- 
2.34.1



More information about the U-Boot mailing list