1a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0+ 2c4b41c9fSMaciej W. Rozycki /* 3c4b41c9fSMaciej W. Rozycki * drivers/net/phy/broadcom.c 4c4b41c9fSMaciej W. Rozycki * 5c4b41c9fSMaciej W. Rozycki * Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet 6c4b41c9fSMaciej W. Rozycki * transceivers. 7c4b41c9fSMaciej W. Rozycki * 8c4b41c9fSMaciej W. Rozycki * Copyright (c) 2006 Maciej W. Rozycki 9c4b41c9fSMaciej W. Rozycki * 10c4b41c9fSMaciej W. Rozycki * Inspired by code written by Amy Fong. 11c4b41c9fSMaciej W. Rozycki */ 12c4b41c9fSMaciej W. Rozycki 13a1cba561SArun Parameswaran #include "bcm-phy-lib.h" 14bf8bfc43SFlorian Fainelli #include <linux/delay.h> 15c4b41c9fSMaciej W. Rozycki #include <linux/module.h> 16c4b41c9fSMaciej W. Rozycki #include <linux/phy.h> 178649f13dSMatt Carlson #include <linux/brcmphy.h> 18b14995acSJon Mason #include <linux/of.h> 19d9221e66SMatt Carlson 20d9221e66SMatt Carlson #define BRCM_PHY_MODEL(phydev) \ 21d9221e66SMatt Carlson ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask) 22d9221e66SMatt Carlson 2332e5a8d6SMatt Carlson #define BRCM_PHY_REV(phydev) \ 2432e5a8d6SMatt Carlson ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask)) 2532e5a8d6SMatt Carlson 26c4b41c9fSMaciej W. Rozycki MODULE_DESCRIPTION("Broadcom PHY driver"); 27c4b41c9fSMaciej W. Rozycki MODULE_AUTHOR("Maciej W. Rozycki"); 28c4b41c9fSMaciej W. Rozycki MODULE_LICENSE("GPL"); 29c4b41c9fSMaciej W. Rozycki 3015acf89eSJonathan Lemon struct bcm54xx_phy_priv { 3115acf89eSJonathan Lemon u64 *stats; 3215acf89eSJonathan Lemon struct bcm_ptp_private *ptp; 3315acf89eSJonathan Lemon }; 3415acf89eSJonathan Lemon 35042cb564STao Ren static int bcm54xx_config_clock_delay(struct phy_device *phydev) 36b14995acSJon Mason { 37b14995acSJon Mason int rc, val; 38b14995acSJon Mason 3973333626SAbhishek Shah /* handling PHY's internal RX clock delay */ 40b14995acSJon Mason val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 41b14995acSJon Mason val |= MII_BCM54XX_AUXCTL_MISC_WREN; 4273333626SAbhishek Shah if (phydev->interface == PHY_INTERFACE_MODE_RGMII || 4373333626SAbhishek Shah phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 4473333626SAbhishek Shah /* Disable RGMII RXC-RXD skew */ 4573333626SAbhishek Shah val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; 4673333626SAbhishek Shah } 4773333626SAbhishek Shah if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 4873333626SAbhishek Shah phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 4973333626SAbhishek Shah /* Enable RGMII RXC-RXD skew */ 5073333626SAbhishek Shah val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; 5173333626SAbhishek Shah } 52b14995acSJon Mason rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, 53b14995acSJon Mason val); 54b14995acSJon Mason if (rc < 0) 55b14995acSJon Mason return rc; 56b14995acSJon Mason 5773333626SAbhishek Shah /* handling PHY's internal TX clock delay */ 58b14995acSJon Mason val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL); 5973333626SAbhishek Shah if (phydev->interface == PHY_INTERFACE_MODE_RGMII || 6073333626SAbhishek Shah phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 6173333626SAbhishek Shah /* Disable internal TX clock delay */ 62b14995acSJon Mason val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN; 6373333626SAbhishek Shah } 6473333626SAbhishek Shah if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 6573333626SAbhishek Shah phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 6673333626SAbhishek Shah /* Enable internal TX clock delay */ 6773333626SAbhishek Shah val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN; 6873333626SAbhishek Shah } 69b14995acSJon Mason rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); 70b14995acSJon Mason if (rc < 0) 71b14995acSJon Mason return rc; 72b14995acSJon Mason 73b14995acSJon Mason return 0; 74b14995acSJon Mason } 75b14995acSJon Mason 76133bf7b4SFlorian Fainelli static int bcm54210e_config_init(struct phy_device *phydev) 77133bf7b4SFlorian Fainelli { 78133bf7b4SFlorian Fainelli int val; 79133bf7b4SFlorian Fainelli 80133bf7b4SFlorian Fainelli bcm54xx_config_clock_delay(phydev); 81133bf7b4SFlorian Fainelli 82133bf7b4SFlorian Fainelli if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) { 83133bf7b4SFlorian Fainelli val = phy_read(phydev, MII_CTRL1000); 84133bf7b4SFlorian Fainelli val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER; 85133bf7b4SFlorian Fainelli phy_write(phydev, MII_CTRL1000, val); 86133bf7b4SFlorian Fainelli } 87133bf7b4SFlorian Fainelli 88133bf7b4SFlorian Fainelli return 0; 89133bf7b4SFlorian Fainelli } 90133bf7b4SFlorian Fainelli 91133bf7b4SFlorian Fainelli static int bcm54612e_config_init(struct phy_device *phydev) 92133bf7b4SFlorian Fainelli { 93133bf7b4SFlorian Fainelli int reg; 94133bf7b4SFlorian Fainelli 95133bf7b4SFlorian Fainelli bcm54xx_config_clock_delay(phydev); 96133bf7b4SFlorian Fainelli 97133bf7b4SFlorian Fainelli /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ 98133bf7b4SFlorian Fainelli if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { 99133bf7b4SFlorian Fainelli int err; 100133bf7b4SFlorian Fainelli 101133bf7b4SFlorian Fainelli reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); 102133bf7b4SFlorian Fainelli err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0, 103133bf7b4SFlorian Fainelli BCM54612E_LED4_CLK125OUT_EN | reg); 104133bf7b4SFlorian Fainelli 105133bf7b4SFlorian Fainelli if (err < 0) 106133bf7b4SFlorian Fainelli return err; 107133bf7b4SFlorian Fainelli } 108133bf7b4SFlorian Fainelli 109133bf7b4SFlorian Fainelli return 0; 110133bf7b4SFlorian Fainelli } 111133bf7b4SFlorian Fainelli 1123afd0218SRobert Hancock static int bcm54616s_config_init(struct phy_device *phydev) 1133afd0218SRobert Hancock { 1143afd0218SRobert Hancock int rc, val; 1153afd0218SRobert Hancock 1163afd0218SRobert Hancock if (phydev->interface != PHY_INTERFACE_MODE_SGMII && 1173afd0218SRobert Hancock phydev->interface != PHY_INTERFACE_MODE_1000BASEX) 1183afd0218SRobert Hancock return 0; 1193afd0218SRobert Hancock 1203afd0218SRobert Hancock /* Ensure proper interface mode is selected. */ 1213afd0218SRobert Hancock /* Disable RGMII mode */ 1223afd0218SRobert Hancock val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 1233afd0218SRobert Hancock if (val < 0) 1243afd0218SRobert Hancock return val; 1253afd0218SRobert Hancock val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN; 1263afd0218SRobert Hancock val |= MII_BCM54XX_AUXCTL_MISC_WREN; 1273afd0218SRobert Hancock rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, 1283afd0218SRobert Hancock val); 1293afd0218SRobert Hancock if (rc < 0) 1303afd0218SRobert Hancock return rc; 1313afd0218SRobert Hancock 1323afd0218SRobert Hancock /* Select 1000BASE-X register set (primary SerDes) */ 1333afd0218SRobert Hancock val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); 1343afd0218SRobert Hancock if (val < 0) 1353afd0218SRobert Hancock return val; 1363afd0218SRobert Hancock val |= BCM54XX_SHD_MODE_1000BX; 1373afd0218SRobert Hancock rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val); 1383afd0218SRobert Hancock if (rc < 0) 1393afd0218SRobert Hancock return rc; 1403afd0218SRobert Hancock 1413afd0218SRobert Hancock /* Power down SerDes interface */ 1423afd0218SRobert Hancock rc = phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN); 1433afd0218SRobert Hancock if (rc < 0) 1443afd0218SRobert Hancock return rc; 1453afd0218SRobert Hancock 1463afd0218SRobert Hancock /* Select proper interface mode */ 1473afd0218SRobert Hancock val &= ~BCM54XX_SHD_INTF_SEL_MASK; 1483afd0218SRobert Hancock val |= phydev->interface == PHY_INTERFACE_MODE_SGMII ? 1493afd0218SRobert Hancock BCM54XX_SHD_INTF_SEL_SGMII : 1503afd0218SRobert Hancock BCM54XX_SHD_INTF_SEL_GBIC; 1513afd0218SRobert Hancock rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val); 1523afd0218SRobert Hancock if (rc < 0) 1533afd0218SRobert Hancock return rc; 1543afd0218SRobert Hancock 1553afd0218SRobert Hancock /* Power up SerDes interface */ 1563afd0218SRobert Hancock rc = phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN); 1573afd0218SRobert Hancock if (rc < 0) 1583afd0218SRobert Hancock return rc; 1593afd0218SRobert Hancock 1603afd0218SRobert Hancock /* Select copper register set */ 1613afd0218SRobert Hancock val &= ~BCM54XX_SHD_MODE_1000BX; 1623afd0218SRobert Hancock rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val); 1633afd0218SRobert Hancock if (rc < 0) 1643afd0218SRobert Hancock return rc; 1653afd0218SRobert Hancock 1663afd0218SRobert Hancock /* Power up copper interface */ 1673afd0218SRobert Hancock return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN); 1683afd0218SRobert Hancock } 1693afd0218SRobert Hancock 17047b1b53bSMatt Carlson /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */ 171772638b6SMatt Carlson static int bcm50610_a0_workaround(struct phy_device *phydev) 172772638b6SMatt Carlson { 173772638b6SMatt Carlson int err; 174772638b6SMatt Carlson 175a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0, 17647b1b53bSMatt Carlson MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | 17747b1b53bSMatt Carlson MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); 17847b1b53bSMatt Carlson if (err < 0) 17947b1b53bSMatt Carlson return err; 18047b1b53bSMatt Carlson 181a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3, 18247b1b53bSMatt Carlson MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); 18347b1b53bSMatt Carlson if (err < 0) 18447b1b53bSMatt Carlson return err; 18547b1b53bSMatt Carlson 186a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, 18747b1b53bSMatt Carlson MII_BCM54XX_EXP_EXP75_VDACCTRL); 18847b1b53bSMatt Carlson if (err < 0) 18947b1b53bSMatt Carlson return err; 19047b1b53bSMatt Carlson 191a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96, 19247b1b53bSMatt Carlson MII_BCM54XX_EXP_EXP96_MYST); 19347b1b53bSMatt Carlson if (err < 0) 19447b1b53bSMatt Carlson return err; 19547b1b53bSMatt Carlson 196a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97, 19747b1b53bSMatt Carlson MII_BCM54XX_EXP_EXP97_MYST); 19847b1b53bSMatt Carlson 19947b1b53bSMatt Carlson return err; 20047b1b53bSMatt Carlson } 20147b1b53bSMatt Carlson 20247b1b53bSMatt Carlson static int bcm54xx_phydsp_config(struct phy_device *phydev) 20347b1b53bSMatt Carlson { 20447b1b53bSMatt Carlson int err, err2; 20547b1b53bSMatt Carlson 20647b1b53bSMatt Carlson /* Enable the SMDSP clock */ 207772638b6SMatt Carlson err = bcm54xx_auxctl_write(phydev, 208772638b6SMatt Carlson MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, 209772638b6SMatt Carlson MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | 210772638b6SMatt Carlson MII_BCM54XX_AUXCTL_ACTL_TX_6DB); 211772638b6SMatt Carlson if (err < 0) 212772638b6SMatt Carlson return err; 213772638b6SMatt Carlson 214219c6efeSMatt Carlson if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 215219c6efeSMatt Carlson BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) { 216219c6efeSMatt Carlson /* Clear bit 9 to fix a phy interop issue. */ 217a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08, 218219c6efeSMatt Carlson MII_BCM54XX_EXP_EXP08_RJCT_2MHZ); 219219c6efeSMatt Carlson if (err < 0) 220219c6efeSMatt Carlson goto error; 221219c6efeSMatt Carlson 222219c6efeSMatt Carlson if (phydev->drv->phy_id == PHY_ID_BCM50610) { 22347b1b53bSMatt Carlson err = bcm50610_a0_workaround(phydev); 224219c6efeSMatt Carlson if (err < 0) 225219c6efeSMatt Carlson goto error; 226219c6efeSMatt Carlson } 227219c6efeSMatt Carlson } 22847b1b53bSMatt Carlson 22947b1b53bSMatt Carlson if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) { 23047b1b53bSMatt Carlson int val; 23147b1b53bSMatt Carlson 232a1cba561SArun Parameswaran val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75); 23347b1b53bSMatt Carlson if (val < 0) 234772638b6SMatt Carlson goto error; 235772638b6SMatt Carlson 23647b1b53bSMatt Carlson val |= MII_BCM54XX_EXP_EXP75_CM_OSC; 237a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val); 23847b1b53bSMatt Carlson } 239772638b6SMatt Carlson 240772638b6SMatt Carlson error: 24147b1b53bSMatt Carlson /* Disable the SMDSP clock */ 24247b1b53bSMatt Carlson err2 = bcm54xx_auxctl_write(phydev, 243772638b6SMatt Carlson MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, 244772638b6SMatt Carlson MII_BCM54XX_AUXCTL_ACTL_TX_6DB); 245772638b6SMatt Carlson 24647b1b53bSMatt Carlson /* Return the first error reported. */ 24747b1b53bSMatt Carlson return err ? err : err2; 248772638b6SMatt Carlson } 249772638b6SMatt Carlson 25032e5a8d6SMatt Carlson static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) 25132e5a8d6SMatt Carlson { 2525ee6f6a1SRoel Kluin u32 orig; 2535ee6f6a1SRoel Kluin int val; 254c704dc23SMatt Carlson bool clk125en = true; 25532e5a8d6SMatt Carlson 25632e5a8d6SMatt Carlson /* Abort if we are using an untested phy. */ 2577ec4e7d3Sroel kluin if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 && 2587ec4e7d3Sroel kluin BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 && 2590ececcfcSFlorian Fainelli BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M && 2605d4358edSFlorian Fainelli BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54210E && 261b0ed0bbfSKevin Lo BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 && 262b0ed0bbfSKevin Lo BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) 26332e5a8d6SMatt Carlson return; 26432e5a8d6SMatt Carlson 265a1cba561SArun Parameswaran val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3); 26632e5a8d6SMatt Carlson if (val < 0) 26732e5a8d6SMatt Carlson return; 26832e5a8d6SMatt Carlson 26932e5a8d6SMatt Carlson orig = val; 27032e5a8d6SMatt Carlson 27132e5a8d6SMatt Carlson if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 27232e5a8d6SMatt Carlson BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 27332e5a8d6SMatt Carlson BRCM_PHY_REV(phydev) >= 0x3) { 274c704dc23SMatt Carlson /* 275c704dc23SMatt Carlson * Here, bit 0 _disables_ CLK125 when set. 276c704dc23SMatt Carlson * This bit is set by default. 277c704dc23SMatt Carlson */ 278c704dc23SMatt Carlson clk125en = false; 27932e5a8d6SMatt Carlson } else { 280c704dc23SMatt Carlson if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) { 281b0ed0bbfSKevin Lo if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) { 28232e5a8d6SMatt Carlson /* Here, bit 0 _enables_ CLK125 when set */ 28332e5a8d6SMatt Carlson val &= ~BCM54XX_SHD_SCR3_DEF_CLK125; 284b0ed0bbfSKevin Lo } 285c704dc23SMatt Carlson clk125en = false; 28632e5a8d6SMatt Carlson } 28732e5a8d6SMatt Carlson } 28832e5a8d6SMatt Carlson 28923677ce3SJoe Perches if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 290c704dc23SMatt Carlson val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS; 291c704dc23SMatt Carlson else 292c704dc23SMatt Carlson val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; 293c704dc23SMatt Carlson 294b0ed0bbfSKevin Lo if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) { 2955d4358edSFlorian Fainelli if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E || 2965d4358edSFlorian Fainelli BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 || 297ad4e1e48SKevin Lo BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811) 2985d4358edSFlorian Fainelli val |= BCM54XX_SHD_SCR3_RXCTXC_DIS; 299b0ed0bbfSKevin Lo else 30052fae083SMatt Carlson val |= BCM54XX_SHD_SCR3_TRDDAPD; 301b0ed0bbfSKevin Lo } 30252fae083SMatt Carlson 30332e5a8d6SMatt Carlson if (orig != val) 304a1cba561SArun Parameswaran bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val); 305c704dc23SMatt Carlson 306a1cba561SArun Parameswaran val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD); 307c704dc23SMatt Carlson if (val < 0) 308c704dc23SMatt Carlson return; 309c704dc23SMatt Carlson 310c704dc23SMatt Carlson orig = val; 311c704dc23SMatt Carlson 31223677ce3SJoe Perches if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 313c704dc23SMatt Carlson val |= BCM54XX_SHD_APD_EN; 314c704dc23SMatt Carlson else 315c704dc23SMatt Carlson val &= ~BCM54XX_SHD_APD_EN; 316c704dc23SMatt Carlson 317c704dc23SMatt Carlson if (orig != val) 318a1cba561SArun Parameswaran bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val); 31932e5a8d6SMatt Carlson } 32032e5a8d6SMatt Carlson 32115acf89eSJonathan Lemon static void bcm54xx_ptp_stop(struct phy_device *phydev) 32215acf89eSJonathan Lemon { 32315acf89eSJonathan Lemon struct bcm54xx_phy_priv *priv = phydev->priv; 32415acf89eSJonathan Lemon 32515acf89eSJonathan Lemon if (priv->ptp) 32615acf89eSJonathan Lemon bcm_ptp_stop(priv->ptp); 32715acf89eSJonathan Lemon } 32815acf89eSJonathan Lemon 32915acf89eSJonathan Lemon static void bcm54xx_ptp_config_init(struct phy_device *phydev) 33015acf89eSJonathan Lemon { 33115acf89eSJonathan Lemon struct bcm54xx_phy_priv *priv = phydev->priv; 33215acf89eSJonathan Lemon 33315acf89eSJonathan Lemon if (priv->ptp) 33415acf89eSJonathan Lemon bcm_ptp_config_init(phydev); 33515acf89eSJonathan Lemon } 33615acf89eSJonathan Lemon 337c4b41c9fSMaciej W. Rozycki static int bcm54xx_config_init(struct phy_device *phydev) 338c4b41c9fSMaciej W. Rozycki { 33973333626SAbhishek Shah int reg, err, val; 340c4b41c9fSMaciej W. Rozycki 341c4b41c9fSMaciej W. Rozycki reg = phy_read(phydev, MII_BCM54XX_ECR); 342c4b41c9fSMaciej W. Rozycki if (reg < 0) 343c4b41c9fSMaciej W. Rozycki return reg; 344c4b41c9fSMaciej W. Rozycki 345c4b41c9fSMaciej W. Rozycki /* Mask interrupts globally. */ 346c4b41c9fSMaciej W. Rozycki reg |= MII_BCM54XX_ECR_IM; 347c4b41c9fSMaciej W. Rozycki err = phy_write(phydev, MII_BCM54XX_ECR, reg); 348c4b41c9fSMaciej W. Rozycki if (err < 0) 349c4b41c9fSMaciej W. Rozycki return err; 350c4b41c9fSMaciej W. Rozycki 351c4b41c9fSMaciej W. Rozycki /* Unmask events we are interested in. */ 352c4b41c9fSMaciej W. Rozycki reg = ~(MII_BCM54XX_INT_DUPLEX | 353c4b41c9fSMaciej W. Rozycki MII_BCM54XX_INT_SPEED | 354c4b41c9fSMaciej W. Rozycki MII_BCM54XX_INT_LINK); 355c4b41c9fSMaciej W. Rozycki err = phy_write(phydev, MII_BCM54XX_IMR, reg); 356c4b41c9fSMaciej W. Rozycki if (err < 0) 357c4b41c9fSMaciej W. Rozycki return err; 358772638b6SMatt Carlson 35963a14ce4SMatt Carlson if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 36063a14ce4SMatt Carlson BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 36163a14ce4SMatt Carlson (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) 362a1cba561SArun Parameswaran bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0); 36363a14ce4SMatt Carlson 36432e5a8d6SMatt Carlson bcm54xx_adjust_rxrefclk(phydev); 36532e5a8d6SMatt Carlson 3663afd0218SRobert Hancock switch (BRCM_PHY_MODEL(phydev)) { 367b1dd9bf6SFlorian Fainelli case PHY_ID_BCM50610: 368b1dd9bf6SFlorian Fainelli case PHY_ID_BCM50610M: 369b1dd9bf6SFlorian Fainelli err = bcm54xx_config_clock_delay(phydev); 370b1dd9bf6SFlorian Fainelli break; 3713afd0218SRobert Hancock case PHY_ID_BCM54210E: 3720fc9ae10SRafał Miłecki err = bcm54210e_config_init(phydev); 3733afd0218SRobert Hancock break; 3743afd0218SRobert Hancock case PHY_ID_BCM54612E: 37562e13097SRafał Miłecki err = bcm54612e_config_init(phydev); 3763afd0218SRobert Hancock break; 3773afd0218SRobert Hancock case PHY_ID_BCM54616S: 3783afd0218SRobert Hancock err = bcm54616s_config_init(phydev); 3793afd0218SRobert Hancock break; 3803afd0218SRobert Hancock case PHY_ID_BCM54810: 38173333626SAbhishek Shah /* For BCM54810, we need to disable BroadR-Reach function */ 38273333626SAbhishek Shah val = bcm_phy_read_exp(phydev, 38373333626SAbhishek Shah BCM54810_EXP_BROADREACH_LRE_MISC_CTL); 38473333626SAbhishek Shah val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; 38573333626SAbhishek Shah err = bcm_phy_write_exp(phydev, 38673333626SAbhishek Shah BCM54810_EXP_BROADREACH_LRE_MISC_CTL, 38773333626SAbhishek Shah val); 3883afd0218SRobert Hancock break; 389b14995acSJon Mason } 3903afd0218SRobert Hancock if (err) 3913afd0218SRobert Hancock return err; 392b14995acSJon Mason 39347b1b53bSMatt Carlson bcm54xx_phydsp_config(phydev); 394d9221e66SMatt Carlson 395b5d007e2SRobert Hancock /* For non-SFP setups, encode link speed into LED1 and LED3 pair 396b5d007e2SRobert Hancock * (green/amber). 397450895d0SVladimir Oltean * Also flash these two LEDs on activity. This means configuring 398450895d0SVladimir Oltean * them for MULTICOLOR and encoding link/activity into them. 399b5d007e2SRobert Hancock * Don't do this for devices on an SFP module, since some of these 400b5d007e2SRobert Hancock * use the LED outputs to control the SFP LOS signal, and changing 401b5d007e2SRobert Hancock * these settings will cause LOS to malfunction. 402450895d0SVladimir Oltean */ 403b5d007e2SRobert Hancock if (!phy_on_sfp(phydev)) { 404450895d0SVladimir Oltean val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) | 405450895d0SVladimir Oltean BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1); 406450895d0SVladimir Oltean bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val); 407450895d0SVladimir Oltean 408450895d0SVladimir Oltean val = BCM_LED_MULTICOLOR_IN_PHASE | 409450895d0SVladimir Oltean BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) | 410450895d0SVladimir Oltean BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT); 411450895d0SVladimir Oltean bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val); 412b5d007e2SRobert Hancock } 413450895d0SVladimir Oltean 41415acf89eSJonathan Lemon bcm54xx_ptp_config_init(phydev); 41515acf89eSJonathan Lemon 416c4b41c9fSMaciej W. Rozycki return 0; 417c4b41c9fSMaciej W. Rozycki } 418c4b41c9fSMaciej W. Rozycki 419d6da08edSFlorian Fainelli static int bcm54xx_iddq_set(struct phy_device *phydev, bool enable) 420d6da08edSFlorian Fainelli { 421d6da08edSFlorian Fainelli int ret = 0; 422d6da08edSFlorian Fainelli 423d6da08edSFlorian Fainelli if (!(phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND)) 424d6da08edSFlorian Fainelli return ret; 425d6da08edSFlorian Fainelli 426d6da08edSFlorian Fainelli ret = bcm_phy_read_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL); 427d6da08edSFlorian Fainelli if (ret < 0) 428d6da08edSFlorian Fainelli goto out; 429d6da08edSFlorian Fainelli 430d6da08edSFlorian Fainelli if (enable) 431d6da08edSFlorian Fainelli ret |= BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP; 432d6da08edSFlorian Fainelli else 433d6da08edSFlorian Fainelli ret &= ~(BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP); 434d6da08edSFlorian Fainelli 435d6da08edSFlorian Fainelli ret = bcm_phy_write_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL, ret); 436d6da08edSFlorian Fainelli out: 437d6da08edSFlorian Fainelli return ret; 438d6da08edSFlorian Fainelli } 439d6da08edSFlorian Fainelli 440d6da08edSFlorian Fainelli static int bcm54xx_suspend(struct phy_device *phydev) 441d6da08edSFlorian Fainelli { 442d6da08edSFlorian Fainelli int ret; 443d6da08edSFlorian Fainelli 44415acf89eSJonathan Lemon bcm54xx_ptp_stop(phydev); 44515acf89eSJonathan Lemon 446d6da08edSFlorian Fainelli /* We cannot use a read/modify/write here otherwise the PHY gets into 447d6da08edSFlorian Fainelli * a bad state where its LEDs keep flashing, thus defeating the purpose 448d6da08edSFlorian Fainelli * of low power mode. 449d6da08edSFlorian Fainelli */ 450d6da08edSFlorian Fainelli ret = phy_write(phydev, MII_BMCR, BMCR_PDOWN); 451d6da08edSFlorian Fainelli if (ret < 0) 452d6da08edSFlorian Fainelli return ret; 453d6da08edSFlorian Fainelli 454d6da08edSFlorian Fainelli return bcm54xx_iddq_set(phydev, true); 455d6da08edSFlorian Fainelli } 456d6da08edSFlorian Fainelli 457fe26821fSFlorian Fainelli static int bcm54xx_resume(struct phy_device *phydev) 458fe26821fSFlorian Fainelli { 459fe26821fSFlorian Fainelli int ret; 460fe26821fSFlorian Fainelli 461d6da08edSFlorian Fainelli ret = bcm54xx_iddq_set(phydev, false); 462d6da08edSFlorian Fainelli if (ret < 0) 463d6da08edSFlorian Fainelli return ret; 464d6da08edSFlorian Fainelli 465fe26821fSFlorian Fainelli /* Writes to register other than BMCR would be ignored 466fe26821fSFlorian Fainelli * unless we clear the PDOWN bit first 467fe26821fSFlorian Fainelli */ 468fe26821fSFlorian Fainelli ret = genphy_resume(phydev); 469fe26821fSFlorian Fainelli if (ret < 0) 470fe26821fSFlorian Fainelli return ret; 471fe26821fSFlorian Fainelli 4727a1468baSFlorian Fainelli /* Upon exiting power down, the PHY remains in an internal reset state 4737a1468baSFlorian Fainelli * for 40us 4747a1468baSFlorian Fainelli */ 4757a1468baSFlorian Fainelli fsleep(40); 4767a1468baSFlorian Fainelli 477d6da08edSFlorian Fainelli /* Issue a soft reset after clearing the power down bit 478d6da08edSFlorian Fainelli * and before doing any other configuration. 479d6da08edSFlorian Fainelli */ 480d6da08edSFlorian Fainelli if (phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND) { 481d6da08edSFlorian Fainelli ret = genphy_soft_reset(phydev); 482d6da08edSFlorian Fainelli if (ret < 0) 483d6da08edSFlorian Fainelli return ret; 484d6da08edSFlorian Fainelli } 485d6da08edSFlorian Fainelli 486fe26821fSFlorian Fainelli return bcm54xx_config_init(phydev); 487fe26821fSFlorian Fainelli } 488fe26821fSFlorian Fainelli 489b0ed0bbfSKevin Lo static int bcm54811_config_init(struct phy_device *phydev) 490b0ed0bbfSKevin Lo { 491b0ed0bbfSKevin Lo int err, reg; 492b0ed0bbfSKevin Lo 493b0ed0bbfSKevin Lo /* Disable BroadR-Reach function. */ 494b0ed0bbfSKevin Lo reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL); 495b0ed0bbfSKevin Lo reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; 496b0ed0bbfSKevin Lo err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL, 497b0ed0bbfSKevin Lo reg); 498b0ed0bbfSKevin Lo if (err < 0) 499b0ed0bbfSKevin Lo return err; 500b0ed0bbfSKevin Lo 501b0ed0bbfSKevin Lo err = bcm54xx_config_init(phydev); 502b0ed0bbfSKevin Lo 503b0ed0bbfSKevin Lo /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ 504b0ed0bbfSKevin Lo if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { 505b0ed0bbfSKevin Lo reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); 506b0ed0bbfSKevin Lo err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0, 507b0ed0bbfSKevin Lo BCM54612E_LED4_CLK125OUT_EN | reg); 508b0ed0bbfSKevin Lo if (err < 0) 509b0ed0bbfSKevin Lo return err; 510b0ed0bbfSKevin Lo } 511b0ed0bbfSKevin Lo 512b0ed0bbfSKevin Lo return err; 513b0ed0bbfSKevin Lo } 514b0ed0bbfSKevin Lo 51557bb7e22SAnton Vorontsov static int bcm5481_config_aneg(struct phy_device *phydev) 51657bb7e22SAnton Vorontsov { 517b14995acSJon Mason struct device_node *np = phydev->mdio.dev.of_node; 51857bb7e22SAnton Vorontsov int ret; 51957bb7e22SAnton Vorontsov 52029f20dd6SJonathan Neuschäfer /* Aneg firstly. */ 52157bb7e22SAnton Vorontsov ret = genphy_config_aneg(phydev); 52257bb7e22SAnton Vorontsov 52357bb7e22SAnton Vorontsov /* Then we can set up the delay. */ 524042cb564STao Ren bcm54xx_config_clock_delay(phydev); 52557bb7e22SAnton Vorontsov 526b14995acSJon Mason if (of_property_read_bool(np, "enet-phy-lane-swap")) { 527b14995acSJon Mason /* Lane Swap - Undocumented register...magic! */ 528b14995acSJon Mason ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9, 529b14995acSJon Mason 0x11B); 530b14995acSJon Mason if (ret < 0) 531b14995acSJon Mason return ret; 532b14995acSJon Mason } 533b14995acSJon Mason 53457bb7e22SAnton Vorontsov return ret; 53557bb7e22SAnton Vorontsov } 53657bb7e22SAnton Vorontsov 53717d3a83aSFlorian Fainelli struct bcm54616s_phy_priv { 53817d3a83aSFlorian Fainelli bool mode_1000bx_en; 53917d3a83aSFlorian Fainelli }; 54017d3a83aSFlorian Fainelli 541b9bcb953STao Ren static int bcm54616s_probe(struct phy_device *phydev) 542b9bcb953STao Ren { 54317d3a83aSFlorian Fainelli struct bcm54616s_phy_priv *priv; 5443afd0218SRobert Hancock int val; 545b9bcb953STao Ren 54617d3a83aSFlorian Fainelli priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 54717d3a83aSFlorian Fainelli if (!priv) 54817d3a83aSFlorian Fainelli return -ENOMEM; 54917d3a83aSFlorian Fainelli 55017d3a83aSFlorian Fainelli phydev->priv = priv; 55117d3a83aSFlorian Fainelli 552b9bcb953STao Ren val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); 553b9bcb953STao Ren if (val < 0) 554b9bcb953STao Ren return val; 555b9bcb953STao Ren 556b9bcb953STao Ren /* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0] 557b9bcb953STao Ren * is 01b, and the link between PHY and its link partner can be 558b9bcb953STao Ren * either 1000Base-X or 100Base-FX. 559b9bcb953STao Ren * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX 560b9bcb953STao Ren * support is still missing as of now. 561b9bcb953STao Ren */ 5623afd0218SRobert Hancock if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) { 563b9bcb953STao Ren val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL); 564b9bcb953STao Ren if (val < 0) 565b9bcb953STao Ren return val; 566b9bcb953STao Ren 567b9bcb953STao Ren /* Bit 0 of the SerDes 100-FX Control register, when set 568b9bcb953STao Ren * to 1, sets the MII/RGMII -> 100BASE-FX configuration. 569b9bcb953STao Ren * When this bit is set to 0, it sets the GMII/RGMII -> 570b9bcb953STao Ren * 1000BASE-X configuration. 571b9bcb953STao Ren */ 572b9bcb953STao Ren if (!(val & BCM54616S_100FX_MODE)) 57317d3a83aSFlorian Fainelli priv->mode_1000bx_en = true; 5744217a64eSMichael Walle 5754217a64eSMichael Walle phydev->port = PORT_FIBRE; 576b9bcb953STao Ren } 577b9bcb953STao Ren 578b9bcb953STao Ren return 0; 579b9bcb953STao Ren } 580b9bcb953STao Ren 581042cb564STao Ren static int bcm54616s_config_aneg(struct phy_device *phydev) 582042cb564STao Ren { 58317d3a83aSFlorian Fainelli struct bcm54616s_phy_priv *priv = phydev->priv; 584042cb564STao Ren int ret; 585042cb564STao Ren 58629f20dd6SJonathan Neuschäfer /* Aneg firstly. */ 58717d3a83aSFlorian Fainelli if (priv->mode_1000bx_en) 588b9bcb953STao Ren ret = genphy_c37_config_aneg(phydev); 589b9bcb953STao Ren else 590042cb564STao Ren ret = genphy_config_aneg(phydev); 591042cb564STao Ren 592042cb564STao Ren /* Then we can set up the delay. */ 593042cb564STao Ren bcm54xx_config_clock_delay(phydev); 594042cb564STao Ren 595042cb564STao Ren return ret; 596042cb564STao Ren } 597042cb564STao Ren 598b9bcb953STao Ren static int bcm54616s_read_status(struct phy_device *phydev) 599b9bcb953STao Ren { 60017d3a83aSFlorian Fainelli struct bcm54616s_phy_priv *priv = phydev->priv; 601b9bcb953STao Ren int err; 602b9bcb953STao Ren 60317d3a83aSFlorian Fainelli if (priv->mode_1000bx_en) 604b9bcb953STao Ren err = genphy_c37_read_status(phydev); 605b9bcb953STao Ren else 606b9bcb953STao Ren err = genphy_read_status(phydev); 607b9bcb953STao Ren 608b9bcb953STao Ren return err; 609b9bcb953STao Ren } 610b9bcb953STao Ren 611d7a2ed92SMatt Carlson static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) 612d7a2ed92SMatt Carlson { 613d7a2ed92SMatt Carlson int val; 614d7a2ed92SMatt Carlson 615d7a2ed92SMatt Carlson val = phy_read(phydev, reg); 616d7a2ed92SMatt Carlson if (val < 0) 617d7a2ed92SMatt Carlson return val; 618d7a2ed92SMatt Carlson 619d7a2ed92SMatt Carlson return phy_write(phydev, reg, val | set); 620d7a2ed92SMatt Carlson } 621d7a2ed92SMatt Carlson 622d7a2ed92SMatt Carlson static int brcm_fet_config_init(struct phy_device *phydev) 623d7a2ed92SMatt Carlson { 624d7a2ed92SMatt Carlson int reg, err, err2, brcmtest; 625d7a2ed92SMatt Carlson 626d7a2ed92SMatt Carlson /* Reset the PHY to bring it to a known state. */ 627d7a2ed92SMatt Carlson err = phy_write(phydev, MII_BMCR, BMCR_RESET); 628d7a2ed92SMatt Carlson if (err < 0) 629d7a2ed92SMatt Carlson return err; 630d7a2ed92SMatt Carlson 631bf8bfc43SFlorian Fainelli /* The datasheet indicates the PHY needs up to 1us to complete a reset, 632bf8bfc43SFlorian Fainelli * build some slack here. 633bf8bfc43SFlorian Fainelli */ 634bf8bfc43SFlorian Fainelli usleep_range(1000, 2000); 635bf8bfc43SFlorian Fainelli 636bf8bfc43SFlorian Fainelli /* The PHY requires 65 MDC clock cycles to complete a write operation 637bf8bfc43SFlorian Fainelli * and turnaround the line properly. 638bf8bfc43SFlorian Fainelli * 639bf8bfc43SFlorian Fainelli * We ignore -EIO here as the MDIO controller (e.g.: mdio-bcm-unimac) 640bf8bfc43SFlorian Fainelli * may flag the lack of turn-around as a read failure. This is 641bf8bfc43SFlorian Fainelli * particularly true with this combination since the MDIO controller 642bf8bfc43SFlorian Fainelli * only used 64 MDC cycles. This is not a critical failure in this 643bf8bfc43SFlorian Fainelli * specific case and it has no functional impact otherwise, so we let 644bf8bfc43SFlorian Fainelli * that one go through. If there is a genuine bus error, the next read 645bf8bfc43SFlorian Fainelli * of MII_BRCM_FET_INTREG will error out. 646bf8bfc43SFlorian Fainelli */ 647bf8bfc43SFlorian Fainelli err = phy_read(phydev, MII_BMCR); 648bf8bfc43SFlorian Fainelli if (err < 0 && err != -EIO) 649bf8bfc43SFlorian Fainelli return err; 650bf8bfc43SFlorian Fainelli 651d7a2ed92SMatt Carlson reg = phy_read(phydev, MII_BRCM_FET_INTREG); 652d7a2ed92SMatt Carlson if (reg < 0) 653d7a2ed92SMatt Carlson return reg; 654d7a2ed92SMatt Carlson 655d7a2ed92SMatt Carlson /* Unmask events we are interested in and mask interrupts globally. */ 656d7a2ed92SMatt Carlson reg = MII_BRCM_FET_IR_DUPLEX_EN | 657d7a2ed92SMatt Carlson MII_BRCM_FET_IR_SPEED_EN | 658d7a2ed92SMatt Carlson MII_BRCM_FET_IR_LINK_EN | 659d7a2ed92SMatt Carlson MII_BRCM_FET_IR_ENABLE | 660d7a2ed92SMatt Carlson MII_BRCM_FET_IR_MASK; 661d7a2ed92SMatt Carlson 662d7a2ed92SMatt Carlson err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 663d7a2ed92SMatt Carlson if (err < 0) 664d7a2ed92SMatt Carlson return err; 665d7a2ed92SMatt Carlson 666d7a2ed92SMatt Carlson /* Enable shadow register access */ 667d7a2ed92SMatt Carlson brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST); 668d7a2ed92SMatt Carlson if (brcmtest < 0) 669d7a2ed92SMatt Carlson return brcmtest; 670d7a2ed92SMatt Carlson 671d7a2ed92SMatt Carlson reg = brcmtest | MII_BRCM_FET_BT_SRE; 672d7a2ed92SMatt Carlson 673d7a2ed92SMatt Carlson err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg); 674d7a2ed92SMatt Carlson if (err < 0) 675d7a2ed92SMatt Carlson return err; 676d7a2ed92SMatt Carlson 677d7a2ed92SMatt Carlson /* Set the LED mode */ 678d7a2ed92SMatt Carlson reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4); 679d7a2ed92SMatt Carlson if (reg < 0) { 680d7a2ed92SMatt Carlson err = reg; 681d7a2ed92SMatt Carlson goto done; 682d7a2ed92SMatt Carlson } 683d7a2ed92SMatt Carlson 684d7a2ed92SMatt Carlson reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK; 685d7a2ed92SMatt Carlson reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1; 686d7a2ed92SMatt Carlson 687d7a2ed92SMatt Carlson err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg); 688d7a2ed92SMatt Carlson if (err < 0) 689d7a2ed92SMatt Carlson goto done; 690d7a2ed92SMatt Carlson 691d7a2ed92SMatt Carlson /* Enable auto MDIX */ 692d7a2ed92SMatt Carlson err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL, 693d7a2ed92SMatt Carlson MII_BRCM_FET_SHDW_MC_FAME); 694d7a2ed92SMatt Carlson if (err < 0) 695d7a2ed92SMatt Carlson goto done; 696d7a2ed92SMatt Carlson 697cdd4e09dSMatt Carlson if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) { 698d7a2ed92SMatt Carlson /* Enable auto power down */ 699d7a2ed92SMatt Carlson err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, 700d7a2ed92SMatt Carlson MII_BRCM_FET_SHDW_AS2_APDE); 701cdd4e09dSMatt Carlson } 702d7a2ed92SMatt Carlson 703d7a2ed92SMatt Carlson done: 704d7a2ed92SMatt Carlson /* Disable shadow register access */ 705d7a2ed92SMatt Carlson err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest); 706d7a2ed92SMatt Carlson if (!err) 707d7a2ed92SMatt Carlson err = err2; 708d7a2ed92SMatt Carlson 709d7a2ed92SMatt Carlson return err; 710d7a2ed92SMatt Carlson } 711d7a2ed92SMatt Carlson 712d7a2ed92SMatt Carlson static int brcm_fet_ack_interrupt(struct phy_device *phydev) 713d7a2ed92SMatt Carlson { 714d7a2ed92SMatt Carlson int reg; 715d7a2ed92SMatt Carlson 716d7a2ed92SMatt Carlson /* Clear pending interrupts. */ 717d7a2ed92SMatt Carlson reg = phy_read(phydev, MII_BRCM_FET_INTREG); 718d7a2ed92SMatt Carlson if (reg < 0) 719d7a2ed92SMatt Carlson return reg; 720d7a2ed92SMatt Carlson 721d7a2ed92SMatt Carlson return 0; 722d7a2ed92SMatt Carlson } 723d7a2ed92SMatt Carlson 724d7a2ed92SMatt Carlson static int brcm_fet_config_intr(struct phy_device *phydev) 725d7a2ed92SMatt Carlson { 726d7a2ed92SMatt Carlson int reg, err; 727d7a2ed92SMatt Carlson 728d7a2ed92SMatt Carlson reg = phy_read(phydev, MII_BRCM_FET_INTREG); 729d7a2ed92SMatt Carlson if (reg < 0) 730d7a2ed92SMatt Carlson return reg; 731d7a2ed92SMatt Carlson 73215772e4dSIoana Ciornei if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 73315772e4dSIoana Ciornei err = brcm_fet_ack_interrupt(phydev); 73415772e4dSIoana Ciornei if (err) 73515772e4dSIoana Ciornei return err; 736d7a2ed92SMatt Carlson 73715772e4dSIoana Ciornei reg &= ~MII_BRCM_FET_IR_MASK; 738d7a2ed92SMatt Carlson err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 73915772e4dSIoana Ciornei } else { 74015772e4dSIoana Ciornei reg |= MII_BRCM_FET_IR_MASK; 74115772e4dSIoana Ciornei err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 74215772e4dSIoana Ciornei if (err) 74315772e4dSIoana Ciornei return err; 74415772e4dSIoana Ciornei 74515772e4dSIoana Ciornei err = brcm_fet_ack_interrupt(phydev); 74615772e4dSIoana Ciornei } 74715772e4dSIoana Ciornei 748d7a2ed92SMatt Carlson return err; 749d7a2ed92SMatt Carlson } 750d7a2ed92SMatt Carlson 7514567d5c3SIoana Ciornei static irqreturn_t brcm_fet_handle_interrupt(struct phy_device *phydev) 7524567d5c3SIoana Ciornei { 7534567d5c3SIoana Ciornei int irq_status; 7544567d5c3SIoana Ciornei 7554567d5c3SIoana Ciornei irq_status = phy_read(phydev, MII_BRCM_FET_INTREG); 7564567d5c3SIoana Ciornei if (irq_status < 0) { 7574567d5c3SIoana Ciornei phy_error(phydev); 7584567d5c3SIoana Ciornei return IRQ_NONE; 7594567d5c3SIoana Ciornei } 7604567d5c3SIoana Ciornei 7614567d5c3SIoana Ciornei if (irq_status == 0) 7624567d5c3SIoana Ciornei return IRQ_NONE; 7634567d5c3SIoana Ciornei 7644567d5c3SIoana Ciornei phy_trigger_machine(phydev); 7654567d5c3SIoana Ciornei 7664567d5c3SIoana Ciornei return IRQ_HANDLED; 7674567d5c3SIoana Ciornei } 7684567d5c3SIoana Ciornei 7695a32fcdbSFlorian Fainelli static int bcm54xx_phy_probe(struct phy_device *phydev) 77028dc4c8fSFlorian Fainelli { 7715a32fcdbSFlorian Fainelli struct bcm54xx_phy_priv *priv; 77228dc4c8fSFlorian Fainelli 77328dc4c8fSFlorian Fainelli priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 77428dc4c8fSFlorian Fainelli if (!priv) 77528dc4c8fSFlorian Fainelli return -ENOMEM; 77628dc4c8fSFlorian Fainelli 77728dc4c8fSFlorian Fainelli phydev->priv = priv; 77828dc4c8fSFlorian Fainelli 77928dc4c8fSFlorian Fainelli priv->stats = devm_kcalloc(&phydev->mdio.dev, 78028dc4c8fSFlorian Fainelli bcm_phy_get_sset_count(phydev), sizeof(u64), 78128dc4c8fSFlorian Fainelli GFP_KERNEL); 78228dc4c8fSFlorian Fainelli if (!priv->stats) 78328dc4c8fSFlorian Fainelli return -ENOMEM; 78428dc4c8fSFlorian Fainelli 78515acf89eSJonathan Lemon priv->ptp = bcm_ptp_probe(phydev); 78615acf89eSJonathan Lemon if (IS_ERR(priv->ptp)) 78715acf89eSJonathan Lemon return PTR_ERR(priv->ptp); 78815acf89eSJonathan Lemon 78928dc4c8fSFlorian Fainelli return 0; 79028dc4c8fSFlorian Fainelli } 79128dc4c8fSFlorian Fainelli 7925a32fcdbSFlorian Fainelli static void bcm54xx_get_stats(struct phy_device *phydev, 79328dc4c8fSFlorian Fainelli struct ethtool_stats *stats, u64 *data) 79428dc4c8fSFlorian Fainelli { 7955a32fcdbSFlorian Fainelli struct bcm54xx_phy_priv *priv = phydev->priv; 79628dc4c8fSFlorian Fainelli 79728dc4c8fSFlorian Fainelli bcm_phy_get_stats(phydev, priv->stats, stats, data); 79828dc4c8fSFlorian Fainelli } 79928dc4c8fSFlorian Fainelli 8008dc84dcdSFlorian Fainelli static void bcm54xx_link_change_notify(struct phy_device *phydev) 8018dc84dcdSFlorian Fainelli { 8028dc84dcdSFlorian Fainelli u16 mask = MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE | 8038dc84dcdSFlorian Fainelli MII_BCM54XX_EXP_EXP08_FORCE_DAC_WAKE; 8048dc84dcdSFlorian Fainelli int ret; 8058dc84dcdSFlorian Fainelli 8068dc84dcdSFlorian Fainelli if (phydev->state != PHY_RUNNING) 8078dc84dcdSFlorian Fainelli return; 8088dc84dcdSFlorian Fainelli 8098dc84dcdSFlorian Fainelli /* Don't change the DAC wake settings if auto power down 8108dc84dcdSFlorian Fainelli * is not requested. 8118dc84dcdSFlorian Fainelli */ 8128dc84dcdSFlorian Fainelli if (!(phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 8138dc84dcdSFlorian Fainelli return; 8148dc84dcdSFlorian Fainelli 8158dc84dcdSFlorian Fainelli ret = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP08); 8168dc84dcdSFlorian Fainelli if (ret < 0) 8178dc84dcdSFlorian Fainelli return; 8188dc84dcdSFlorian Fainelli 8198dc84dcdSFlorian Fainelli /* Enable/disable 10BaseT auto and forced early DAC wake depending 8208dc84dcdSFlorian Fainelli * on the negotiated speed, those settings should only be done 8218dc84dcdSFlorian Fainelli * for 10Mbits/sec. 8228dc84dcdSFlorian Fainelli */ 8238dc84dcdSFlorian Fainelli if (phydev->speed == SPEED_10) 8248dc84dcdSFlorian Fainelli ret |= mask; 8258dc84dcdSFlorian Fainelli else 8268dc84dcdSFlorian Fainelli ret &= ~mask; 8278dc84dcdSFlorian Fainelli bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08, ret); 8288dc84dcdSFlorian Fainelli } 8298dc84dcdSFlorian Fainelli 830d5bf9071SChristian Hohnstaedt static struct phy_driver broadcom_drivers[] = { 831d5bf9071SChristian Hohnstaedt { 832fcb26ec5SDmitry Baryshkov .phy_id = PHY_ID_BCM5411, 833c4b41c9fSMaciej W. Rozycki .phy_id_mask = 0xfffffff0, 834c4b41c9fSMaciej W. Rozycki .name = "Broadcom BCM5411", 835dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 8365a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 8375a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 8385a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 8395a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 840c4b41c9fSMaciej W. Rozycki .config_init = bcm54xx_config_init, 841a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 8424567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 8438dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 844d5bf9071SChristian Hohnstaedt }, { 845fcb26ec5SDmitry Baryshkov .phy_id = PHY_ID_BCM5421, 846c4b41c9fSMaciej W. Rozycki .phy_id_mask = 0xfffffff0, 847c4b41c9fSMaciej W. Rozycki .name = "Broadcom BCM5421", 848dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 8495a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 8505a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 8515a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 8525a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 853c4b41c9fSMaciej W. Rozycki .config_init = bcm54xx_config_init, 854a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 8554567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 8568dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 857d5bf9071SChristian Hohnstaedt }, { 8580fc9ae10SRafał Miłecki .phy_id = PHY_ID_BCM54210E, 8590fc9ae10SRafał Miłecki .phy_id_mask = 0xfffffff0, 8600fc9ae10SRafał Miłecki .name = "Broadcom BCM54210E", 861dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 8625a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 8635a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 8645a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 8655a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 8660fc9ae10SRafał Miłecki .config_init = bcm54xx_config_init, 8670fc9ae10SRafał Miłecki .config_intr = bcm_phy_config_intr, 8684567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 8698dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 870d6da08edSFlorian Fainelli .suspend = bcm54xx_suspend, 871d6da08edSFlorian Fainelli .resume = bcm54xx_resume, 8720fc9ae10SRafał Miłecki }, { 873fcb26ec5SDmitry Baryshkov .phy_id = PHY_ID_BCM5461, 874c4b41c9fSMaciej W. Rozycki .phy_id_mask = 0xfffffff0, 875c4b41c9fSMaciej W. Rozycki .name = "Broadcom BCM5461", 876dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 8775a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 8785a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 8795a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 8805a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 881c4b41c9fSMaciej W. Rozycki .config_init = bcm54xx_config_init, 882a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 8834567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 8848dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 885d5bf9071SChristian Hohnstaedt }, { 886d92ead16SXo Wang .phy_id = PHY_ID_BCM54612E, 887d92ead16SXo Wang .phy_id_mask = 0xfffffff0, 888d92ead16SXo Wang .name = "Broadcom BCM54612E", 889dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 8905a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 8915a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 8925a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 8935a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 894d92ead16SXo Wang .config_init = bcm54xx_config_init, 895d92ead16SXo Wang .config_intr = bcm_phy_config_intr, 8964567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 8978dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 898d92ead16SXo Wang }, { 8993bca4cf6SAlessio Igor Bogani .phy_id = PHY_ID_BCM54616S, 9003bca4cf6SAlessio Igor Bogani .phy_id_mask = 0xfffffff0, 9013bca4cf6SAlessio Igor Bogani .name = "Broadcom BCM54616S", 902dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 903d15c7e87SRobert Hancock .soft_reset = genphy_soft_reset, 9043bca4cf6SAlessio Igor Bogani .config_init = bcm54xx_config_init, 905042cb564STao Ren .config_aneg = bcm54616s_config_aneg, 906a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 9074567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 908b9bcb953STao Ren .read_status = bcm54616s_read_status, 909b9bcb953STao Ren .probe = bcm54616s_probe, 9108dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 9113bca4cf6SAlessio Igor Bogani }, { 912fcb26ec5SDmitry Baryshkov .phy_id = PHY_ID_BCM5464, 913b1394f96SPaul Gortmaker .phy_id_mask = 0xfffffff0, 914b1394f96SPaul Gortmaker .name = "Broadcom BCM5464", 915dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 9165a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 9175a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 9185a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 9195a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 920b1394f96SPaul Gortmaker .config_init = bcm54xx_config_init, 921a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 9224567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 923283da99aSVladimir Oltean .suspend = genphy_suspend, 924283da99aSVladimir Oltean .resume = genphy_resume, 9258dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 926d5bf9071SChristian Hohnstaedt }, { 927fcb26ec5SDmitry Baryshkov .phy_id = PHY_ID_BCM5481, 92857bb7e22SAnton Vorontsov .phy_id_mask = 0xfffffff0, 92957bb7e22SAnton Vorontsov .name = "Broadcom BCM5481", 930dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 9315a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 9325a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 9335a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 9345a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 93557bb7e22SAnton Vorontsov .config_init = bcm54xx_config_init, 9369753c21fSHeiner Kallweit .config_aneg = bcm5481_config_aneg, 937a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 9384567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 9398dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 940d5bf9071SChristian Hohnstaedt }, { 941b14995acSJon Mason .phy_id = PHY_ID_BCM54810, 942b14995acSJon Mason .phy_id_mask = 0xfffffff0, 943b14995acSJon Mason .name = "Broadcom BCM54810", 944dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 9455a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 9465a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 9475a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 9485a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 949b14995acSJon Mason .config_init = bcm54xx_config_init, 9509753c21fSHeiner Kallweit .config_aneg = bcm5481_config_aneg, 951b14995acSJon Mason .config_intr = bcm_phy_config_intr, 9524567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 95372e78d22SFlorian Fainelli .suspend = bcm54xx_suspend, 954fe26821fSFlorian Fainelli .resume = bcm54xx_resume, 9558dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 956b14995acSJon Mason }, { 957b0ed0bbfSKevin Lo .phy_id = PHY_ID_BCM54811, 958b0ed0bbfSKevin Lo .phy_id_mask = 0xfffffff0, 959b0ed0bbfSKevin Lo .name = "Broadcom BCM54811", 960b0ed0bbfSKevin Lo /* PHY_GBIT_FEATURES */ 9615a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 9625a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 9635a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 9645a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 965b0ed0bbfSKevin Lo .config_init = bcm54811_config_init, 966b0ed0bbfSKevin Lo .config_aneg = bcm5481_config_aneg, 967b0ed0bbfSKevin Lo .config_intr = bcm_phy_config_intr, 9684567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 96972e78d22SFlorian Fainelli .suspend = bcm54xx_suspend, 970b0ed0bbfSKevin Lo .resume = bcm54xx_resume, 9718dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 972b0ed0bbfSKevin Lo }, { 973fcb26ec5SDmitry Baryshkov .phy_id = PHY_ID_BCM5482, 97403157ac3SNate Case .phy_id_mask = 0xfffffff0, 97503157ac3SNate Case .name = "Broadcom BCM5482", 976dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 9775a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 9785a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 9795a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 9805a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 9811e2e61afSMichael Walle .config_init = bcm54xx_config_init, 982a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 9834567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 9848dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 985d5bf9071SChristian Hohnstaedt }, { 986772638b6SMatt Carlson .phy_id = PHY_ID_BCM50610, 987772638b6SMatt Carlson .phy_id_mask = 0xfffffff0, 988772638b6SMatt Carlson .name = "Broadcom BCM50610", 989dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 9905a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 9915a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 9925a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 9935a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 994772638b6SMatt Carlson .config_init = bcm54xx_config_init, 995a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 9964567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 9978dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 99838b6a907SFlorian Fainelli .suspend = bcm54xx_suspend, 99938b6a907SFlorian Fainelli .resume = bcm54xx_resume, 1000d5bf9071SChristian Hohnstaedt }, { 10014f4598fdSMatt Carlson .phy_id = PHY_ID_BCM50610M, 10024f4598fdSMatt Carlson .phy_id_mask = 0xfffffff0, 10034f4598fdSMatt Carlson .name = "Broadcom BCM50610M", 1004dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 10055a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 10065a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 10075a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 10085a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 10094f4598fdSMatt Carlson .config_init = bcm54xx_config_init, 1010a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 10114567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 10128dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 101338b6a907SFlorian Fainelli .suspend = bcm54xx_suspend, 101438b6a907SFlorian Fainelli .resume = bcm54xx_resume, 1015d5bf9071SChristian Hohnstaedt }, { 1016d9221e66SMatt Carlson .phy_id = PHY_ID_BCM57780, 10172fbb69aaSMatt Carlson .phy_id_mask = 0xfffffff0, 10182fbb69aaSMatt Carlson .name = "Broadcom BCM57780", 1019dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 10205a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 10215a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 10225a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 10235a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 10242fbb69aaSMatt Carlson .config_init = bcm54xx_config_init, 1025a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 10264567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 10278dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 1028d5bf9071SChristian Hohnstaedt }, { 10296a443a0fSMatt Carlson .phy_id = PHY_ID_BCMAC131, 1030d7a2ed92SMatt Carlson .phy_id_mask = 0xfffffff0, 1031d7a2ed92SMatt Carlson .name = "Broadcom BCMAC131", 1032dcdecdcfSHeiner Kallweit /* PHY_BASIC_FEATURES */ 1033d7a2ed92SMatt Carlson .config_init = brcm_fet_config_init, 1034d7a2ed92SMatt Carlson .config_intr = brcm_fet_config_intr, 10354567d5c3SIoana Ciornei .handle_interrupt = brcm_fet_handle_interrupt, 1036d5bf9071SChristian Hohnstaedt }, { 10377a938f80SDmitry Baryshkov .phy_id = PHY_ID_BCM5241, 10387a938f80SDmitry Baryshkov .phy_id_mask = 0xfffffff0, 10397a938f80SDmitry Baryshkov .name = "Broadcom BCM5241", 1040dcdecdcfSHeiner Kallweit /* PHY_BASIC_FEATURES */ 10417a938f80SDmitry Baryshkov .config_init = brcm_fet_config_init, 10427a938f80SDmitry Baryshkov .config_intr = brcm_fet_config_intr, 10434567d5c3SIoana Ciornei .handle_interrupt = brcm_fet_handle_interrupt, 104428dc4c8fSFlorian Fainelli }, { 104528dc4c8fSFlorian Fainelli .phy_id = PHY_ID_BCM5395, 104628dc4c8fSFlorian Fainelli .phy_id_mask = 0xfffffff0, 104728dc4c8fSFlorian Fainelli .name = "Broadcom BCM5395", 104828dc4c8fSFlorian Fainelli .flags = PHY_IS_INTERNAL, 1049dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 105028dc4c8fSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 105128dc4c8fSFlorian Fainelli .get_strings = bcm_phy_get_strings, 10525a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 10535a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 10548dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 105523b83922SBhadram Varka }, { 1056123aff2aSFlorian Fainelli .phy_id = PHY_ID_BCM53125, 1057123aff2aSFlorian Fainelli .phy_id_mask = 0xfffffff0, 1058123aff2aSFlorian Fainelli .name = "Broadcom BCM53125", 1059123aff2aSFlorian Fainelli .flags = PHY_IS_INTERNAL, 1060123aff2aSFlorian Fainelli /* PHY_GBIT_FEATURES */ 1061123aff2aSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 1062123aff2aSFlorian Fainelli .get_strings = bcm_phy_get_strings, 10635a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 10645a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 1065123aff2aSFlorian Fainelli .config_init = bcm54xx_config_init, 1066123aff2aSFlorian Fainelli .config_intr = bcm_phy_config_intr, 10674567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 10688dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 1069123aff2aSFlorian Fainelli }, { 1070*39bfb3c1SKurt Kanzenbach .phy_id = PHY_ID_BCM53128, 1071*39bfb3c1SKurt Kanzenbach .phy_id_mask = 0xfffffff0, 1072*39bfb3c1SKurt Kanzenbach .name = "Broadcom BCM53128", 1073*39bfb3c1SKurt Kanzenbach .flags = PHY_IS_INTERNAL, 1074*39bfb3c1SKurt Kanzenbach /* PHY_GBIT_FEATURES */ 1075*39bfb3c1SKurt Kanzenbach .get_sset_count = bcm_phy_get_sset_count, 1076*39bfb3c1SKurt Kanzenbach .get_strings = bcm_phy_get_strings, 1077*39bfb3c1SKurt Kanzenbach .get_stats = bcm54xx_get_stats, 1078*39bfb3c1SKurt Kanzenbach .probe = bcm54xx_phy_probe, 1079*39bfb3c1SKurt Kanzenbach .config_init = bcm54xx_config_init, 1080*39bfb3c1SKurt Kanzenbach .config_intr = bcm_phy_config_intr, 1081*39bfb3c1SKurt Kanzenbach .handle_interrupt = bcm_phy_handle_interrupt, 1082*39bfb3c1SKurt Kanzenbach .link_change_notify = bcm54xx_link_change_notify, 1083*39bfb3c1SKurt Kanzenbach }, { 108423b83922SBhadram Varka .phy_id = PHY_ID_BCM89610, 108523b83922SBhadram Varka .phy_id_mask = 0xfffffff0, 108623b83922SBhadram Varka .name = "Broadcom BCM89610", 1087dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 10885a32fcdbSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 10895a32fcdbSFlorian Fainelli .get_strings = bcm_phy_get_strings, 10905a32fcdbSFlorian Fainelli .get_stats = bcm54xx_get_stats, 10915a32fcdbSFlorian Fainelli .probe = bcm54xx_phy_probe, 109223b83922SBhadram Varka .config_init = bcm54xx_config_init, 109323b83922SBhadram Varka .config_intr = bcm_phy_config_intr, 10944567d5c3SIoana Ciornei .handle_interrupt = bcm_phy_handle_interrupt, 10958dc84dcdSFlorian Fainelli .link_change_notify = bcm54xx_link_change_notify, 1096d5bf9071SChristian Hohnstaedt } }; 10977a938f80SDmitry Baryshkov 109850fd7150SJohan Hovold module_phy_driver(broadcom_drivers); 10994e4f10f6SDavid Woodhouse 1100cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused broadcom_tbl[] = { 1101fcb26ec5SDmitry Baryshkov { PHY_ID_BCM5411, 0xfffffff0 }, 1102fcb26ec5SDmitry Baryshkov { PHY_ID_BCM5421, 0xfffffff0 }, 11030fc9ae10SRafał Miłecki { PHY_ID_BCM54210E, 0xfffffff0 }, 1104fcb26ec5SDmitry Baryshkov { PHY_ID_BCM5461, 0xfffffff0 }, 1105d92ead16SXo Wang { PHY_ID_BCM54612E, 0xfffffff0 }, 11063bca4cf6SAlessio Igor Bogani { PHY_ID_BCM54616S, 0xfffffff0 }, 1107fcb26ec5SDmitry Baryshkov { PHY_ID_BCM5464, 0xfffffff0 }, 11083c25a860SAaro Koskinen { PHY_ID_BCM5481, 0xfffffff0 }, 1109b14995acSJon Mason { PHY_ID_BCM54810, 0xfffffff0 }, 1110b0ed0bbfSKevin Lo { PHY_ID_BCM54811, 0xfffffff0 }, 1111fcb26ec5SDmitry Baryshkov { PHY_ID_BCM5482, 0xfffffff0 }, 11124e4f10f6SDavid Woodhouse { PHY_ID_BCM50610, 0xfffffff0 }, 11134e4f10f6SDavid Woodhouse { PHY_ID_BCM50610M, 0xfffffff0 }, 11144e4f10f6SDavid Woodhouse { PHY_ID_BCM57780, 0xfffffff0 }, 11154e4f10f6SDavid Woodhouse { PHY_ID_BCMAC131, 0xfffffff0 }, 11167a938f80SDmitry Baryshkov { PHY_ID_BCM5241, 0xfffffff0 }, 111728dc4c8fSFlorian Fainelli { PHY_ID_BCM5395, 0xfffffff0 }, 1118123aff2aSFlorian Fainelli { PHY_ID_BCM53125, 0xfffffff0 }, 1119*39bfb3c1SKurt Kanzenbach { PHY_ID_BCM53128, 0xfffffff0 }, 112023b83922SBhadram Varka { PHY_ID_BCM89610, 0xfffffff0 }, 11214e4f10f6SDavid Woodhouse { } 11224e4f10f6SDavid Woodhouse }; 11234e4f10f6SDavid Woodhouse 11244e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, broadcom_tbl); 1125