Add helpers in the generic PHY folder which can be used using 'select GENERIC_PHY_COMMON_PROPS' from Kconfig, without otherwise needing to enable GENERIC_PHY. These helpers need to deal with the slight messiness of the fact that the polarity properties are arrays per protocol, and with the fact that there is no default value mandated by the standard properties, all default values depend on driver and protocol (PHY_POL_NORMAL may be a good default for SGMII, whereas PHY_POL_AUTO may be a good default for PCIe). Push the supported mask of polarities to these helpers, to simplify drivers such that they don't need to validate what's in the device tree (or other firmware description). The proposed maintainership model is joint custody between netdev and linux-phy, because of the fact that these properties can be applied to Ethernet PCS blocks just as well as Generic PHY devices. I've added as maintainers those from "ETHERNET PHY LIBRARY", "NETWORKING DRIVERS" and "GENERIC PHY FRAMEWORK". Signed-off-by: Vladimir Oltean --- MAINTAINERS | 21 +++++ drivers/phy/Kconfig | 9 +++ drivers/phy/Makefile | 1 + drivers/phy/phy-common-props.c | 117 +++++++++++++++++++++++++++ include/linux/phy/phy-common-props.h | 20 +++++ 5 files changed, 168 insertions(+) create mode 100644 drivers/phy/phy-common-props.c create mode 100644 include/linux/phy/phy-common-props.h diff --git a/MAINTAINERS b/MAINTAINERS index e9a8d945632b..658feb06cc29 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10445,6 +10445,27 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git F: include/asm-generic/ F: include/uapi/asm-generic/ +GENERIC PHY COMMON PROPERTIES +M: Andrew Lunn +M: "David S. Miller" +M: Eric Dumazet +M: Heiner Kallweit +M: Jakub Kicinski +M: Kishon Vijay Abraham I +M: Paolo Abeni +R: Russell King +M: Vinod Koul +L: linux-phy@lists.infradead.org +L: netdev@vger.kernel.org +S: Maintained +Q: https://patchwork.kernel.org/project/linux-phy/list/ +Q: https://patchwork.kernel.org/project/netdevbpf/list/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy.git +F: Documentation/devicetree/bindings/phy/phy-common-props.yaml +F: drivers/phy/phy-common-props.c + GENERIC PHY FRAMEWORK M: Vinod Koul M: Kishon Vijay Abraham I diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 678dd0452f0a..479986434086 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -16,6 +16,15 @@ config GENERIC_PHY phy users can obtain reference to the PHY. All the users of this framework should select this config. +config GENERIC_PHY_COMMON_PROPS + bool + help + Generic PHY common property parsing. + + Select this from consumer drivers to gain access to helpers for + parsing properties from the + Documentation/devicetree/bindings/phy/phy-common-props.yaml schema. + config GENERIC_PHY_MIPI_DPHY bool select GENERIC_PHY diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index bfb27fb5a494..d07accc15086 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -4,6 +4,7 @@ # obj-$(CONFIG_GENERIC_PHY) += phy-core.o +obj-$(CONFIG_GENERIC_PHY_COMMON_PROPS) += phy-common-props.o obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o diff --git a/drivers/phy/phy-common-props.c b/drivers/phy/phy-common-props.c new file mode 100644 index 000000000000..4c9dca98d23f --- /dev/null +++ b/drivers/phy/phy-common-props.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * phy-common-props.c -- Common PHY properties + * + * Copyright 2025 NXP + */ +#include +#include +#include +#include +#include +#include + +static int phy_get_polarity_for_mode(struct fwnode_handle *fwnode, + const char *mode_name, + unsigned int supported, + unsigned int default_val, + const char *polarity_prop, + const char *names_prop) +{ + int err, n_pols, n_names, idx = -1; + u32 val, *pols; + + if (!fwnode) + return default_val; + + n_pols = fwnode_property_count_u32(fwnode, polarity_prop); + if (n_pols <= 0) + return default_val; + + n_names = fwnode_property_string_array_count(fwnode, names_prop); + if (n_names >= 0 && n_pols != n_names) { + pr_err("%pfw mismatch between \"%s\" and \"%s\" property count (%d vs %d)\n", + fwnode, polarity_prop, names_prop, n_pols, n_names); + return -EINVAL; + } + + if (mode_name) + idx = fwnode_property_match_string(fwnode, names_prop, mode_name); + if (idx < 0) + idx = fwnode_property_match_string(fwnode, names_prop, "default"); + /* + * If the mode name is missing, it can only mean the specified polarity + * is the default one for all modes, so reject any other polarity count + * than 1. + */ + if (idx < 0 && n_pols != 1) { + pr_err("%pfw \"%s \" property has %d elements, but cannot find \"%s\" in \"%s\" and there is no default value\n", + fwnode, polarity_prop, n_pols, mode_name, names_prop); + return -EINVAL; + } + + if (n_pols == 1) { + err = fwnode_property_read_u32(fwnode, polarity_prop, &val); + if (err) + return err; + + return val; + } + + /* We implicitly know idx >= 0 here */ + pols = kcalloc(n_pols, sizeof(*pols), GFP_KERNEL); + if (!pols) + return -ENOMEM; + + err = fwnode_property_read_u32_array(fwnode, polarity_prop, pols, n_pols); + if (err == 0) { + val = pols[idx]; + if (!(supported & BIT(val))) { + pr_err("%pfw mismatch between '%s' and '%s' property count (%d vs %d)\n", + fwnode, polarity_prop, names_prop, n_pols, n_names); + err = -EOPNOTSUPP; + } + } + + kfree(pols); + + return (err < 0) ? err : val; +} + +/** + * phy_get_rx_polarity - Get RX polarity for PHY differential lane + * @fwnode: Pointer to the PHY's firmware 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 + * + * Return: One of PHY_POL_NORMAL, PHY_POL_INVERT or PHY_POL_AUTO on success, or + * negative error on failure. + */ +int phy_get_rx_polarity(struct fwnode_handle *fwnode, const char *mode_name, + unsigned int supported, unsigned int default_val) +{ + return phy_get_polarity_for_mode(fwnode, mode_name, supported, + default_val, "rx-polarity", + "rx-polarity-names"); +} +EXPORT_SYMBOL_GPL(phy_get_rx_polarity); + +/** + * phy_get_tx_polarity - Get TX polarity for PHY differential lane + * @fwnode: Pointer to the PHY's firmware node. + * @mode_name: The name of the PHY mode to look up. + * @supported: Bit mask of PHY_POL_NORMAL and PHY_POL_INVERT + * @default_val: Default polarity value if property is missing + * + * Return: One of PHY_POL_NORMAL or PHY_POL_INVERT on success, or negative + * error on failure. + */ +int phy_get_tx_polarity(struct fwnode_handle *fwnode, const char *mode_name, + unsigned int supported, unsigned int default_val) +{ + return phy_get_polarity_for_mode(fwnode, mode_name, supported, + default_val, "tx-polarity", + "tx-polarity-names"); +} +EXPORT_SYMBOL_GPL(phy_get_tx_polarity); diff --git a/include/linux/phy/phy-common-props.h b/include/linux/phy/phy-common-props.h new file mode 100644 index 000000000000..0b8ba76e2a15 --- /dev/null +++ b/include/linux/phy/phy-common-props.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * phy-common-props.h -- Common properties for generic PHYs + * + * Copyright 2025 NXP + */ + +#ifndef __PHY_COMMON_PROPS_H +#define __PHY_COMMON_PROPS_H + +#include + +struct fwnode_handle; + +int phy_get_rx_polarity(struct fwnode_handle *fwnode, const char *mode_name, + unsigned int supported, unsigned int default_val); +int phy_get_tx_polarity(struct fwnode_handle *fwnode, const char *mode_name, + unsigned int supported, unsigned int default_val); + +#endif /* __PHY_COMMON_PROPS_H */ -- 2.34.1