summaryrefslogtreecommitdiff
path: root/test/dm
diff options
context:
space:
mode:
Diffstat (limited to 'test/dm')
-rw-r--r--test/dm/Makefile3
-rw-r--r--test/dm/acpi.c10
-rw-r--r--test/dm/eth.c6
-rw-r--r--test/dm/fwu_mdata.c48
-rw-r--r--test/dm/net_defrag.c82
-rw-r--r--test/dm/part.c53
-rw-r--r--test/dm/phy_common_props.c319
-rw-r--r--test/dm/pmbus.c242
-rw-r--r--test/dm/regulator.c38
-rw-r--r--test/dm/reset.c107
-rw-r--r--test/dm/spi.c16
-rw-r--r--test/dm/sysinfo.c16
12 files changed, 932 insertions, 8 deletions
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 771b703b737..76aa1fff9ba 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_MULTIPLEXER) += mux-emul.o
obj-$(CONFIG_MUX_MMIO) += mux-mmio.o
obj-y += fdtdec.o
obj-$(CONFIG_MTD_RAW_NAND) += nand.o
+obj-$(CONFIG_IP_DEFRAG) += net_defrag.o
obj-$(CONFIG_UT_DM) += nop.o
obj-y += ofnode.o
obj-y += ofread.o
@@ -88,11 +89,13 @@ obj-$(CONFIG_P2SB) += p2sb.o
obj-$(CONFIG_PCI_ENDPOINT) += pci_ep.o
obj-$(CONFIG_PCH) += pch.o
obj-$(CONFIG_PHY) += phy.o
+obj-$(CONFIG_PHY_COMMON_PROPS) += phy_common_props.o
ifneq ($(CONFIG_PINMUX),)
obj-$(CONFIG_PINCONF) += pinmux.o
endif
obj-$(CONFIG_POWER_DOMAIN) += power-domain.o
obj-$(CONFIG_ACPI_PMC) += pmc.o
+obj-$(CONFIG_CMD_PMBUS) += pmbus.o
obj-$(CONFIG_DM_PMIC) += pmic.o
obj-$(CONFIG_DM_PWM) += pwm.o
obj-$(CONFIG_ARM_FFA_TRANSPORT) += ffa.o
diff --git a/test/dm/acpi.c b/test/dm/acpi.c
index 559ea269de2..293ea0274b5 100644
--- a/test/dm/acpi.c
+++ b/test/dm/acpi.c
@@ -136,7 +136,7 @@ static int testacpi_inject_dsdt(const struct udevice *dev, struct acpi_ctx *ctx)
return 0;
}
-struct acpi_ops testacpi_ops = {
+static const struct acpi_ops testacpi_ops = {
.get_name = testacpi_get_name,
.write_tables = testacpi_write_tables,
.fill_madt = testacpi_fill_madt,
@@ -374,14 +374,14 @@ static int dm_test_acpi_ctx_and_base_tables(struct unit_test_state *uts)
rsdt = PTR_ALIGN((void *)rsdp + sizeof(*rsdp), 16);
ut_asserteq_ptr(rsdt, ctx.rsdt);
ut_asserteq_mem("RSDT", rsdt->header.signature, ACPI_NAME_LEN);
- ut_asserteq(sizeof(*rsdt), rsdt->header.length);
- ut_assertok(table_compute_checksum(rsdt, sizeof(*rsdt)));
+ ut_asserteq(sizeof(struct acpi_table_header), rsdt->header.length);
+ ut_assertok(table_compute_checksum(rsdt, rsdt->header.length));
xsdt = PTR_ALIGN((void *)rsdt + sizeof(*rsdt), 16);
ut_asserteq_ptr(xsdt, ctx.xsdt);
ut_asserteq_mem("XSDT", xsdt->header.signature, ACPI_NAME_LEN);
- ut_asserteq(sizeof(*xsdt), xsdt->header.length);
- ut_assertok(table_compute_checksum(xsdt, sizeof(*xsdt)));
+ ut_asserteq(sizeof(struct acpi_table_header), xsdt->header.length);
+ ut_assertok(table_compute_checksum(xsdt, xsdt->header.length));
end = PTR_ALIGN((void *)xsdt + sizeof(*xsdt), 64);
ut_asserteq_ptr(end, ctx.current);
diff --git a/test/dm/eth.c b/test/dm/eth.c
index 1087ae9572d..ed0b57d8861 100644
--- a/test/dm/eth.c
+++ b/test/dm/eth.c
@@ -449,7 +449,7 @@ static int dm_test_net_retry(struct unit_test_state *uts)
}
DM_TEST(dm_test_net_retry, UTF_SCAN_FDT);
-#if CONFIG_IS_ENABLED(NET)
+#if CONFIG_IS_ENABLED(NET_LEGACY)
static int sb_check_arp_reply(struct udevice *dev, void *packet,
unsigned int len)
{
@@ -517,7 +517,7 @@ static int sb_with_async_arp_handler(struct udevice *dev, void *packet,
}
#endif
-#if CONFIG_IS_ENABLED(NET)
+#if CONFIG_IS_ENABLED(NET_LEGACY)
static int dm_test_eth_async_arp_reply(struct unit_test_state *uts)
{
net_ping_ip = string_to_ip("1.1.2.2");
@@ -537,7 +537,7 @@ static int dm_test_eth_async_arp_reply(struct unit_test_state *uts)
DM_TEST(dm_test_eth_async_arp_reply, UTF_SCAN_FDT);
#endif
-#if CONFIG_IS_ENABLED(NET)
+#if CONFIG_IS_ENABLED(NET_LEGACY)
static int sb_check_ping_reply(struct udevice *dev, void *packet,
unsigned int len)
{
diff --git a/test/dm/fwu_mdata.c b/test/dm/fwu_mdata.c
index cfe543d8a23..8624ccf61f7 100644
--- a/test/dm/fwu_mdata.c
+++ b/test/dm/fwu_mdata.c
@@ -143,3 +143,51 @@ static int dm_test_fwu_mdata_write(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_fwu_mdata_write, UTF_SCAN_FDT);
+
+static int dm_test_fwu_mdata_get_image_guid(struct unit_test_state *uts)
+{
+ efi_guid_t image_type_guid =
+ EFI_GUID(0x09d7cf52, 0x0720, 0x4710, \
+ 0x91, 0xd1, 0x08, 0x46, 0x9b, 0x7f, 0xe9, 0xc8);
+ efi_guid_t bank_0_image_guid =
+ EFI_GUID(0x10057a86, 0xdaf1, 0x4f93, \
+ 0xba, 0x7f, 0xb1, 0x95, 0xf7, 0xfa, 0x41, 0x70);
+ efi_guid_t bank_1_image_guid =
+ EFI_GUID(0xdb62ed3e, 0x6237, 0x4fb4, \
+ 0x80, 0xc4, 0x1b, 0x74, 0xd8, 0x46, 0xa8, 0xe7);
+ efi_guid_t wrong_image_type_guid =
+ EFI_GUID(0x12345678, 0x1302, 0x133f, \
+ 0x18, 0x0a, 0x14, 0x05, 0x18, 0x05, 0x14, 0x0b);
+ struct udevice *dev;
+ efi_guid_t image_guid;
+
+ ut_assertok(setup_blk_device(uts));
+ ut_assertok(populate_mmc_disk_image(uts));
+ ut_assertok(write_mmc_blk_device(uts));
+
+ /*
+ * Trigger lib/fwu_updates/fwu.c fwu_boottime_checks()
+ * to populate g_dev global pointer in that library.
+ */
+ ut_assertok(event_notify_null(EVT_POST_PREBOOT));
+
+ ut_assertok(uclass_first_device_err(UCLASS_FWU_MDATA, &dev));
+
+ ut_assertok(fwu_init());
+
+ ut_assertok(fwu_mdata_get_image_guid(&image_guid, &image_type_guid, 0));
+ ut_assertok(guidcmp(&image_guid, &bank_0_image_guid));
+
+ ut_assertok(fwu_mdata_get_image_guid(&image_guid, &image_type_guid, 1));
+ ut_assertok(guidcmp(&image_guid, &bank_1_image_guid));
+
+ ut_asserteq(-EINVAL, fwu_mdata_get_image_guid(&image_guid,
+ &image_type_guid, 2));
+
+ ut_asserteq(-ENOENT, fwu_mdata_get_image_guid(&image_guid,
+ &wrong_image_type_guid,
+ 0));
+
+ return 0;
+}
+DM_TEST(dm_test_fwu_mdata_get_image_guid, UTF_SCAN_FDT);
diff --git a/test/dm/net_defrag.c b/test/dm/net_defrag.c
new file mode 100644
index 00000000000..3fd40de90cd
--- /dev/null
+++ b/test/dm/net_defrag.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Regression test for IP fragment reassembly.
+ *
+ * The test drives the real RX path via net_process_received_packet(). Final IP
+ * fragment (MF=0) is duplicated, crafted payload triggers redelivery of the datagram,
+ * which fails the test for the unfixed code.
+ */
+
+#include <net.h>
+#include <string.h>
+#include <test/ut.h>
+#include <dm/test.h>
+
+#define FRAG_LEN (8)
+#define PAYLOAD_OFFSET (ETHER_HDR_SIZE + IP_HDR_SIZE)
+#define FRAME_LEN (PAYLOAD_OFFSET + FRAG_LEN)
+
+static int udp_rx_count;
+
+static void defrag_udp_handler(uchar *pkt, unsigned int dport,
+ struct in_addr sip, unsigned int sport,
+ unsigned int len)
+{
+ udp_rx_count++;
+}
+
+static int build_frag(uchar *buf, u16 off_flags, const u16 *payload)
+{
+ struct ethernet_hdr *et = (struct ethernet_hdr *)buf;
+ struct ip_udp_hdr *ip = (struct ip_udp_hdr *)(buf + ETHER_HDR_SIZE);
+
+ memset(buf, 0, FRAME_LEN);
+ et->et_protlen = htons(PROT_IP);
+
+ ip->ip_hl_v = 0x45;
+ ip->ip_len = htons(IP_HDR_SIZE + FRAG_LEN);
+ ip->ip_id = htons(0x4321);
+ ip->ip_off = htons(off_flags);
+ ip->ip_ttl = 64;
+ ip->ip_p = IPPROTO_UDP;
+ /* Broadcast destination is accepted regardless of net_ip. */
+ ip->ip_dst.s_addr = 0xffffffff;
+ ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE);
+
+ memcpy(buf + PAYLOAD_OFFSET, payload, FRAG_LEN);
+
+ return FRAME_LEN;
+}
+
+static int dm_test_net_ip_defrag_dup_last(struct unit_test_state *uts)
+{
+ rxhand_f *saved_handler = net_get_udp_handler();
+ uchar frame[FRAME_LEN];
+ /* UDP header, carried by first fragment. */
+ u16 udp_hdr[4] = { htons(5000), htons(5001),
+ htons(UDP_HDR_SIZE + FRAG_LEN), 0 };
+ /*
+ * Second fragment's payload doubles as a fake hole
+ * {last_byte >= FRAG_LEN, next_hole = 0, prev_hole = 0}, so that the
+ * buggy code re-reading it on a duplicate re-delivers the datagram.
+ */
+ u16 frag_b[4] = { 2 * FRAG_LEN, 0, 0, 0 };
+
+ udp_rx_count = 0;
+ net_set_udp_handler(defrag_udp_handler);
+
+ /* UDP header, offset 0, MF=1; then data, offset 1, MF=0 */
+ net_process_received_packet(frame, build_frag(frame, IP_FLAGS_MFRAG, udp_hdr));
+ net_process_received_packet(frame, build_frag(frame, 1, frag_b));
+ ut_asserteq(1, udp_rx_count);
+
+ /* Duplicate the final fragment: UDP datagram must not be delivered again. */
+ net_process_received_packet(frame, build_frag(frame, 1, frag_b));
+ ut_asserteq(1, udp_rx_count);
+
+ net_set_udp_handler(saved_handler);
+
+ return 0;
+}
+
+DM_TEST(dm_test_net_ip_defrag_dup_last, 0);
diff --git a/test/dm/part.c b/test/dm/part.c
index caae23bd4aa..ad37d7f406f 100644
--- a/test/dm/part.c
+++ b/test/dm/part.c
@@ -195,3 +195,56 @@ static int dm_test_part_get_info_by_type(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_part_get_info_by_type, UTF_SCAN_PDATA | UTF_SCAN_FDT);
+
+static int dm_test_part_get_info_by_uuid(struct unit_test_state *uts)
+{
+ struct disk_partition parts[] = {
+ {
+ .start = 48,
+ .size = 1,
+ .name = "test1",
+ .uuid = "c5bce7a2-03f0-4d03-9048-01ff23b9d527",
+ },
+ {
+ .start = 49,
+ .size = 1,
+ .name = "test2",
+ .uuid = "9df346e8-2c53-4cd8-b9ac-3af83f9a9b74",
+ },
+ };
+ char disk_guid[UUID_STR_LEN + 1] =
+ "8d60b397-1bb6-4d33-80ee-b1587d24c2f8";
+ struct blk_desc *mmc_dev_desc;
+ struct disk_partition info;
+ int part, i;
+
+ ut_asserteq(2, blk_get_device_by_str("mmc", "2", &mmc_dev_desc));
+
+ if (CONFIG_IS_ENABLED(RANDOM_UUID)) {
+ for (i = 0; i < ARRAY_SIZE(parts); i++)
+ gen_rand_uuid_str(parts[i].uuid, UUID_STR_FORMAT_STD);
+
+ gen_rand_uuid_str(disk_guid, UUID_STR_FORMAT_STD);
+ }
+
+ ut_assertok(gpt_restore(mmc_dev_desc, disk_guid, parts,
+ ARRAY_SIZE(parts)));
+
+ for (i = 0; i < ARRAY_SIZE(parts); i++) {
+ part = part_get_info_by_uuid(mmc_dev_desc, parts[i].uuid,
+ &info);
+
+ ut_asserteq(i + 1, part);
+ ut_asserteq_str(parts[i].name, info.name);
+ ut_asserteq(parts[i].start, info.start);
+ ut_asserteq(parts[i].size, info.size);
+ }
+
+ part = part_get_info_by_uuid(mmc_dev_desc,
+ "00000000-0000-0000-0000-000000000000",
+ &info);
+ ut_assert(part < 0);
+
+ return 0;
+}
+DM_TEST(dm_test_part_get_info_by_uuid, UTF_SCAN_PDATA | UTF_SCAN_FDT);
diff --git a/test/dm/phy_common_props.c b/test/dm/phy_common_props.c
new file mode 100644
index 00000000000..21f5042b7a0
--- /dev/null
+++ b/test/dm/phy_common_props.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * U-Boot sandbox DM tests for PHY common props
+ *
+ * Ported from Linux KUnit test:
+ * linux/drivers/phy/phy-common-props-test.c
+ *
+ * Copyright 2025-2026 NXP
+ */
+#include <dm.h>
+#include <dm/ofnode.h>
+#include <dm/test.h>
+#include <linux/bitops.h>
+#include <linux/phy/phy-common-props.h>
+#include <dt-bindings/phy/phy.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+/* --- RX polarity tests -------------------------------------------------- */
+
+/* Test: rx-polarity property is missing => default PHY_POL_NORMAL */
+static int dm_test_phy_common_props_rx_missing(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-missing");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ ut_asserteq(0, ret);
+ ut_asserteq(PHY_POL_NORMAL, val);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_rx_missing, UTF_SCAN_FDT);
+
+/* Test: rx-polarity has more values than rx-polarity-names => -EINVAL */
+static int dm_test_phy_common_props_rx_more_values(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-more-values");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ ut_asserteq(-EINVAL, ret);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_rx_more_values, UTF_SCAN_FDT);
+
+/* Test: rx-polarity has 1 value and rx-polarity-names does not exist */
+static int dm_test_phy_common_props_rx_single_value(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-single");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ ut_asserteq(0, ret);
+ ut_asserteq(PHY_POL_INVERT, val);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_rx_single_value, UTF_SCAN_FDT);
+
+/* Test: rx-polarity-names has more values than rx-polarity => -EINVAL */
+static int dm_test_phy_common_props_rx_more_names(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-more-names");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ ut_asserteq(-EINVAL, ret);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_rx_more_names, UTF_SCAN_FDT);
+
+/* Test: valid arrays, find polarity by mode name */
+static int dm_test_phy_common_props_rx_find_by_name(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-find-by-name");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ ut_asserteq(0, ret);
+ ut_asserteq(PHY_POL_NORMAL, val);
+
+ ret = phy_get_manual_rx_polarity(node, "2500base-x", &val);
+ ut_asserteq(0, ret);
+ ut_asserteq(PHY_POL_INVERT, val);
+
+ /* "usb-ss" has PHY_POL_AUTO; auto is supported here */
+ ret = phy_get_rx_polarity(node, "usb-ss", BIT(PHY_POL_AUTO),
+ PHY_POL_AUTO, &val);
+ ut_asserteq(0, ret);
+ ut_asserteq(PHY_POL_AUTO, val);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_rx_find_by_name, UTF_SCAN_FDT);
+
+/* Test: name not found, no "default" entry => -EINVAL */
+static int dm_test_phy_common_props_rx_no_default(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-no-default");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ ut_asserteq(-EINVAL, ret);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_rx_no_default, UTF_SCAN_FDT);
+
+/* Test: name not found, "default" entry exists => use default polarity */
+static int dm_test_phy_common_props_rx_with_default(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-with-default");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ ut_asserteq(0, ret);
+ ut_asserteq(PHY_POL_INVERT, val);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_rx_with_default, UTF_SCAN_FDT);
+
+/* Test: polarity value found but not in supported set => -EOPNOTSUPP */
+static int dm_test_phy_common_props_rx_unsupported(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-unsupported");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ ut_asserteq(-EOPNOTSUPP, ret);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_rx_unsupported, UTF_SCAN_FDT);
+
+/* --- TX polarity tests -------------------------------------------------- */
+
+/* Test: tx-polarity property is missing => default PHY_POL_NORMAL */
+static int dm_test_phy_common_props_tx_missing(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-missing");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ ut_asserteq(0, ret);
+ ut_asserteq(PHY_POL_NORMAL, val);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_tx_missing, UTF_SCAN_FDT);
+
+/* Test: tx-polarity has more values than tx-polarity-names => -EINVAL */
+static int dm_test_phy_common_props_tx_more_values(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-more-values");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ ut_asserteq(-EINVAL, ret);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_tx_more_values, UTF_SCAN_FDT);
+
+/* Test: tx-polarity has 1 value and tx-polarity-names does not exist */
+static int dm_test_phy_common_props_tx_single_value(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-single");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ ut_asserteq(0, ret);
+ ut_asserteq(PHY_POL_INVERT, val);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_tx_single_value, UTF_SCAN_FDT);
+
+/* Test: tx-polarity-names has more values than tx-polarity => -EINVAL */
+static int dm_test_phy_common_props_tx_more_names(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-more-names");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ ut_asserteq(-EINVAL, ret);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_tx_more_names, UTF_SCAN_FDT);
+
+/* Test: valid arrays, find polarity by mode name */
+static int dm_test_phy_common_props_tx_find_by_name(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-find-by-name");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ ut_asserteq(0, ret);
+ ut_asserteq(PHY_POL_NORMAL, val);
+
+ ret = phy_get_manual_tx_polarity(node, "2500base-x", &val);
+ ut_asserteq(0, ret);
+ ut_asserteq(PHY_POL_INVERT, val);
+
+ ret = phy_get_manual_tx_polarity(node, "1000base-x", &val);
+ ut_asserteq(0, ret);
+ ut_asserteq(PHY_POL_NORMAL, val);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_tx_find_by_name, UTF_SCAN_FDT);
+
+/* Test: name not found, no "default" entry => -EINVAL */
+static int dm_test_phy_common_props_tx_no_default(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-no-default");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ ut_asserteq(-EINVAL, ret);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_tx_no_default, UTF_SCAN_FDT);
+
+/* Test: name not found, "default" entry exists => use default polarity */
+static int dm_test_phy_common_props_tx_with_default(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-with-default");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ ut_asserteq(0, ret);
+ ut_asserteq(PHY_POL_INVERT, val);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_tx_with_default, UTF_SCAN_FDT);
+
+/* Test: polarity value found but not in supported set => -EOPNOTSUPP */
+static int dm_test_phy_common_props_tx_unsupported(struct unit_test_state *uts)
+{
+ ofnode node = ofnode_path("/phy-common-props-unsupported");
+ unsigned int val;
+ int ret;
+
+ ut_assert(ofnode_valid(node));
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ ut_asserteq(-EOPNOTSUPP, ret);
+
+ return 0;
+}
+
+DM_TEST(dm_test_phy_common_props_tx_unsupported, UTF_SCAN_FDT);
diff --git a/test/dm/pmbus.c b/test/dm/pmbus.c
new file mode 100644
index 00000000000..0184b201829
--- /dev/null
+++ b/test/dm/pmbus.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2026 Free Mobile - Vincent Jardin
+ *
+ * Unit tests for the PMBus 1.x framework, the generic
+ * PMBus regulator and the pmbus CLI command.
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <pmbus.h>
+#include <dm/test.h>
+#include <test/test.h>
+#include <test/ut.h>
+
+/* The line pmbus dev prints when a chip is selected */
+#define PMBUS_ACTIVE_LINE \
+ "pmbus: active i2c0:0x70 rail=\"sandbox-pmbus-vout\" " \
+ "MFR_ID=\"SANDBOX\" MODEL=\"PMBUS-EMUL\" vendor=(generic)"
+
+/* The line pmbus list prints for the bound chip */
+#define PMBUS_LIST_LINE \
+ " i2c0:0x70 rail=\"sandbox-pmbus-vout\" node=pmbus@70 " \
+ "driver=pmbus_generic_regulator"
+
+/* Select the emulated chip and check the resulting banner line */
+static int pmbus_select(struct unit_test_state *uts)
+{
+ ut_assertok(run_command("pmbus dev 0:70", 0));
+ ut_assert_nextline(PMBUS_ACTIVE_LINE);
+ return 0;
+}
+
+/* The chip is reachable via UCLASS_REGULATOR (compatible = "pmbus") */
+static int dm_test_pmbus_bind(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_REGULATOR, "pmbus@70",
+ &dev));
+ ut_asserteq_str("pmbus_generic_regulator", dev->driver->name);
+ ut_asserteq(UCLASS_I2C, device_get_uclass_id(dev_get_parent(dev)));
+
+ return 0;
+}
+
+DM_TEST(dm_test_pmbus_bind, UTF_SCAN_FDT);
+
+/* pmbus dev by <bus>:<addr> and by regulator-name select the chip */
+static int dm_test_pmbus_dev(struct unit_test_state *uts)
+{
+ ut_assertok(run_command("pmbus dev 0:70", 0));
+ ut_assert_nextline(PMBUS_ACTIVE_LINE);
+ ut_assert_console_end();
+
+ /* Selecting by DT regulator-name resolves to the same chip */
+ ut_assertok(run_command("pmbus dev sandbox-pmbus-vout", 0));
+ ut_assert_nextline(PMBUS_ACTIVE_LINE);
+ ut_assert_console_end();
+
+ /* pmbus dev with no argument reprints the active chip */
+ ut_assertok(run_command("pmbus dev", 0));
+ ut_assert_nextline(PMBUS_ACTIVE_LINE);
+ ut_assert_console_end();
+
+ return 0;
+}
+
+DM_TEST(dm_test_pmbus_dev, UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* pmbus list enumerates the bound chip among the UCLASS_REGULATOR devices */
+static int dm_test_pmbus_list(struct unit_test_state *uts)
+{
+ ut_assertok(run_command("pmbus list", 0));
+ ut_assert_skip_to_line(PMBUS_LIST_LINE);
+
+ return 0;
+}
+
+DM_TEST(dm_test_pmbus_list, UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* pmbus info decodes identification + the detected driver_info */
+static int dm_test_pmbus_info(struct unit_test_state *uts)
+{
+ ut_assertok(pmbus_select(uts));
+
+ ut_assertok(run_command("pmbus info", 0));
+ ut_assert_nextline("pmbus device i2c0:0x70");
+ ut_assert_nextline(" regulator-name: \"sandbox-pmbus-vout\"");
+ ut_assert_nextline(" MFR_ID : \"SANDBOX\"");
+ ut_assert_nextline(" MFR_MODEL : \"PMBUS-EMUL\"");
+ ut_assert_nextline(" MFR_REVISION : \"1.0\" raw=0x312e30");
+ ut_assert_nextline(" PMBUS_REVISION: 0x33 (PMBus 1.3)");
+ ut_assert_nextline(" vendor : (none)");
+ ut_assert_nextline(" driver_info : pages=1");
+ ut_assert_nextline(" [VOLTAGE_IN ] format=LINEAR");
+ ut_assert_nextline(" [VOLTAGE_OUT ] format=LINEAR");
+ ut_assert_nextline(" [CURRENT_IN ] format=LINEAR");
+ ut_assert_nextline(" [CURRENT_OUT ] format=LINEAR");
+ ut_assert_nextline(" [POWER ] format=LINEAR");
+ ut_assert_nextline(" [TEMPERATURE ] format=LINEAR");
+ ut_assert_console_end();
+
+ return 0;
+}
+
+DM_TEST(dm_test_pmbus_info, UTF_SCAN_FDT | UTF_CONSOLE);
+
+/*
+ * pmbus telemetry decodes the implemented sensors and prints
+ * "(not supported)" for the commands the emulator NAKs (READ_IIN,
+ * READ_POUT). LINEAR11 is used for VIN/IOUT/TEMP, LINEAR16 (with the
+ * VOUT_MODE 2^-8 exponent) for VOUT.
+ */
+static int dm_test_pmbus_telemetry(struct unit_test_state *uts)
+{
+ ut_assertok(pmbus_select(uts));
+
+ ut_assertok(run_command("pmbus telemetry", 0));
+ ut_assert_nextline("pmbus telemetry @ i2c0:0x70");
+ ut_assert_nextline(" VIN : raw=0x0abc 1400.000V");
+ ut_assert_nextline(" VOUT : raw=0x0200 2.000V");
+ ut_assert_nextline(" IIN : (not supported)");
+ ut_assert_nextline(" IOUT : raw=0x0123 291.000A");
+ ut_assert_nextline(" POUT : (not supported)");
+ ut_assert_nextline(" TEMP : raw=0x0019 25.000C");
+ ut_assert_console_end();
+
+ return 0;
+}
+
+DM_TEST(dm_test_pmbus_telemetry, UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* pmbus status decodes every STATUS_* register; the emulator is clean */
+static int dm_test_pmbus_status(struct unit_test_state *uts)
+{
+ ut_assertok(pmbus_select(uts));
+
+ ut_assertok(run_command("pmbus status", 0));
+ ut_assert_nextline("pmbus status @ i2c0:0x70");
+ ut_assert_nextline(" STATUS_WORD (79h) = 0x0000 [clean]");
+ ut_assert_nextline(" STATUS_VOUT (7Ah) = 0x00 [clean]");
+ ut_assert_nextline(" STATUS_IOUT (7Bh) = 0x00 [clean]");
+ ut_assert_nextline(" STATUS_INPUT (7Ch) = 0x00 [clean]");
+ ut_assert_nextline(" STATUS_TEMP (7Dh) = 0x00 [clean]");
+ ut_assert_nextline(" STATUS_CML (7Eh) = 0x00 [clean]");
+ ut_assert_console_end();
+
+ return 0;
+}
+
+DM_TEST(dm_test_pmbus_status, UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* pmbus read/pmbus write raw register access (byte, word, string) */
+static int dm_test_pmbus_read_write(struct unit_test_state *uts)
+{
+ ut_assertok(pmbus_select(uts));
+
+ /* Symbolic and numeric register names both resolve */
+ ut_assertok(run_command("pmbus read VOUT_MODE", 0));
+ ut_assert_nextline(" 20h VOUT_MODE b=0x18");
+ ut_assertok(run_command("pmbus read 8b w", 0));
+ ut_assert_nextline(" 8bh READ_VOUT w=0x0200");
+ ut_assertok(run_command("pmbus read MFR_ID s", 0));
+ ut_assert_nextline(" 99h MFR_ID s=\"SANDBOX\"");
+
+ /* A word write is observable on the next read-back */
+ ut_assertok(run_command("pmbus write VOUT_COMMAND 123 w", 0));
+ ut_assert_nextline("pmbus: wrote 0x123 to 21h (VOUT_COMMAND)");
+ ut_assertok(run_command("pmbus read VOUT_COMMAND w", 0));
+ ut_assert_nextline(" 21h VOUT_COMMAND w=0x0123");
+ ut_assert_console_end();
+
+ return 0;
+}
+
+DM_TEST(dm_test_pmbus_read_write, UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* pmbus vout reads back VOUT via the active driver_info decoder */
+static int dm_test_pmbus_vout(struct unit_test_state *uts)
+{
+ ut_assertok(pmbus_select(uts));
+
+ ut_assertok(run_command("pmbus vout", 0));
+ ut_assert_nextline("pmbus VOUT @ i2c0:0x70 raw=0x0200 2.000V");
+ ut_assert_console_end();
+
+ return 0;
+}
+
+DM_TEST(dm_test_pmbus_vout, UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* pmbus dump walks every standard register; spot-check one line */
+static int dm_test_pmbus_dump(struct unit_test_state *uts)
+{
+ ut_assertok(pmbus_select(uts));
+
+ ut_assertok(run_command("pmbus dump", 0));
+ ut_assert_nextline("pmbus dump @ i2c0:0x70 (registers known to <pmbus.h>)");
+ ut_assert_skip_to_line(" 20h VOUT_MODE b=0x18");
+
+ return 0;
+}
+
+DM_TEST(dm_test_pmbus_dump, UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* pmbus clear [faults] issues CLEAR_FAULTS (03h) */
+static int dm_test_pmbus_clear(struct unit_test_state *uts)
+{
+ ut_assertok(pmbus_select(uts));
+
+ ut_assertok(run_command("pmbus clear faults", 0));
+ ut_assert_nextline("pmbus: CLEAR_FAULTS (03h) issued (RAM sticky STATUS_* cleared)");
+ ut_assert_console_end();
+
+ return 0;
+}
+
+DM_TEST(dm_test_pmbus_clear, UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* pmbus scan finds the emulated chip by its MFR_ID block read */
+static int dm_test_pmbus_scan(struct unit_test_state *uts)
+{
+ ut_assertok(run_command("pmbus scan 0", 0));
+ ut_assert_skip_to_line(" i2c0:0x70 MFR_ID=\"SANDBOX\"");
+
+ return 0;
+}
+
+DM_TEST(dm_test_pmbus_scan, UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* pmbus help lists vendor extensions; none are registered here */
+static int dm_test_pmbus_help(struct unit_test_state *uts)
+{
+ ut_assertok(run_command("pmbus help", 0));
+ ut_assert_nextline("pmbus: no vendor extensions registered.");
+ ut_assert_skip_to_line(" board hook (boot snapshot) and re run 'pmbus help'.");
+
+ return 0;
+}
+
+DM_TEST(dm_test_pmbus_help, UTF_SCAN_FDT | UTF_CONSOLE);
diff --git a/test/dm/regulator.c b/test/dm/regulator.c
index 449748ad52f..51007d4079d 100644
--- a/test/dm/regulator.c
+++ b/test/dm/regulator.c
@@ -28,6 +28,7 @@ enum {
BUCK3,
LDO1,
LDO2,
+ LDO3,
OUTPUT_COUNT,
};
@@ -44,6 +45,7 @@ static const char *regulator_names[OUTPUT_COUNT][OUTPUT_NAME_COUNT] = {
{ SANDBOX_BUCK3_DEVNAME, SANDBOX_BUCK3_PLATNAME },
{ SANDBOX_LDO1_DEVNAME, SANDBOX_LDO1_PLATNAME},
{ SANDBOX_LDO2_DEVNAME, SANDBOX_LDO2_PLATNAME},
+ { SANDBOX_LDO3_DEVNAME, SANDBOX_LDO3_PLATNAME},
};
/* Test regulator get method */
@@ -118,6 +120,42 @@ static int dm_test_power_regulator_set_get_voltage(struct unit_test_state *uts)
}
DM_TEST(dm_test_power_regulator_set_get_voltage, UTF_SCAN_FDT);
+/* Test regulator set Voltage clamp method */
+static int dm_test_power_regulator_set_value_clamp(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+ const char *platname;
+
+ /* LDO3 have 'min' 1.8V and 'max' 3.3V */
+ platname = regulator_names[LDO3][PLATNAME];
+ ut_assertok(regulator_get_by_platname(platname, &dev));
+
+ /* 'target' in 'min'/'max' range - should not clamp voltage */
+ ut_assertok(regulator_set_value_clamp(dev, 1700000, 1800000, 1950000));
+ ut_asserteq(1800000, regulator_get_value(dev));
+ ut_assertok(regulator_set_value_clamp(dev, 2700000, 3300000, 3600000));
+ ut_asserteq(3300000, regulator_get_value(dev));
+
+ /* 'target' out of 'min'/'max' range - should clamp voltage */
+ ut_assertok(regulator_set_value_clamp(dev, 1700000, 1700000, 1950000));
+ ut_asserteq(1800000, regulator_get_value(dev));
+ ut_assertok(regulator_set_value_clamp(dev, 2700000, 3400000, 3600000));
+ ut_asserteq(3300000, regulator_get_value(dev));
+
+ /* 'min'/'max' out of range - should return -EINVAL */
+ ut_asserteq(-EINVAL,
+ regulator_set_value_clamp(dev, 1200000, 1500000, 1700000));
+ ut_asserteq(-EINVAL,
+ regulator_set_value_clamp(dev, 3500000, 4000000, 5000000));
+
+ /* 'min' higher than 'max' - should return -EINVAL */
+ ut_asserteq(-EINVAL,
+ regulator_set_value_clamp(dev, 3100000, 3000000, 2900000));
+
+ return 0;
+}
+DM_TEST(dm_test_power_regulator_set_value_clamp, UTF_SCAN_FDT);
+
/* Test regulator set and get Current method */
static int dm_test_power_regulator_set_get_current(struct unit_test_state *uts)
{
diff --git a/test/dm/reset.c b/test/dm/reset.c
index dceb6a1dad3..91fa7ff723b 100644
--- a/test/dm/reset.c
+++ b/test/dm/reset.c
@@ -19,6 +19,9 @@
/* This is the other reset phandle specifier handled by bulk */
#define OTHER_RESET_ID 2
+/* Line on reset-ctl-fallback (sandbox,reset-ctl-fallback-only); see test.dts */
+#define FALLBACK_RESET_ID 5
+
/* Base test of the reset uclass */
static int dm_test_reset_base(struct unit_test_state *uts)
{
@@ -120,6 +123,110 @@ static int dm_test_reset_devm(struct unit_test_state *uts)
}
DM_TEST(dm_test_reset_devm, UTF_SCAN_FDT);
+static int dm_test_reset_reset(struct unit_test_state *uts)
+{
+ struct udevice *dev_reset;
+ struct udevice *dev_test;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl",
+ &dev_reset));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test",
+ &dev_test));
+ ut_assertok(sandbox_reset_test_get(dev_test));
+
+ /* Verify reset_count starts at 0 */
+ ut_asserteq(0, sandbox_reset_get_count(dev_reset, TEST_RESET_ID));
+
+ ut_assertok(sandbox_reset_test_assert(dev_test));
+ ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+
+ ut_assertok(sandbox_reset_test_reset(dev_test));
+
+ /* Verify reset was pulsed (count incremented) */
+ ut_asserteq(1, sandbox_reset_get_count(dev_reset, TEST_RESET_ID));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+
+ ut_assertok(sandbox_reset_test_free(dev_test));
+
+ return 0;
+}
+DM_TEST(dm_test_reset_reset, UTF_SCAN_FDT);
+
+/*
+ * reset_reset() fallback path: controller has no rst_reset op, so the
+ * core does assert -> udelay -> deassert. rst_reset-only accounting
+ * (reset_count) stays zero. Leave the line asserted before reset_reset()
+ * so we verify the fallback actually pulses it back to deasserted.
+ */
+static int dm_test_reset_reset_fallback_path(struct unit_test_state *uts)
+{
+ struct udevice *dev_reset_fb;
+ struct udevice *dev_test;
+ struct reset_ctl ctl;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl-fallback",
+ &dev_reset_fb));
+ ut_asserteq(0, sandbox_reset_query(dev_reset_fb, FALLBACK_RESET_ID));
+ ut_asserteq(0, sandbox_reset_get_count(dev_reset_fb, FALLBACK_RESET_ID));
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test",
+ &dev_test));
+ ut_assertok(reset_get_by_name(dev_test, "fallback", &ctl));
+ ut_asserteq_ptr(ctl.dev, dev_reset_fb);
+ ut_asserteq(FALLBACK_RESET_ID, ctl.id);
+
+ ut_assertok(reset_assert(&ctl));
+ ut_asserteq(1, sandbox_reset_query(dev_reset_fb, FALLBACK_RESET_ID));
+ ut_asserteq(0, sandbox_reset_get_count(dev_reset_fb, FALLBACK_RESET_ID));
+
+ ut_assertok(reset_reset(&ctl, 1));
+ ut_asserteq(0, sandbox_reset_get_count(dev_reset_fb, FALLBACK_RESET_ID));
+ ut_asserteq(0, sandbox_reset_query(dev_reset_fb, FALLBACK_RESET_ID));
+
+ ut_assertok(reset_free(&ctl));
+
+ return 0;
+}
+DM_TEST(dm_test_reset_reset_fallback_path, UTF_SCAN_FDT);
+
+static int dm_test_reset_reset_bulk(struct unit_test_state *uts)
+{
+ struct udevice *dev_reset;
+ struct udevice *dev_test;
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl",
+ &dev_reset));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, OTHER_RESET_ID));
+
+ ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test",
+ &dev_test));
+ ut_assertok(sandbox_reset_test_get_bulk(dev_test));
+
+ /* Verify reset_count starts at 0 */
+ ut_asserteq(0, sandbox_reset_get_count(dev_reset, TEST_RESET_ID));
+ ut_asserteq(0, sandbox_reset_get_count(dev_reset, OTHER_RESET_ID));
+
+ ut_assertok(sandbox_reset_test_assert_bulk(dev_test));
+ ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_asserteq(1, sandbox_reset_query(dev_reset, OTHER_RESET_ID));
+
+ ut_assertok(sandbox_reset_test_reset_bulk(dev_test));
+
+ /* Verify resets were pulsed (counts incremented) */
+ ut_asserteq(1, sandbox_reset_get_count(dev_reset, TEST_RESET_ID));
+ ut_asserteq(1, sandbox_reset_get_count(dev_reset, OTHER_RESET_ID));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID));
+ ut_asserteq(0, sandbox_reset_query(dev_reset, OTHER_RESET_ID));
+
+ ut_assertok(sandbox_reset_test_release_bulk(dev_test));
+
+ return 0;
+}
+DM_TEST(dm_test_reset_reset_bulk, UTF_SCAN_FDT);
+
static int dm_test_reset_bulk(struct unit_test_state *uts)
{
struct udevice *dev_reset;
diff --git a/test/dm/spi.c b/test/dm/spi.c
index 249a9238fed..a89ba06274f 100644
--- a/test/dm/spi.c
+++ b/test/dm/spi.c
@@ -170,6 +170,22 @@ static int dm_test_spi_claim_bus(struct unit_test_state *uts)
}
DM_TEST(dm_test_spi_claim_bus, UTF_SCAN_PDATA | UTF_SCAN_FDT);
+static int dm_test_spi_set_wordlen(struct unit_test_state *uts)
+{
+ struct spi_slave *slave;
+ struct udevice *bus;
+ const int busnum = 0, cs = 0;
+
+ ut_assertok(spi_get_bus_and_cs(busnum, cs, &bus, &slave));
+ ut_assertok(spi_set_wordlen(slave, 8));
+ ut_asserteq(8, sandbox_spi_get_wordlen(slave->dev));
+ ut_assertok(spi_set_wordlen(slave, 9));
+ ut_asserteq(9, sandbox_spi_get_wordlen(slave->dev));
+
+ return 0;
+}
+DM_TEST(dm_test_spi_set_wordlen, UTF_SCAN_PDATA | UTF_SCAN_FDT);
+
/* Test that sandbox SPI works correctly */
static int dm_test_spi_xfer(struct unit_test_state *uts)
{
diff --git a/test/dm/sysinfo.c b/test/dm/sysinfo.c
index 14ebe6b42e7..611f2e98d14 100644
--- a/test/dm/sysinfo.c
+++ b/test/dm/sysinfo.c
@@ -66,3 +66,19 @@ static int dm_test_sysinfo(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_sysinfo, UTF_SCAN_PDATA | UTF_SCAN_FDT);
+
+static int dm_test_sysinfo_get_and_detect(struct unit_test_state *uts)
+{
+ struct udevice *sysinfo;
+ bool called_detect = false;
+
+ ut_assertok(sysinfo_get_and_detect(&sysinfo));
+ ut_assert(sysinfo);
+
+ ut_assertok(sysinfo_get_bool(sysinfo, BOOL_CALLED_DETECT,
+ &called_detect));
+ ut_assert(called_detect);
+
+ return 0;
+}
+DM_TEST(dm_test_sysinfo_get_and_detect, UTF_SCAN_PDATA | UTF_SCAN_FDT);