Add a new PHY_COMMON_PROPS library that provides helper functions for
PHY drivers to read standardized polarity properties from the device
tree node:

  - phy_get_rx_polarity() / phy_get_tx_polarity()
  - phy_get_manual_rx_polarity() / phy_get_manual_tx_polarity()

Also add include/dt-bindings/phy/phy.h with PHY_POL_NORMAL,
PHY_POL_INVERT, and PHY_POL_AUTO constants for use in device trees.

Ported from Merge tag 'phy-for-7.0':
  git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy

Link: https://git.kernel.org/linus/e7556b59ba65179612bce3fa56bb53d1b4fb20db
Signed-off-by: Lucien.Jheng <[email protected]>
---
 drivers/phy/Kconfig                  |   8 +
 drivers/phy/Makefile                 |   1 +
 drivers/phy/phy-common-props.c       | 286 +++++++++++++++++++++++++++
 include/dt-bindings/phy/phy.h        |  32 +++
 include/linux/phy/phy-common-props.h |  70 +++++++
 5 files changed, 397 insertions(+)
 create mode 100644 drivers/phy/phy-common-props.c
 create mode 100644 include/dt-bindings/phy/phy.h
 create mode 100644 include/linux/phy/phy-common-props.h

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 87729b479bd..9a6d56a7fdc 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -329,4 +329,12 @@ source "drivers/phy/qcom/Kconfig"
 source "drivers/phy/renesas/Kconfig"
 source "drivers/phy/starfive/Kconfig"
 
+config PHY_COMMON_PROPS
+       bool "Common PHY properties support"
+       help
+         Enable support for common PHY properties defined in the device tree,
+         such as rx-polarity and tx-polarity. This provides helpers for PHY
+         drivers to read polarity and other standard PHY properties from the
+         device tree node.
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 5a6df0ecfeb..bbf795bd478 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o
 obj-$(CONFIG_$(PHASE_)PHY_IMX8MQ_USB) += phy-imx8mq-usb.o
 obj-$(CONFIG_PHY_IMX8M_PCIE) += phy-imx8m-pcie.o
 obj-$(CONFIG_PHY_XILINX_ZYNQMP) += phy-zynqmp.o
+obj-$(CONFIG_PHY_COMMON_PROPS) += phy-common-props.o
 obj-y += cadence/
 obj-y += ti/
 obj-y += qcom/
diff --git a/drivers/phy/phy-common-props.c b/drivers/phy/phy-common-props.c
new file mode 100644
index 00000000000..e02051e53b4
--- /dev/null
+++ b/drivers/phy/phy-common-props.c
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * phy-common-props.c  --  Common PHY properties
+ *
+ * Copyright 2025-2026 NXP
+ * Ported to U-Boot 2026
+ */
+#include <dm/ofnode.h>
+#include <log.h>
+#include <malloc.h>
+#include <linux/phy/phy-common-props.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+
+/**
+ * ofnode_count_u32_prop - Count number of u32 elements in a property
+ * @node: Device tree node
+ * @propname: Property name
+ *
+ * Return: number of u32 elements, or negative error code
+ */
+static int ofnode_count_u32_prop(ofnode node, const char *propname)
+{
+       int size;
+
+       size = ofnode_read_size(node, propname);
+       if (size < 0) {
+               pr_debug("%s: property '%s' not found (err=%d)\n",
+                        __func__, propname, size);
+               return size;
+       }
+
+       pr_debug("%s: property '%s' has %zu bytes (%zu elements)\n",
+                __func__, propname, (size_t)size, (size_t)(size / 
sizeof(u32)));
+
+       return size / sizeof(u32);
+}
+
+/**
+ * ofnode_get_u32_prop_for_name - Find u32 property by name, or default value
+ * @node: Device tree node; if invalid or @props_title is absent, -ENOENT is 
returned
+ * @name: Property name used as lookup key in @names_title (must not be NULL)
+ * @props_title: Name of u32 array property holding values
+ * @names_title: Name of string array property holding lookup keys
+ * @default_val: Default value if @props_title exists but is empty
+ * @val: Pointer to store the returned value
+ *
+ * This function retrieves a u32 value from @props_title based on a name lookup
+ * in @names_title. The value stored in @val is determined as follows:
+ *
+ * - If @node is invalid or @props_title is absent: -ENOENT is returned
+ * - If @props_title exists but is empty: @default_val is used
+ * - If @props_title has exactly one element and @names_title is empty:
+ *   that element is used
+ * - Otherwise: @val is set to the element at the same index where @name is
+ *   found in @names_title.
+ * - If @name is not found, the function looks for a "default" entry in
+ *   @names_title and uses the corresponding value from @props_title
+ *
+ * When both @props_title and @names_title are present, they must have the
+ * same number of elements (except when @props_title has exactly one element).
+ *
+ * Return: zero on success, negative error on failure.
+ */
+static int ofnode_get_u32_prop_for_name(ofnode node, const char *name,
+                                       const char *props_title,
+                                       const char *names_title,
+                                       unsigned int default_val,
+                                       unsigned int *val)
+{
+       int err, n_props, n_names, idx;
+       u32 *props;
+
+       if (!name) {
+               printf("Error: Lookup key inside \"%s\" is mandatory\n",
+                      names_title);
+               return -EINVAL;
+       }
+
+       pr_debug("%s: looking up '%s' in props='%s' names='%s' default=%u\n",
+                __func__, name, props_title, names_title, default_val);
+
+       n_props = ofnode_count_u32_prop(node, props_title);
+       if (n_props < 0) {
+               /* property is absent */
+               pr_debug("%s: '%s' is absent, returning -ENOENT\n",
+                        __func__, props_title);
+               return -ENOENT;
+       }
+       if (n_props == 0) {
+               /* property exists but is empty, use default */
+               pr_debug("%s: '%s' is empty, using default value %u\n",
+                        __func__, props_title, default_val);
+               *val = default_val;
+               return 0;
+       }
+
+       n_names = ofnode_read_string_count(node, names_title);
+
+       pr_debug("%s: '%s' has %d elements, '%s' has %d entries\n",
+                __func__, props_title, n_props, names_title, n_names);
+       if (n_names >= 0 && n_props != n_names) {
+               printf("Error: mismatch between \"%s\" and \"%s\" property 
count (%d vs %d)\n",
+                      props_title, names_title, n_props, n_names);
+               return -EINVAL;
+       }
+
+       idx = ofnode_stringlist_search(node, names_title, name);
+       if (idx >= 0) {
+               pr_debug("%s: found '%s' at index %d in '%s'\n",
+                        __func__, name, idx, names_title);
+       } else {
+               pr_debug("%s: '%s' not found in '%s', trying 'default'\n",
+                        __func__, name, names_title);
+               idx = ofnode_stringlist_search(node, names_title, "default");
+               if (idx >= 0)
+                       pr_debug("%s: 'default' entry found at index %d\n",
+                                __func__, idx);
+               else
+                       pr_debug("%s: 'default' entry not found in '%s'\n",
+                                __func__, names_title);
+       }
+       /*
+        * If the mode name is missing, it can only mean the specified property
+        * is the default one for all modes, so reject any other property count
+        * than 1.
+        */
+       if (idx < 0 && n_props != 1) {
+               printf("Error: \"%s\" property has %d elements, but cannot find 
\"%s\" in \"%s\" and there is no default value\n",
+                      props_title, n_props, name, names_title);
+               return -EINVAL;
+       }
+
+       if (n_props == 1) {
+               pr_debug("%s: single-element '%s', reading directly\n",
+                        __func__, props_title);
+               err = ofnode_read_u32(node, props_title, val);
+               if (err) {
+                       pr_debug("%s: failed to read '%s' (err=%d)\n",
+                                __func__, props_title, err);
+                       return err;
+               }
+               pr_debug("%s: resolved value %u for name '%s' from '%s'\n",
+                        __func__, *val, name, props_title);
+               return 0;
+       }
+
+       /* We implicitly know idx >= 0 here */
+       props = calloc(n_props, sizeof(*props));
+       if (!props)
+               return -ENOMEM;
+
+       err = ofnode_read_u32_array(node, props_title, props, n_props);
+       if (err >= 0) {
+               *val = props[idx];
+               pr_debug("%s: resolved value %u at index %d for name '%s' from 
'%s'\n",
+                        __func__, *val, idx, name, props_title);
+       } else {
+               pr_debug("%s: failed to read u32 array '%s' (err=%d)\n",
+                        __func__, props_title, err);
+       }
+
+       free(props);
+
+       return err;
+}
+
+/**
+ * phy_get_polarity_for_mode - Get polarity for a specific PHY mode
+ * @node: Device tree node
+ * @mode_name: The name of the PHY mode to look up
+ * @supported: Bit mask of supported polarity values
+ * @default_val: Default polarity value if property is missing
+ * @polarity_prop: Name of the polarity property
+ * @names_prop: Name of the names property
+ * @val: Pointer to returned polarity
+ *
+ * Return: zero on success, negative error on failure.
+ */
+static int phy_get_polarity_for_mode(ofnode node, const char *mode_name,
+                                    unsigned int supported,
+                                    unsigned int default_val,
+                                    const char *polarity_prop,
+                                    const char *names_prop,
+                                    unsigned int *val)
+{
+       int err;
+
+       pr_debug("%s: querying '%s' for mode '%s' (supported=0x%x, 
default=%u)\n",
+                __func__, polarity_prop, mode_name, supported, default_val);
+
+       err = ofnode_get_u32_prop_for_name(node, mode_name, polarity_prop,
+                                          names_prop, default_val, val);
+       if (err) {
+               pr_debug("%s: '%s' lookup failed for mode '%s' (err=%d)\n",
+                        __func__, polarity_prop, mode_name, err);
+               return err;
+       }
+
+       pr_debug("%s: '%s' for mode '%s' = %u\n",
+                __func__, polarity_prop, mode_name, *val);
+
+       if (!(supported & BIT(*val))) {
+               printf("Error: %d is not a supported value for '%s' element 
'%s'\n",
+                      *val, polarity_prop, mode_name);
+               err = -EOPNOTSUPP;
+       }
+
+       return err;
+}
+
+/**
+ * phy_get_rx_polarity - Get RX polarity for PHY differential lane
+ * @node: Pointer to the PHY's device tree node.
+ * @mode_name: The name of the PHY mode to look up.
+ * @supported: Bit mask of PHY_POL_NORMAL, PHY_POL_INVERT and PHY_POL_AUTO
+ * @default_val: Default polarity value if property is missing
+ * @val: Pointer to returned polarity.
+ *
+ * Return: zero on success, negative error on failure.
+ */
+int phy_get_rx_polarity(ofnode node, const char *mode_name,
+                       unsigned int supported, unsigned int default_val,
+                       unsigned int *val)
+{
+       return phy_get_polarity_for_mode(node, mode_name, supported,
+                                        default_val, "rx-polarity",
+                                        "rx-polarity-names", val);
+}
+
+/**
+ * phy_get_tx_polarity - Get TX polarity for PHY differential lane
+ * @node: Pointer to the PHY's device tree node.
+ * @mode_name: The name of the PHY mode to look up.
+ * @supported: Bit mask of PHY_POL_NORMAL, PHY_POL_INVERT and PHY_POL_AUTO
+ * @default_val: Default polarity value if property is missing
+ * @val: Pointer to returned polarity.
+ *
+ * Return: zero on success, negative error on failure.
+ */
+int phy_get_tx_polarity(ofnode node, const char *mode_name,
+                       unsigned int supported, unsigned int default_val,
+                       unsigned int *val)
+{
+       return phy_get_polarity_for_mode(node, mode_name, supported,
+                                        default_val, "tx-polarity",
+                                        "tx-polarity-names", val);
+}
+
+/**
+ * phy_get_manual_rx_polarity - Get manual RX polarity for PHY differential 
lane
+ * @node: Pointer to the PHY's device tree node.
+ * @mode_name: The name of the PHY mode to look up.
+ * @val: Pointer to returned polarity.
+ *
+ * Helper for PHYs which do not support protocols with automatic RX polarity
+ * detection and correction.
+ *
+ * Return: zero on success, negative error on failure.
+ */
+int phy_get_manual_rx_polarity(ofnode node, const char *mode_name,
+                              unsigned int *val)
+{
+       return phy_get_rx_polarity(node, mode_name,
+                                  BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
+                                  PHY_POL_NORMAL, val);
+}
+
+/**
+ * phy_get_manual_tx_polarity - Get manual TX polarity for PHY differential 
lane
+ * @node: Pointer to the PHY's device tree node.
+ * @mode_name: The name of the PHY mode to look up.
+ * @val: Pointer to returned polarity.
+ *
+ * Helper for PHYs without any custom default value for the TX polarity.
+ *
+ * Return: zero on success, negative error on failure.
+ */
+int phy_get_manual_tx_polarity(ofnode node, const char *mode_name,
+                              unsigned int *val)
+{
+       return phy_get_tx_polarity(node, mode_name,
+                                  BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
+                                  PHY_POL_NORMAL, val);
+}
diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
new file mode 100644
index 00000000000..56b5c57a84c
--- /dev/null
+++ b/include/dt-bindings/phy/phy.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
+/*
+ *
+ * This header provides constants for the phy framework
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ * Author: Gabriel Fernandez <[email protected]>
+ */
+
+#ifndef _DT_BINDINGS_PHY
+#define _DT_BINDINGS_PHY
+
+#define PHY_NONE               0
+#define PHY_TYPE_SATA          1
+#define PHY_TYPE_PCIE          2
+#define PHY_TYPE_USB2          3
+#define PHY_TYPE_USB3          4
+#define PHY_TYPE_UFS           5
+#define PHY_TYPE_DP            6
+#define PHY_TYPE_XPCS          7
+#define PHY_TYPE_SGMII         8
+#define PHY_TYPE_QSGMII                9
+#define PHY_TYPE_DPHY          10
+#define PHY_TYPE_CPHY          11
+#define PHY_TYPE_USXGMII       12
+#define PHY_TYPE_XAUI          13
+
+#define PHY_POL_NORMAL         0
+#define PHY_POL_INVERT         1
+#define PHY_POL_AUTO           2
+
+#endif /* _DT_BINDINGS_PHY */
diff --git a/include/linux/phy/phy-common-props.h 
b/include/linux/phy/phy-common-props.h
new file mode 100644
index 00000000000..77158f3e5f1
--- /dev/null
+++ b/include/linux/phy/phy-common-props.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * phy-common-props.h -- Common properties for generic PHYs
+ *
+ * Copyright 2025-2026 NXP
+ * Ported to U-Boot 2026
+ */
+
+#ifndef __PHY_COMMON_PROPS_H
+#define __PHY_COMMON_PROPS_H
+
+#include <dt-bindings/phy/phy.h>
+#include <dm/ofnode.h>
+
+/**
+ * phy_get_rx_polarity - Get RX polarity for PHY differential lane
+ * @node: Pointer to the PHY's device tree node.
+ * @mode_name: The name of the PHY mode to look up.
+ * @supported: Bit mask of PHY_POL_NORMAL, PHY_POL_INVERT and PHY_POL_AUTO
+ * @default_val: Default polarity value if property is missing
+ * @val: Pointer to returned polarity.
+ *
+ * Return: zero on success, negative error on failure.
+ */
+int phy_get_rx_polarity(ofnode node, const char *mode_name,
+                       unsigned int supported, unsigned int default_val,
+                       unsigned int *val);
+
+/**
+ * phy_get_tx_polarity - Get TX polarity for PHY differential lane
+ * @node: Pointer to the PHY's device tree node.
+ * @mode_name: The name of the PHY mode to look up.
+ * @supported: Bit mask of PHY_POL_NORMAL, PHY_POL_INVERT and PHY_POL_AUTO
+ * @default_val: Default polarity value if property is missing
+ * @val: Pointer to returned polarity.
+ *
+ * Return: zero on success, negative error on failure.
+ */
+int phy_get_tx_polarity(ofnode node, const char *mode_name,
+                       unsigned int supported, unsigned int default_val,
+                       unsigned int *val);
+
+/**
+ * phy_get_manual_rx_polarity - Get manual RX polarity for PHY differential 
lane
+ * @node: Pointer to the PHY's device tree node.
+ * @mode_name: The name of the PHY mode to look up.
+ * @val: Pointer to returned polarity.
+ *
+ * Helper for PHYs which do not support protocols with automatic RX polarity
+ * detection and correction.
+ *
+ * Return: zero on success, negative error on failure.
+ */
+int phy_get_manual_rx_polarity(ofnode node, const char *mode_name,
+                              unsigned int *val);
+
+/**
+ * phy_get_manual_tx_polarity - Get manual TX polarity for PHY differential 
lane
+ * @node: Pointer to the PHY's device tree node.
+ * @mode_name: The name of the PHY mode to look up.
+ * @val: Pointer to returned polarity.
+ *
+ * Helper for PHYs without any custom default value for the TX polarity.
+ *
+ * Return: zero on success, negative error on failure.
+ */
+int phy_get_manual_tx_polarity(ofnode node, const char *mode_name,
+                              unsigned int *val);
+
+#endif /* __PHY_COMMON_PROPS_H */
-- 
2.34.1

Reply via email to