xref: /openbmc/linux/drivers/net/phy/bcm7xxx.c (revision 4cef191d)
1b560a58cSFlorian Fainelli /*
2b560a58cSFlorian Fainelli  * Broadcom BCM7xxx internal transceivers support.
3b560a58cSFlorian Fainelli  *
4b560a58cSFlorian Fainelli  * Copyright (C) 2014, Broadcom Corporation
5b560a58cSFlorian Fainelli  *
6b560a58cSFlorian Fainelli  * This program is free software; you can redistribute it and/or
7b560a58cSFlorian Fainelli  * modify it under the terms of the GNU General Public License
8b560a58cSFlorian Fainelli  * as published by the Free Software Foundation; either version
9b560a58cSFlorian Fainelli  * 2 of the License, or (at your option) any later version.
10b560a58cSFlorian Fainelli  */
11b560a58cSFlorian Fainelli 
12b560a58cSFlorian Fainelli #include <linux/module.h>
13b560a58cSFlorian Fainelli #include <linux/phy.h>
14b560a58cSFlorian Fainelli #include <linux/delay.h>
15a1cba561SArun Parameswaran #include "bcm-phy-lib.h"
16b560a58cSFlorian Fainelli #include <linux/bitops.h>
17b560a58cSFlorian Fainelli #include <linux/brcmphy.h>
18b8f9a029SFlorian Fainelli #include <linux/mdio.h>
19b560a58cSFlorian Fainelli 
20b560a58cSFlorian Fainelli /* Broadcom BCM7xxx internal PHY registers */
21b560a58cSFlorian Fainelli 
22b560a58cSFlorian Fainelli /* 40nm only register definitions */
23b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_AUX_CTL	0x10
24b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_FALSE_CAR	0x13
25b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_DISC		0x14
26b560a58cSFlorian Fainelli #define MII_BCM7XXX_AUX_MODE		0x1d
273ccc3055SFlorian Fainelli #define  MII_BCM7XXX_64CLK_MDIO		BIT(12)
28b560a58cSFlorian Fainelli #define MII_BCM7XXX_TEST		0x1f
29b560a58cSFlorian Fainelli #define  MII_BCM7XXX_SHD_MODE_2		BIT(2)
30b560a58cSFlorian Fainelli 
31a3622f2cSFlorian Fainelli /* 28nm only register definitions */
32a3622f2cSFlorian Fainelli #define MISC_ADDR(base, channel)	base, channel
33a3622f2cSFlorian Fainelli 
34a3622f2cSFlorian Fainelli #define DSP_TAP10			MISC_ADDR(0x0a, 0)
35a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_1			MISC_ADDR(0x32, 1)
36a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_2			MISC_ADDR(0x32, 2)
37a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_4			MISC_ADDR(0x33, 0)
38a3622f2cSFlorian Fainelli 
39a3622f2cSFlorian Fainelli #define AFE_RXCONFIG_0			MISC_ADDR(0x38, 0)
40a3622f2cSFlorian Fainelli #define AFE_RXCONFIG_1			MISC_ADDR(0x38, 1)
41a490631fSFlorian Fainelli #define AFE_RXCONFIG_2			MISC_ADDR(0x38, 2)
42a3622f2cSFlorian Fainelli #define AFE_RX_LP_COUNTER		MISC_ADDR(0x38, 3)
43a3622f2cSFlorian Fainelli #define AFE_TX_CONFIG			MISC_ADDR(0x39, 0)
44a490631fSFlorian Fainelli #define AFE_VDCA_ICTRL_0		MISC_ADDR(0x39, 1)
45a490631fSFlorian Fainelli #define AFE_VDAC_OTHERS_0		MISC_ADDR(0x39, 3)
46a3622f2cSFlorian Fainelli #define AFE_HPF_TRIM_OTHERS		MISC_ADDR(0x3a, 0)
47a3622f2cSFlorian Fainelli 
489c41f2baSFlorian Fainelli static void r_rc_cal_reset(struct phy_device *phydev)
499c41f2baSFlorian Fainelli {
509c41f2baSFlorian Fainelli 	/* Reset R_CAL/RC_CAL Engine */
51a1cba561SArun Parameswaran 	bcm_phy_write_exp(phydev, 0x00b0, 0x0010);
529c41f2baSFlorian Fainelli 
539c41f2baSFlorian Fainelli 	/* Disable Reset R_AL/RC_CAL Engine */
54a1cba561SArun Parameswaran 	bcm_phy_write_exp(phydev, 0x00b0, 0x0000);
559c41f2baSFlorian Fainelli }
569c41f2baSFlorian Fainelli 
572a9df742SFlorian Fainelli static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev)
58b560a58cSFlorian Fainelli {
59b560a58cSFlorian Fainelli 	/* Increase VCO range to prevent unlocking problem of PLL at low
60b560a58cSFlorian Fainelli 	 * temp
61b560a58cSFlorian Fainelli 	 */
62a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
63b560a58cSFlorian Fainelli 
64b560a58cSFlorian Fainelli 	/* Change Ki to 011 */
65a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
66b560a58cSFlorian Fainelli 
67b560a58cSFlorian Fainelli 	/* Disable loading of TVCO buffer to bandgap, set bandgap trim
68b560a58cSFlorian Fainelli 	 * to 111
69b560a58cSFlorian Fainelli 	 */
70a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
71b560a58cSFlorian Fainelli 
72b560a58cSFlorian Fainelli 	/* Adjust bias current trim by -3 */
73a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b);
74b560a58cSFlorian Fainelli 
75b560a58cSFlorian Fainelli 	/* Switch to CORE_BASE1E */
769200c27aSArun Parameswaran 	phy_write(phydev, MII_BRCM_CORE_BASE1E, 0xd);
77b560a58cSFlorian Fainelli 
789c41f2baSFlorian Fainelli 	r_rc_cal_reset(phydev);
79b560a58cSFlorian Fainelli 
809918542eSFlorian Fainelli 	/* write AFE_RXCONFIG_0 */
81a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
829918542eSFlorian Fainelli 
839918542eSFlorian Fainelli 	/* write AFE_RXCONFIG_1 */
84a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
859918542eSFlorian Fainelli 
869918542eSFlorian Fainelli 	/* write AFE_RX_LP_COUNTER */
87a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
889918542eSFlorian Fainelli 
899918542eSFlorian Fainelli 	/* write AFE_HPF_TRIM_OTHERS */
90a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
919918542eSFlorian Fainelli 
929918542eSFlorian Fainelli 	/* write AFTE_TX_CONFIG */
93a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
949918542eSFlorian Fainelli 
95b560a58cSFlorian Fainelli 	return 0;
96b560a58cSFlorian Fainelli }
97b560a58cSFlorian Fainelli 
98a490631fSFlorian Fainelli static int bcm7xxx_28nm_d0_afe_config_init(struct phy_device *phydev)
99a490631fSFlorian Fainelli {
100a490631fSFlorian Fainelli 	/* AFE_RXCONFIG_0 */
101a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb15);
102a490631fSFlorian Fainelli 
103a490631fSFlorian Fainelli 	/* AFE_RXCONFIG_1 */
104a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
105a490631fSFlorian Fainelli 
106a490631fSFlorian Fainelli 	/* AFE_RXCONFIG_2, set rCal offset for HT=0 code and LT=-2 code */
107a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0x2003);
108a490631fSFlorian Fainelli 
109a490631fSFlorian Fainelli 	/* AFE_RX_LP_COUNTER, set RX bandwidth to maximum */
110a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
111a490631fSFlorian Fainelli 
1126da8253bSFlorian Fainelli 	/* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
113a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
114a490631fSFlorian Fainelli 
115a490631fSFlorian Fainelli 	/* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
116a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
117a490631fSFlorian Fainelli 
118a490631fSFlorian Fainelli 	/* AFE_VDAC_OTHERS_0, set 1000BT Cidac=010 for all ports */
119a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_VDAC_OTHERS_0, 0xa020);
120a490631fSFlorian Fainelli 
121a490631fSFlorian Fainelli 	/* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
122a490631fSFlorian Fainelli 	 * offset for HT=0 code
123a490631fSFlorian Fainelli 	 */
124a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
125a490631fSFlorian Fainelli 
126a490631fSFlorian Fainelli 	/* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
1279200c27aSArun Parameswaran 	phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010);
128a490631fSFlorian Fainelli 
129a490631fSFlorian Fainelli 	/* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
130a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
131a490631fSFlorian Fainelli 
132a490631fSFlorian Fainelli 	/* Reset R_CAL/RC_CAL engine */
133a490631fSFlorian Fainelli 	r_rc_cal_reset(phydev);
134a490631fSFlorian Fainelli 
135a490631fSFlorian Fainelli 	return 0;
136a490631fSFlorian Fainelli }
137a490631fSFlorian Fainelli 
1380c2fdc25SFlorian Fainelli static int bcm7xxx_28nm_e0_plus_afe_config_init(struct phy_device *phydev)
1390c2fdc25SFlorian Fainelli {
1400c2fdc25SFlorian Fainelli 	/* AFE_RXCONFIG_1, provide more margin for INL/DNL measurement */
141a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9b2f);
1420c2fdc25SFlorian Fainelli 
1436da8253bSFlorian Fainelli 	/* AFE_TX_CONFIG, set 100BT Cfeed=011 to improve rise/fall time */
144a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x431);
1456da8253bSFlorian Fainelli 
1460c2fdc25SFlorian Fainelli 	/* AFE_VDCA_ICTRL_0, set Iq=1101 instead of 0111 for AB symmetry */
147a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_VDCA_ICTRL_0, 0xa7da);
1480c2fdc25SFlorian Fainelli 
1490c2fdc25SFlorian Fainelli 	/* AFE_HPF_TRIM_OTHERS, set 100Tx/10BT to -4.5% swing and set rCal
1500c2fdc25SFlorian Fainelli 	 * offset for HT=0 code
1510c2fdc25SFlorian Fainelli 	 */
152a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x00e3);
1530c2fdc25SFlorian Fainelli 
1540c2fdc25SFlorian Fainelli 	/* CORE_BASE1E, force trim to overwrite and set I_ext trim to 0000 */
1559200c27aSArun Parameswaran 	phy_write(phydev, MII_BRCM_CORE_BASE1E, 0x0010);
1560c2fdc25SFlorian Fainelli 
1570c2fdc25SFlorian Fainelli 	/* DSP_TAP10, adjust bias current trim (+0% swing, +0 tick) */
158a1cba561SArun Parameswaran 	bcm_phy_write_misc(phydev, DSP_TAP10, 0x011b);
1590c2fdc25SFlorian Fainelli 
1600c2fdc25SFlorian Fainelli 	/* Reset R_CAL/RC_CAL engine */
1610c2fdc25SFlorian Fainelli 	r_rc_cal_reset(phydev);
1620c2fdc25SFlorian Fainelli 
1630c2fdc25SFlorian Fainelli 	return 0;
1640c2fdc25SFlorian Fainelli }
1650c2fdc25SFlorian Fainelli 
166b560a58cSFlorian Fainelli static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
167b560a58cSFlorian Fainelli {
168d8ebfed3SFlorian Fainelli 	u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
169d8ebfed3SFlorian Fainelli 	u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags);
170d8ebfed3SFlorian Fainelli 	int ret = 0;
171b560a58cSFlorian Fainelli 
1726ec259c1SFlorian Fainelli 	pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n",
17384eff6d1SAndrew Lunn 		     phydev_name(phydev), phydev->drv->name, rev, patch);
174d8ebfed3SFlorian Fainelli 
1758e346e15SFlorian Fainelli 	/* Dummy read to a register to workaround an issue upon reset where the
1768e346e15SFlorian Fainelli 	 * internal inverter may not allow the first MDIO transaction to pass
1778e346e15SFlorian Fainelli 	 * the MDIO management controller and make us return 0xffff for such
1788e346e15SFlorian Fainelli 	 * reads.
1798e346e15SFlorian Fainelli 	 */
1808e346e15SFlorian Fainelli 	phy_read(phydev, MII_BMSR);
1818e346e15SFlorian Fainelli 
182d8ebfed3SFlorian Fainelli 	switch (rev) {
183d8ebfed3SFlorian Fainelli 	case 0xb0:
1842a9df742SFlorian Fainelli 		ret = bcm7xxx_28nm_b0_afe_config_init(phydev);
185d8ebfed3SFlorian Fainelli 		break;
186a490631fSFlorian Fainelli 	case 0xd0:
187a490631fSFlorian Fainelli 		ret = bcm7xxx_28nm_d0_afe_config_init(phydev);
188a490631fSFlorian Fainelli 		break;
1890c2fdc25SFlorian Fainelli 	case 0xe0:
1900c2fdc25SFlorian Fainelli 	case 0xf0:
19160efff0cSFlorian Fainelli 	/* Rev G0 introduces a roll over */
19260efff0cSFlorian Fainelli 	case 0x10:
1930c2fdc25SFlorian Fainelli 		ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev);
1940c2fdc25SFlorian Fainelli 		break;
195d8ebfed3SFlorian Fainelli 	default:
196d8ebfed3SFlorian Fainelli 		break;
197d8ebfed3SFlorian Fainelli 	}
198d8ebfed3SFlorian Fainelli 
1999df54ddaSFlorian Fainelli 	if (ret)
2009df54ddaSFlorian Fainelli 		return ret;
2019df54ddaSFlorian Fainelli 
202a1cba561SArun Parameswaran 	ret = bcm_phy_enable_eee(phydev);
203b8f9a029SFlorian Fainelli 	if (ret)
204b8f9a029SFlorian Fainelli 		return ret;
205b8f9a029SFlorian Fainelli 
206a1cba561SArun Parameswaran 	return bcm_phy_enable_apd(phydev, true);
207b560a58cSFlorian Fainelli }
208b560a58cSFlorian Fainelli 
2094fd14e0bSFlorian Fainelli static int bcm7xxx_28nm_resume(struct phy_device *phydev)
2104fd14e0bSFlorian Fainelli {
2114fd14e0bSFlorian Fainelli 	int ret;
2124fd14e0bSFlorian Fainelli 
2134fd14e0bSFlorian Fainelli 	/* Re-apply workarounds coming out suspend/resume */
2144fd14e0bSFlorian Fainelli 	ret = bcm7xxx_28nm_config_init(phydev);
2154fd14e0bSFlorian Fainelli 	if (ret)
2164fd14e0bSFlorian Fainelli 		return ret;
2174fd14e0bSFlorian Fainelli 
2184fd14e0bSFlorian Fainelli 	/* 28nm Gigabit PHYs come out of reset without any half-duplex
2194fd14e0bSFlorian Fainelli 	 * or "hub" compliant advertised mode, fix that. This does not
2204fd14e0bSFlorian Fainelli 	 * cause any problems with the PHY library since genphy_config_aneg()
2214fd14e0bSFlorian Fainelli 	 * gracefully handles auto-negotiated and forced modes.
2224fd14e0bSFlorian Fainelli 	 */
2234fd14e0bSFlorian Fainelli 	return genphy_config_aneg(phydev);
2244fd14e0bSFlorian Fainelli }
2254fd14e0bSFlorian Fainelli 
226b560a58cSFlorian Fainelli static int phy_set_clr_bits(struct phy_device *dev, int location,
227b560a58cSFlorian Fainelli 					int set_mask, int clr_mask)
228b560a58cSFlorian Fainelli {
229b560a58cSFlorian Fainelli 	int v, ret;
230b560a58cSFlorian Fainelli 
231b560a58cSFlorian Fainelli 	v = phy_read(dev, location);
232b560a58cSFlorian Fainelli 	if (v < 0)
233b560a58cSFlorian Fainelli 		return v;
234b560a58cSFlorian Fainelli 
235b560a58cSFlorian Fainelli 	v &= ~clr_mask;
236b560a58cSFlorian Fainelli 	v |= set_mask;
237b560a58cSFlorian Fainelli 
238b560a58cSFlorian Fainelli 	ret = phy_write(dev, location, v);
239b560a58cSFlorian Fainelli 	if (ret < 0)
240b560a58cSFlorian Fainelli 		return ret;
241b560a58cSFlorian Fainelli 
242b560a58cSFlorian Fainelli 	return v;
243b560a58cSFlorian Fainelli }
244b560a58cSFlorian Fainelli 
245b560a58cSFlorian Fainelli static int bcm7xxx_config_init(struct phy_device *phydev)
246b560a58cSFlorian Fainelli {
247b560a58cSFlorian Fainelli 	int ret;
248b560a58cSFlorian Fainelli 
249b560a58cSFlorian Fainelli 	/* Enable 64 clock MDIO */
2503ccc3055SFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XXX_64CLK_MDIO);
251b560a58cSFlorian Fainelli 	phy_read(phydev, MII_BCM7XXX_AUX_MODE);
252b560a58cSFlorian Fainelli 
253b560a58cSFlorian Fainelli 	/* set shadow mode 2 */
254b560a58cSFlorian Fainelli 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
255b560a58cSFlorian Fainelli 			MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2);
256b560a58cSFlorian Fainelli 	if (ret < 0)
257b560a58cSFlorian Fainelli 		return ret;
258b560a58cSFlorian Fainelli 
259b560a58cSFlorian Fainelli 	/* set iddq_clkbias */
260b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00);
261b560a58cSFlorian Fainelli 	udelay(10);
262b560a58cSFlorian Fainelli 
263b560a58cSFlorian Fainelli 	/* reset iddq_clkbias */
264b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00);
265b560a58cSFlorian Fainelli 
266b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
267b560a58cSFlorian Fainelli 
268b560a58cSFlorian Fainelli 	/* reset shadow mode 2 */
26950d89980SFlorian Fainelli 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2);
270b560a58cSFlorian Fainelli 	if (ret < 0)
271b560a58cSFlorian Fainelli 		return ret;
272b560a58cSFlorian Fainelli 
273b560a58cSFlorian Fainelli 	return 0;
274b560a58cSFlorian Fainelli }
275b560a58cSFlorian Fainelli 
276b560a58cSFlorian Fainelli /* Workaround for putting the PHY in IDDQ mode, required
27782c084f5SFlorian Fainelli  * for all BCM7XXX 40nm and 65nm PHYs
278b560a58cSFlorian Fainelli  */
279b560a58cSFlorian Fainelli static int bcm7xxx_suspend(struct phy_device *phydev)
280b560a58cSFlorian Fainelli {
281b560a58cSFlorian Fainelli 	int ret;
282b560a58cSFlorian Fainelli 	const struct bcm7xxx_regs {
283b560a58cSFlorian Fainelli 		int reg;
284b560a58cSFlorian Fainelli 		u16 value;
285b560a58cSFlorian Fainelli 	} bcm7xxx_suspend_cfg[] = {
286b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_TEST, 0x008b },
287b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 },
288b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_100TX_DISC, 0x7000 },
289b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_TEST, 0x000f },
290b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 },
291b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_TEST, 0x000b },
292b560a58cSFlorian Fainelli 	};
293b560a58cSFlorian Fainelli 	unsigned int i;
294b560a58cSFlorian Fainelli 
295b560a58cSFlorian Fainelli 	for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) {
296b560a58cSFlorian Fainelli 		ret = phy_write(phydev,
297b560a58cSFlorian Fainelli 				bcm7xxx_suspend_cfg[i].reg,
298b560a58cSFlorian Fainelli 				bcm7xxx_suspend_cfg[i].value);
299b560a58cSFlorian Fainelli 		if (ret)
300b560a58cSFlorian Fainelli 			return ret;
301b560a58cSFlorian Fainelli 	}
302b560a58cSFlorian Fainelli 
303b560a58cSFlorian Fainelli 	return 0;
304b560a58cSFlorian Fainelli }
305b560a58cSFlorian Fainelli 
306153df3c7SFlorian Fainelli #define BCM7XXX_28NM_GPHY(_oui, _name)					\
307153df3c7SFlorian Fainelli {									\
308153df3c7SFlorian Fainelli 	.phy_id		= (_oui),					\
309153df3c7SFlorian Fainelli 	.phy_id_mask	= 0xfffffff0,					\
310153df3c7SFlorian Fainelli 	.name		= _name,					\
311153df3c7SFlorian Fainelli 	.features	= PHY_GBIT_FEATURES |				\
312153df3c7SFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,	\
313153df3c7SFlorian Fainelli 	.flags		= PHY_IS_INTERNAL,				\
3142a9df742SFlorian Fainelli 	.config_init	= bcm7xxx_28nm_config_init,			\
315153df3c7SFlorian Fainelli 	.config_aneg	= genphy_config_aneg,				\
316153df3c7SFlorian Fainelli 	.read_status	= genphy_read_status,				\
317153df3c7SFlorian Fainelli 	.resume		= bcm7xxx_28nm_resume,				\
318153df3c7SFlorian Fainelli }
319153df3c7SFlorian Fainelli 
3203125c081SFlorian Fainelli #define BCM7XXX_40NM_EPHY(_oui, _name)					\
3213125c081SFlorian Fainelli {									\
3223125c081SFlorian Fainelli 	.phy_id         = (_oui),					\
3233125c081SFlorian Fainelli 	.phy_id_mask    = 0xfffffff0,					\
3243125c081SFlorian Fainelli 	.name           = _name,					\
3253125c081SFlorian Fainelli 	.features       = PHY_BASIC_FEATURES |				\
3263125c081SFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,	\
3273125c081SFlorian Fainelli 	.flags          = PHY_IS_INTERNAL,				\
3283125c081SFlorian Fainelli 	.config_init    = bcm7xxx_config_init,				\
3293125c081SFlorian Fainelli 	.config_aneg    = genphy_config_aneg,				\
3303125c081SFlorian Fainelli 	.read_status    = genphy_read_status,				\
3313125c081SFlorian Fainelli 	.suspend        = bcm7xxx_suspend,				\
3323125c081SFlorian Fainelli 	.resume         = bcm7xxx_config_init,				\
3333125c081SFlorian Fainelli }
3343125c081SFlorian Fainelli 
335b560a58cSFlorian Fainelli static struct phy_driver bcm7xxx_driver[] = {
336430ad68fSFlorian Fainelli 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
337430ad68fSFlorian Fainelli 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
338153df3c7SFlorian Fainelli 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
339153df3c7SFlorian Fainelli 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
34059e33c2bSFlorian Fainelli 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7439_2, "Broadcom BCM7439 (2)"),
341153df3c7SFlorian Fainelli 	BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"),
3424cef191dSJaedon Shin 	BCM7XXX_40NM_EPHY(PHY_ID_BCM7346, "Broadcom BCM7346"),
3434cef191dSJaedon Shin 	BCM7XXX_40NM_EPHY(PHY_ID_BCM7362, "Broadcom BCM7362"),
3443125c081SFlorian Fainelli 	BCM7XXX_40NM_EPHY(PHY_ID_BCM7425, "Broadcom BCM7425"),
3453125c081SFlorian Fainelli 	BCM7XXX_40NM_EPHY(PHY_ID_BCM7429, "Broadcom BCM7429"),
3463125c081SFlorian Fainelli 	BCM7XXX_40NM_EPHY(PHY_ID_BCM7435, "Broadcom BCM7435"),
347b6333531SDavid S. Miller };
348b560a58cSFlorian Fainelli 
349b560a58cSFlorian Fainelli static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
350430ad68fSFlorian Fainelli 	{ PHY_ID_BCM7250, 0xfffffff0, },
351430ad68fSFlorian Fainelli 	{ PHY_ID_BCM7364, 0xfffffff0, },
352b560a58cSFlorian Fainelli 	{ PHY_ID_BCM7366, 0xfffffff0, },
3534cef191dSJaedon Shin 	{ PHY_ID_BCM7346, 0xfffffff0, },
3544cef191dSJaedon Shin 	{ PHY_ID_BCM7362, 0xfffffff0, },
355d068b02cSPetri Gynther 	{ PHY_ID_BCM7425, 0xfffffff0, },
356d068b02cSPetri Gynther 	{ PHY_ID_BCM7429, 0xfffffff0, },
357b560a58cSFlorian Fainelli 	{ PHY_ID_BCM7439, 0xfffffff0, },
3589458ceabSFlorian Fainelli 	{ PHY_ID_BCM7435, 0xfffffff0, },
359b560a58cSFlorian Fainelli 	{ PHY_ID_BCM7445, 0xfffffff0, },
360b560a58cSFlorian Fainelli 	{ }
361b560a58cSFlorian Fainelli };
362b560a58cSFlorian Fainelli 
36350fd7150SJohan Hovold module_phy_driver(bcm7xxx_driver);
364b560a58cSFlorian Fainelli 
365b560a58cSFlorian Fainelli MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl);
366b560a58cSFlorian Fainelli 
367b560a58cSFlorian Fainelli MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver");
368b560a58cSFlorian Fainelli MODULE_LICENSE("GPL");
369b560a58cSFlorian Fainelli MODULE_AUTHOR("Broadcom Corporation");
370