1c4b41c9fSMaciej W. Rozycki /* 2c4b41c9fSMaciej W. Rozycki * drivers/net/phy/broadcom.c 3c4b41c9fSMaciej W. Rozycki * 4c4b41c9fSMaciej W. Rozycki * Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet 5c4b41c9fSMaciej W. Rozycki * transceivers. 6c4b41c9fSMaciej W. Rozycki * 7c4b41c9fSMaciej W. Rozycki * Copyright (c) 2006 Maciej W. Rozycki 8c4b41c9fSMaciej W. Rozycki * 9c4b41c9fSMaciej W. Rozycki * Inspired by code written by Amy Fong. 10c4b41c9fSMaciej W. Rozycki * 11c4b41c9fSMaciej W. Rozycki * This program is free software; you can redistribute it and/or 12c4b41c9fSMaciej W. Rozycki * modify it under the terms of the GNU General Public License 13c4b41c9fSMaciej W. Rozycki * as published by the Free Software Foundation; either version 14c4b41c9fSMaciej W. Rozycki * 2 of the License, or (at your option) any later version. 15c4b41c9fSMaciej W. Rozycki */ 16c4b41c9fSMaciej W. Rozycki 17a1cba561SArun Parameswaran #include "bcm-phy-lib.h" 18c4b41c9fSMaciej W. Rozycki #include <linux/module.h> 19c4b41c9fSMaciej W. Rozycki #include <linux/phy.h> 208649f13dSMatt Carlson #include <linux/brcmphy.h> 21b14995acSJon Mason #include <linux/of.h> 22d9221e66SMatt Carlson 23d9221e66SMatt Carlson #define BRCM_PHY_MODEL(phydev) \ 24d9221e66SMatt Carlson ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask) 25d9221e66SMatt Carlson 2632e5a8d6SMatt Carlson #define BRCM_PHY_REV(phydev) \ 2732e5a8d6SMatt Carlson ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask)) 2832e5a8d6SMatt Carlson 29c4b41c9fSMaciej W. Rozycki MODULE_DESCRIPTION("Broadcom PHY driver"); 30c4b41c9fSMaciej W. Rozycki MODULE_AUTHOR("Maciej W. Rozycki"); 31c4b41c9fSMaciej W. Rozycki MODULE_LICENSE("GPL"); 32c4b41c9fSMaciej W. Rozycki 330fc9ae10SRafał Miłecki static int bcm54210e_config_init(struct phy_device *phydev) 340fc9ae10SRafał Miłecki { 350fc9ae10SRafał Miłecki int val; 360fc9ae10SRafał Miłecki 370fc9ae10SRafał Miłecki val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 380fc9ae10SRafał Miłecki val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; 390fc9ae10SRafał Miłecki val |= MII_BCM54XX_AUXCTL_MISC_WREN; 400fc9ae10SRafał Miłecki bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, val); 410fc9ae10SRafał Miłecki 420fc9ae10SRafał Miłecki val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL); 430fc9ae10SRafał Miłecki val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN; 440fc9ae10SRafał Miłecki bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); 450fc9ae10SRafał Miłecki 462355a654SRafał Miłecki if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) { 472355a654SRafał Miłecki val = phy_read(phydev, MII_CTRL1000); 482355a654SRafał Miłecki val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER; 492355a654SRafał Miłecki phy_write(phydev, MII_CTRL1000, val); 502355a654SRafał Miłecki } 512355a654SRafał Miłecki 520fc9ae10SRafał Miłecki return 0; 530fc9ae10SRafał Miłecki } 540fc9ae10SRafał Miłecki 5562e13097SRafał Miłecki static int bcm54612e_config_init(struct phy_device *phydev) 5662e13097SRafał Miłecki { 5762e13097SRafał Miłecki /* Clear TX internal delay unless requested. */ 5862e13097SRafał Miłecki if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) && 5962e13097SRafał Miłecki (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) { 6062e13097SRafał Miłecki /* Disable TXD to GTXCLK clock delay (default set) */ 6162e13097SRafał Miłecki /* Bit 9 is the only field in shadow register 00011 */ 6262e13097SRafał Miłecki bcm_phy_write_shadow(phydev, 0x03, 0); 6362e13097SRafał Miłecki } 6462e13097SRafał Miłecki 6562e13097SRafał Miłecki /* Clear RX internal delay unless requested. */ 6662e13097SRafał Miłecki if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) && 6762e13097SRafał Miłecki (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) { 6862e13097SRafał Miłecki u16 reg; 6962e13097SRafał Miłecki 7062e13097SRafał Miłecki reg = bcm54xx_auxctl_read(phydev, 7162e13097SRafał Miłecki MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 7262e13097SRafał Miłecki /* Disable RXD to RXC delay (default set) */ 7362e13097SRafał Miłecki reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; 7462e13097SRafał Miłecki /* Clear shadow selector field */ 7562e13097SRafał Miłecki reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK; 7662e13097SRafał Miłecki bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, 7762e13097SRafał Miłecki MII_BCM54XX_AUXCTL_MISC_WREN | reg); 7862e13097SRafał Miłecki } 7962e13097SRafał Miłecki 8062e13097SRafał Miłecki return 0; 8162e13097SRafał Miłecki } 8262e13097SRafał Miłecki 8373333626SAbhishek Shah static int bcm5481x_config(struct phy_device *phydev) 84b14995acSJon Mason { 85b14995acSJon Mason int rc, val; 86b14995acSJon Mason 8773333626SAbhishek Shah /* handling PHY's internal RX clock delay */ 88b14995acSJon Mason val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 89b14995acSJon Mason val |= MII_BCM54XX_AUXCTL_MISC_WREN; 9073333626SAbhishek Shah if (phydev->interface == PHY_INTERFACE_MODE_RGMII || 9173333626SAbhishek Shah phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 9273333626SAbhishek Shah /* Disable RGMII RXC-RXD skew */ 9373333626SAbhishek Shah val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; 9473333626SAbhishek Shah } 9573333626SAbhishek Shah if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 9673333626SAbhishek Shah phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 9773333626SAbhishek Shah /* Enable RGMII RXC-RXD skew */ 9873333626SAbhishek Shah val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; 9973333626SAbhishek Shah } 100b14995acSJon Mason rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, 101b14995acSJon Mason val); 102b14995acSJon Mason if (rc < 0) 103b14995acSJon Mason return rc; 104b14995acSJon Mason 10573333626SAbhishek Shah /* handling PHY's internal TX clock delay */ 106b14995acSJon Mason val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL); 10773333626SAbhishek Shah if (phydev->interface == PHY_INTERFACE_MODE_RGMII || 10873333626SAbhishek Shah phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 10973333626SAbhishek Shah /* Disable internal TX clock delay */ 110b14995acSJon Mason val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN; 11173333626SAbhishek Shah } 11273333626SAbhishek Shah if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || 11373333626SAbhishek Shah phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { 11473333626SAbhishek Shah /* Enable internal TX clock delay */ 11573333626SAbhishek Shah val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN; 11673333626SAbhishek Shah } 117b14995acSJon Mason rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); 118b14995acSJon Mason if (rc < 0) 119b14995acSJon Mason return rc; 120b14995acSJon Mason 121b14995acSJon Mason return 0; 122b14995acSJon Mason } 123b14995acSJon Mason 12447b1b53bSMatt Carlson /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */ 125772638b6SMatt Carlson static int bcm50610_a0_workaround(struct phy_device *phydev) 126772638b6SMatt Carlson { 127772638b6SMatt Carlson int err; 128772638b6SMatt Carlson 129a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0, 13047b1b53bSMatt Carlson MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | 13147b1b53bSMatt Carlson MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); 13247b1b53bSMatt Carlson if (err < 0) 13347b1b53bSMatt Carlson return err; 13447b1b53bSMatt Carlson 135a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3, 13647b1b53bSMatt Carlson MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); 13747b1b53bSMatt Carlson if (err < 0) 13847b1b53bSMatt Carlson return err; 13947b1b53bSMatt Carlson 140a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, 14147b1b53bSMatt Carlson MII_BCM54XX_EXP_EXP75_VDACCTRL); 14247b1b53bSMatt Carlson if (err < 0) 14347b1b53bSMatt Carlson return err; 14447b1b53bSMatt Carlson 145a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96, 14647b1b53bSMatt Carlson MII_BCM54XX_EXP_EXP96_MYST); 14747b1b53bSMatt Carlson if (err < 0) 14847b1b53bSMatt Carlson return err; 14947b1b53bSMatt Carlson 150a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97, 15147b1b53bSMatt Carlson MII_BCM54XX_EXP_EXP97_MYST); 15247b1b53bSMatt Carlson 15347b1b53bSMatt Carlson return err; 15447b1b53bSMatt Carlson } 15547b1b53bSMatt Carlson 15647b1b53bSMatt Carlson static int bcm54xx_phydsp_config(struct phy_device *phydev) 15747b1b53bSMatt Carlson { 15847b1b53bSMatt Carlson int err, err2; 15947b1b53bSMatt Carlson 16047b1b53bSMatt Carlson /* Enable the SMDSP clock */ 161772638b6SMatt Carlson err = bcm54xx_auxctl_write(phydev, 162772638b6SMatt Carlson MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, 163772638b6SMatt Carlson MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | 164772638b6SMatt Carlson MII_BCM54XX_AUXCTL_ACTL_TX_6DB); 165772638b6SMatt Carlson if (err < 0) 166772638b6SMatt Carlson return err; 167772638b6SMatt Carlson 168219c6efeSMatt Carlson if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 169219c6efeSMatt Carlson BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) { 170219c6efeSMatt Carlson /* Clear bit 9 to fix a phy interop issue. */ 171a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08, 172219c6efeSMatt Carlson MII_BCM54XX_EXP_EXP08_RJCT_2MHZ); 173219c6efeSMatt Carlson if (err < 0) 174219c6efeSMatt Carlson goto error; 175219c6efeSMatt Carlson 176219c6efeSMatt Carlson if (phydev->drv->phy_id == PHY_ID_BCM50610) { 17747b1b53bSMatt Carlson err = bcm50610_a0_workaround(phydev); 178219c6efeSMatt Carlson if (err < 0) 179219c6efeSMatt Carlson goto error; 180219c6efeSMatt Carlson } 181219c6efeSMatt Carlson } 18247b1b53bSMatt Carlson 18347b1b53bSMatt Carlson if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) { 18447b1b53bSMatt Carlson int val; 18547b1b53bSMatt Carlson 186a1cba561SArun Parameswaran val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75); 18747b1b53bSMatt Carlson if (val < 0) 188772638b6SMatt Carlson goto error; 189772638b6SMatt Carlson 19047b1b53bSMatt Carlson val |= MII_BCM54XX_EXP_EXP75_CM_OSC; 191a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val); 19247b1b53bSMatt Carlson } 193772638b6SMatt Carlson 194772638b6SMatt Carlson error: 19547b1b53bSMatt Carlson /* Disable the SMDSP clock */ 19647b1b53bSMatt Carlson err2 = bcm54xx_auxctl_write(phydev, 197772638b6SMatt Carlson MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, 198772638b6SMatt Carlson MII_BCM54XX_AUXCTL_ACTL_TX_6DB); 199772638b6SMatt Carlson 20047b1b53bSMatt Carlson /* Return the first error reported. */ 20147b1b53bSMatt Carlson return err ? err : err2; 202772638b6SMatt Carlson } 203772638b6SMatt Carlson 20432e5a8d6SMatt Carlson static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) 20532e5a8d6SMatt Carlson { 2065ee6f6a1SRoel Kluin u32 orig; 2075ee6f6a1SRoel Kluin int val; 208c704dc23SMatt Carlson bool clk125en = true; 20932e5a8d6SMatt Carlson 21032e5a8d6SMatt Carlson /* Abort if we are using an untested phy. */ 2117ec4e7d3Sroel kluin if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 && 2127ec4e7d3Sroel kluin BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 && 21332e5a8d6SMatt Carlson BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M) 21432e5a8d6SMatt Carlson return; 21532e5a8d6SMatt Carlson 216a1cba561SArun Parameswaran val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3); 21732e5a8d6SMatt Carlson if (val < 0) 21832e5a8d6SMatt Carlson return; 21932e5a8d6SMatt Carlson 22032e5a8d6SMatt Carlson orig = val; 22132e5a8d6SMatt Carlson 22232e5a8d6SMatt Carlson if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 22332e5a8d6SMatt Carlson BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 22432e5a8d6SMatt Carlson BRCM_PHY_REV(phydev) >= 0x3) { 225c704dc23SMatt Carlson /* 226c704dc23SMatt Carlson * Here, bit 0 _disables_ CLK125 when set. 227c704dc23SMatt Carlson * This bit is set by default. 228c704dc23SMatt Carlson */ 229c704dc23SMatt Carlson clk125en = false; 23032e5a8d6SMatt Carlson } else { 231c704dc23SMatt Carlson if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) { 23232e5a8d6SMatt Carlson /* Here, bit 0 _enables_ CLK125 when set */ 23332e5a8d6SMatt Carlson val &= ~BCM54XX_SHD_SCR3_DEF_CLK125; 234c704dc23SMatt Carlson clk125en = false; 23532e5a8d6SMatt Carlson } 23632e5a8d6SMatt Carlson } 23732e5a8d6SMatt Carlson 23823677ce3SJoe Perches if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 239c704dc23SMatt Carlson val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS; 240c704dc23SMatt Carlson else 241c704dc23SMatt Carlson val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; 242c704dc23SMatt Carlson 24352fae083SMatt Carlson if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) 24452fae083SMatt Carlson val |= BCM54XX_SHD_SCR3_TRDDAPD; 24552fae083SMatt Carlson 24632e5a8d6SMatt Carlson if (orig != val) 247a1cba561SArun Parameswaran bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val); 248c704dc23SMatt Carlson 249a1cba561SArun Parameswaran val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD); 250c704dc23SMatt Carlson if (val < 0) 251c704dc23SMatt Carlson return; 252c704dc23SMatt Carlson 253c704dc23SMatt Carlson orig = val; 254c704dc23SMatt Carlson 25523677ce3SJoe Perches if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 256c704dc23SMatt Carlson val |= BCM54XX_SHD_APD_EN; 257c704dc23SMatt Carlson else 258c704dc23SMatt Carlson val &= ~BCM54XX_SHD_APD_EN; 259c704dc23SMatt Carlson 260c704dc23SMatt Carlson if (orig != val) 261a1cba561SArun Parameswaran bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val); 26232e5a8d6SMatt Carlson } 26332e5a8d6SMatt Carlson 264c4b41c9fSMaciej W. Rozycki static int bcm54xx_config_init(struct phy_device *phydev) 265c4b41c9fSMaciej W. Rozycki { 26673333626SAbhishek Shah int reg, err, val; 267c4b41c9fSMaciej W. Rozycki 268c4b41c9fSMaciej W. Rozycki reg = phy_read(phydev, MII_BCM54XX_ECR); 269c4b41c9fSMaciej W. Rozycki if (reg < 0) 270c4b41c9fSMaciej W. Rozycki return reg; 271c4b41c9fSMaciej W. Rozycki 272c4b41c9fSMaciej W. Rozycki /* Mask interrupts globally. */ 273c4b41c9fSMaciej W. Rozycki reg |= MII_BCM54XX_ECR_IM; 274c4b41c9fSMaciej W. Rozycki err = phy_write(phydev, MII_BCM54XX_ECR, reg); 275c4b41c9fSMaciej W. Rozycki if (err < 0) 276c4b41c9fSMaciej W. Rozycki return err; 277c4b41c9fSMaciej W. Rozycki 278c4b41c9fSMaciej W. Rozycki /* Unmask events we are interested in. */ 279c4b41c9fSMaciej W. Rozycki reg = ~(MII_BCM54XX_INT_DUPLEX | 280c4b41c9fSMaciej W. Rozycki MII_BCM54XX_INT_SPEED | 281c4b41c9fSMaciej W. Rozycki MII_BCM54XX_INT_LINK); 282c4b41c9fSMaciej W. Rozycki err = phy_write(phydev, MII_BCM54XX_IMR, reg); 283c4b41c9fSMaciej W. Rozycki if (err < 0) 284c4b41c9fSMaciej W. Rozycki return err; 285772638b6SMatt Carlson 28663a14ce4SMatt Carlson if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 || 28763a14ce4SMatt Carlson BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) && 28863a14ce4SMatt Carlson (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) 289a1cba561SArun Parameswaran bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0); 29063a14ce4SMatt Carlson 291c704dc23SMatt Carlson if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) || 29252fae083SMatt Carlson (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) || 293c704dc23SMatt Carlson (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) 29432e5a8d6SMatt Carlson bcm54xx_adjust_rxrefclk(phydev); 29532e5a8d6SMatt Carlson 2960fc9ae10SRafał Miłecki if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E) { 2970fc9ae10SRafał Miłecki err = bcm54210e_config_init(phydev); 2980fc9ae10SRafał Miłecki if (err) 2990fc9ae10SRafał Miłecki return err; 30062e13097SRafał Miłecki } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) { 30162e13097SRafał Miłecki err = bcm54612e_config_init(phydev); 30262e13097SRafał Miłecki if (err) 30362e13097SRafał Miłecki return err; 3040fc9ae10SRafał Miłecki } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) { 30573333626SAbhishek Shah /* For BCM54810, we need to disable BroadR-Reach function */ 30673333626SAbhishek Shah val = bcm_phy_read_exp(phydev, 30773333626SAbhishek Shah BCM54810_EXP_BROADREACH_LRE_MISC_CTL); 30873333626SAbhishek Shah val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; 30973333626SAbhishek Shah err = bcm_phy_write_exp(phydev, 31073333626SAbhishek Shah BCM54810_EXP_BROADREACH_LRE_MISC_CTL, 31173333626SAbhishek Shah val); 31273333626SAbhishek Shah if (err < 0) 313b14995acSJon Mason return err; 314b14995acSJon Mason } 315b14995acSJon Mason 31647b1b53bSMatt Carlson bcm54xx_phydsp_config(phydev); 317d9221e66SMatt Carlson 318c4b41c9fSMaciej W. Rozycki return 0; 319c4b41c9fSMaciej W. Rozycki } 320c4b41c9fSMaciej W. Rozycki 321cd9af3daSNate Case static int bcm5482_config_init(struct phy_device *phydev) 322cd9af3daSNate Case { 323cd9af3daSNate Case int err, reg; 324cd9af3daSNate Case 325cd9af3daSNate Case err = bcm54xx_config_init(phydev); 326cd9af3daSNate Case 327cd9af3daSNate Case if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { 328cd9af3daSNate Case /* 329cd9af3daSNate Case * Enable secondary SerDes and its use as an LED source 330cd9af3daSNate Case */ 331a1cba561SArun Parameswaran reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD); 332a1cba561SArun Parameswaran bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD, 333cd9af3daSNate Case reg | 334cd9af3daSNate Case BCM5482_SHD_SSD_LEDM | 335cd9af3daSNate Case BCM5482_SHD_SSD_EN); 336cd9af3daSNate Case 337cd9af3daSNate Case /* 338cd9af3daSNate Case * Enable SGMII slave mode and auto-detection 339cd9af3daSNate Case */ 340042a75b9SMatt Carlson reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD; 341a1cba561SArun Parameswaran err = bcm_phy_read_exp(phydev, reg); 342042a75b9SMatt Carlson if (err < 0) 343042a75b9SMatt Carlson return err; 344a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, reg, err | 345cd9af3daSNate Case BCM5482_SSD_SGMII_SLAVE_EN | 346cd9af3daSNate Case BCM5482_SSD_SGMII_SLAVE_AD); 347042a75b9SMatt Carlson if (err < 0) 348042a75b9SMatt Carlson return err; 349cd9af3daSNate Case 350cd9af3daSNate Case /* 351cd9af3daSNate Case * Disable secondary SerDes powerdown 352cd9af3daSNate Case */ 353042a75b9SMatt Carlson reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD; 354a1cba561SArun Parameswaran err = bcm_phy_read_exp(phydev, reg); 355042a75b9SMatt Carlson if (err < 0) 356042a75b9SMatt Carlson return err; 357a1cba561SArun Parameswaran err = bcm_phy_write_exp(phydev, reg, 358042a75b9SMatt Carlson err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); 359042a75b9SMatt Carlson if (err < 0) 360042a75b9SMatt Carlson return err; 361cd9af3daSNate Case 362cd9af3daSNate Case /* 363cd9af3daSNate Case * Select 1000BASE-X register set (primary SerDes) 364cd9af3daSNate Case */ 365a1cba561SArun Parameswaran reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE); 366a1cba561SArun Parameswaran bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE, 367cd9af3daSNate Case reg | BCM5482_SHD_MODE_1000BX); 368cd9af3daSNate Case 369cd9af3daSNate Case /* 370cd9af3daSNate Case * LED1=ACTIVITYLED, LED3=LINKSPD[2] 371cd9af3daSNate Case * (Use LED1 as secondary SerDes ACTIVITY LED) 372cd9af3daSNate Case */ 373a1cba561SArun Parameswaran bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, 374cd9af3daSNate Case BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) | 375cd9af3daSNate Case BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2)); 376cd9af3daSNate Case 377cd9af3daSNate Case /* 378cd9af3daSNate Case * Auto-negotiation doesn't seem to work quite right 379cd9af3daSNate Case * in this mode, so we disable it and force it to the 380cd9af3daSNate Case * right speed/duplex setting. Only 'link status' 381cd9af3daSNate Case * is important. 382cd9af3daSNate Case */ 383cd9af3daSNate Case phydev->autoneg = AUTONEG_DISABLE; 384cd9af3daSNate Case phydev->speed = SPEED_1000; 385cd9af3daSNate Case phydev->duplex = DUPLEX_FULL; 386cd9af3daSNate Case } 387cd9af3daSNate Case 388cd9af3daSNate Case return err; 389cd9af3daSNate Case } 390cd9af3daSNate Case 391cd9af3daSNate Case static int bcm5482_read_status(struct phy_device *phydev) 392cd9af3daSNate Case { 393cd9af3daSNate Case int err; 394cd9af3daSNate Case 395cd9af3daSNate Case err = genphy_read_status(phydev); 396cd9af3daSNate Case 397cd9af3daSNate Case if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { 398cd9af3daSNate Case /* 399cd9af3daSNate Case * Only link status matters for 1000Base-X mode, so force 400cd9af3daSNate Case * 1000 Mbit/s full-duplex status 401cd9af3daSNate Case */ 402cd9af3daSNate Case if (phydev->link) { 403cd9af3daSNate Case phydev->speed = SPEED_1000; 404cd9af3daSNate Case phydev->duplex = DUPLEX_FULL; 405cd9af3daSNate Case } 406cd9af3daSNate Case } 407cd9af3daSNate Case 408cd9af3daSNate Case return err; 409cd9af3daSNate Case } 410cd9af3daSNate Case 41157bb7e22SAnton Vorontsov static int bcm5481_config_aneg(struct phy_device *phydev) 41257bb7e22SAnton Vorontsov { 413b14995acSJon Mason struct device_node *np = phydev->mdio.dev.of_node; 41457bb7e22SAnton Vorontsov int ret; 41557bb7e22SAnton Vorontsov 41657bb7e22SAnton Vorontsov /* Aneg firsly. */ 41757bb7e22SAnton Vorontsov ret = genphy_config_aneg(phydev); 41857bb7e22SAnton Vorontsov 41957bb7e22SAnton Vorontsov /* Then we can set up the delay. */ 42073333626SAbhishek Shah bcm5481x_config(phydev); 42157bb7e22SAnton Vorontsov 422b14995acSJon Mason if (of_property_read_bool(np, "enet-phy-lane-swap")) { 423b14995acSJon Mason /* Lane Swap - Undocumented register...magic! */ 424b14995acSJon Mason ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9, 425b14995acSJon Mason 0x11B); 426b14995acSJon Mason if (ret < 0) 427b14995acSJon Mason return ret; 428b14995acSJon Mason } 429b14995acSJon Mason 43057bb7e22SAnton Vorontsov return ret; 43157bb7e22SAnton Vorontsov } 43257bb7e22SAnton Vorontsov 433d7a2ed92SMatt Carlson static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) 434d7a2ed92SMatt Carlson { 435d7a2ed92SMatt Carlson int val; 436d7a2ed92SMatt Carlson 437d7a2ed92SMatt Carlson val = phy_read(phydev, reg); 438d7a2ed92SMatt Carlson if (val < 0) 439d7a2ed92SMatt Carlson return val; 440d7a2ed92SMatt Carlson 441d7a2ed92SMatt Carlson return phy_write(phydev, reg, val | set); 442d7a2ed92SMatt Carlson } 443d7a2ed92SMatt Carlson 444d7a2ed92SMatt Carlson static int brcm_fet_config_init(struct phy_device *phydev) 445d7a2ed92SMatt Carlson { 446d7a2ed92SMatt Carlson int reg, err, err2, brcmtest; 447d7a2ed92SMatt Carlson 448d7a2ed92SMatt Carlson /* Reset the PHY to bring it to a known state. */ 449d7a2ed92SMatt Carlson err = phy_write(phydev, MII_BMCR, BMCR_RESET); 450d7a2ed92SMatt Carlson if (err < 0) 451d7a2ed92SMatt Carlson return err; 452d7a2ed92SMatt Carlson 453d7a2ed92SMatt Carlson reg = phy_read(phydev, MII_BRCM_FET_INTREG); 454d7a2ed92SMatt Carlson if (reg < 0) 455d7a2ed92SMatt Carlson return reg; 456d7a2ed92SMatt Carlson 457d7a2ed92SMatt Carlson /* Unmask events we are interested in and mask interrupts globally. */ 458d7a2ed92SMatt Carlson reg = MII_BRCM_FET_IR_DUPLEX_EN | 459d7a2ed92SMatt Carlson MII_BRCM_FET_IR_SPEED_EN | 460d7a2ed92SMatt Carlson MII_BRCM_FET_IR_LINK_EN | 461d7a2ed92SMatt Carlson MII_BRCM_FET_IR_ENABLE | 462d7a2ed92SMatt Carlson MII_BRCM_FET_IR_MASK; 463d7a2ed92SMatt Carlson 464d7a2ed92SMatt Carlson err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 465d7a2ed92SMatt Carlson if (err < 0) 466d7a2ed92SMatt Carlson return err; 467d7a2ed92SMatt Carlson 468d7a2ed92SMatt Carlson /* Enable shadow register access */ 469d7a2ed92SMatt Carlson brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST); 470d7a2ed92SMatt Carlson if (brcmtest < 0) 471d7a2ed92SMatt Carlson return brcmtest; 472d7a2ed92SMatt Carlson 473d7a2ed92SMatt Carlson reg = brcmtest | MII_BRCM_FET_BT_SRE; 474d7a2ed92SMatt Carlson 475d7a2ed92SMatt Carlson err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg); 476d7a2ed92SMatt Carlson if (err < 0) 477d7a2ed92SMatt Carlson return err; 478d7a2ed92SMatt Carlson 479d7a2ed92SMatt Carlson /* Set the LED mode */ 480d7a2ed92SMatt Carlson reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4); 481d7a2ed92SMatt Carlson if (reg < 0) { 482d7a2ed92SMatt Carlson err = reg; 483d7a2ed92SMatt Carlson goto done; 484d7a2ed92SMatt Carlson } 485d7a2ed92SMatt Carlson 486d7a2ed92SMatt Carlson reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK; 487d7a2ed92SMatt Carlson reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1; 488d7a2ed92SMatt Carlson 489d7a2ed92SMatt Carlson err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg); 490d7a2ed92SMatt Carlson if (err < 0) 491d7a2ed92SMatt Carlson goto done; 492d7a2ed92SMatt Carlson 493d7a2ed92SMatt Carlson /* Enable auto MDIX */ 494d7a2ed92SMatt Carlson err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL, 495d7a2ed92SMatt Carlson MII_BRCM_FET_SHDW_MC_FAME); 496d7a2ed92SMatt Carlson if (err < 0) 497d7a2ed92SMatt Carlson goto done; 498d7a2ed92SMatt Carlson 499cdd4e09dSMatt Carlson if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) { 500d7a2ed92SMatt Carlson /* Enable auto power down */ 501d7a2ed92SMatt Carlson err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, 502d7a2ed92SMatt Carlson MII_BRCM_FET_SHDW_AS2_APDE); 503cdd4e09dSMatt Carlson } 504d7a2ed92SMatt Carlson 505d7a2ed92SMatt Carlson done: 506d7a2ed92SMatt Carlson /* Disable shadow register access */ 507d7a2ed92SMatt Carlson err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest); 508d7a2ed92SMatt Carlson if (!err) 509d7a2ed92SMatt Carlson err = err2; 510d7a2ed92SMatt Carlson 511d7a2ed92SMatt Carlson return err; 512d7a2ed92SMatt Carlson } 513d7a2ed92SMatt Carlson 514d7a2ed92SMatt Carlson static int brcm_fet_ack_interrupt(struct phy_device *phydev) 515d7a2ed92SMatt Carlson { 516d7a2ed92SMatt Carlson int reg; 517d7a2ed92SMatt Carlson 518d7a2ed92SMatt Carlson /* Clear pending interrupts. */ 519d7a2ed92SMatt Carlson reg = phy_read(phydev, MII_BRCM_FET_INTREG); 520d7a2ed92SMatt Carlson if (reg < 0) 521d7a2ed92SMatt Carlson return reg; 522d7a2ed92SMatt Carlson 523d7a2ed92SMatt Carlson return 0; 524d7a2ed92SMatt Carlson } 525d7a2ed92SMatt Carlson 526d7a2ed92SMatt Carlson static int brcm_fet_config_intr(struct phy_device *phydev) 527d7a2ed92SMatt Carlson { 528d7a2ed92SMatt Carlson int reg, err; 529d7a2ed92SMatt Carlson 530d7a2ed92SMatt Carlson reg = phy_read(phydev, MII_BRCM_FET_INTREG); 531d7a2ed92SMatt Carlson if (reg < 0) 532d7a2ed92SMatt Carlson return reg; 533d7a2ed92SMatt Carlson 534d7a2ed92SMatt Carlson if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 535d7a2ed92SMatt Carlson reg &= ~MII_BRCM_FET_IR_MASK; 536d7a2ed92SMatt Carlson else 537d7a2ed92SMatt Carlson reg |= MII_BRCM_FET_IR_MASK; 538d7a2ed92SMatt Carlson 539d7a2ed92SMatt Carlson err = phy_write(phydev, MII_BRCM_FET_INTREG, reg); 540d7a2ed92SMatt Carlson return err; 541d7a2ed92SMatt Carlson } 542d7a2ed92SMatt Carlson 54328dc4c8fSFlorian Fainelli struct bcm53xx_phy_priv { 54428dc4c8fSFlorian Fainelli u64 *stats; 54528dc4c8fSFlorian Fainelli }; 54628dc4c8fSFlorian Fainelli 54728dc4c8fSFlorian Fainelli static int bcm53xx_phy_probe(struct phy_device *phydev) 54828dc4c8fSFlorian Fainelli { 54928dc4c8fSFlorian Fainelli struct bcm53xx_phy_priv *priv; 55028dc4c8fSFlorian Fainelli 55128dc4c8fSFlorian Fainelli priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); 55228dc4c8fSFlorian Fainelli if (!priv) 55328dc4c8fSFlorian Fainelli return -ENOMEM; 55428dc4c8fSFlorian Fainelli 55528dc4c8fSFlorian Fainelli phydev->priv = priv; 55628dc4c8fSFlorian Fainelli 55728dc4c8fSFlorian Fainelli priv->stats = devm_kcalloc(&phydev->mdio.dev, 55828dc4c8fSFlorian Fainelli bcm_phy_get_sset_count(phydev), sizeof(u64), 55928dc4c8fSFlorian Fainelli GFP_KERNEL); 56028dc4c8fSFlorian Fainelli if (!priv->stats) 56128dc4c8fSFlorian Fainelli return -ENOMEM; 56228dc4c8fSFlorian Fainelli 56328dc4c8fSFlorian Fainelli return 0; 56428dc4c8fSFlorian Fainelli } 56528dc4c8fSFlorian Fainelli 56628dc4c8fSFlorian Fainelli static void bcm53xx_phy_get_stats(struct phy_device *phydev, 56728dc4c8fSFlorian Fainelli struct ethtool_stats *stats, u64 *data) 56828dc4c8fSFlorian Fainelli { 56928dc4c8fSFlorian Fainelli struct bcm53xx_phy_priv *priv = phydev->priv; 57028dc4c8fSFlorian Fainelli 57128dc4c8fSFlorian Fainelli bcm_phy_get_stats(phydev, priv->stats, stats, data); 57228dc4c8fSFlorian Fainelli } 57328dc4c8fSFlorian Fainelli 574d5bf9071SChristian Hohnstaedt static struct phy_driver broadcom_drivers[] = { 575d5bf9071SChristian Hohnstaedt { 576fcb26ec5SDmitry Baryshkov .phy_id = PHY_ID_BCM5411, 577c4b41c9fSMaciej W. Rozycki .phy_id_mask = 0xfffffff0, 578c4b41c9fSMaciej W. Rozycki .name = "Broadcom BCM5411", 579529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 5801b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 581c4b41c9fSMaciej W. Rozycki .config_init = bcm54xx_config_init, 582a1cba561SArun Parameswaran .ack_interrupt = bcm_phy_ack_intr, 583a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 584d5bf9071SChristian Hohnstaedt }, { 585fcb26ec5SDmitry Baryshkov .phy_id = PHY_ID_BCM5421, 586c4b41c9fSMaciej W. Rozycki .phy_id_mask = 0xfffffff0, 587c4b41c9fSMaciej W. Rozycki .name = "Broadcom BCM5421", 588529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 5891b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 590c4b41c9fSMaciej W. Rozycki .config_init = bcm54xx_config_init, 591a1cba561SArun Parameswaran .ack_interrupt = bcm_phy_ack_intr, 592a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 593d5bf9071SChristian Hohnstaedt }, { 5940fc9ae10SRafał Miłecki .phy_id = PHY_ID_BCM54210E, 5950fc9ae10SRafał Miłecki .phy_id_mask = 0xfffffff0, 5960fc9ae10SRafał Miłecki .name = "Broadcom BCM54210E", 5970fc9ae10SRafał Miłecki .features = PHY_GBIT_FEATURES, 5981b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 5990fc9ae10SRafał Miłecki .config_init = bcm54xx_config_init, 6000fc9ae10SRafał Miłecki .ack_interrupt = bcm_phy_ack_intr, 6010fc9ae10SRafał Miłecki .config_intr = bcm_phy_config_intr, 6020fc9ae10SRafał Miłecki }, { 603fcb26ec5SDmitry Baryshkov .phy_id = PHY_ID_BCM5461, 604c4b41c9fSMaciej W. Rozycki .phy_id_mask = 0xfffffff0, 605c4b41c9fSMaciej W. Rozycki .name = "Broadcom BCM5461", 606529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 6071b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 608c4b41c9fSMaciej W. Rozycki .config_init = bcm54xx_config_init, 609a1cba561SArun Parameswaran .ack_interrupt = bcm_phy_ack_intr, 610a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 611d5bf9071SChristian Hohnstaedt }, { 612d92ead16SXo Wang .phy_id = PHY_ID_BCM54612E, 613d92ead16SXo Wang .phy_id_mask = 0xfffffff0, 614d92ead16SXo Wang .name = "Broadcom BCM54612E", 615529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 6161b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 617d92ead16SXo Wang .config_init = bcm54xx_config_init, 618d92ead16SXo Wang .ack_interrupt = bcm_phy_ack_intr, 619d92ead16SXo Wang .config_intr = bcm_phy_config_intr, 620d92ead16SXo Wang }, { 6213bca4cf6SAlessio Igor Bogani .phy_id = PHY_ID_BCM54616S, 6223bca4cf6SAlessio Igor Bogani .phy_id_mask = 0xfffffff0, 6233bca4cf6SAlessio Igor Bogani .name = "Broadcom BCM54616S", 624529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 6251b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 6263bca4cf6SAlessio Igor Bogani .config_init = bcm54xx_config_init, 627a1cba561SArun Parameswaran .ack_interrupt = bcm_phy_ack_intr, 628a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 6293bca4cf6SAlessio Igor Bogani }, { 630fcb26ec5SDmitry Baryshkov .phy_id = PHY_ID_BCM5464, 631b1394f96SPaul Gortmaker .phy_id_mask = 0xfffffff0, 632b1394f96SPaul Gortmaker .name = "Broadcom BCM5464", 633529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 6341b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 635b1394f96SPaul Gortmaker .config_init = bcm54xx_config_init, 636a1cba561SArun Parameswaran .ack_interrupt = bcm_phy_ack_intr, 637a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 638d5bf9071SChristian Hohnstaedt }, { 639fcb26ec5SDmitry Baryshkov .phy_id = PHY_ID_BCM5481, 64057bb7e22SAnton Vorontsov .phy_id_mask = 0xfffffff0, 64157bb7e22SAnton Vorontsov .name = "Broadcom BCM5481", 642529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 6431b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 64457bb7e22SAnton Vorontsov .config_init = bcm54xx_config_init, 6459753c21fSHeiner Kallweit .config_aneg = bcm5481_config_aneg, 646a1cba561SArun Parameswaran .ack_interrupt = bcm_phy_ack_intr, 647a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 648d5bf9071SChristian Hohnstaedt }, { 649b14995acSJon Mason .phy_id = PHY_ID_BCM54810, 650b14995acSJon Mason .phy_id_mask = 0xfffffff0, 651b14995acSJon Mason .name = "Broadcom BCM54810", 652529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 6531b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 654b14995acSJon Mason .config_init = bcm54xx_config_init, 6559753c21fSHeiner Kallweit .config_aneg = bcm5481_config_aneg, 656b14995acSJon Mason .ack_interrupt = bcm_phy_ack_intr, 657b14995acSJon Mason .config_intr = bcm_phy_config_intr, 658b14995acSJon Mason }, { 659fcb26ec5SDmitry Baryshkov .phy_id = PHY_ID_BCM5482, 66003157ac3SNate Case .phy_id_mask = 0xfffffff0, 66103157ac3SNate Case .name = "Broadcom BCM5482", 662529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 6631b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 664cd9af3daSNate Case .config_init = bcm5482_config_init, 6659753c21fSHeiner Kallweit .read_status = bcm5482_read_status, 666a1cba561SArun Parameswaran .ack_interrupt = bcm_phy_ack_intr, 667a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 668d5bf9071SChristian Hohnstaedt }, { 669772638b6SMatt Carlson .phy_id = PHY_ID_BCM50610, 670772638b6SMatt Carlson .phy_id_mask = 0xfffffff0, 671772638b6SMatt Carlson .name = "Broadcom BCM50610", 672529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 6731b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 674772638b6SMatt Carlson .config_init = bcm54xx_config_init, 675a1cba561SArun Parameswaran .ack_interrupt = bcm_phy_ack_intr, 676a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 677d5bf9071SChristian Hohnstaedt }, { 6784f4598fdSMatt Carlson .phy_id = PHY_ID_BCM50610M, 6794f4598fdSMatt Carlson .phy_id_mask = 0xfffffff0, 6804f4598fdSMatt Carlson .name = "Broadcom BCM50610M", 681529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 6821b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 6834f4598fdSMatt Carlson .config_init = bcm54xx_config_init, 684a1cba561SArun Parameswaran .ack_interrupt = bcm_phy_ack_intr, 685a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 686d5bf9071SChristian Hohnstaedt }, { 687d9221e66SMatt Carlson .phy_id = PHY_ID_BCM57780, 6882fbb69aaSMatt Carlson .phy_id_mask = 0xfffffff0, 6892fbb69aaSMatt Carlson .name = "Broadcom BCM57780", 690529ed127STimur Tabi .features = PHY_GBIT_FEATURES, 6911b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 6922fbb69aaSMatt Carlson .config_init = bcm54xx_config_init, 693a1cba561SArun Parameswaran .ack_interrupt = bcm_phy_ack_intr, 694a1cba561SArun Parameswaran .config_intr = bcm_phy_config_intr, 695d5bf9071SChristian Hohnstaedt }, { 6966a443a0fSMatt Carlson .phy_id = PHY_ID_BCMAC131, 697d7a2ed92SMatt Carlson .phy_id_mask = 0xfffffff0, 698d7a2ed92SMatt Carlson .name = "Broadcom BCMAC131", 699529ed127STimur Tabi .features = PHY_BASIC_FEATURES, 7001b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 701d7a2ed92SMatt Carlson .config_init = brcm_fet_config_init, 702d7a2ed92SMatt Carlson .ack_interrupt = brcm_fet_ack_interrupt, 703d7a2ed92SMatt Carlson .config_intr = brcm_fet_config_intr, 704d5bf9071SChristian Hohnstaedt }, { 7057a938f80SDmitry Baryshkov .phy_id = PHY_ID_BCM5241, 7067a938f80SDmitry Baryshkov .phy_id_mask = 0xfffffff0, 7077a938f80SDmitry Baryshkov .name = "Broadcom BCM5241", 708529ed127STimur Tabi .features = PHY_BASIC_FEATURES, 7091b86f702SAndrew Lunn .flags = PHY_HAS_INTERRUPT, 7107a938f80SDmitry Baryshkov .config_init = brcm_fet_config_init, 7117a938f80SDmitry Baryshkov .ack_interrupt = brcm_fet_ack_interrupt, 7127a938f80SDmitry Baryshkov .config_intr = brcm_fet_config_intr, 71328dc4c8fSFlorian Fainelli }, { 71428dc4c8fSFlorian Fainelli .phy_id = PHY_ID_BCM5395, 71528dc4c8fSFlorian Fainelli .phy_id_mask = 0xfffffff0, 71628dc4c8fSFlorian Fainelli .name = "Broadcom BCM5395", 71728dc4c8fSFlorian Fainelli .flags = PHY_IS_INTERNAL, 71828dc4c8fSFlorian Fainelli .features = PHY_GBIT_FEATURES, 71928dc4c8fSFlorian Fainelli .get_sset_count = bcm_phy_get_sset_count, 72028dc4c8fSFlorian Fainelli .get_strings = bcm_phy_get_strings, 72128dc4c8fSFlorian Fainelli .get_stats = bcm53xx_phy_get_stats, 72228dc4c8fSFlorian Fainelli .probe = bcm53xx_phy_probe, 723*23b83922SBhadram Varka }, { 724*23b83922SBhadram Varka .phy_id = PHY_ID_BCM89610, 725*23b83922SBhadram Varka .phy_id_mask = 0xfffffff0, 726*23b83922SBhadram Varka .name = "Broadcom BCM89610", 727*23b83922SBhadram Varka .features = PHY_GBIT_FEATURES, 728*23b83922SBhadram Varka .flags = PHY_HAS_INTERRUPT, 729*23b83922SBhadram Varka .config_init = bcm54xx_config_init, 730*23b83922SBhadram Varka .ack_interrupt = bcm_phy_ack_intr, 731*23b83922SBhadram Varka .config_intr = bcm_phy_config_intr, 732d5bf9071SChristian Hohnstaedt } }; 7337a938f80SDmitry Baryshkov 73450fd7150SJohan Hovold module_phy_driver(broadcom_drivers); 7354e4f10f6SDavid Woodhouse 736cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused broadcom_tbl[] = { 737fcb26ec5SDmitry Baryshkov { PHY_ID_BCM5411, 0xfffffff0 }, 738fcb26ec5SDmitry Baryshkov { PHY_ID_BCM5421, 0xfffffff0 }, 7390fc9ae10SRafał Miłecki { PHY_ID_BCM54210E, 0xfffffff0 }, 740fcb26ec5SDmitry Baryshkov { PHY_ID_BCM5461, 0xfffffff0 }, 741d92ead16SXo Wang { PHY_ID_BCM54612E, 0xfffffff0 }, 7423bca4cf6SAlessio Igor Bogani { PHY_ID_BCM54616S, 0xfffffff0 }, 743fcb26ec5SDmitry Baryshkov { PHY_ID_BCM5464, 0xfffffff0 }, 7443c25a860SAaro Koskinen { PHY_ID_BCM5481, 0xfffffff0 }, 745b14995acSJon Mason { PHY_ID_BCM54810, 0xfffffff0 }, 746fcb26ec5SDmitry Baryshkov { PHY_ID_BCM5482, 0xfffffff0 }, 7474e4f10f6SDavid Woodhouse { PHY_ID_BCM50610, 0xfffffff0 }, 7484e4f10f6SDavid Woodhouse { PHY_ID_BCM50610M, 0xfffffff0 }, 7494e4f10f6SDavid Woodhouse { PHY_ID_BCM57780, 0xfffffff0 }, 7504e4f10f6SDavid Woodhouse { PHY_ID_BCMAC131, 0xfffffff0 }, 7517a938f80SDmitry Baryshkov { PHY_ID_BCM5241, 0xfffffff0 }, 75228dc4c8fSFlorian Fainelli { PHY_ID_BCM5395, 0xfffffff0 }, 753*23b83922SBhadram Varka { PHY_ID_BCM89610, 0xfffffff0 }, 7544e4f10f6SDavid Woodhouse { } 7554e4f10f6SDavid Woodhouse }; 7564e4f10f6SDavid Woodhouse 7574e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, broadcom_tbl); 758