[PATCH v4 3/3] test: dm: add PHY common props unit tests and sandbox DT nodes

Lucien.Jheng lucienzx159 at gmail.com
Sat Apr 25 10:06:49 CEST 2026


Add sandbox DM unit tests for the PHY common properties library and the
corresponding device tree test nodes to arch/sandbox/dts/test.dts.
Also enable CONFIG_PHY_COMMON_PROPS in configs/sandbox_defconfig so
the tests are built and run in the sandbox environment.

The test file covers rx/tx polarity lookups for all relevant cases:

  - missing property (defaults to PHY_POL_NORMAL)
  - single value without names array (applies to all modes)
  - count mismatch between values and names arrays (-EINVAL)
  - name found by exact match
  - name not found with no "default" fallback (-EINVAL)
  - name not found with a "default" entry (uses fallback value)
  - unsupported polarity value (-EOPNOTSUPP)

Ported from Linux KUnit test:
  linux/drivers/phy/phy-common-props-test.c

Signed-off-by: Lucien.Jheng <lucienzx159 at gmail.com>
---
``` execute phy common props tests in sandbox:
Bloblist at 100 not found (err=-2)
pinctrl_select_state_full() sandbox_serial serial: pinctrl_select_state_full: uclass_get_device_by_phandle_id: err=-19


U-Boot 2026.01-rc5--gd1a76e2e4a64-dirty (Apr 25 2026 - 15:40:39 +0800)

Reset Status: WARM Reset Status: COLD
Model: sandbox
DRAM:  256 MiB
Core:  294 devices, 105 uclasses, devicetree: board, universal payload active
WDT:   Not starting wdt-gpio-toggle
WDT:   Not starting wdt-gpio-level
WDT:   Not starting wdt at 0
NAND:  4100 MiB
MMC:   Can't map file 'mmc1.img': Invalid argument
   sandbox_mmc_probe() mmc1: Unable to map file 'mmc1.img'
Can't map file 'mmc1.img': Invalid argument
   sandbox_mmc_probe() mmc1: Unable to map file 'mmc1.img'
           mmc_probe() mmc1 - probe failed: -1
mmc2: 2 (SD)Can't map file 'mmc1.img': Invalid argument
   sandbox_mmc_probe() mmc1: Unable to map file 'mmc1.img'
, mmc0: 0 (SD)
Loading Environment from nowhere... OK
In:    serial
Out:   serial,vidconsole
Err:   serial,vidconsole
Model: sandbox
Net:   eth0: eth at 10002000, eth5: eth at 10003000, eth3: sbe5, eth6: eth at 10004000, eth8: phy-test-eth, eth4: dsa-test-eth, eth2: lan0, eth7: lan1

Test: phy_common_props_rx_find_by_name: phy_common_props.c
Test: phy_common_props_rx_find_by_name: phy_common_props.c (flat tree)
Test: phy_common_props_rx_missing: phy_common_props.c
Test: phy_common_props_rx_missing: phy_common_props.c (flat tree)
Test: phy_common_props_rx_more_names: phy_common_props.c
Test: phy_common_props_rx_more_names: phy_common_props.c (flat tree)
Test: phy_common_props_rx_more_values: phy_common_props.c
Test: phy_common_props_rx_more_values: phy_common_props.c (flat tree)
Test: phy_common_props_rx_no_default: phy_common_props.c
Test: phy_common_props_rx_no_default: phy_common_props.c (flat tree)
Test: phy_common_props_rx_single_value: phy_common_props.c
Test: phy_common_props_rx_single_value: phy_common_props.c (flat tree)
Test: phy_common_props_rx_unsupported: phy_common_props.c
Test: phy_common_props_rx_unsupported: phy_common_props.c (flat tree)
Test: phy_common_props_rx_with_default: phy_common_props.c
Test: phy_common_props_rx_with_default: phy_common_props.c (flat tree)
Test: phy_common_props_tx_find_by_name: phy_common_props.c
Test: phy_common_props_tx_find_by_name: phy_common_props.c (flat tree)
Test: phy_common_props_tx_missing: phy_common_props.c
Test: phy_common_props_tx_missing: phy_common_props.c (flat tree)
Test: phy_common_props_tx_more_names: phy_common_props.c
Test: phy_common_props_tx_more_names: phy_common_props.c (flat tree)
Test: phy_common_props_tx_more_values: phy_common_props.c
Test: phy_common_props_tx_more_values: phy_common_props.c (flat tree)
Test: phy_common_props_tx_no_default: phy_common_props.c
Test: phy_common_props_tx_no_default: phy_common_props.c (flat tree)
Test: phy_common_props_tx_single_value: phy_common_props.c
Test: phy_common_props_tx_single_value: phy_common_props.c (flat tree)
Test: phy_common_props_tx_unsupported: phy_common_props.c
Test: phy_common_props_tx_unsupported: phy_common_props.c (flat tree)
Test: phy_common_props_tx_with_default: phy_common_props.c
Test: phy_common_props_tx_with_default: phy_common_props.c (flat tree)
Tests run: 16, 41 ms, average: 2 ms, failures: 0

 arch/sandbox/dts/test.dts  |  60 +++++++
 configs/sandbox_defconfig  |   1 +
 test/dm/Makefile           |   1 +
 test/dm/phy_common_props.c | 319 +++++++++++++++++++++++++++++++++++++
 4 files changed, 381 insertions(+)
 create mode 100644 test/dm/phy_common_props.c

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index ac92ebf1afd..0887de4333b 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -16,6 +16,7 @@
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/pinctrl/sandbox-pinmux.h>
 #include <dt-bindings/mux/mux.h>
+#include <dt-bindings/phy/phy.h>

 / {
 	model = "sandbox";
@@ -502,6 +503,65 @@
 		phy-names = "phy1";
 	};

+	/* PHY common props test nodes */
+	phy_common_props_missing: phy-common-props-missing {
+		/* empty: no rx-polarity or tx-polarity properties */
+	};
+
+	phy_common_props_more_values: phy-common-props-more-values {
+		/* 3 values but only 2 names => count mismatch */
+		rx-polarity = <PHY_POL_NORMAL PHY_POL_INVERT PHY_POL_NORMAL>;
+		rx-polarity-names = "sgmii", "2500base-x";
+		tx-polarity = <PHY_POL_NORMAL PHY_POL_INVERT PHY_POL_NORMAL>;
+		tx-polarity-names = "sgmii", "2500base-x";
+	};
+
+	phy_common_props_single: phy-common-props-single {
+		/* 1 value, no names array => value applies to all modes */
+		rx-polarity = <PHY_POL_INVERT>;
+		tx-polarity = <PHY_POL_INVERT>;
+	};
+
+	phy_common_props_more_names: phy-common-props-more-names {
+		/* 2 values but 3 names => count mismatch */
+		rx-polarity = <PHY_POL_NORMAL PHY_POL_INVERT>;
+		rx-polarity-names = "sgmii", "2500base-x", "1000base-x";
+		tx-polarity = <PHY_POL_NORMAL PHY_POL_INVERT>;
+		tx-polarity-names = "sgmii", "2500base-x", "1000base-x";
+	};
+
+	phy_common_props_find_by_name: phy-common-props-find-by-name {
+		/* valid 3-element arrays, lookup by mode name */
+		rx-polarity = <PHY_POL_NORMAL PHY_POL_INVERT PHY_POL_AUTO>;
+		rx-polarity-names = "sgmii", "2500base-x", "usb-ss";
+		tx-polarity = <PHY_POL_NORMAL PHY_POL_INVERT PHY_POL_NORMAL>;
+		tx-polarity-names = "sgmii", "2500base-x", "1000base-x";
+	};
+
+	phy_common_props_no_default: phy-common-props-no-default {
+		/* name not in array, no "default" entry => -EINVAL */
+		rx-polarity = <PHY_POL_NORMAL PHY_POL_INVERT>;
+		rx-polarity-names = "2500base-x", "1000base-x";
+		tx-polarity = <PHY_POL_NORMAL PHY_POL_INVERT>;
+		tx-polarity-names = "2500base-x", "1000base-x";
+	};
+
+	phy_common_props_with_default: phy-common-props-with-default {
+		/* name not in array, but "default" entry exists */
+		rx-polarity = <PHY_POL_NORMAL PHY_POL_INVERT>;
+		rx-polarity-names = "2500base-x", "default";
+		tx-polarity = <PHY_POL_NORMAL PHY_POL_INVERT>;
+		tx-polarity-names = "2500base-x", "default";
+	};
+
+	phy_common_props_unsupported: phy-common-props-unsupported {
+		/* PHY_POL_AUTO is not supported for manual-only modes */
+		rx-polarity = <PHY_POL_AUTO>;
+		rx-polarity-names = "sgmii";
+		tx-polarity = <PHY_POL_AUTO>;
+		tx-polarity-names = "sgmii";
+	};
+
 	some-bus {
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index b681b91c3f9..487bb3ec03c 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -284,6 +284,7 @@ CONFIG_PCI_REGION_MULTI_ENTRY=y
 CONFIG_PCI_FTPCI100=y
 CONFIG_PCI_SANDBOX=y
 CONFIG_PHY=y
+CONFIG_PHY_COMMON_PROPS=y
 CONFIG_PHY_SANDBOX=y
 CONFIG_PINCTRL=y
 CONFIG_PINCONF=y
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 771b703b737..d69b0e08d66 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -88,6 +88,7 @@ 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
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);
--
2.34.1



More information about the U-Boot mailing list