[PATCH v4 6/7] test: dm: add comprehensive tests for NVMEM bit field operations
Aswin Murugan
aswin.murugan at oss.qualcomm.com
Wed Apr 8 14:18:40 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)
- 4-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 v4:
1. Created separate test file for NVMEM bitfield tests
2. Fixed test to use correct I2C EEPROM functions
3. 4-byte cell with 12-bit field spanning byte boundary
---
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 762c1d9bbe2..4fb4d0a8ef5 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -959,6 +959,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";
};
@@ -976,6 +981,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 771b703b737..c60bb077e10 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