xref: /linux/drivers/net/phy/broadcom.c (revision 23b8392201e0681b76630c4cea68e1a2e1821ec6)
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