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

Merge branch 'phy-package'

Christian Marangi says:

====================
net: phy: Introduce PHY Package concept

Idea of this big series is to introduce the concept of PHY package in DT
and give PHY drivers a way to derive the base address from DT.

The concept of PHY package is nothing new and is already a thing in the
kernel with the API phy_package_join/leave/read/write.

What is currently lacking is describing this in DT and better reference
a base address to calculate offset from.

In the scenario of a PHY package where multiple address are used and
there isn't a way to get the base address of the PHY package from some
regs, getting the information from DT is the only way.

A possible example to this problem is this:

ethernet-phy-package@0 {
compatible = "qcom,qca8075-package";
#address-cells = <1>;
#size-cells = <0>;

reg = <0>;
qcom,package-mode = "qsgmii";

ethernet-phy@1 {
reg = <1>;
};

phy4: ethernet-phy@4 {
reg = <4>;
};
};

The mdio parse functions are changed to address for this additional
special node, the function is changed to simply detect this node and
search also in this. (we match the node name to be "ethernet-phy-package")

PHY driver can then use introduced helper of_phy_package_join to join the
PHY to the PHY package and derive the base address from DT.

Changes v7:
- Rebase on top of net-next
- Add Reviewed-by tag for DT patch
- Change tx-driver-strength to tx-drive-strength
- Drop driver reference in DT
Changes v6:
- Back to absolute PHY implementation
- Correctly drop refcount for node on error condition and on PHY leave
- Drop DT include patch in favor for 3 boolean vendor property
- Fix Documentation problem for compatible and missing type and
description
- Drop redundand gpio-controller dependency and description
- Skip scanphy with invalid PHY Package node and make reg mandatory
- Rework fiber read status to use more generic function
- Split qca808x LED generalization patch to permit easier review
- Correctly return -EINVAL with wrong data passed to vendor property
- Drop removing LED ops for qca807x PHY driver with gpio-controller
Changes v5:
- Rebase on top of net-next
- Change implementation to base addr + offset in subnode
- Adapt to all the changes and cleanup done to at803x
Changes v4:
- Rework DT implementation
- Drop of autojoin support and rework to simple helper
- Rework PHY driver to the new implementation
- Add compatible for qca807x package
- Further cleanup patches
Changes v3:
- Add back compatible implementation
- Detach patch that can be handled separately (phy_package_mmd,
phy_package extended)
- Rework code to new simplified implementation with base addr + offset
- Improve documentation with additional info and description
Changes v2:
- Drop compatible "ethernet-phy-package", use node name prefix matching
instead
- Improve DT example
- Add reg for ethernet-phy-package
- Drop phy-mode for ethernet-phy-package
- Drop patch for generalization of phy-mode
- Drop global-phy property (handle internally to the PHY driver)
- Rework OF phy package code and PHY driver to handle base address
- Fix missing of_node_put
- Add some missing docs for added variables in struct
- Move some define from dt-bindings include to PHY driver
- Handle qsgmii validation in PHY driver
- Fix wrong include for gpiolib
- Drop reduntant version.h include
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+1676 -375
+52
Documentation/devicetree/bindings/net/ethernet-phy-package.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/net/ethernet-phy-package.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Ethernet PHY Package Common Properties 8 + 9 + maintainers: 10 + - Christian Marangi <ansuelsmth@gmail.com> 11 + 12 + description: 13 + PHY packages are multi-port Ethernet PHY of the same family 14 + and each Ethernet PHY is affected by the global configuration 15 + of the PHY package. 16 + 17 + Each reg of the PHYs defined in the PHY package node is 18 + absolute and describe the real address of the Ethernet PHY on 19 + the MDIO bus. 20 + 21 + properties: 22 + $nodename: 23 + pattern: "^ethernet-phy-package@[a-f0-9]+$" 24 + 25 + reg: 26 + minimum: 0 27 + maximum: 31 28 + description: 29 + The base ID number for the PHY package. 30 + Commonly the ID of the first PHY in the PHY package. 31 + 32 + Some PHY in the PHY package might be not defined but 33 + still occupy ID on the device (just not attached to 34 + anything) hence the PHY package reg might correspond 35 + to a not attached PHY (offset 0). 36 + 37 + '#address-cells': 38 + const: 1 39 + 40 + '#size-cells': 41 + const: 0 42 + 43 + patternProperties: 44 + ^ethernet-phy@[a-f0-9]+$: 45 + $ref: ethernet-phy.yaml# 46 + 47 + required: 48 + - reg 49 + - '#address-cells' 50 + - '#size-cells' 51 + 52 + additionalProperties: true
+184
Documentation/devicetree/bindings/net/qcom,qca807x.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/net/qcom,qca807x.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Qualcomm QCA807x Ethernet PHY 8 + 9 + maintainers: 10 + - Christian Marangi <ansuelsmth@gmail.com> 11 + - Robert Marko <robert.marko@sartura.hr> 12 + 13 + description: | 14 + Qualcomm QCA8072/5 Ethernet PHY is PHY package of 2 or 5 15 + IEEE 802.3 clause 22 compliant 10BASE-Te, 100BASE-TX and 16 + 1000BASE-T PHY-s. 17 + 18 + They feature 2 SerDes, one for PSGMII or QSGMII connection with 19 + MAC, while second one is SGMII for connection to MAC or fiber. 20 + 21 + Both models have a combo port that supports 1000BASE-X and 22 + 100BASE-FX fiber. 23 + 24 + Each PHY inside of QCA807x series has 4 digitally controlled 25 + output only pins that natively drive LED-s for up to 2 attached 26 + LEDs. Some vendor also use these 4 output for GPIO usage without 27 + attaching LEDs. 28 + 29 + Note that output pins can be set to drive LEDs OR GPIO, mixed 30 + definition are not accepted. 31 + 32 + $ref: ethernet-phy-package.yaml# 33 + 34 + properties: 35 + compatible: 36 + enum: 37 + - qcom,qca8072-package 38 + - qcom,qca8075-package 39 + 40 + qcom,package-mode: 41 + description: | 42 + PHY package can be configured in 3 mode following this table: 43 + 44 + First Serdes mode Second Serdes mode 45 + Option 1 PSGMII for copper Disabled 46 + ports 0-4 47 + Option 2 PSGMII for copper 1000BASE-X / 100BASE-FX 48 + ports 0-4 49 + Option 3 QSGMII for copper SGMII for 50 + ports 0-3 copper port 4 51 + 52 + PSGMII mode (option 1 or 2) is configured dynamically based on 53 + the presence of a connected SFP device. 54 + $ref: /schemas/types.yaml#/definitions/string 55 + enum: 56 + - qsgmii 57 + - psgmii 58 + default: psgmii 59 + 60 + qcom,tx-drive-strength-milliwatt: 61 + description: set the TX Amplifier value in mv. 62 + $ref: /schemas/types.yaml#/definitions/uint32 63 + enum: [140, 160, 180, 200, 220, 64 + 240, 260, 280, 300, 320, 65 + 400, 500, 600] 66 + default: 600 67 + 68 + patternProperties: 69 + ^ethernet-phy@[a-f0-9]+$: 70 + $ref: ethernet-phy.yaml# 71 + 72 + properties: 73 + qcom,dac-full-amplitude: 74 + description: 75 + Set Analog MDI driver amplitude to FULL. 76 + 77 + With this not defined, amplitude is set to DSP. 78 + (amplitude is adjusted based on cable length) 79 + 80 + With this enabled and qcom,dac-full-bias-current 81 + and qcom,dac-disable-bias-current-tweak disabled, 82 + bias current is half. 83 + type: boolean 84 + 85 + qcom,dac-full-bias-current: 86 + description: 87 + Set Analog MDI driver bias current to FULL. 88 + 89 + With this not defined, bias current is set to DSP. 90 + (bias current is adjusted based on cable length) 91 + 92 + Actual bias current might be different with 93 + qcom,dac-disable-bias-current-tweak disabled. 94 + type: boolean 95 + 96 + qcom,dac-disable-bias-current-tweak: 97 + description: | 98 + Set Analog MDI driver bias current to disable tweak 99 + to bias current. 100 + 101 + With this not defined, bias current tweak are enabled 102 + by default. 103 + 104 + With this enabled the following tweak are NOT applied: 105 + - With both FULL amplitude and FULL bias current: bias current 106 + is set to half. 107 + - With only DSP amplitude: bias current is set to half and 108 + is set to 1/4 with cable < 10m. 109 + - With DSP bias current (included both DSP amplitude and 110 + DSP bias current): bias current is half the detected current 111 + with cable < 10m. 112 + type: boolean 113 + 114 + gpio-controller: true 115 + 116 + '#gpio-cells': 117 + const: 2 118 + 119 + if: 120 + required: 121 + - gpio-controller 122 + then: 123 + properties: 124 + leds: false 125 + 126 + unevaluatedProperties: false 127 + 128 + required: 129 + - compatible 130 + 131 + unevaluatedProperties: false 132 + 133 + examples: 134 + - | 135 + #include <dt-bindings/leds/common.h> 136 + 137 + mdio { 138 + #address-cells = <1>; 139 + #size-cells = <0>; 140 + 141 + ethernet-phy-package@0 { 142 + #address-cells = <1>; 143 + #size-cells = <0>; 144 + compatible = "qcom,qca8075-package"; 145 + reg = <0>; 146 + 147 + qcom,package-mode = "qsgmii"; 148 + 149 + ethernet-phy@0 { 150 + reg = <0>; 151 + 152 + leds { 153 + #address-cells = <1>; 154 + #size-cells = <0>; 155 + 156 + led@0 { 157 + reg = <0>; 158 + color = <LED_COLOR_ID_GREEN>; 159 + function = LED_FUNCTION_LAN; 160 + default-state = "keep"; 161 + }; 162 + }; 163 + }; 164 + 165 + ethernet-phy@1 { 166 + reg = <1>; 167 + }; 168 + 169 + ethernet-phy@2 { 170 + reg = <2>; 171 + 172 + gpio-controller; 173 + #gpio-cells = <2>; 174 + }; 175 + 176 + ethernet-phy@3 { 177 + reg = <3>; 178 + }; 179 + 180 + ethernet-phy@4 { 181 + reg = <4>; 182 + }; 183 + }; 184 + };
+56 -23
drivers/net/mdio/of_mdio.c
··· 139 139 } 140 140 EXPORT_SYMBOL(of_mdiobus_child_is_phy); 141 141 142 + static int __of_mdiobus_parse_phys(struct mii_bus *mdio, struct device_node *np, 143 + bool *scanphys) 144 + { 145 + struct device_node *child; 146 + int addr, rc = 0; 147 + 148 + /* Loop over the child nodes and register a phy_device for each phy */ 149 + for_each_available_child_of_node(np, child) { 150 + if (of_node_name_eq(child, "ethernet-phy-package")) { 151 + /* Ignore invalid ethernet-phy-package node */ 152 + if (!of_property_present(child, "reg")) 153 + continue; 154 + 155 + rc = __of_mdiobus_parse_phys(mdio, child, NULL); 156 + if (rc && rc != -ENODEV) 157 + goto exit; 158 + 159 + continue; 160 + } 161 + 162 + addr = of_mdio_parse_addr(&mdio->dev, child); 163 + if (addr < 0) { 164 + /* Skip scanning for invalid ethernet-phy-package node */ 165 + if (scanphys) 166 + *scanphys = true; 167 + continue; 168 + } 169 + 170 + if (of_mdiobus_child_is_phy(child)) 171 + rc = of_mdiobus_register_phy(mdio, child, addr); 172 + else 173 + rc = of_mdiobus_register_device(mdio, child, addr); 174 + 175 + if (rc == -ENODEV) 176 + dev_err(&mdio->dev, 177 + "MDIO device at address %d is missing.\n", 178 + addr); 179 + else if (rc) 180 + goto exit; 181 + } 182 + 183 + return 0; 184 + exit: 185 + of_node_put(child); 186 + return rc; 187 + } 188 + 142 189 /** 143 190 * __of_mdiobus_register - Register mii_bus and create PHYs from the device tree 144 191 * @mdio: pointer to mii_bus structure ··· 227 180 return rc; 228 181 229 182 /* Loop over the child nodes and register a phy_device for each phy */ 230 - for_each_available_child_of_node(np, child) { 231 - addr = of_mdio_parse_addr(&mdio->dev, child); 232 - if (addr < 0) { 233 - scanphys = true; 234 - continue; 235 - } 236 - 237 - if (of_mdiobus_child_is_phy(child)) 238 - rc = of_mdiobus_register_phy(mdio, child, addr); 239 - else 240 - rc = of_mdiobus_register_device(mdio, child, addr); 241 - 242 - if (rc == -ENODEV) 243 - dev_err(&mdio->dev, 244 - "MDIO device at address %d is missing.\n", 245 - addr); 246 - else if (rc) 247 - goto unregister; 248 - } 183 + rc = __of_mdiobus_parse_phys(mdio, np, &scanphys); 184 + if (rc) 185 + goto unregister; 249 186 250 187 if (!scanphys) 251 188 return 0; 252 189 253 190 /* auto scan for PHYs with empty reg property */ 254 191 for_each_available_child_of_node(np, child) { 255 - /* Skip PHYs with reg property set */ 256 - if (of_property_present(child, "reg")) 192 + /* Skip PHYs with reg property set or ethernet-phy-package node */ 193 + if (of_property_present(child, "reg") || 194 + of_node_name_eq(child, "ethernet-phy-package")) 257 195 continue; 258 196 259 197 for (addr = 0; addr < PHY_MAX_ADDR; addr++) { ··· 259 227 if (!rc) 260 228 break; 261 229 if (rc != -ENODEV) 262 - goto unregister; 230 + goto put_unregister; 263 231 } 264 232 } 265 233 } 266 234 267 235 return 0; 268 236 269 - unregister: 237 + put_unregister: 270 238 of_node_put(child); 239 + unregister: 271 240 mdiobus_unregister(mdio); 272 241 return rc; 273 242 }
+2 -1
drivers/net/phy/broadcom.c
··· 665 665 static int bcm54616s_read_status(struct phy_device *phydev) 666 666 { 667 667 struct bcm54616s_phy_priv *priv = phydev->priv; 668 + bool changed; 668 669 int err; 669 670 670 671 if (priv->mode_1000bx_en) 671 - err = genphy_c37_read_status(phydev); 672 + err = genphy_c37_read_status(phydev, &changed); 672 673 else 673 674 err = genphy_read_status(phydev); 674 675
+36 -8
drivers/net/phy/mdio_bus.c
··· 459 459 * found, set the of_node pointer for the mdio device. This allows 460 460 * auto-probed phy devices to be supplied with information passed in 461 461 * via DT. 462 + * If a PHY package is found, PHY is searched also there. 462 463 */ 463 - static void of_mdiobus_link_mdiodev(struct mii_bus *bus, 464 - struct mdio_device *mdiodev) 464 + static int of_mdiobus_find_phy(struct device *dev, struct mdio_device *mdiodev, 465 + struct device_node *np) 465 466 { 466 - struct device *dev = &mdiodev->dev; 467 467 struct device_node *child; 468 468 469 - if (dev->of_node || !bus->dev.of_node) 470 - return; 471 - 472 - for_each_available_child_of_node(bus->dev.of_node, child) { 469 + for_each_available_child_of_node(np, child) { 473 470 int addr; 471 + 472 + if (of_node_name_eq(child, "ethernet-phy-package")) { 473 + /* Validate PHY package reg presence */ 474 + if (!of_property_present(child, "reg")) { 475 + of_node_put(child); 476 + return -EINVAL; 477 + } 478 + 479 + if (!of_mdiobus_find_phy(dev, mdiodev, child)) { 480 + /* The refcount for the PHY package will be 481 + * incremented later when PHY join the Package. 482 + */ 483 + of_node_put(child); 484 + return 0; 485 + } 486 + 487 + continue; 488 + } 474 489 475 490 addr = of_mdio_parse_addr(dev, child); 476 491 if (addr < 0) ··· 496 481 /* The refcount on "child" is passed to the mdio 497 482 * device. Do _not_ use of_node_put(child) here. 498 483 */ 499 - return; 484 + return 0; 500 485 } 501 486 } 487 + 488 + return -ENODEV; 489 + } 490 + 491 + static void of_mdiobus_link_mdiodev(struct mii_bus *bus, 492 + struct mdio_device *mdiodev) 493 + { 494 + struct device *dev = &mdiodev->dev; 495 + 496 + if (dev->of_node || !bus->dev.of_node) 497 + return; 498 + 499 + of_mdiobus_find_phy(dev, mdiodev, bus->dev.of_node); 502 500 } 503 501 #else /* !IS_ENABLED(CONFIG_OF_MDIO) */ 504 502 static inline void of_mdiobus_link_mdiodev(struct mii_bus *mdio,
+105 -2
drivers/net/phy/phy_device.c
··· 1712 1712 shared->priv_size = priv_size; 1713 1713 } 1714 1714 shared->base_addr = base_addr; 1715 + shared->np = NULL; 1715 1716 refcount_set(&shared->refcnt, 1); 1716 1717 bus->shared[base_addr] = shared; 1717 1718 } else { ··· 1736 1735 EXPORT_SYMBOL_GPL(phy_package_join); 1737 1736 1738 1737 /** 1738 + * of_phy_package_join - join a common PHY group in PHY package 1739 + * @phydev: target phy_device struct 1740 + * @priv_size: if non-zero allocate this amount of bytes for private data 1741 + * 1742 + * This is a variant of phy_package_join for PHY package defined in DT. 1743 + * 1744 + * The parent node of the @phydev is checked as a valid PHY package node 1745 + * structure (by matching the node name "ethernet-phy-package") and the 1746 + * base_addr for the PHY package is passed to phy_package_join. 1747 + * 1748 + * With this configuration the shared struct will also have the np value 1749 + * filled to use additional DT defined properties in PHY specific 1750 + * probe_once and config_init_once PHY package OPs. 1751 + * 1752 + * Returns < 0 on error, 0 on success. Esp. calling phy_package_join() 1753 + * with the same cookie but a different priv_size is an error. Or a parent 1754 + * node is not detected or is not valid or doesn't match the expected node 1755 + * name for PHY package. 1756 + */ 1757 + int of_phy_package_join(struct phy_device *phydev, size_t priv_size) 1758 + { 1759 + struct device_node *node = phydev->mdio.dev.of_node; 1760 + struct device_node *package_node; 1761 + u32 base_addr; 1762 + int ret; 1763 + 1764 + if (!node) 1765 + return -EINVAL; 1766 + 1767 + package_node = of_get_parent(node); 1768 + if (!package_node) 1769 + return -EINVAL; 1770 + 1771 + if (!of_node_name_eq(package_node, "ethernet-phy-package")) { 1772 + ret = -EINVAL; 1773 + goto exit; 1774 + } 1775 + 1776 + if (of_property_read_u32(package_node, "reg", &base_addr)) { 1777 + ret = -EINVAL; 1778 + goto exit; 1779 + } 1780 + 1781 + ret = phy_package_join(phydev, base_addr, priv_size); 1782 + if (ret) 1783 + goto exit; 1784 + 1785 + phydev->shared->np = package_node; 1786 + 1787 + return 0; 1788 + exit: 1789 + of_node_put(package_node); 1790 + return ret; 1791 + } 1792 + EXPORT_SYMBOL_GPL(of_phy_package_join); 1793 + 1794 + /** 1739 1795 * phy_package_leave - leave a common PHY group 1740 1796 * @phydev: target phy_device struct 1741 1797 * ··· 1807 1749 1808 1750 if (!shared) 1809 1751 return; 1752 + 1753 + /* Decrease the node refcount on leave if present */ 1754 + if (shared->np) 1755 + of_node_put(shared->np); 1810 1756 1811 1757 if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) { 1812 1758 bus->shared[shared->base_addr] = NULL; ··· 1863 1801 return ret; 1864 1802 } 1865 1803 EXPORT_SYMBOL_GPL(devm_phy_package_join); 1804 + 1805 + /** 1806 + * devm_of_phy_package_join - resource managed of_phy_package_join() 1807 + * @dev: device that is registering this PHY package 1808 + * @phydev: target phy_device struct 1809 + * @priv_size: if non-zero allocate this amount of bytes for private data 1810 + * 1811 + * Managed of_phy_package_join(). Shared storage fetched by this function, 1812 + * phy_package_leave() is automatically called on driver detach. See 1813 + * of_phy_package_join() for more information. 1814 + */ 1815 + int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev, 1816 + size_t priv_size) 1817 + { 1818 + struct phy_device **ptr; 1819 + int ret; 1820 + 1821 + ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr), 1822 + GFP_KERNEL); 1823 + if (!ptr) 1824 + return -ENOMEM; 1825 + 1826 + ret = of_phy_package_join(phydev, priv_size); 1827 + 1828 + if (!ret) { 1829 + *ptr = phydev; 1830 + devres_add(dev, ptr); 1831 + } else { 1832 + devres_free(ptr); 1833 + } 1834 + 1835 + return ret; 1836 + } 1837 + EXPORT_SYMBOL_GPL(devm_of_phy_package_join); 1866 1838 1867 1839 /** 1868 1840 * phy_detach - detach a PHY device from its network device ··· 2621 2525 /** 2622 2526 * genphy_c37_read_status - check the link status and update current link state 2623 2527 * @phydev: target phy_device struct 2528 + * @changed: pointer where to store if link changed 2624 2529 * 2625 2530 * Description: Check the link, then figure out the current state 2626 2531 * by comparing what we advertise with what the link partner 2627 2532 * advertises. This function is for Clause 37 1000Base-X mode. 2533 + * 2534 + * If link has changed, @changed is set to true, false otherwise. 2628 2535 */ 2629 - int genphy_c37_read_status(struct phy_device *phydev) 2536 + int genphy_c37_read_status(struct phy_device *phydev, bool *changed) 2630 2537 { 2631 2538 int lpa, err, old_link = phydev->link; 2632 2539 ··· 2639 2540 return err; 2640 2541 2641 2542 /* why bother the PHY if nothing can have changed */ 2642 - if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) 2543 + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) { 2544 + *changed = false; 2643 2545 return 0; 2546 + } 2644 2547 2548 + /* Signal link has changed */ 2549 + *changed = true; 2645 2550 phydev->duplex = DUPLEX_UNKNOWN; 2646 2551 phydev->pause = 0; 2647 2552 phydev->asym_pause = 0;
+8
drivers/net/phy/qcom/Kconfig
··· 20 20 select QCOM_NET_PHYLIB 21 21 help 22 22 Currently supports the QCA8081 model 23 + 24 + config QCA807X_PHY 25 + tristate "Qualcomm QCA807x PHYs" 26 + select QCOM_NET_PHYLIB 27 + depends on OF_MDIO 28 + help 29 + Currently supports the Qualcomm QCA8072, QCA8075 and the PSGMII 30 + control PHY.
+1
drivers/net/phy/qcom/Makefile
··· 3 3 obj-$(CONFIG_AT803X_PHY) += at803x.o 4 4 obj-$(CONFIG_QCA83XX_PHY) += qca83xx.o 5 5 obj-$(CONFIG_QCA808X_PHY) += qca808x.o 6 + obj-$(CONFIG_QCA807X_PHY) += qca807x.o
+2 -36
drivers/net/phy/qcom/at803x.c
··· 504 504 } 505 505 } 506 506 507 - static int at803x_read_status(struct phy_device *phydev) 508 - { 509 - struct at803x_ss_mask ss_mask = { 0 }; 510 - int err, old_link = phydev->link; 511 - 512 - /* Update the link, but return if there was an error */ 513 - err = genphy_update_link(phydev); 514 - if (err) 515 - return err; 516 - 517 - /* why bother the PHY if nothing can have changed */ 518 - if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) 519 - return 0; 520 - 521 - phydev->speed = SPEED_UNKNOWN; 522 - phydev->duplex = DUPLEX_UNKNOWN; 523 - phydev->pause = 0; 524 - phydev->asym_pause = 0; 525 - 526 - err = genphy_read_lpa(phydev); 527 - if (err < 0) 528 - return err; 529 - 530 - ss_mask.speed_mask = AT803X_SS_SPEED_MASK; 531 - ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK); 532 - err = at803x_read_specific_status(phydev, ss_mask); 533 - if (err < 0) 534 - return err; 535 - 536 - if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) 537 - phy_resolve_aneg_pause(phydev); 538 - 539 - return 0; 540 - } 541 - 542 507 static int at803x_config_aneg(struct phy_device *phydev) 543 508 { 544 509 struct at803x_priv *priv = phydev->priv; ··· 912 947 static int at8031_read_status(struct phy_device *phydev) 913 948 { 914 949 struct at803x_priv *priv = phydev->priv; 950 + bool changed; 915 951 916 952 if (priv->is_1000basex) 917 - return genphy_c37_read_status(phydev); 953 + return genphy_c37_read_status(phydev, &changed); 918 954 919 955 return at803x_read_status(phydev); 920 956 }
+849
drivers/net/phy/qcom/qca807x.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (c) 2023 Sartura Ltd. 4 + * 5 + * Author: Robert Marko <robert.marko@sartura.hr> 6 + * Christian Marangi <ansuelsmth@gmail.com> 7 + * 8 + * Qualcomm QCA8072 and QCA8075 PHY driver 9 + */ 10 + 11 + #include <linux/module.h> 12 + #include <linux/of.h> 13 + #include <linux/phy.h> 14 + #include <linux/bitfield.h> 15 + #include <linux/gpio/driver.h> 16 + #include <linux/sfp.h> 17 + 18 + #include "qcom.h" 19 + 20 + #define QCA807X_CHIP_CONFIGURATION 0x1f 21 + #define QCA807X_BT_BX_REG_SEL BIT(15) 22 + #define QCA807X_BT_BX_REG_SEL_FIBER 0 23 + #define QCA807X_BT_BX_REG_SEL_COPPER 1 24 + #define QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK GENMASK(3, 0) 25 + #define QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII 4 26 + #define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER 3 27 + #define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER 0 28 + 29 + #define QCA807X_MEDIA_SELECT_STATUS 0x1a 30 + #define QCA807X_MEDIA_DETECTED_COPPER BIT(5) 31 + #define QCA807X_MEDIA_DETECTED_1000_BASE_X BIT(4) 32 + #define QCA807X_MEDIA_DETECTED_100_BASE_FX BIT(3) 33 + 34 + #define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION 0x807e 35 + #define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN BIT(0) 36 + 37 + #define QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH 0x801a 38 + #define QCA807X_CONTROL_DAC_MASK GENMASK(2, 0) 39 + /* List of tweaks enabled by this bit: 40 + * - With both FULL amplitude and FULL bias current: bias current 41 + * is set to half. 42 + * - With only DSP amplitude: bias current is set to half and 43 + * is set to 1/4 with cable < 10m. 44 + * - With DSP bias current (included both DSP amplitude and 45 + * DSP bias current): bias current is half the detected current 46 + * with cable < 10m. 47 + */ 48 + #define QCA807X_CONTROL_DAC_BIAS_CURRENT_TWEAK BIT(2) 49 + #define QCA807X_CONTROL_DAC_DSP_BIAS_CURRENT BIT(1) 50 + #define QCA807X_CONTROL_DAC_DSP_AMPLITUDE BIT(0) 51 + 52 + #define QCA807X_MMD7_LED_100N_1 0x8074 53 + #define QCA807X_MMD7_LED_100N_2 0x8075 54 + #define QCA807X_MMD7_LED_1000N_1 0x8076 55 + #define QCA807X_MMD7_LED_1000N_2 0x8077 56 + 57 + #define QCA807X_MMD7_LED_CTRL(x) (0x8074 + ((x) * 2)) 58 + #define QCA807X_MMD7_LED_FORCE_CTRL(x) (0x8075 + ((x) * 2)) 59 + 60 + /* LED hw control pattern for fiber port */ 61 + #define QCA807X_LED_FIBER_PATTERN_MASK GENMASK(11, 1) 62 + #define QCA807X_LED_FIBER_TXACT_BLK_EN BIT(10) 63 + #define QCA807X_LED_FIBER_RXACT_BLK_EN BIT(9) 64 + #define QCA807X_LED_FIBER_FDX_ON_EN BIT(6) 65 + #define QCA807X_LED_FIBER_HDX_ON_EN BIT(5) 66 + #define QCA807X_LED_FIBER_1000BX_ON_EN BIT(2) 67 + #define QCA807X_LED_FIBER_100FX_ON_EN BIT(1) 68 + 69 + /* Some device repurpose the LED as GPIO out */ 70 + #define QCA807X_GPIO_FORCE_EN QCA808X_LED_FORCE_EN 71 + #define QCA807X_GPIO_FORCE_MODE_MASK QCA808X_LED_FORCE_MODE_MASK 72 + 73 + #define QCA807X_FUNCTION_CONTROL 0x10 74 + #define QCA807X_FC_MDI_CROSSOVER_MODE_MASK GENMASK(6, 5) 75 + #define QCA807X_FC_MDI_CROSSOVER_AUTO 3 76 + #define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX 1 77 + #define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI 0 78 + 79 + /* PQSGMII Analog PHY specific */ 80 + #define PQSGMII_CTRL_REG 0x0 81 + #define PQSGMII_ANALOG_SW_RESET BIT(6) 82 + #define PQSGMII_DRIVE_CONTROL_1 0xb 83 + #define PQSGMII_TX_DRIVER_MASK GENMASK(7, 4) 84 + #define PQSGMII_TX_DRIVER_140MV 0x0 85 + #define PQSGMII_TX_DRIVER_160MV 0x1 86 + #define PQSGMII_TX_DRIVER_180MV 0x2 87 + #define PQSGMII_TX_DRIVER_200MV 0x3 88 + #define PQSGMII_TX_DRIVER_220MV 0x4 89 + #define PQSGMII_TX_DRIVER_240MV 0x5 90 + #define PQSGMII_TX_DRIVER_260MV 0x6 91 + #define PQSGMII_TX_DRIVER_280MV 0x7 92 + #define PQSGMII_TX_DRIVER_300MV 0x8 93 + #define PQSGMII_TX_DRIVER_320MV 0x9 94 + #define PQSGMII_TX_DRIVER_400MV 0xa 95 + #define PQSGMII_TX_DRIVER_500MV 0xb 96 + #define PQSGMII_TX_DRIVER_600MV 0xc 97 + #define PQSGMII_MODE_CTRL 0x6d 98 + #define PQSGMII_MODE_CTRL_AZ_WORKAROUND_MASK BIT(0) 99 + #define PQSGMII_MMD3_SERDES_CONTROL 0x805a 100 + 101 + #define PHY_ID_QCA8072 0x004dd0b2 102 + #define PHY_ID_QCA8075 0x004dd0b1 103 + 104 + #define QCA807X_COMBO_ADDR_OFFSET 4 105 + #define QCA807X_PQSGMII_ADDR_OFFSET 5 106 + #define SERDES_RESET_SLEEP 100 107 + 108 + enum qca807x_global_phy { 109 + QCA807X_COMBO_ADDR = 4, 110 + QCA807X_PQSGMII_ADDR = 5, 111 + }; 112 + 113 + struct qca807x_shared_priv { 114 + unsigned int package_mode; 115 + u32 tx_drive_strength; 116 + }; 117 + 118 + struct qca807x_gpio_priv { 119 + struct phy_device *phy; 120 + }; 121 + 122 + struct qca807x_priv { 123 + bool dac_full_amplitude; 124 + bool dac_full_bias_current; 125 + bool dac_disable_bias_current_tweak; 126 + }; 127 + 128 + static int qca807x_cable_test_start(struct phy_device *phydev) 129 + { 130 + /* we do all the (time consuming) work later */ 131 + return 0; 132 + } 133 + 134 + static int qca807x_led_parse_netdev(struct phy_device *phydev, unsigned long rules, 135 + u16 *offload_trigger) 136 + { 137 + /* Parsing specific to netdev trigger */ 138 + switch (phydev->port) { 139 + case PORT_TP: 140 + if (test_bit(TRIGGER_NETDEV_TX, &rules)) 141 + *offload_trigger |= QCA808X_LED_TX_BLINK; 142 + if (test_bit(TRIGGER_NETDEV_RX, &rules)) 143 + *offload_trigger |= QCA808X_LED_RX_BLINK; 144 + if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) 145 + *offload_trigger |= QCA808X_LED_SPEED10_ON; 146 + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) 147 + *offload_trigger |= QCA808X_LED_SPEED100_ON; 148 + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) 149 + *offload_trigger |= QCA808X_LED_SPEED1000_ON; 150 + if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules)) 151 + *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON; 152 + if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules)) 153 + *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON; 154 + break; 155 + case PORT_FIBRE: 156 + if (test_bit(TRIGGER_NETDEV_TX, &rules)) 157 + *offload_trigger |= QCA807X_LED_FIBER_TXACT_BLK_EN; 158 + if (test_bit(TRIGGER_NETDEV_RX, &rules)) 159 + *offload_trigger |= QCA807X_LED_FIBER_RXACT_BLK_EN; 160 + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) 161 + *offload_trigger |= QCA807X_LED_FIBER_100FX_ON_EN; 162 + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) 163 + *offload_trigger |= QCA807X_LED_FIBER_1000BX_ON_EN; 164 + if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules)) 165 + *offload_trigger |= QCA807X_LED_FIBER_HDX_ON_EN; 166 + if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules)) 167 + *offload_trigger |= QCA807X_LED_FIBER_FDX_ON_EN; 168 + break; 169 + default: 170 + return -EOPNOTSUPP; 171 + } 172 + 173 + if (rules && !*offload_trigger) 174 + return -EOPNOTSUPP; 175 + 176 + return 0; 177 + } 178 + 179 + static int qca807x_led_hw_control_enable(struct phy_device *phydev, u8 index) 180 + { 181 + u16 reg; 182 + 183 + if (index > 1) 184 + return -EINVAL; 185 + 186 + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); 187 + return qca808x_led_reg_hw_control_enable(phydev, reg); 188 + } 189 + 190 + static int qca807x_led_hw_is_supported(struct phy_device *phydev, u8 index, 191 + unsigned long rules) 192 + { 193 + u16 offload_trigger = 0; 194 + 195 + if (index > 1) 196 + return -EINVAL; 197 + 198 + return qca807x_led_parse_netdev(phydev, rules, &offload_trigger); 199 + } 200 + 201 + static int qca807x_led_hw_control_set(struct phy_device *phydev, u8 index, 202 + unsigned long rules) 203 + { 204 + u16 reg, mask, offload_trigger = 0; 205 + int ret; 206 + 207 + if (index > 1) 208 + return -EINVAL; 209 + 210 + ret = qca807x_led_parse_netdev(phydev, rules, &offload_trigger); 211 + if (ret) 212 + return ret; 213 + 214 + ret = qca807x_led_hw_control_enable(phydev, index); 215 + if (ret) 216 + return ret; 217 + 218 + switch (phydev->port) { 219 + case PORT_TP: 220 + reg = QCA807X_MMD7_LED_CTRL(index); 221 + mask = QCA808X_LED_PATTERN_MASK; 222 + break; 223 + case PORT_FIBRE: 224 + /* HW control pattern bits are in LED FORCE reg */ 225 + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); 226 + mask = QCA807X_LED_FIBER_PATTERN_MASK; 227 + break; 228 + default: 229 + return -EINVAL; 230 + } 231 + 232 + return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, mask, 233 + offload_trigger); 234 + } 235 + 236 + static bool qca807x_led_hw_control_status(struct phy_device *phydev, u8 index) 237 + { 238 + u16 reg; 239 + 240 + if (index > 1) 241 + return false; 242 + 243 + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); 244 + return qca808x_led_reg_hw_control_status(phydev, reg); 245 + } 246 + 247 + static int qca807x_led_hw_control_get(struct phy_device *phydev, u8 index, 248 + unsigned long *rules) 249 + { 250 + u16 reg; 251 + int val; 252 + 253 + if (index > 1) 254 + return -EINVAL; 255 + 256 + /* Check if we have hw control enabled */ 257 + if (qca807x_led_hw_control_status(phydev, index)) 258 + return -EINVAL; 259 + 260 + /* Parsing specific to netdev trigger */ 261 + switch (phydev->port) { 262 + case PORT_TP: 263 + reg = QCA807X_MMD7_LED_CTRL(index); 264 + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); 265 + if (val & QCA808X_LED_TX_BLINK) 266 + set_bit(TRIGGER_NETDEV_TX, rules); 267 + if (val & QCA808X_LED_RX_BLINK) 268 + set_bit(TRIGGER_NETDEV_RX, rules); 269 + if (val & QCA808X_LED_SPEED10_ON) 270 + set_bit(TRIGGER_NETDEV_LINK_10, rules); 271 + if (val & QCA808X_LED_SPEED100_ON) 272 + set_bit(TRIGGER_NETDEV_LINK_100, rules); 273 + if (val & QCA808X_LED_SPEED1000_ON) 274 + set_bit(TRIGGER_NETDEV_LINK_1000, rules); 275 + if (val & QCA808X_LED_HALF_DUPLEX_ON) 276 + set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules); 277 + if (val & QCA808X_LED_FULL_DUPLEX_ON) 278 + set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules); 279 + break; 280 + case PORT_FIBRE: 281 + /* HW control pattern bits are in LED FORCE reg */ 282 + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); 283 + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); 284 + if (val & QCA807X_LED_FIBER_TXACT_BLK_EN) 285 + set_bit(TRIGGER_NETDEV_TX, rules); 286 + if (val & QCA807X_LED_FIBER_RXACT_BLK_EN) 287 + set_bit(TRIGGER_NETDEV_RX, rules); 288 + if (val & QCA807X_LED_FIBER_100FX_ON_EN) 289 + set_bit(TRIGGER_NETDEV_LINK_100, rules); 290 + if (val & QCA807X_LED_FIBER_1000BX_ON_EN) 291 + set_bit(TRIGGER_NETDEV_LINK_1000, rules); 292 + if (val & QCA807X_LED_FIBER_HDX_ON_EN) 293 + set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules); 294 + if (val & QCA807X_LED_FIBER_FDX_ON_EN) 295 + set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules); 296 + break; 297 + default: 298 + return -EINVAL; 299 + } 300 + 301 + return 0; 302 + } 303 + 304 + static int qca807x_led_hw_control_reset(struct phy_device *phydev, u8 index) 305 + { 306 + u16 reg, mask; 307 + 308 + if (index > 1) 309 + return -EINVAL; 310 + 311 + switch (phydev->port) { 312 + case PORT_TP: 313 + reg = QCA807X_MMD7_LED_CTRL(index); 314 + mask = QCA808X_LED_PATTERN_MASK; 315 + break; 316 + case PORT_FIBRE: 317 + /* HW control pattern bits are in LED FORCE reg */ 318 + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); 319 + mask = QCA807X_LED_FIBER_PATTERN_MASK; 320 + break; 321 + default: 322 + return -EINVAL; 323 + } 324 + 325 + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, mask); 326 + } 327 + 328 + static int qca807x_led_brightness_set(struct phy_device *phydev, 329 + u8 index, enum led_brightness value) 330 + { 331 + u16 reg; 332 + int ret; 333 + 334 + if (index > 1) 335 + return -EINVAL; 336 + 337 + /* If we are setting off the LED reset any hw control rule */ 338 + if (!value) { 339 + ret = qca807x_led_hw_control_reset(phydev, index); 340 + if (ret) 341 + return ret; 342 + } 343 + 344 + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); 345 + return qca808x_led_reg_brightness_set(phydev, reg, value); 346 + } 347 + 348 + static int qca807x_led_blink_set(struct phy_device *phydev, u8 index, 349 + unsigned long *delay_on, 350 + unsigned long *delay_off) 351 + { 352 + u16 reg; 353 + 354 + if (index > 1) 355 + return -EINVAL; 356 + 357 + reg = QCA807X_MMD7_LED_FORCE_CTRL(index); 358 + return qca808x_led_reg_blink_set(phydev, reg, delay_on, delay_off); 359 + } 360 + 361 + #ifdef CONFIG_GPIOLIB 362 + static int qca807x_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) 363 + { 364 + return GPIO_LINE_DIRECTION_OUT; 365 + } 366 + 367 + static int qca807x_gpio_get(struct gpio_chip *gc, unsigned int offset) 368 + { 369 + struct qca807x_gpio_priv *priv = gpiochip_get_data(gc); 370 + u16 reg; 371 + int val; 372 + 373 + reg = QCA807X_MMD7_LED_FORCE_CTRL(offset); 374 + val = phy_read_mmd(priv->phy, MDIO_MMD_AN, reg); 375 + 376 + return FIELD_GET(QCA807X_GPIO_FORCE_MODE_MASK, val); 377 + } 378 + 379 + static void qca807x_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) 380 + { 381 + struct qca807x_gpio_priv *priv = gpiochip_get_data(gc); 382 + u16 reg; 383 + int val; 384 + 385 + reg = QCA807X_MMD7_LED_FORCE_CTRL(offset); 386 + 387 + val = phy_read_mmd(priv->phy, MDIO_MMD_AN, reg); 388 + val &= ~QCA807X_GPIO_FORCE_MODE_MASK; 389 + val |= QCA807X_GPIO_FORCE_EN; 390 + val |= FIELD_PREP(QCA807X_GPIO_FORCE_MODE_MASK, value); 391 + 392 + phy_write_mmd(priv->phy, MDIO_MMD_AN, reg, val); 393 + } 394 + 395 + static int qca807x_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int value) 396 + { 397 + qca807x_gpio_set(gc, offset, value); 398 + 399 + return 0; 400 + } 401 + 402 + static int qca807x_gpio(struct phy_device *phydev) 403 + { 404 + struct device *dev = &phydev->mdio.dev; 405 + struct qca807x_gpio_priv *priv; 406 + struct gpio_chip *gc; 407 + 408 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 409 + if (!priv) 410 + return -ENOMEM; 411 + 412 + priv->phy = phydev; 413 + 414 + gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL); 415 + if (!gc) 416 + return -ENOMEM; 417 + 418 + gc->label = dev_name(dev); 419 + gc->base = -1; 420 + gc->ngpio = 2; 421 + gc->parent = dev; 422 + gc->owner = THIS_MODULE; 423 + gc->can_sleep = true; 424 + gc->get_direction = qca807x_gpio_get_direction; 425 + gc->direction_output = qca807x_gpio_dir_out; 426 + gc->get = qca807x_gpio_get; 427 + gc->set = qca807x_gpio_set; 428 + 429 + return devm_gpiochip_add_data(dev, gc, priv); 430 + } 431 + #endif 432 + 433 + static int qca807x_read_fiber_status(struct phy_device *phydev) 434 + { 435 + bool changed; 436 + int ss, err; 437 + 438 + err = genphy_c37_read_status(phydev, &changed); 439 + if (err || !changed) 440 + return err; 441 + 442 + /* Read the QCA807x PHY-Specific Status register fiber page, 443 + * which indicates the speed and duplex that the PHY is actually 444 + * using, irrespective of whether we are in autoneg mode or not. 445 + */ 446 + ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); 447 + if (ss < 0) 448 + return ss; 449 + 450 + phydev->speed = SPEED_UNKNOWN; 451 + phydev->duplex = DUPLEX_UNKNOWN; 452 + if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { 453 + switch (FIELD_GET(AT803X_SS_SPEED_MASK, ss)) { 454 + case AT803X_SS_SPEED_100: 455 + phydev->speed = SPEED_100; 456 + break; 457 + case AT803X_SS_SPEED_1000: 458 + phydev->speed = SPEED_1000; 459 + break; 460 + } 461 + 462 + if (ss & AT803X_SS_DUPLEX) 463 + phydev->duplex = DUPLEX_FULL; 464 + else 465 + phydev->duplex = DUPLEX_HALF; 466 + } 467 + 468 + return 0; 469 + } 470 + 471 + static int qca807x_read_status(struct phy_device *phydev) 472 + { 473 + if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) { 474 + switch (phydev->port) { 475 + case PORT_FIBRE: 476 + return qca807x_read_fiber_status(phydev); 477 + case PORT_TP: 478 + return at803x_read_status(phydev); 479 + default: 480 + return -EINVAL; 481 + } 482 + } 483 + 484 + return at803x_read_status(phydev); 485 + } 486 + 487 + static int qca807x_phy_package_probe_once(struct phy_device *phydev) 488 + { 489 + struct phy_package_shared *shared = phydev->shared; 490 + struct qca807x_shared_priv *priv = shared->priv; 491 + unsigned int tx_drive_strength; 492 + const char *package_mode_name; 493 + 494 + /* Default to 600mw if not defined */ 495 + if (of_property_read_u32(shared->np, "qcom,tx-drive-strength-milliwatt", 496 + &tx_drive_strength)) 497 + tx_drive_strength = 600; 498 + 499 + switch (tx_drive_strength) { 500 + case 140: 501 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_140MV; 502 + break; 503 + case 160: 504 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_160MV; 505 + break; 506 + case 180: 507 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_180MV; 508 + break; 509 + case 200: 510 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_200MV; 511 + break; 512 + case 220: 513 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_220MV; 514 + break; 515 + case 240: 516 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_240MV; 517 + break; 518 + case 260: 519 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_260MV; 520 + break; 521 + case 280: 522 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_280MV; 523 + break; 524 + case 300: 525 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_300MV; 526 + break; 527 + case 320: 528 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_320MV; 529 + break; 530 + case 400: 531 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_400MV; 532 + break; 533 + case 500: 534 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_500MV; 535 + break; 536 + case 600: 537 + priv->tx_drive_strength = PQSGMII_TX_DRIVER_600MV; 538 + break; 539 + default: 540 + return -EINVAL; 541 + } 542 + 543 + priv->package_mode = PHY_INTERFACE_MODE_NA; 544 + if (!of_property_read_string(shared->np, "qcom,package-mode", 545 + &package_mode_name)) { 546 + if (!strcasecmp(package_mode_name, 547 + phy_modes(PHY_INTERFACE_MODE_PSGMII))) 548 + priv->package_mode = PHY_INTERFACE_MODE_PSGMII; 549 + else if (!strcasecmp(package_mode_name, 550 + phy_modes(PHY_INTERFACE_MODE_QSGMII))) 551 + priv->package_mode = PHY_INTERFACE_MODE_QSGMII; 552 + else 553 + return -EINVAL; 554 + } 555 + 556 + return 0; 557 + } 558 + 559 + static int qca807x_phy_package_config_init_once(struct phy_device *phydev) 560 + { 561 + struct phy_package_shared *shared = phydev->shared; 562 + struct qca807x_shared_priv *priv = shared->priv; 563 + int val, ret; 564 + 565 + phy_lock_mdio_bus(phydev); 566 + 567 + /* Set correct PHY package mode */ 568 + val = __phy_package_read(phydev, QCA807X_COMBO_ADDR, 569 + QCA807X_CHIP_CONFIGURATION); 570 + val &= ~QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK; 571 + /* package_mode can be QSGMII or PSGMII and we validate 572 + * this in probe_once. 573 + * With package_mode to NA, we default to PSGMII. 574 + */ 575 + switch (priv->package_mode) { 576 + case PHY_INTERFACE_MODE_QSGMII: 577 + val |= QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII; 578 + break; 579 + case PHY_INTERFACE_MODE_PSGMII: 580 + default: 581 + val |= QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER; 582 + } 583 + ret = __phy_package_write(phydev, QCA807X_COMBO_ADDR, 584 + QCA807X_CHIP_CONFIGURATION, val); 585 + if (ret) 586 + goto exit; 587 + 588 + /* After mode change Serdes reset is required */ 589 + val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR, 590 + PQSGMII_CTRL_REG); 591 + val &= ~PQSGMII_ANALOG_SW_RESET; 592 + ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR, 593 + PQSGMII_CTRL_REG, val); 594 + if (ret) 595 + goto exit; 596 + 597 + msleep(SERDES_RESET_SLEEP); 598 + 599 + val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR, 600 + PQSGMII_CTRL_REG); 601 + val |= PQSGMII_ANALOG_SW_RESET; 602 + ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR, 603 + PQSGMII_CTRL_REG, val); 604 + if (ret) 605 + goto exit; 606 + 607 + /* Workaround to enable AZ transmitting ability */ 608 + val = __phy_package_read_mmd(phydev, QCA807X_PQSGMII_ADDR, 609 + MDIO_MMD_PMAPMD, PQSGMII_MODE_CTRL); 610 + val &= ~PQSGMII_MODE_CTRL_AZ_WORKAROUND_MASK; 611 + ret = __phy_package_write_mmd(phydev, QCA807X_PQSGMII_ADDR, 612 + MDIO_MMD_PMAPMD, PQSGMII_MODE_CTRL, val); 613 + if (ret) 614 + goto exit; 615 + 616 + /* Set PQSGMII TX AMP strength */ 617 + val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR, 618 + PQSGMII_DRIVE_CONTROL_1); 619 + val &= ~PQSGMII_TX_DRIVER_MASK; 620 + val |= FIELD_PREP(PQSGMII_TX_DRIVER_MASK, priv->tx_drive_strength); 621 + ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR, 622 + PQSGMII_DRIVE_CONTROL_1, val); 623 + if (ret) 624 + goto exit; 625 + 626 + /* Prevent PSGMII going into hibernation via PSGMII self test */ 627 + val = __phy_package_read_mmd(phydev, QCA807X_COMBO_ADDR, 628 + MDIO_MMD_PCS, PQSGMII_MMD3_SERDES_CONTROL); 629 + val &= ~BIT(1); 630 + ret = __phy_package_write_mmd(phydev, QCA807X_COMBO_ADDR, 631 + MDIO_MMD_PCS, PQSGMII_MMD3_SERDES_CONTROL, val); 632 + 633 + exit: 634 + phy_unlock_mdio_bus(phydev); 635 + 636 + return ret; 637 + } 638 + 639 + static int qca807x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) 640 + { 641 + struct phy_device *phydev = upstream; 642 + __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; 643 + phy_interface_t iface; 644 + int ret; 645 + DECLARE_PHY_INTERFACE_MASK(interfaces); 646 + 647 + sfp_parse_support(phydev->sfp_bus, id, support, interfaces); 648 + iface = sfp_select_interface(phydev->sfp_bus, support); 649 + 650 + dev_info(&phydev->mdio.dev, "%s SFP module inserted\n", phy_modes(iface)); 651 + 652 + switch (iface) { 653 + case PHY_INTERFACE_MODE_1000BASEX: 654 + case PHY_INTERFACE_MODE_100BASEX: 655 + /* Set PHY mode to PSGMII combo (1/4 copper + combo ports) mode */ 656 + ret = phy_modify(phydev, 657 + QCA807X_CHIP_CONFIGURATION, 658 + QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK, 659 + QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER); 660 + /* Enable fiber mode autodection (1000Base-X or 100Base-FX) */ 661 + ret = phy_set_bits_mmd(phydev, 662 + MDIO_MMD_AN, 663 + QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION, 664 + QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN); 665 + /* Select fiber page */ 666 + ret = phy_clear_bits(phydev, 667 + QCA807X_CHIP_CONFIGURATION, 668 + QCA807X_BT_BX_REG_SEL); 669 + 670 + phydev->port = PORT_FIBRE; 671 + break; 672 + default: 673 + dev_err(&phydev->mdio.dev, "Incompatible SFP module inserted\n"); 674 + return -EINVAL; 675 + } 676 + 677 + return ret; 678 + } 679 + 680 + static void qca807x_sfp_remove(void *upstream) 681 + { 682 + struct phy_device *phydev = upstream; 683 + 684 + /* Select copper page */ 685 + phy_set_bits(phydev, 686 + QCA807X_CHIP_CONFIGURATION, 687 + QCA807X_BT_BX_REG_SEL); 688 + 689 + phydev->port = PORT_TP; 690 + } 691 + 692 + static const struct sfp_upstream_ops qca807x_sfp_ops = { 693 + .attach = phy_sfp_attach, 694 + .detach = phy_sfp_detach, 695 + .module_insert = qca807x_sfp_insert, 696 + .module_remove = qca807x_sfp_remove, 697 + }; 698 + 699 + static int qca807x_probe(struct phy_device *phydev) 700 + { 701 + struct device_node *node = phydev->mdio.dev.of_node; 702 + struct qca807x_shared_priv *shared_priv; 703 + struct device *dev = &phydev->mdio.dev; 704 + struct phy_package_shared *shared; 705 + struct qca807x_priv *priv; 706 + int ret; 707 + 708 + ret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv)); 709 + if (ret) 710 + return ret; 711 + 712 + if (phy_package_probe_once(phydev)) { 713 + ret = qca807x_phy_package_probe_once(phydev); 714 + if (ret) 715 + return ret; 716 + } 717 + 718 + shared = phydev->shared; 719 + shared_priv = shared->priv; 720 + 721 + /* Make sure PHY follow PHY package mode if enforced */ 722 + if (shared_priv->package_mode != PHY_INTERFACE_MODE_NA && 723 + phydev->interface != shared_priv->package_mode) 724 + return -EINVAL; 725 + 726 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 727 + if (!priv) 728 + return -ENOMEM; 729 + 730 + priv->dac_full_amplitude = of_property_read_bool(node, "qcom,dac-full-amplitude"); 731 + priv->dac_full_bias_current = of_property_read_bool(node, "qcom,dac-full-bias-current"); 732 + priv->dac_disable_bias_current_tweak = of_property_read_bool(node, 733 + "qcom,dac-disable-bias-current-tweak"); 734 + 735 + if (IS_ENABLED(CONFIG_GPIOLIB)) { 736 + /* Make sure we don't have mixed leds node and gpio-controller 737 + * to prevent registering leds and having gpio-controller usage 738 + * conflicting with them. 739 + */ 740 + if (of_find_property(node, "leds", NULL) && 741 + of_find_property(node, "gpio-controller", NULL)) { 742 + phydev_err(phydev, "Invalid property detected. LEDs and gpio-controller are mutually exclusive."); 743 + return -EINVAL; 744 + } 745 + 746 + /* Do not register a GPIO controller unless flagged for it */ 747 + if (of_property_read_bool(node, "gpio-controller")) { 748 + ret = qca807x_gpio(phydev); 749 + if (ret) 750 + return ret; 751 + } 752 + } 753 + 754 + /* Attach SFP bus on combo port*/ 755 + if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) { 756 + ret = phy_sfp_probe(phydev, &qca807x_sfp_ops); 757 + if (ret) 758 + return ret; 759 + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); 760 + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising); 761 + } 762 + 763 + phydev->priv = priv; 764 + 765 + return 0; 766 + } 767 + 768 + static int qca807x_config_init(struct phy_device *phydev) 769 + { 770 + struct qca807x_priv *priv = phydev->priv; 771 + u16 control_dac; 772 + int ret; 773 + 774 + if (phy_package_init_once(phydev)) { 775 + ret = qca807x_phy_package_config_init_once(phydev); 776 + if (ret) 777 + return ret; 778 + } 779 + 780 + control_dac = phy_read_mmd(phydev, MDIO_MMD_AN, 781 + QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH); 782 + control_dac &= ~QCA807X_CONTROL_DAC_MASK; 783 + if (!priv->dac_full_amplitude) 784 + control_dac |= QCA807X_CONTROL_DAC_DSP_AMPLITUDE; 785 + if (!priv->dac_full_amplitude) 786 + control_dac |= QCA807X_CONTROL_DAC_DSP_BIAS_CURRENT; 787 + if (!priv->dac_disable_bias_current_tweak) 788 + control_dac |= QCA807X_CONTROL_DAC_BIAS_CURRENT_TWEAK; 789 + return phy_write_mmd(phydev, MDIO_MMD_AN, 790 + QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH, 791 + control_dac); 792 + } 793 + 794 + static struct phy_driver qca807x_drivers[] = { 795 + { 796 + PHY_ID_MATCH_EXACT(PHY_ID_QCA8072), 797 + .name = "Qualcomm QCA8072", 798 + .flags = PHY_POLL_CABLE_TEST, 799 + /* PHY_GBIT_FEATURES */ 800 + .probe = qca807x_probe, 801 + .config_init = qca807x_config_init, 802 + .read_status = qca807x_read_status, 803 + .config_intr = at803x_config_intr, 804 + .handle_interrupt = at803x_handle_interrupt, 805 + .soft_reset = genphy_soft_reset, 806 + .get_tunable = at803x_get_tunable, 807 + .set_tunable = at803x_set_tunable, 808 + .resume = genphy_resume, 809 + .suspend = genphy_suspend, 810 + .cable_test_start = qca807x_cable_test_start, 811 + .cable_test_get_status = qca808x_cable_test_get_status, 812 + }, 813 + { 814 + PHY_ID_MATCH_EXACT(PHY_ID_QCA8075), 815 + .name = "Qualcomm QCA8075", 816 + .flags = PHY_POLL_CABLE_TEST, 817 + /* PHY_GBIT_FEATURES */ 818 + .probe = qca807x_probe, 819 + .config_init = qca807x_config_init, 820 + .read_status = qca807x_read_status, 821 + .config_intr = at803x_config_intr, 822 + .handle_interrupt = at803x_handle_interrupt, 823 + .soft_reset = genphy_soft_reset, 824 + .get_tunable = at803x_get_tunable, 825 + .set_tunable = at803x_set_tunable, 826 + .resume = genphy_resume, 827 + .suspend = genphy_suspend, 828 + .cable_test_start = qca807x_cable_test_start, 829 + .cable_test_get_status = qca808x_cable_test_get_status, 830 + .led_brightness_set = qca807x_led_brightness_set, 831 + .led_blink_set = qca807x_led_blink_set, 832 + .led_hw_is_supported = qca807x_led_hw_is_supported, 833 + .led_hw_control_set = qca807x_led_hw_control_set, 834 + .led_hw_control_get = qca807x_led_hw_control_get, 835 + }, 836 + }; 837 + module_phy_driver(qca807x_drivers); 838 + 839 + static struct mdio_device_id __maybe_unused qca807x_tbl[] = { 840 + { PHY_ID_MATCH_EXACT(PHY_ID_QCA8072) }, 841 + { PHY_ID_MATCH_EXACT(PHY_ID_QCA8075) }, 842 + { } 843 + }; 844 + 845 + MODULE_AUTHOR("Robert Marko <robert.marko@sartura.hr>"); 846 + MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>"); 847 + MODULE_DESCRIPTION("Qualcomm QCA807x PHY driver"); 848 + MODULE_DEVICE_TABLE(mdio, qca807x_tbl); 849 + MODULE_LICENSE("GPL");
+4 -304
drivers/net/phy/qcom/qca808x.c
··· 2 2 3 3 #include <linux/phy.h> 4 4 #include <linux/module.h> 5 - #include <linux/ethtool_netlink.h> 6 5 7 6 #include "qcom.h" 8 7 ··· 62 63 #define QCA808X_DBG_AN_TEST 0xb 63 64 #define QCA808X_HIBERNATION_EN BIT(15) 64 65 65 - #define QCA808X_CDT_ENABLE_TEST BIT(15) 66 - #define QCA808X_CDT_INTER_CHECK_DIS BIT(13) 67 - #define QCA808X_CDT_STATUS BIT(11) 68 - #define QCA808X_CDT_LENGTH_UNIT BIT(10) 69 - 70 - #define QCA808X_MMD3_CDT_STATUS 0x8064 71 - #define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065 72 - #define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066 73 - #define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067 74 - #define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068 75 - #define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8) 76 - #define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0) 77 - 78 - #define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12) 79 - #define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8) 80 - #define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4) 81 - #define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0) 82 - 83 - #define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0) 84 - #define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0) 85 - #define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1) 86 - #define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2) 87 - #define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3) 88 - 89 - #define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2) 90 - #define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1) 91 - #define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2) 92 - #define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3) 93 - 94 - /* NORMAL are MDI with type set to 0 */ 95 - #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1 96 - #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ 97 - QCA808X_CDT_STATUS_STAT_MDI1) 98 - #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ 99 - QCA808X_CDT_STATUS_STAT_MDI1) 100 - #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2 101 - #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ 102 - QCA808X_CDT_STATUS_STAT_MDI2) 103 - #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ 104 - QCA808X_CDT_STATUS_STAT_MDI2) 105 - #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3 106 - #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ 107 - QCA808X_CDT_STATUS_STAT_MDI3) 108 - #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ 109 - QCA808X_CDT_STATUS_STAT_MDI3) 110 - 111 - /* Added for reference of existence but should be handled by wait_for_completion already */ 112 - #define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3)) 113 - 114 - #define QCA808X_MMD7_LED_GLOBAL 0x8073 115 - #define QCA808X_LED_BLINK_1 GENMASK(11, 6) 116 - #define QCA808X_LED_BLINK_2 GENMASK(5, 0) 117 - /* Values are the same for both BLINK_1 and BLINK_2 */ 118 - #define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3) 119 - #define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0) 120 - #define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1) 121 - #define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2) 122 - #define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3) 123 - #define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4) 124 - #define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5) 125 - #define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6) 126 - #define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7) 127 - #define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0) 128 - #define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0) 129 - #define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1) 130 - #define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2) 131 - #define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3) 132 - #define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4) 133 - #define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5) 134 - #define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6) 135 - #define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7) 136 - 137 66 #define QCA808X_MMD7_LED2_CTRL 0x8074 138 67 #define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075 139 68 #define QCA808X_MMD7_LED1_CTRL 0x8076 ··· 69 142 #define QCA808X_MMD7_LED0_CTRL 0x8078 70 143 #define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2)) 71 144 72 - /* LED hw control pattern is the same for every LED */ 73 - #define QCA808X_LED_PATTERN_MASK GENMASK(15, 0) 74 - #define QCA808X_LED_SPEED2500_ON BIT(15) 75 - #define QCA808X_LED_SPEED2500_BLINK BIT(14) 76 - /* Follow blink trigger even if duplex or speed condition doesn't match */ 77 - #define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13) 78 - #define QCA808X_LED_FULL_DUPLEX_ON BIT(12) 79 - #define QCA808X_LED_HALF_DUPLEX_ON BIT(11) 80 - #define QCA808X_LED_TX_BLINK BIT(10) 81 - #define QCA808X_LED_RX_BLINK BIT(9) 82 - #define QCA808X_LED_TX_ON_10MS BIT(8) 83 - #define QCA808X_LED_RX_ON_10MS BIT(7) 84 - #define QCA808X_LED_SPEED1000_ON BIT(6) 85 - #define QCA808X_LED_SPEED100_ON BIT(5) 86 - #define QCA808X_LED_SPEED10_ON BIT(4) 87 - #define QCA808X_LED_COLLISION_BLINK BIT(3) 88 - #define QCA808X_LED_SPEED1000_BLINK BIT(2) 89 - #define QCA808X_LED_SPEED100_BLINK BIT(1) 90 - #define QCA808X_LED_SPEED10_BLINK BIT(0) 91 - 92 145 #define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079 93 146 #define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2)) 94 - 95 - /* LED force ctrl is the same for every LED 96 - * No documentation exist for this, not even internal one 97 - * with NDA as QCOM gives only info about configuring 98 - * hw control pattern rules and doesn't indicate any way 99 - * to force the LED to specific mode. 100 - * These define comes from reverse and testing and maybe 101 - * lack of some info or some info are not entirely correct. 102 - * For the basic LED control and hw control these finding 103 - * are enough to support LED control in all the required APIs. 104 - * 105 - * On doing some comparison with implementation with qca807x, 106 - * it was found that it's 1:1 equal to it and confirms all the 107 - * reverse done. It was also found further specification with the 108 - * force mode and the blink modes. 109 - */ 110 - #define QCA808X_LED_FORCE_EN BIT(15) 111 - #define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13) 112 - #define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3) 113 - #define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2) 114 - #define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1) 115 - #define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0) 116 147 117 148 #define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a 118 149 /* QSDK sets by default 0x46 to this reg that sets BIT 6 for ··· 291 406 return ret; 292 407 } 293 408 294 - static bool qca808x_cdt_fault_length_valid(int cdt_code) 295 - { 296 - switch (cdt_code) { 297 - case QCA808X_CDT_STATUS_STAT_SAME_SHORT: 298 - case QCA808X_CDT_STATUS_STAT_SAME_OPEN: 299 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: 300 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: 301 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: 302 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: 303 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: 304 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: 305 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: 306 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: 307 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: 308 - return true; 309 - default: 310 - return false; 311 - } 312 - } 313 - 314 - static int qca808x_cable_test_result_trans(int cdt_code) 315 - { 316 - switch (cdt_code) { 317 - case QCA808X_CDT_STATUS_STAT_NORMAL: 318 - return ETHTOOL_A_CABLE_RESULT_CODE_OK; 319 - case QCA808X_CDT_STATUS_STAT_SAME_SHORT: 320 - return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; 321 - case QCA808X_CDT_STATUS_STAT_SAME_OPEN: 322 - return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; 323 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: 324 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: 325 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: 326 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: 327 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: 328 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: 329 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: 330 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: 331 - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: 332 - return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; 333 - case QCA808X_CDT_STATUS_STAT_FAIL: 334 - default: 335 - return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; 336 - } 337 - } 338 - 339 - static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair, 340 - int result) 341 - { 342 - int val; 343 - u32 cdt_length_reg = 0; 344 - 345 - switch (pair) { 346 - case ETHTOOL_A_CABLE_PAIR_A: 347 - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A; 348 - break; 349 - case ETHTOOL_A_CABLE_PAIR_B: 350 - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B; 351 - break; 352 - case ETHTOOL_A_CABLE_PAIR_C: 353 - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C; 354 - break; 355 - case ETHTOOL_A_CABLE_PAIR_D: 356 - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D; 357 - break; 358 - default: 359 - return -EINVAL; 360 - } 361 - 362 - val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg); 363 - if (val < 0) 364 - return val; 365 - 366 - if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT) 367 - val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val); 368 - else 369 - val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val); 370 - 371 - return at803x_cdt_fault_length(val); 372 - } 373 - 374 409 static int qca808x_cable_test_start(struct phy_device *phydev) 375 410 { 376 411 int ret; ··· 328 523 phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050); 329 524 phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060); 330 525 phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060); 331 - 332 - return 0; 333 - } 334 - 335 - static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair, 336 - u16 status) 337 - { 338 - int length, result; 339 - u16 pair_code; 340 - 341 - switch (pair) { 342 - case ETHTOOL_A_CABLE_PAIR_A: 343 - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status); 344 - break; 345 - case ETHTOOL_A_CABLE_PAIR_B: 346 - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status); 347 - break; 348 - case ETHTOOL_A_CABLE_PAIR_C: 349 - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status); 350 - break; 351 - case ETHTOOL_A_CABLE_PAIR_D: 352 - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status); 353 - break; 354 - default: 355 - return -EINVAL; 356 - } 357 - 358 - result = qca808x_cable_test_result_trans(pair_code); 359 - ethnl_cable_test_result(phydev, pair, result); 360 - 361 - if (qca808x_cdt_fault_length_valid(pair_code)) { 362 - length = qca808x_cdt_fault_length(phydev, pair, result); 363 - ethnl_cable_test_fault_length(phydev, pair, length); 364 - } 365 - 366 - return 0; 367 - } 368 - 369 - static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) 370 - { 371 - int ret, val; 372 - 373 - *finished = false; 374 - 375 - val = QCA808X_CDT_ENABLE_TEST | 376 - QCA808X_CDT_LENGTH_UNIT; 377 - ret = at803x_cdt_start(phydev, val); 378 - if (ret) 379 - return ret; 380 - 381 - ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST); 382 - if (ret) 383 - return ret; 384 - 385 - val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS); 386 - if (val < 0) 387 - return val; 388 - 389 - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val); 390 - if (ret) 391 - return ret; 392 - 393 - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val); 394 - if (ret) 395 - return ret; 396 - 397 - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val); 398 - if (ret) 399 - return ret; 400 - 401 - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val); 402 - if (ret) 403 - return ret; 404 - 405 - *finished = true; 406 526 407 527 return 0; 408 528 } ··· 437 707 return -EINVAL; 438 708 439 709 reg = QCA808X_MMD7_LED_FORCE_CTRL(index); 440 - 441 - return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, 442 - QCA808X_LED_FORCE_EN); 710 + return qca808x_led_reg_hw_control_enable(phydev, reg); 443 711 } 444 712 445 713 static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index, ··· 478 750 static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index) 479 751 { 480 752 u16 reg; 481 - int val; 482 753 483 754 if (index > 2) 484 755 return false; 485 756 486 757 reg = QCA808X_MMD7_LED_FORCE_CTRL(index); 487 - 488 - val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); 489 - 490 - return !(val & QCA808X_LED_FORCE_EN); 758 + return qca808x_led_reg_hw_control_status(phydev, reg); 491 759 } 492 760 493 761 static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index, ··· 551 827 } 552 828 553 829 reg = QCA808X_MMD7_LED_FORCE_CTRL(index); 554 - 555 - return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, 556 - QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, 557 - QCA808X_LED_FORCE_EN | (value ? QCA808X_LED_FORCE_ON : 558 - QCA808X_LED_FORCE_OFF)); 830 + return qca808x_led_reg_brightness_set(phydev, reg, value); 559 831 } 560 832 561 833 static int qca808x_led_blink_set(struct phy_device *phydev, u8 index, 562 834 unsigned long *delay_on, 563 835 unsigned long *delay_off) 564 836 { 565 - int ret; 566 837 u16 reg; 567 838 568 839 if (index > 2) 569 840 return -EINVAL; 570 841 571 842 reg = QCA808X_MMD7_LED_FORCE_CTRL(index); 572 - 573 - /* Set blink to 50% off, 50% on at 4Hz by default */ 574 - ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL, 575 - QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK, 576 - QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50); 577 - if (ret) 578 - return ret; 579 - 580 - /* We use BLINK_1 for normal blinking */ 581 - ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg, 582 - QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, 583 - QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1); 584 - if (ret) 585 - return ret; 586 - 587 - /* We set blink to 4Hz, aka 250ms */ 588 - *delay_on = 250 / 2; 589 - *delay_off = 250 / 2; 590 - 591 - return 0; 843 + return qca808x_led_reg_blink_set(phydev, reg, delay_on, delay_off); 592 844 } 593 845 594 846 static int qca808x_led_polarity_set(struct phy_device *phydev, int index,
+247
drivers/net/phy/qcom/qcom-phy-lib.c
··· 5 5 6 6 #include <linux/netdevice.h> 7 7 #include <linux/etherdevice.h> 8 + #include <linux/ethtool_netlink.h> 8 9 9 10 #include "qcom.h" 10 11 ··· 312 311 } 313 312 EXPORT_SYMBOL_GPL(at803x_prepare_config_aneg); 314 313 314 + int at803x_read_status(struct phy_device *phydev) 315 + { 316 + struct at803x_ss_mask ss_mask = { 0 }; 317 + int err, old_link = phydev->link; 318 + 319 + /* Update the link, but return if there was an error */ 320 + err = genphy_update_link(phydev); 321 + if (err) 322 + return err; 323 + 324 + /* why bother the PHY if nothing can have changed */ 325 + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) 326 + return 0; 327 + 328 + phydev->speed = SPEED_UNKNOWN; 329 + phydev->duplex = DUPLEX_UNKNOWN; 330 + phydev->pause = 0; 331 + phydev->asym_pause = 0; 332 + 333 + err = genphy_read_lpa(phydev); 334 + if (err < 0) 335 + return err; 336 + 337 + ss_mask.speed_mask = AT803X_SS_SPEED_MASK; 338 + ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK); 339 + err = at803x_read_specific_status(phydev, ss_mask); 340 + if (err < 0) 341 + return err; 342 + 343 + if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) 344 + phy_resolve_aneg_pause(phydev); 345 + 346 + return 0; 347 + } 348 + EXPORT_SYMBOL_GPL(at803x_read_status); 349 + 315 350 static int at803x_get_downshift(struct phy_device *phydev, u8 *d) 316 351 { 317 352 int val; ··· 464 427 return ret < 0 ? ret : 0; 465 428 } 466 429 EXPORT_SYMBOL_GPL(at803x_cdt_wait_for_completion); 430 + 431 + static bool qca808x_cdt_fault_length_valid(int cdt_code) 432 + { 433 + switch (cdt_code) { 434 + case QCA808X_CDT_STATUS_STAT_SAME_SHORT: 435 + case QCA808X_CDT_STATUS_STAT_SAME_OPEN: 436 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: 437 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: 438 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: 439 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: 440 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: 441 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: 442 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: 443 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: 444 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: 445 + return true; 446 + default: 447 + return false; 448 + } 449 + } 450 + 451 + static int qca808x_cable_test_result_trans(int cdt_code) 452 + { 453 + switch (cdt_code) { 454 + case QCA808X_CDT_STATUS_STAT_NORMAL: 455 + return ETHTOOL_A_CABLE_RESULT_CODE_OK; 456 + case QCA808X_CDT_STATUS_STAT_SAME_SHORT: 457 + return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; 458 + case QCA808X_CDT_STATUS_STAT_SAME_OPEN: 459 + return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; 460 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: 461 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: 462 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: 463 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: 464 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: 465 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: 466 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: 467 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: 468 + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: 469 + return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; 470 + case QCA808X_CDT_STATUS_STAT_FAIL: 471 + default: 472 + return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; 473 + } 474 + } 475 + 476 + static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair, 477 + int result) 478 + { 479 + int val; 480 + u32 cdt_length_reg = 0; 481 + 482 + switch (pair) { 483 + case ETHTOOL_A_CABLE_PAIR_A: 484 + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A; 485 + break; 486 + case ETHTOOL_A_CABLE_PAIR_B: 487 + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B; 488 + break; 489 + case ETHTOOL_A_CABLE_PAIR_C: 490 + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C; 491 + break; 492 + case ETHTOOL_A_CABLE_PAIR_D: 493 + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D; 494 + break; 495 + default: 496 + return -EINVAL; 497 + } 498 + 499 + val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg); 500 + if (val < 0) 501 + return val; 502 + 503 + if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT) 504 + val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val); 505 + else 506 + val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val); 507 + 508 + return at803x_cdt_fault_length(val); 509 + } 510 + 511 + static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair, 512 + u16 status) 513 + { 514 + int length, result; 515 + u16 pair_code; 516 + 517 + switch (pair) { 518 + case ETHTOOL_A_CABLE_PAIR_A: 519 + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status); 520 + break; 521 + case ETHTOOL_A_CABLE_PAIR_B: 522 + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status); 523 + break; 524 + case ETHTOOL_A_CABLE_PAIR_C: 525 + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status); 526 + break; 527 + case ETHTOOL_A_CABLE_PAIR_D: 528 + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status); 529 + break; 530 + default: 531 + return -EINVAL; 532 + } 533 + 534 + result = qca808x_cable_test_result_trans(pair_code); 535 + ethnl_cable_test_result(phydev, pair, result); 536 + 537 + if (qca808x_cdt_fault_length_valid(pair_code)) { 538 + length = qca808x_cdt_fault_length(phydev, pair, result); 539 + ethnl_cable_test_fault_length(phydev, pair, length); 540 + } 541 + 542 + return 0; 543 + } 544 + 545 + int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) 546 + { 547 + int ret, val; 548 + 549 + *finished = false; 550 + 551 + val = QCA808X_CDT_ENABLE_TEST | 552 + QCA808X_CDT_LENGTH_UNIT; 553 + ret = at803x_cdt_start(phydev, val); 554 + if (ret) 555 + return ret; 556 + 557 + ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST); 558 + if (ret) 559 + return ret; 560 + 561 + val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS); 562 + if (val < 0) 563 + return val; 564 + 565 + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val); 566 + if (ret) 567 + return ret; 568 + 569 + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val); 570 + if (ret) 571 + return ret; 572 + 573 + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val); 574 + if (ret) 575 + return ret; 576 + 577 + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val); 578 + if (ret) 579 + return ret; 580 + 581 + *finished = true; 582 + 583 + return 0; 584 + } 585 + EXPORT_SYMBOL_GPL(qca808x_cable_test_get_status); 586 + 587 + int qca808x_led_reg_hw_control_enable(struct phy_device *phydev, u16 reg) 588 + { 589 + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, 590 + QCA808X_LED_FORCE_EN); 591 + } 592 + EXPORT_SYMBOL_GPL(qca808x_led_reg_hw_control_enable); 593 + 594 + bool qca808x_led_reg_hw_control_status(struct phy_device *phydev, u16 reg) 595 + { 596 + int val; 597 + 598 + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); 599 + return !(val & QCA808X_LED_FORCE_EN); 600 + } 601 + EXPORT_SYMBOL_GPL(qca808x_led_reg_hw_control_status); 602 + 603 + int qca808x_led_reg_brightness_set(struct phy_device *phydev, 604 + u16 reg, enum led_brightness value) 605 + { 606 + return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, 607 + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, 608 + QCA808X_LED_FORCE_EN | (value ? QCA808X_LED_FORCE_ON : 609 + QCA808X_LED_FORCE_OFF)); 610 + } 611 + EXPORT_SYMBOL_GPL(qca808x_led_reg_brightness_set); 612 + 613 + int qca808x_led_reg_blink_set(struct phy_device *phydev, u16 reg, 614 + unsigned long *delay_on, 615 + unsigned long *delay_off) 616 + { 617 + int ret; 618 + 619 + /* Set blink to 50% off, 50% on at 4Hz by default */ 620 + ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL, 621 + QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK, 622 + QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50); 623 + if (ret) 624 + return ret; 625 + 626 + /* We use BLINK_1 for normal blinking */ 627 + ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg, 628 + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, 629 + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1); 630 + if (ret) 631 + return ret; 632 + 633 + /* We set blink to 4Hz, aka 250ms */ 634 + *delay_on = 250 / 2; 635 + *delay_off = 250 / 2; 636 + 637 + return 0; 638 + } 639 + EXPORT_SYMBOL_GPL(qca808x_led_reg_blink_set);
+123
drivers/net/phy/qcom/qcom.h
··· 54 54 #define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) 55 55 #define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) 56 56 57 + #define QCA808X_CDT_ENABLE_TEST BIT(15) 58 + #define QCA808X_CDT_INTER_CHECK_DIS BIT(13) 59 + #define QCA808X_CDT_STATUS BIT(11) 60 + #define QCA808X_CDT_LENGTH_UNIT BIT(10) 61 + 62 + #define QCA808X_MMD3_CDT_STATUS 0x8064 63 + #define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065 64 + #define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066 65 + #define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067 66 + #define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068 67 + #define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8) 68 + #define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0) 69 + 70 + #define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12) 71 + #define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8) 72 + #define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4) 73 + #define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0) 74 + 75 + #define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0) 76 + #define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0) 77 + #define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1) 78 + #define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2) 79 + #define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3) 80 + 81 + #define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2) 82 + #define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1) 83 + #define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2) 84 + #define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3) 85 + 86 + /* NORMAL are MDI with type set to 0 */ 87 + #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1 88 + #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ 89 + QCA808X_CDT_STATUS_STAT_MDI1) 90 + #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ 91 + QCA808X_CDT_STATUS_STAT_MDI1) 92 + #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2 93 + #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ 94 + QCA808X_CDT_STATUS_STAT_MDI2) 95 + #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ 96 + QCA808X_CDT_STATUS_STAT_MDI2) 97 + #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3 98 + #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ 99 + QCA808X_CDT_STATUS_STAT_MDI3) 100 + #define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ 101 + QCA808X_CDT_STATUS_STAT_MDI3) 102 + 103 + /* Added for reference of existence but should be handled by wait_for_completion already */ 104 + #define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3)) 105 + 106 + #define QCA808X_MMD7_LED_GLOBAL 0x8073 107 + #define QCA808X_LED_BLINK_1 GENMASK(11, 6) 108 + #define QCA808X_LED_BLINK_2 GENMASK(5, 0) 109 + /* Values are the same for both BLINK_1 and BLINK_2 */ 110 + #define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3) 111 + #define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0) 112 + #define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1) 113 + #define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2) 114 + #define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3) 115 + #define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4) 116 + #define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5) 117 + #define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6) 118 + #define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7) 119 + #define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0) 120 + #define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0) 121 + #define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1) 122 + #define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2) 123 + #define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3) 124 + #define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4) 125 + #define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5) 126 + #define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6) 127 + #define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7) 128 + 129 + /* LED hw control pattern is the same for every LED */ 130 + #define QCA808X_LED_PATTERN_MASK GENMASK(15, 0) 131 + #define QCA808X_LED_SPEED2500_ON BIT(15) 132 + #define QCA808X_LED_SPEED2500_BLINK BIT(14) 133 + /* Follow blink trigger even if duplex or speed condition doesn't match */ 134 + #define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13) 135 + #define QCA808X_LED_FULL_DUPLEX_ON BIT(12) 136 + #define QCA808X_LED_HALF_DUPLEX_ON BIT(11) 137 + #define QCA808X_LED_TX_BLINK BIT(10) 138 + #define QCA808X_LED_RX_BLINK BIT(9) 139 + #define QCA808X_LED_TX_ON_10MS BIT(8) 140 + #define QCA808X_LED_RX_ON_10MS BIT(7) 141 + #define QCA808X_LED_SPEED1000_ON BIT(6) 142 + #define QCA808X_LED_SPEED100_ON BIT(5) 143 + #define QCA808X_LED_SPEED10_ON BIT(4) 144 + #define QCA808X_LED_COLLISION_BLINK BIT(3) 145 + #define QCA808X_LED_SPEED1000_BLINK BIT(2) 146 + #define QCA808X_LED_SPEED100_BLINK BIT(1) 147 + #define QCA808X_LED_SPEED10_BLINK BIT(0) 148 + 149 + /* LED force ctrl is the same for every LED 150 + * No documentation exist for this, not even internal one 151 + * with NDA as QCOM gives only info about configuring 152 + * hw control pattern rules and doesn't indicate any way 153 + * to force the LED to specific mode. 154 + * These define comes from reverse and testing and maybe 155 + * lack of some info or some info are not entirely correct. 156 + * For the basic LED control and hw control these finding 157 + * are enough to support LED control in all the required APIs. 158 + * 159 + * On doing some comparison with implementation with qca807x, 160 + * it was found that it's 1:1 equal to it and confirms all the 161 + * reverse done. It was also found further specification with the 162 + * force mode and the blink modes. 163 + */ 164 + #define QCA808X_LED_FORCE_EN BIT(15) 165 + #define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13) 166 + #define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3) 167 + #define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2) 168 + #define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1) 169 + #define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0) 170 + 57 171 #define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C 58 172 #define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B 59 173 #define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A ··· 224 110 struct at803x_ss_mask ss_mask); 225 111 int at803x_config_mdix(struct phy_device *phydev, u8 ctrl); 226 112 int at803x_prepare_config_aneg(struct phy_device *phydev); 113 + int at803x_read_status(struct phy_device *phydev); 227 114 int at803x_get_tunable(struct phy_device *phydev, 228 115 struct ethtool_tunable *tuna, void *data); 229 116 int at803x_set_tunable(struct phy_device *phydev, ··· 233 118 int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start); 234 119 int at803x_cdt_wait_for_completion(struct phy_device *phydev, 235 120 u32 cdt_en); 121 + int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished); 122 + int qca808x_led_reg_hw_control_enable(struct phy_device *phydev, u16 reg); 123 + bool qca808x_led_reg_hw_control_status(struct phy_device *phydev, u16 reg); 124 + int qca808x_led_reg_brightness_set(struct phy_device *phydev, 125 + u16 reg, enum led_brightness value); 126 + int qca808x_led_reg_blink_set(struct phy_device *phydev, u16 reg, 127 + unsigned long *delay_on, 128 + unsigned long *delay_off);
+7 -1
include/linux/phy.h
··· 329 329 * struct phy_package_shared - Shared information in PHY packages 330 330 * @base_addr: Base PHY address of PHY package used to combine PHYs 331 331 * in one package and for offset calculation of phy_package_read/write 332 + * @np: Pointer to the Device Node if PHY package defined in DT 332 333 * @refcnt: Number of PHYs connected to this shared data 333 334 * @flags: Initialization of PHY package 334 335 * @priv_size: Size of the shared private data @priv ··· 341 340 */ 342 341 struct phy_package_shared { 343 342 u8 base_addr; 343 + /* With PHY package defined in DT this points to the PHY package node */ 344 + struct device_node *np; 344 345 refcount_t refcnt; 345 346 unsigned long flags; 346 347 size_t priv_size; ··· 1876 1873 1877 1874 /* Clause 37 */ 1878 1875 int genphy_c37_config_aneg(struct phy_device *phydev); 1879 - int genphy_c37_read_status(struct phy_device *phydev); 1876 + int genphy_c37_read_status(struct phy_device *phydev, bool *changed); 1880 1877 1881 1878 /* Clause 45 PHY */ 1882 1879 int genphy_c45_restart_aneg(struct phy_device *phydev); ··· 2003 2000 const struct ethtool_link_ksettings *cmd); 2004 2001 int phy_ethtool_nway_reset(struct net_device *ndev); 2005 2002 int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size); 2003 + int of_phy_package_join(struct phy_device *phydev, size_t priv_size); 2006 2004 void phy_package_leave(struct phy_device *phydev); 2007 2005 int devm_phy_package_join(struct device *dev, struct phy_device *phydev, 2008 2006 int base_addr, size_t priv_size); 2007 + int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev, 2008 + size_t priv_size); 2009 2009 2010 2010 int __init mdio_bus_init(void); 2011 2011 void mdio_bus_exit(void);