Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'phy_common_properties' into next

phy common properties

Vladimir Oltean <vladimir.oltean@nxp.com> wrote:

Introduce "rx-polarity" and "tx-polarity" device tree properties with
Kunit tests

+858 -103
+157
Documentation/devicetree/bindings/phy/phy-common-props.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/phy/phy-common-props.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Common PHY and network PCS properties 8 + 9 + description: 10 + Common PHY and network PCS properties, such as peak-to-peak transmit 11 + amplitude. 12 + 13 + maintainers: 14 + - Marek Behún <kabel@kernel.org> 15 + 16 + $defs: 17 + protocol-names: 18 + description: 19 + Names of the PHY modes. If a value of 'default' is provided, the system 20 + should use it for any PHY mode that is otherwise not defined here. If 21 + 'default' is not provided, the system should use manufacturer default value. 22 + minItems: 1 23 + maxItems: 16 24 + uniqueItems: true 25 + items: 26 + enum: 27 + - default 28 + 29 + # ethernet modes 30 + - sgmii 31 + - qsgmii 32 + - xgmii 33 + - 1000base-x 34 + - 2500base-x 35 + - 5gbase-r 36 + - rxaui 37 + - xaui 38 + - 10gbase-kr 39 + - usxgmii 40 + - 10gbase-r 41 + - 25gbase-r 42 + 43 + # PCIe modes 44 + - pcie 45 + - pcie1 46 + - pcie2 47 + - pcie3 48 + - pcie4 49 + - pcie5 50 + - pcie6 51 + 52 + # USB modes 53 + - usb 54 + - usb-ls 55 + - usb-fs 56 + - usb-hs 57 + - usb-ss 58 + - usb-ss+ 59 + - usb-4 60 + 61 + # storage modes 62 + - sata 63 + - ufs-hs 64 + - ufs-hs-a 65 + - ufs-hs-b 66 + 67 + # display modes 68 + - lvds 69 + - dp 70 + - dp-rbr 71 + - dp-hbr 72 + - dp-hbr2 73 + - dp-hbr3 74 + - dp-uhbr-10 75 + - dp-uhbr-13.5 76 + - dp-uhbr-20 77 + 78 + # camera modes 79 + - mipi-dphy 80 + - mipi-dphy-univ 81 + - mipi-dphy-v2.5-univ 82 + 83 + properties: 84 + tx-p2p-microvolt: 85 + description: 86 + Transmit amplitude voltages in microvolts, peak-to-peak. If this property 87 + contains multiple values for various PHY modes, the 88 + 'tx-p2p-microvolt-names' property must be provided and contain 89 + corresponding mode names. 90 + 91 + tx-p2p-microvolt-names: 92 + description: 93 + Names of the modes corresponding to voltages in the 'tx-p2p-microvolt' 94 + property. Required only if multiple voltages are provided. 95 + $ref: "#/$defs/protocol-names" 96 + 97 + rx-polarity: 98 + description: 99 + An array of values indicating whether the differential receiver's 100 + polarity is inverted. Each value can be one of 101 + PHY_POL_NORMAL (0) which means the negative signal is decoded from the 102 + RXN input, and the positive signal from the RXP input; 103 + PHY_POL_INVERT (1) which means the negative signal is decoded from the 104 + RXP input, and the positive signal from the RXN input; 105 + PHY_POL_AUTO (2) which means the receiver performs automatic polarity 106 + detection and correction, which is a mandatory part of link training for 107 + some protocols (PCIe, USB SS). 108 + 109 + The values are defined in <dt-bindings/phy/phy.h>. If the property is 110 + absent, the default value is undefined. 111 + 112 + Note that the RXP and RXN inputs refer to the block that this property is 113 + under, and do not necessarily directly translate to external pins. 114 + 115 + If this property contains multiple values for various protocols, the 116 + 'rx-polarity-names' property must be provided. 117 + $ref: /schemas/types.yaml#/definitions/uint32-array 118 + minItems: 1 119 + maxItems: 16 120 + items: 121 + enum: [0, 1, 2] 122 + 123 + rx-polarity-names: 124 + $ref: '#/$defs/protocol-names' 125 + 126 + tx-polarity: 127 + description: 128 + Like 'rx-polarity', except it applies to differential transmitters, 129 + and only the values of PHY_POL_NORMAL and PHY_POL_INVERT are possible. 130 + $ref: /schemas/types.yaml#/definitions/uint32-array 131 + minItems: 1 132 + maxItems: 16 133 + items: 134 + enum: [0, 1] 135 + 136 + tx-polarity-names: 137 + $ref: '#/$defs/protocol-names' 138 + 139 + dependencies: 140 + tx-p2p-microvolt-names: [ tx-p2p-microvolt ] 141 + rx-polarity-names: [ rx-polarity ] 142 + tx-polarity-names: [ tx-polarity ] 143 + 144 + additionalProperties: true 145 + 146 + examples: 147 + - | 148 + #include <dt-bindings/phy/phy.h> 149 + 150 + phy: phy { 151 + #phy-cells = <1>; 152 + tx-p2p-microvolt = <915000>, <1100000>, <1200000>; 153 + tx-p2p-microvolt-names = "2500base-x", "usb-hs", "usb-ss"; 154 + rx-polarity = <PHY_POL_AUTO>, <PHY_POL_NORMAL>; 155 + rx-polarity-names = "usb-ss", "default"; 156 + tx-polarity = <PHY_POL_INVERT>; 157 + };
-103
Documentation/devicetree/bindings/phy/transmit-amplitude.yaml
··· 1 - # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 - %YAML 1.2 3 - --- 4 - $id: http://devicetree.org/schemas/phy/transmit-amplitude.yaml# 5 - $schema: http://devicetree.org/meta-schemas/core.yaml# 6 - 7 - title: Common PHY and network PCS transmit amplitude property 8 - 9 - description: 10 - Binding describing the peak-to-peak transmit amplitude for common PHYs 11 - and network PCSes. 12 - 13 - maintainers: 14 - - Marek Behún <kabel@kernel.org> 15 - 16 - properties: 17 - tx-p2p-microvolt: 18 - description: 19 - Transmit amplitude voltages in microvolts, peak-to-peak. If this property 20 - contains multiple values for various PHY modes, the 21 - 'tx-p2p-microvolt-names' property must be provided and contain 22 - corresponding mode names. 23 - 24 - tx-p2p-microvolt-names: 25 - description: | 26 - Names of the modes corresponding to voltages in the 'tx-p2p-microvolt' 27 - property. Required only if multiple voltages are provided. 28 - 29 - If a value of 'default' is provided, the system should use it for any PHY 30 - mode that is otherwise not defined here. If 'default' is not provided, the 31 - system should use manufacturer default value. 32 - minItems: 1 33 - maxItems: 16 34 - items: 35 - enum: 36 - - default 37 - 38 - # ethernet modes 39 - - sgmii 40 - - qsgmii 41 - - xgmii 42 - - 1000base-x 43 - - 2500base-x 44 - - 5gbase-r 45 - - rxaui 46 - - xaui 47 - - 10gbase-kr 48 - - usxgmii 49 - - 10gbase-r 50 - - 25gbase-r 51 - 52 - # PCIe modes 53 - - pcie 54 - - pcie1 55 - - pcie2 56 - - pcie3 57 - - pcie4 58 - - pcie5 59 - - pcie6 60 - 61 - # USB modes 62 - - usb 63 - - usb-ls 64 - - usb-fs 65 - - usb-hs 66 - - usb-ss 67 - - usb-ss+ 68 - - usb-4 69 - 70 - # storage modes 71 - - sata 72 - - ufs-hs 73 - - ufs-hs-a 74 - - ufs-hs-b 75 - 76 - # display modes 77 - - lvds 78 - - dp 79 - - dp-rbr 80 - - dp-hbr 81 - - dp-hbr2 82 - - dp-hbr3 83 - - dp-uhbr-10 84 - - dp-uhbr-13.5 85 - - dp-uhbr-20 86 - 87 - # camera modes 88 - - mipi-dphy 89 - - mipi-dphy-univ 90 - - mipi-dphy-v2.5-univ 91 - 92 - dependencies: 93 - tx-p2p-microvolt-names: [ tx-p2p-microvolt ] 94 - 95 - additionalProperties: true 96 - 97 - examples: 98 - - | 99 - phy: phy { 100 - #phy-cells = <1>; 101 - tx-p2p-microvolt = <915000>, <1100000>, <1200000>; 102 - tx-p2p-microvolt-names = "2500base-x", "usb-hs", "usb-ss"; 103 - };
+10
MAINTAINERS
··· 20517 20517 S: Maintained 20518 20518 F: drivers/mtd/devices/phram.c 20519 20519 20520 + PHY COMMON PROPERTIES 20521 + M: Vladimir Oltean <vladimir.oltean@nxp.com> 20522 + L: netdev@vger.kernel.org 20523 + S: Maintained 20524 + Q: https://patchwork.kernel.org/project/netdevbpf/list/ 20525 + F: Documentation/devicetree/bindings/phy/phy-common-props.yaml 20526 + F: drivers/phy/phy-common-props-test.c 20527 + F: drivers/phy/phy-common-props.c 20528 + F: include/linux/phy/phy-common-props.h 20529 + 20520 20530 PICOLCD HID DRIVER 20521 20531 M: Bruno Prémont <bonbons@linux-vserver.org> 20522 20532 L: linux-input@vger.kernel.org
+22
drivers/phy/Kconfig
··· 5 5 6 6 menu "PHY Subsystem" 7 7 8 + config PHY_COMMON_PROPS 9 + bool 10 + help 11 + This parses properties common between generic PHYs and Ethernet PHYs. 12 + 13 + Select this from consumer drivers to gain access to helpers for 14 + parsing properties from the 15 + Documentation/devicetree/bindings/phy/phy-common-props.yaml schema. 16 + 17 + config PHY_COMMON_PROPS_TEST 18 + tristate "KUnit tests for PHY common props" if !KUNIT_ALL_TESTS 19 + select PHY_COMMON_PROPS 20 + depends on KUNIT 21 + default KUNIT_ALL_TESTS 22 + help 23 + This builds KUnit tests for the PHY common property API. 24 + 25 + For more information on KUnit and unit tests in general, 26 + please refer to the KUnit documentation in Documentation/dev-tools/kunit/. 27 + 28 + When in doubt, say N. 29 + 8 30 config GENERIC_PHY 9 31 bool "PHY Core" 10 32 help
+2
drivers/phy/Makefile
··· 3 3 # Makefile for the phy drivers. 4 4 # 5 5 6 + obj-$(CONFIG_PHY_COMMON_PROPS) += phy-common-props.o 7 + obj-$(CONFIG_PHY_COMMON_PROPS_TEST) += phy-common-props-test.o 6 8 obj-$(CONFIG_GENERIC_PHY) += phy-core.o 7 9 obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o 8 10 obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o
+422
drivers/phy/phy-common-props-test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * phy-common-props-test.c -- Unit tests for PHY common properties API 4 + * 5 + * Copyright 2025-2026 NXP 6 + */ 7 + #include <kunit/test.h> 8 + #include <linux/property.h> 9 + #include <linux/phy/phy-common-props.h> 10 + #include <dt-bindings/phy/phy.h> 11 + 12 + /* Test: rx-polarity property is missing */ 13 + static void phy_test_rx_polarity_is_missing(struct kunit *test) 14 + { 15 + static const struct property_entry entries[] = { 16 + {} 17 + }; 18 + struct fwnode_handle *node; 19 + unsigned int val; 20 + int ret; 21 + 22 + node = fwnode_create_software_node(entries, NULL); 23 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 24 + 25 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 26 + KUNIT_EXPECT_EQ(test, ret, 0); 27 + KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL); 28 + 29 + fwnode_remove_software_node(node); 30 + } 31 + 32 + /* Test: rx-polarity has more values than rx-polarity-names */ 33 + static void phy_test_rx_polarity_more_values_than_names(struct kunit *test) 34 + { 35 + static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT, PHY_POL_NORMAL }; 36 + static const char * const rx_pol_names[] = { "sgmii", "2500base-x" }; 37 + static const struct property_entry entries[] = { 38 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 39 + PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names), 40 + {} 41 + }; 42 + struct fwnode_handle *node; 43 + unsigned int val; 44 + int ret; 45 + 46 + node = fwnode_create_software_node(entries, NULL); 47 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 48 + 49 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 50 + KUNIT_EXPECT_EQ(test, ret, -EINVAL); 51 + 52 + fwnode_remove_software_node(node); 53 + } 54 + 55 + /* Test: rx-polarity has 1 value and rx-polarity-names does not exist */ 56 + static void phy_test_rx_polarity_single_value_no_names(struct kunit *test) 57 + { 58 + static const u32 rx_pol[] = { PHY_POL_INVERT }; 59 + static const struct property_entry entries[] = { 60 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 61 + {} 62 + }; 63 + struct fwnode_handle *node; 64 + unsigned int val; 65 + int ret; 66 + 67 + node = fwnode_create_software_node(entries, NULL); 68 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 69 + 70 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 71 + KUNIT_EXPECT_EQ(test, ret, 0); 72 + KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT); 73 + 74 + fwnode_remove_software_node(node); 75 + } 76 + 77 + /* Test: rx-polarity-names has more values than rx-polarity */ 78 + static void phy_test_rx_polarity_more_names_than_values(struct kunit *test) 79 + { 80 + static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT }; 81 + static const char * const rx_pol_names[] = { "sgmii", "2500base-x", "1000base-x" }; 82 + static const struct property_entry entries[] = { 83 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 84 + PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names), 85 + {} 86 + }; 87 + struct fwnode_handle *node; 88 + unsigned int val; 89 + int ret; 90 + 91 + node = fwnode_create_software_node(entries, NULL); 92 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 93 + 94 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 95 + KUNIT_EXPECT_EQ(test, ret, -EINVAL); 96 + 97 + fwnode_remove_software_node(node); 98 + } 99 + 100 + /* Test: rx-polarity and rx-polarity-names have same length, find the name */ 101 + static void phy_test_rx_polarity_find_by_name(struct kunit *test) 102 + { 103 + static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT, PHY_POL_AUTO }; 104 + static const char * const rx_pol_names[] = { "sgmii", "2500base-x", "usb-ss" }; 105 + static const struct property_entry entries[] = { 106 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 107 + PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names), 108 + {} 109 + }; 110 + struct fwnode_handle *node; 111 + unsigned int val; 112 + int ret; 113 + 114 + node = fwnode_create_software_node(entries, NULL); 115 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 116 + 117 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 118 + KUNIT_EXPECT_EQ(test, ret, 0); 119 + KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL); 120 + 121 + ret = phy_get_manual_rx_polarity(node, "2500base-x", &val); 122 + KUNIT_EXPECT_EQ(test, ret, 0); 123 + KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT); 124 + 125 + ret = phy_get_rx_polarity(node, "usb-ss", BIT(PHY_POL_AUTO), 126 + PHY_POL_AUTO, &val); 127 + KUNIT_EXPECT_EQ(test, ret, 0); 128 + KUNIT_EXPECT_EQ(test, val, PHY_POL_AUTO); 129 + 130 + fwnode_remove_software_node(node); 131 + } 132 + 133 + /* Test: same length, name not found, no "default" - error */ 134 + static void phy_test_rx_polarity_name_not_found_no_default(struct kunit *test) 135 + { 136 + static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT }; 137 + static const char * const rx_pol_names[] = { "2500base-x", "1000base-x" }; 138 + static const struct property_entry entries[] = { 139 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 140 + PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names), 141 + {} 142 + }; 143 + struct fwnode_handle *node; 144 + unsigned int val; 145 + int ret; 146 + 147 + node = fwnode_create_software_node(entries, NULL); 148 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 149 + 150 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 151 + KUNIT_EXPECT_EQ(test, ret, -EINVAL); 152 + 153 + fwnode_remove_software_node(node); 154 + } 155 + 156 + /* Test: same length, name not found, but "default" exists */ 157 + static void phy_test_rx_polarity_name_not_found_with_default(struct kunit *test) 158 + { 159 + static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT }; 160 + static const char * const rx_pol_names[] = { "2500base-x", "default" }; 161 + static const struct property_entry entries[] = { 162 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 163 + PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names), 164 + {} 165 + }; 166 + struct fwnode_handle *node; 167 + unsigned int val; 168 + int ret; 169 + 170 + node = fwnode_create_software_node(entries, NULL); 171 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 172 + 173 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 174 + KUNIT_EXPECT_EQ(test, ret, 0); 175 + KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT); 176 + 177 + fwnode_remove_software_node(node); 178 + } 179 + 180 + /* Test: polarity found but value is unsupported */ 181 + static void phy_test_rx_polarity_unsupported_value(struct kunit *test) 182 + { 183 + static const u32 rx_pol[] = { PHY_POL_AUTO }; 184 + static const char * const rx_pol_names[] = { "sgmii" }; 185 + static const struct property_entry entries[] = { 186 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 187 + PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names), 188 + {} 189 + }; 190 + struct fwnode_handle *node; 191 + unsigned int val; 192 + int ret; 193 + 194 + node = fwnode_create_software_node(entries, NULL); 195 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 196 + 197 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 198 + KUNIT_EXPECT_EQ(test, ret, -EOPNOTSUPP); 199 + 200 + fwnode_remove_software_node(node); 201 + } 202 + 203 + /* Test: tx-polarity property is missing */ 204 + static void phy_test_tx_polarity_is_missing(struct kunit *test) 205 + { 206 + static const struct property_entry entries[] = { 207 + {} 208 + }; 209 + struct fwnode_handle *node; 210 + unsigned int val; 211 + int ret; 212 + 213 + node = fwnode_create_software_node(entries, NULL); 214 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 215 + 216 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 217 + KUNIT_EXPECT_EQ(test, ret, 0); 218 + KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL); 219 + 220 + fwnode_remove_software_node(node); 221 + } 222 + 223 + /* Test: tx-polarity has more values than tx-polarity-names */ 224 + static void phy_test_tx_polarity_more_values_than_names(struct kunit *test) 225 + { 226 + static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT, PHY_POL_NORMAL }; 227 + static const char * const tx_pol_names[] = { "sgmii", "2500base-x" }; 228 + static const struct property_entry entries[] = { 229 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 230 + PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names), 231 + {} 232 + }; 233 + struct fwnode_handle *node; 234 + unsigned int val; 235 + int ret; 236 + 237 + node = fwnode_create_software_node(entries, NULL); 238 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 239 + 240 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 241 + KUNIT_EXPECT_EQ(test, ret, -EINVAL); 242 + 243 + fwnode_remove_software_node(node); 244 + } 245 + 246 + /* Test: tx-polarity has 1 value and tx-polarity-names does not exist */ 247 + static void phy_test_tx_polarity_single_value_no_names(struct kunit *test) 248 + { 249 + static const u32 tx_pol[] = { PHY_POL_INVERT }; 250 + static const struct property_entry entries[] = { 251 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 252 + {} 253 + }; 254 + struct fwnode_handle *node; 255 + unsigned int val; 256 + int ret; 257 + 258 + node = fwnode_create_software_node(entries, NULL); 259 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 260 + 261 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 262 + KUNIT_EXPECT_EQ(test, ret, 0); 263 + KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT); 264 + 265 + fwnode_remove_software_node(node); 266 + } 267 + 268 + /* Test: tx-polarity-names has more values than tx-polarity */ 269 + static void phy_test_tx_polarity_more_names_than_values(struct kunit *test) 270 + { 271 + static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT }; 272 + static const char * const tx_pol_names[] = { "sgmii", "2500base-x", "1000base-x" }; 273 + static const struct property_entry entries[] = { 274 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 275 + PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names), 276 + {} 277 + }; 278 + struct fwnode_handle *node; 279 + unsigned int val; 280 + int ret; 281 + 282 + node = fwnode_create_software_node(entries, NULL); 283 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 284 + 285 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 286 + KUNIT_EXPECT_EQ(test, ret, -EINVAL); 287 + 288 + fwnode_remove_software_node(node); 289 + } 290 + 291 + /* Test: tx-polarity and tx-polarity-names have same length, find the name */ 292 + static void phy_test_tx_polarity_find_by_name(struct kunit *test) 293 + { 294 + static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT, PHY_POL_NORMAL }; 295 + static const char * const tx_pol_names[] = { "sgmii", "2500base-x", "1000base-x" }; 296 + static const struct property_entry entries[] = { 297 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 298 + PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names), 299 + {} 300 + }; 301 + struct fwnode_handle *node; 302 + unsigned int val; 303 + int ret; 304 + 305 + node = fwnode_create_software_node(entries, NULL); 306 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 307 + 308 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 309 + KUNIT_EXPECT_EQ(test, ret, 0); 310 + KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL); 311 + 312 + ret = phy_get_manual_tx_polarity(node, "2500base-x", &val); 313 + KUNIT_EXPECT_EQ(test, ret, 0); 314 + KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT); 315 + 316 + ret = phy_get_manual_tx_polarity(node, "1000base-x", &val); 317 + KUNIT_EXPECT_EQ(test, ret, 0); 318 + KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL); 319 + 320 + fwnode_remove_software_node(node); 321 + } 322 + 323 + /* Test: same length, name not found, no "default" - error */ 324 + static void phy_test_tx_polarity_name_not_found_no_default(struct kunit *test) 325 + { 326 + static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT }; 327 + static const char * const tx_pol_names[] = { "2500base-x", "1000base-x" }; 328 + static const struct property_entry entries[] = { 329 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 330 + PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names), 331 + {} 332 + }; 333 + struct fwnode_handle *node; 334 + unsigned int val; 335 + int ret; 336 + 337 + node = fwnode_create_software_node(entries, NULL); 338 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 339 + 340 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 341 + KUNIT_EXPECT_EQ(test, ret, -EINVAL); 342 + 343 + fwnode_remove_software_node(node); 344 + } 345 + 346 + /* Test: same length, name not found, but "default" exists */ 347 + static void phy_test_tx_polarity_name_not_found_with_default(struct kunit *test) 348 + { 349 + static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT }; 350 + static const char * const tx_pol_names[] = { "2500base-x", "default" }; 351 + static const struct property_entry entries[] = { 352 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 353 + PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names), 354 + {} 355 + }; 356 + struct fwnode_handle *node; 357 + unsigned int val; 358 + int ret; 359 + 360 + node = fwnode_create_software_node(entries, NULL); 361 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 362 + 363 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 364 + KUNIT_EXPECT_EQ(test, ret, 0); 365 + KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT); 366 + 367 + fwnode_remove_software_node(node); 368 + } 369 + 370 + /* Test: polarity found but value is unsupported (AUTO for TX) */ 371 + static void phy_test_tx_polarity_unsupported_value(struct kunit *test) 372 + { 373 + static const u32 tx_pol[] = { PHY_POL_AUTO }; 374 + static const char * const tx_pol_names[] = { "sgmii" }; 375 + static const struct property_entry entries[] = { 376 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 377 + PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names), 378 + {} 379 + }; 380 + struct fwnode_handle *node; 381 + unsigned int val; 382 + int ret; 383 + 384 + node = fwnode_create_software_node(entries, NULL); 385 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 386 + 387 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 388 + KUNIT_EXPECT_EQ(test, ret, -EOPNOTSUPP); 389 + 390 + fwnode_remove_software_node(node); 391 + } 392 + 393 + static struct kunit_case phy_common_props_test_cases[] = { 394 + KUNIT_CASE(phy_test_rx_polarity_is_missing), 395 + KUNIT_CASE(phy_test_rx_polarity_more_values_than_names), 396 + KUNIT_CASE(phy_test_rx_polarity_single_value_no_names), 397 + KUNIT_CASE(phy_test_rx_polarity_more_names_than_values), 398 + KUNIT_CASE(phy_test_rx_polarity_find_by_name), 399 + KUNIT_CASE(phy_test_rx_polarity_name_not_found_no_default), 400 + KUNIT_CASE(phy_test_rx_polarity_name_not_found_with_default), 401 + KUNIT_CASE(phy_test_rx_polarity_unsupported_value), 402 + KUNIT_CASE(phy_test_tx_polarity_is_missing), 403 + KUNIT_CASE(phy_test_tx_polarity_more_values_than_names), 404 + KUNIT_CASE(phy_test_tx_polarity_single_value_no_names), 405 + KUNIT_CASE(phy_test_tx_polarity_more_names_than_values), 406 + KUNIT_CASE(phy_test_tx_polarity_find_by_name), 407 + KUNIT_CASE(phy_test_tx_polarity_name_not_found_no_default), 408 + KUNIT_CASE(phy_test_tx_polarity_name_not_found_with_default), 409 + KUNIT_CASE(phy_test_tx_polarity_unsupported_value), 410 + {} 411 + }; 412 + 413 + static struct kunit_suite phy_common_props_test_suite = { 414 + .name = "phy-common-props", 415 + .test_cases = phy_common_props_test_cases, 416 + }; 417 + 418 + kunit_test_suite(phy_common_props_test_suite); 419 + 420 + MODULE_DESCRIPTION("Test module for PHY common properties API"); 421 + MODULE_AUTHOR("Vladimir Oltean <vladimir.oltean@nxp.com>"); 422 + MODULE_LICENSE("GPL");
+209
drivers/phy/phy-common-props.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * phy-common-props.c -- Common PHY properties 4 + * 5 + * Copyright 2025-2026 NXP 6 + */ 7 + #include <linux/export.h> 8 + #include <linux/fwnode.h> 9 + #include <linux/phy/phy-common-props.h> 10 + #include <linux/printk.h> 11 + #include <linux/property.h> 12 + #include <linux/slab.h> 13 + 14 + /** 15 + * fwnode_get_u32_prop_for_name - Find u32 property by name, or default value 16 + * @fwnode: Pointer to firmware node, or NULL to use @default_val 17 + * @name: Property name used as lookup key in @names_title (must not be NULL) 18 + * @props_title: Name of u32 array property holding values 19 + * @names_title: Name of string array property holding lookup keys 20 + * @default_val: Default value if @fwnode is NULL or @props_title is empty 21 + * @val: Pointer to store the returned value 22 + * 23 + * This function retrieves a u32 value from @props_title based on a name lookup 24 + * in @names_title. The value stored in @val is determined as follows: 25 + * 26 + * - If @fwnode is NULL or @props_title is empty: @default_val is used 27 + * - If @props_title has exactly one element and @names_title is empty: 28 + * that element is used 29 + * - Otherwise: @val is set to the element at the same index where @name is 30 + * found in @names_title. 31 + * - If @name is not found, the function looks for a "default" entry in 32 + * @names_title and uses the corresponding value from @props_title 33 + * 34 + * When both @props_title and @names_title are present, they must have the 35 + * same number of elements (except when @props_title has exactly one element). 36 + * 37 + * Return: zero on success, negative error on failure. 38 + */ 39 + static int fwnode_get_u32_prop_for_name(struct fwnode_handle *fwnode, 40 + const char *name, 41 + const char *props_title, 42 + const char *names_title, 43 + unsigned int default_val, 44 + unsigned int *val) 45 + { 46 + int err, n_props, n_names, idx; 47 + u32 *props; 48 + 49 + if (!name) { 50 + pr_err("Lookup key inside \"%s\" is mandatory\n", names_title); 51 + return -EINVAL; 52 + } 53 + 54 + n_props = fwnode_property_count_u32(fwnode, props_title); 55 + if (n_props <= 0) { 56 + /* fwnode is NULL, or is missing requested property */ 57 + *val = default_val; 58 + return 0; 59 + } 60 + 61 + n_names = fwnode_property_string_array_count(fwnode, names_title); 62 + if (n_names >= 0 && n_props != n_names) { 63 + pr_err("%pfw mismatch between \"%s\" and \"%s\" property count (%d vs %d)\n", 64 + fwnode, props_title, names_title, n_props, n_names); 65 + return -EINVAL; 66 + } 67 + 68 + idx = fwnode_property_match_string(fwnode, names_title, name); 69 + if (idx < 0) 70 + idx = fwnode_property_match_string(fwnode, names_title, "default"); 71 + /* 72 + * If the mode name is missing, it can only mean the specified property 73 + * is the default one for all modes, so reject any other property count 74 + * than 1. 75 + */ 76 + if (idx < 0 && n_props != 1) { 77 + pr_err("%pfw \"%s \" property has %d elements, but cannot find \"%s\" in \"%s\" and there is no default value\n", 78 + fwnode, props_title, n_props, name, names_title); 79 + return -EINVAL; 80 + } 81 + 82 + if (n_props == 1) { 83 + err = fwnode_property_read_u32(fwnode, props_title, val); 84 + if (err) 85 + return err; 86 + 87 + return 0; 88 + } 89 + 90 + /* We implicitly know idx >= 0 here */ 91 + props = kcalloc(n_props, sizeof(*props), GFP_KERNEL); 92 + if (!props) 93 + return -ENOMEM; 94 + 95 + err = fwnode_property_read_u32_array(fwnode, props_title, props, n_props); 96 + if (err >= 0) 97 + *val = props[idx]; 98 + 99 + kfree(props); 100 + 101 + return err; 102 + } 103 + 104 + static int phy_get_polarity_for_mode(struct fwnode_handle *fwnode, 105 + const char *mode_name, 106 + unsigned int supported, 107 + unsigned int default_val, 108 + const char *polarity_prop, 109 + const char *names_prop, 110 + unsigned int *val) 111 + { 112 + int err; 113 + 114 + err = fwnode_get_u32_prop_for_name(fwnode, mode_name, polarity_prop, 115 + names_prop, default_val, val); 116 + if (err) 117 + return err; 118 + 119 + if (!(supported & BIT(*val))) { 120 + pr_err("%d is not a supported value for %pfw '%s' element '%s'\n", 121 + *val, fwnode, polarity_prop, mode_name); 122 + err = -EOPNOTSUPP; 123 + } 124 + 125 + return err; 126 + } 127 + 128 + /** 129 + * phy_get_rx_polarity - Get RX polarity for PHY differential lane 130 + * @fwnode: Pointer to the PHY's firmware node. 131 + * @mode_name: The name of the PHY mode to look up. 132 + * @supported: Bit mask of PHY_POL_NORMAL, PHY_POL_INVERT and PHY_POL_AUTO 133 + * @default_val: Default polarity value if property is missing 134 + * @val: Pointer to returned polarity. 135 + * 136 + * Return: zero on success, negative error on failure. 137 + */ 138 + int __must_check phy_get_rx_polarity(struct fwnode_handle *fwnode, 139 + const char *mode_name, 140 + unsigned int supported, 141 + unsigned int default_val, 142 + unsigned int *val) 143 + { 144 + return phy_get_polarity_for_mode(fwnode, mode_name, supported, 145 + default_val, "rx-polarity", 146 + "rx-polarity-names", val); 147 + } 148 + EXPORT_SYMBOL_GPL(phy_get_rx_polarity); 149 + 150 + /** 151 + * phy_get_tx_polarity - Get TX polarity for PHY differential lane 152 + * @fwnode: Pointer to the PHY's firmware node. 153 + * @mode_name: The name of the PHY mode to look up. 154 + * @supported: Bit mask of PHY_POL_NORMAL and PHY_POL_INVERT 155 + * @default_val: Default polarity value if property is missing 156 + * @val: Pointer to returned polarity. 157 + * 158 + * Return: zero on success, negative error on failure. 159 + */ 160 + int __must_check phy_get_tx_polarity(struct fwnode_handle *fwnode, 161 + const char *mode_name, unsigned int supported, 162 + unsigned int default_val, unsigned int *val) 163 + { 164 + return phy_get_polarity_for_mode(fwnode, mode_name, supported, 165 + default_val, "tx-polarity", 166 + "tx-polarity-names", val); 167 + } 168 + EXPORT_SYMBOL_GPL(phy_get_tx_polarity); 169 + 170 + /** 171 + * phy_get_manual_rx_polarity - Get manual RX polarity for PHY differential lane 172 + * @fwnode: Pointer to the PHY's firmware node. 173 + * @mode_name: The name of the PHY mode to look up. 174 + * @val: Pointer to returned polarity. 175 + * 176 + * Helper for PHYs which do not support protocols with automatic RX polarity 177 + * detection and correction. 178 + * 179 + * Return: zero on success, negative error on failure. 180 + */ 181 + int __must_check phy_get_manual_rx_polarity(struct fwnode_handle *fwnode, 182 + const char *mode_name, 183 + unsigned int *val) 184 + { 185 + return phy_get_rx_polarity(fwnode, mode_name, 186 + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT), 187 + PHY_POL_NORMAL, val); 188 + } 189 + EXPORT_SYMBOL_GPL(phy_get_manual_rx_polarity); 190 + 191 + /** 192 + * phy_get_manual_tx_polarity - Get manual TX polarity for PHY differential lane 193 + * @fwnode: Pointer to the PHY's firmware node. 194 + * @mode_name: The name of the PHY mode to look up. 195 + * @val: Pointer to returned polarity. 196 + * 197 + * Helper for PHYs without any custom default value for the TX polarity. 198 + * 199 + * Return: zero on success, negative error on failure. 200 + */ 201 + int __must_check phy_get_manual_tx_polarity(struct fwnode_handle *fwnode, 202 + const char *mode_name, 203 + unsigned int *val) 204 + { 205 + return phy_get_tx_polarity(fwnode, mode_name, 206 + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT), 207 + PHY_POL_NORMAL, val); 208 + } 209 + EXPORT_SYMBOL_GPL(phy_get_manual_tx_polarity);
+4
include/dt-bindings/phy/phy.h
··· 25 25 #define PHY_TYPE_USXGMII 12 26 26 #define PHY_TYPE_XAUI 13 27 27 28 + #define PHY_POL_NORMAL 0 29 + #define PHY_POL_INVERT 1 30 + #define PHY_POL_AUTO 2 31 + 28 32 #endif /* _DT_BINDINGS_PHY */
+32
include/linux/phy/phy-common-props.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * phy-common-props.h -- Common properties for generic PHYs 4 + * 5 + * Copyright 2025 NXP 6 + */ 7 + 8 + #ifndef __PHY_COMMON_PROPS_H 9 + #define __PHY_COMMON_PROPS_H 10 + 11 + #include <dt-bindings/phy/phy.h> 12 + 13 + struct fwnode_handle; 14 + 15 + int __must_check phy_get_rx_polarity(struct fwnode_handle *fwnode, 16 + const char *mode_name, 17 + unsigned int supported, 18 + unsigned int default_val, 19 + unsigned int *val); 20 + int __must_check phy_get_tx_polarity(struct fwnode_handle *fwnode, 21 + const char *mode_name, 22 + unsigned int supported, 23 + unsigned int default_val, 24 + unsigned int *val); 25 + int __must_check phy_get_manual_rx_polarity(struct fwnode_handle *fwnode, 26 + const char *mode_name, 27 + unsigned int *val); 28 + int __must_check phy_get_manual_tx_polarity(struct fwnode_handle *fwnode, 29 + const char *mode_name, 30 + unsigned int *val); 31 + 32 + #endif /* __PHY_COMMON_PROPS_H */