xref: /openbmc/linux/drivers/net/phy/bcm7xxx.c (revision 9df54dda)
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>
15b560a58cSFlorian Fainelli #include <linux/bitops.h>
16b560a58cSFlorian Fainelli #include <linux/brcmphy.h>
17b560a58cSFlorian Fainelli 
18b560a58cSFlorian Fainelli /* Broadcom BCM7xxx internal PHY registers */
19b560a58cSFlorian Fainelli #define MII_BCM7XXX_CHANNEL_WIDTH	0x2000
20b560a58cSFlorian Fainelli 
21b560a58cSFlorian Fainelli /* 40nm only register definitions */
22b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_AUX_CTL	0x10
23b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_FALSE_CAR	0x13
24b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_DISC		0x14
25b560a58cSFlorian Fainelli #define MII_BCM7XXX_AUX_MODE		0x1d
26b560a58cSFlorian Fainelli #define  MII_BCM7XX_64CLK_MDIO		BIT(12)
27b560a58cSFlorian Fainelli #define MII_BCM7XXX_CORE_BASE1E		0x1e
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)
41a3622f2cSFlorian Fainelli #define AFE_RX_LP_COUNTER		MISC_ADDR(0x38, 3)
42a3622f2cSFlorian Fainelli #define AFE_TX_CONFIG			MISC_ADDR(0x39, 0)
43a3622f2cSFlorian Fainelli #define AFE_HPF_TRIM_OTHERS		MISC_ADDR(0x3a, 0)
44a3622f2cSFlorian Fainelli 
45a3622f2cSFlorian Fainelli #define CORE_EXPB0			0xb0
46a3622f2cSFlorian Fainelli 
47b560a58cSFlorian Fainelli static int bcm7445_config_init(struct phy_device *phydev)
48b560a58cSFlorian Fainelli {
49b560a58cSFlorian Fainelli 	int ret;
50b560a58cSFlorian Fainelli 	const struct bcm7445_regs {
51b560a58cSFlorian Fainelli 		int reg;
52b560a58cSFlorian Fainelli 		u16 value;
53b560a58cSFlorian Fainelli 	} bcm7445_regs_cfg[] = {
54b560a58cSFlorian Fainelli 		/* increases ADC latency by 24ns */
55b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_SEL, 0x0038 },
56b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_DATA, 0xAB95 },
57b560a58cSFlorian Fainelli 		/* increases internal 1V LDO voltage by 5% */
58b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_SEL, 0x2038 },
59b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_DATA, 0xBB22 },
60b560a58cSFlorian Fainelli 		/* reduce RX low pass filter corner frequency */
61b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_SEL, 0x6038 },
62b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_DATA, 0xFFC5 },
63b560a58cSFlorian Fainelli 		/* reduce RX high pass filter corner frequency */
64b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_SEL, 0x003a },
65b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_DATA, 0x2002 },
66b560a58cSFlorian Fainelli 	};
67b560a58cSFlorian Fainelli 	unsigned int i;
68b560a58cSFlorian Fainelli 
69b560a58cSFlorian Fainelli 	for (i = 0; i < ARRAY_SIZE(bcm7445_regs_cfg); i++) {
70b560a58cSFlorian Fainelli 		ret = phy_write(phydev,
71b560a58cSFlorian Fainelli 				bcm7445_regs_cfg[i].reg,
72b560a58cSFlorian Fainelli 				bcm7445_regs_cfg[i].value);
73b560a58cSFlorian Fainelli 		if (ret)
74b560a58cSFlorian Fainelli 			return ret;
75b560a58cSFlorian Fainelli 	}
76b560a58cSFlorian Fainelli 
77b560a58cSFlorian Fainelli 	return 0;
78b560a58cSFlorian Fainelli }
79b560a58cSFlorian Fainelli 
80b560a58cSFlorian Fainelli static void phy_write_exp(struct phy_device *phydev,
81b560a58cSFlorian Fainelli 					u16 reg, u16 value)
82b560a58cSFlorian Fainelli {
83b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER | reg);
84b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
85b560a58cSFlorian Fainelli }
86b560a58cSFlorian Fainelli 
87b560a58cSFlorian Fainelli static void phy_write_misc(struct phy_device *phydev,
88b560a58cSFlorian Fainelli 					u16 reg, u16 chl, u16 value)
89b560a58cSFlorian Fainelli {
90b560a58cSFlorian Fainelli 	int tmp;
91b560a58cSFlorian Fainelli 
92b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
93b560a58cSFlorian Fainelli 
94b560a58cSFlorian Fainelli 	tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
95b560a58cSFlorian Fainelli 	tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
96b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
97b560a58cSFlorian Fainelli 
98b560a58cSFlorian Fainelli 	tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg;
99b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp);
100b560a58cSFlorian Fainelli 
101b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
102b560a58cSFlorian Fainelli }
103b560a58cSFlorian Fainelli 
104b560a58cSFlorian Fainelli static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev)
105b560a58cSFlorian Fainelli {
106b560a58cSFlorian Fainelli 	/* Increase VCO range to prevent unlocking problem of PLL at low
107b560a58cSFlorian Fainelli 	 * temp
108b560a58cSFlorian Fainelli 	 */
109a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
110b560a58cSFlorian Fainelli 
111b560a58cSFlorian Fainelli 	/* Change Ki to 011 */
112a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
113b560a58cSFlorian Fainelli 
114b560a58cSFlorian Fainelli 	/* Disable loading of TVCO buffer to bandgap, set bandgap trim
115b560a58cSFlorian Fainelli 	 * to 111
116b560a58cSFlorian Fainelli 	 */
117a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
118b560a58cSFlorian Fainelli 
119b560a58cSFlorian Fainelli 	/* Adjust bias current trim by -3 */
120a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, DSP_TAP10, 0x690b);
121b560a58cSFlorian Fainelli 
122b560a58cSFlorian Fainelli 	/* Switch to CORE_BASE1E */
123b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd);
124b560a58cSFlorian Fainelli 
125b560a58cSFlorian Fainelli 	/* Reset R_CAL/RC_CAL Engine */
126a3622f2cSFlorian Fainelli 	phy_write_exp(phydev, CORE_EXPB0, 0x0010);
127b560a58cSFlorian Fainelli 
128b560a58cSFlorian Fainelli 	/* Disable Reset R_CAL/RC_CAL Engine */
129a3622f2cSFlorian Fainelli 	phy_write_exp(phydev, CORE_EXPB0, 0x0000);
130b560a58cSFlorian Fainelli 
1319918542eSFlorian Fainelli 	/* write AFE_RXCONFIG_0 */
1329918542eSFlorian Fainelli 	phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
1339918542eSFlorian Fainelli 
1349918542eSFlorian Fainelli 	/* write AFE_RXCONFIG_1 */
1359918542eSFlorian Fainelli 	phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
1369918542eSFlorian Fainelli 
1379918542eSFlorian Fainelli 	/* write AFE_RX_LP_COUNTER */
138a62ea5a7SFlorian Fainelli 	phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
1399918542eSFlorian Fainelli 
1409918542eSFlorian Fainelli 	/* write AFE_HPF_TRIM_OTHERS */
1419918542eSFlorian Fainelli 	phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
1429918542eSFlorian Fainelli 
1439918542eSFlorian Fainelli 	/* write AFTE_TX_CONFIG */
1449918542eSFlorian Fainelli 	phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
1459918542eSFlorian Fainelli 
146b560a58cSFlorian Fainelli 	return 0;
147b560a58cSFlorian Fainelli }
148b560a58cSFlorian Fainelli 
1499df54ddaSFlorian Fainelli static int bcm7xxx_apd_enable(struct phy_device *phydev)
1509df54ddaSFlorian Fainelli {
1519df54ddaSFlorian Fainelli 	int val;
1529df54ddaSFlorian Fainelli 
1539df54ddaSFlorian Fainelli 	/* Enable powering down of the DLL during auto-power down */
1549df54ddaSFlorian Fainelli 	val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
1559df54ddaSFlorian Fainelli 	if (val < 0)
1569df54ddaSFlorian Fainelli 		return val;
1579df54ddaSFlorian Fainelli 
1589df54ddaSFlorian Fainelli 	val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
1599df54ddaSFlorian Fainelli 	bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
1609df54ddaSFlorian Fainelli 
1619df54ddaSFlorian Fainelli 	/* Enable auto-power down */
1629df54ddaSFlorian Fainelli 	val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
1639df54ddaSFlorian Fainelli 	if (val < 0)
1649df54ddaSFlorian Fainelli 		return val;
1659df54ddaSFlorian Fainelli 
1669df54ddaSFlorian Fainelli 	val |= BCM54XX_SHD_APD_EN;
1679df54ddaSFlorian Fainelli 	return bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
1689df54ddaSFlorian Fainelli }
1699df54ddaSFlorian Fainelli 
170b560a58cSFlorian Fainelli static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
171b560a58cSFlorian Fainelli {
172b560a58cSFlorian Fainelli 	int ret;
173b560a58cSFlorian Fainelli 
174b560a58cSFlorian Fainelli 	ret = bcm7445_config_init(phydev);
175b560a58cSFlorian Fainelli 	if (ret)
176b560a58cSFlorian Fainelli 		return ret;
177b560a58cSFlorian Fainelli 
1789df54ddaSFlorian Fainelli 	ret = bcm7xxx_28nm_afe_config_init(phydev);
1799df54ddaSFlorian Fainelli 	if (ret)
1809df54ddaSFlorian Fainelli 		return ret;
1819df54ddaSFlorian Fainelli 
1829df54ddaSFlorian Fainelli 	return bcm7xxx_apd_enable(phydev);
183b560a58cSFlorian Fainelli }
184b560a58cSFlorian Fainelli 
1854fd14e0bSFlorian Fainelli static int bcm7xxx_28nm_resume(struct phy_device *phydev)
1864fd14e0bSFlorian Fainelli {
1874fd14e0bSFlorian Fainelli 	int ret;
1884fd14e0bSFlorian Fainelli 
1894fd14e0bSFlorian Fainelli 	/* Re-apply workarounds coming out suspend/resume */
1904fd14e0bSFlorian Fainelli 	ret = bcm7xxx_28nm_config_init(phydev);
1914fd14e0bSFlorian Fainelli 	if (ret)
1924fd14e0bSFlorian Fainelli 		return ret;
1934fd14e0bSFlorian Fainelli 
1944fd14e0bSFlorian Fainelli 	/* 28nm Gigabit PHYs come out of reset without any half-duplex
1954fd14e0bSFlorian Fainelli 	 * or "hub" compliant advertised mode, fix that. This does not
1964fd14e0bSFlorian Fainelli 	 * cause any problems with the PHY library since genphy_config_aneg()
1974fd14e0bSFlorian Fainelli 	 * gracefully handles auto-negotiated and forced modes.
1984fd14e0bSFlorian Fainelli 	 */
1994fd14e0bSFlorian Fainelli 	return genphy_config_aneg(phydev);
2004fd14e0bSFlorian Fainelli }
2014fd14e0bSFlorian Fainelli 
202b560a58cSFlorian Fainelli static int phy_set_clr_bits(struct phy_device *dev, int location,
203b560a58cSFlorian Fainelli 					int set_mask, int clr_mask)
204b560a58cSFlorian Fainelli {
205b560a58cSFlorian Fainelli 	int v, ret;
206b560a58cSFlorian Fainelli 
207b560a58cSFlorian Fainelli 	v = phy_read(dev, location);
208b560a58cSFlorian Fainelli 	if (v < 0)
209b560a58cSFlorian Fainelli 		return v;
210b560a58cSFlorian Fainelli 
211b560a58cSFlorian Fainelli 	v &= ~clr_mask;
212b560a58cSFlorian Fainelli 	v |= set_mask;
213b560a58cSFlorian Fainelli 
214b560a58cSFlorian Fainelli 	ret = phy_write(dev, location, v);
215b560a58cSFlorian Fainelli 	if (ret < 0)
216b560a58cSFlorian Fainelli 		return ret;
217b560a58cSFlorian Fainelli 
218b560a58cSFlorian Fainelli 	return v;
219b560a58cSFlorian Fainelli }
220b560a58cSFlorian Fainelli 
221b560a58cSFlorian Fainelli static int bcm7xxx_config_init(struct phy_device *phydev)
222b560a58cSFlorian Fainelli {
223b560a58cSFlorian Fainelli 	int ret;
224b560a58cSFlorian Fainelli 
225b560a58cSFlorian Fainelli 	/* Enable 64 clock MDIO */
226b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO);
227b560a58cSFlorian Fainelli 	phy_read(phydev, MII_BCM7XXX_AUX_MODE);
228b560a58cSFlorian Fainelli 
229b560a58cSFlorian Fainelli 	/* Workaround only required for 100Mbits/sec */
230b560a58cSFlorian Fainelli 	if (!(phydev->dev_flags & PHY_BRCM_100MBPS_WAR))
231b560a58cSFlorian Fainelli 		return 0;
232b560a58cSFlorian Fainelli 
233b560a58cSFlorian Fainelli 	/* set shadow mode 2 */
234b560a58cSFlorian Fainelli 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
235b560a58cSFlorian Fainelli 			MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2);
236b560a58cSFlorian Fainelli 	if (ret < 0)
237b560a58cSFlorian Fainelli 		return ret;
238b560a58cSFlorian Fainelli 
239b560a58cSFlorian Fainelli 	/* set iddq_clkbias */
240b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00);
241b560a58cSFlorian Fainelli 	udelay(10);
242b560a58cSFlorian Fainelli 
243b560a58cSFlorian Fainelli 	/* reset iddq_clkbias */
244b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00);
245b560a58cSFlorian Fainelli 
246b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
247b560a58cSFlorian Fainelli 
248b560a58cSFlorian Fainelli 	/* reset shadow mode 2 */
249b560a58cSFlorian Fainelli 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0);
250b560a58cSFlorian Fainelli 	if (ret < 0)
251b560a58cSFlorian Fainelli 		return ret;
252b560a58cSFlorian Fainelli 
253b560a58cSFlorian Fainelli 	return 0;
254b560a58cSFlorian Fainelli }
255b560a58cSFlorian Fainelli 
256b560a58cSFlorian Fainelli /* Workaround for putting the PHY in IDDQ mode, required
25782c084f5SFlorian Fainelli  * for all BCM7XXX 40nm and 65nm PHYs
258b560a58cSFlorian Fainelli  */
259b560a58cSFlorian Fainelli static int bcm7xxx_suspend(struct phy_device *phydev)
260b560a58cSFlorian Fainelli {
261b560a58cSFlorian Fainelli 	int ret;
262b560a58cSFlorian Fainelli 	const struct bcm7xxx_regs {
263b560a58cSFlorian Fainelli 		int reg;
264b560a58cSFlorian Fainelli 		u16 value;
265b560a58cSFlorian Fainelli 	} bcm7xxx_suspend_cfg[] = {
266b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_TEST, 0x008b },
267b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 },
268b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_100TX_DISC, 0x7000 },
269b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_TEST, 0x000f },
270b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 },
271b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_TEST, 0x000b },
272b560a58cSFlorian Fainelli 	};
273b560a58cSFlorian Fainelli 	unsigned int i;
274b560a58cSFlorian Fainelli 
275b560a58cSFlorian Fainelli 	for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) {
276b560a58cSFlorian Fainelli 		ret = phy_write(phydev,
277b560a58cSFlorian Fainelli 				bcm7xxx_suspend_cfg[i].reg,
278b560a58cSFlorian Fainelli 				bcm7xxx_suspend_cfg[i].value);
279b560a58cSFlorian Fainelli 		if (ret)
280b560a58cSFlorian Fainelli 			return ret;
281b560a58cSFlorian Fainelli 	}
282b560a58cSFlorian Fainelli 
283b560a58cSFlorian Fainelli 	return 0;
284b560a58cSFlorian Fainelli }
285b560a58cSFlorian Fainelli 
286b560a58cSFlorian Fainelli static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
287b560a58cSFlorian Fainelli {
288b560a58cSFlorian Fainelli 	return 0;
289b560a58cSFlorian Fainelli }
290b560a58cSFlorian Fainelli 
291b560a58cSFlorian Fainelli static struct phy_driver bcm7xxx_driver[] = {
292b560a58cSFlorian Fainelli {
293b560a58cSFlorian Fainelli 	.phy_id		= PHY_ID_BCM7366,
294b560a58cSFlorian Fainelli 	.phy_id_mask	= 0xfffffff0,
295b560a58cSFlorian Fainelli 	.name		= "Broadcom BCM7366",
296b560a58cSFlorian Fainelli 	.features	= PHY_GBIT_FEATURES |
297b560a58cSFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
298b560a58cSFlorian Fainelli 	.flags		= PHY_IS_INTERNAL,
299b560a58cSFlorian Fainelli 	.config_init	= bcm7xxx_28nm_afe_config_init,
300b560a58cSFlorian Fainelli 	.config_aneg	= genphy_config_aneg,
301b560a58cSFlorian Fainelli 	.read_status	= genphy_read_status,
3024fd14e0bSFlorian Fainelli 	.resume		= bcm7xxx_28nm_resume,
303b560a58cSFlorian Fainelli 	.driver		= { .owner = THIS_MODULE },
304b560a58cSFlorian Fainelli }, {
305b560a58cSFlorian Fainelli 	.phy_id		= PHY_ID_BCM7439,
306b560a58cSFlorian Fainelli 	.phy_id_mask	= 0xfffffff0,
307b560a58cSFlorian Fainelli 	.name		= "Broadcom BCM7439",
308b560a58cSFlorian Fainelli 	.features	= PHY_GBIT_FEATURES |
309b560a58cSFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
310b560a58cSFlorian Fainelli 	.flags		= PHY_IS_INTERNAL,
311b560a58cSFlorian Fainelli 	.config_init	= bcm7xxx_28nm_afe_config_init,
312b560a58cSFlorian Fainelli 	.config_aneg	= genphy_config_aneg,
313b560a58cSFlorian Fainelli 	.read_status	= genphy_read_status,
3144fd14e0bSFlorian Fainelli 	.resume		= bcm7xxx_28nm_resume,
315b560a58cSFlorian Fainelli 	.driver		= { .owner = THIS_MODULE },
316b560a58cSFlorian Fainelli }, {
317b560a58cSFlorian Fainelli 	.phy_id		= PHY_ID_BCM7445,
318b560a58cSFlorian Fainelli 	.phy_id_mask	= 0xfffffff0,
319b560a58cSFlorian Fainelli 	.name		= "Broadcom BCM7445",
320b560a58cSFlorian Fainelli 	.features	= PHY_GBIT_FEATURES |
321b560a58cSFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
322b560a58cSFlorian Fainelli 	.flags		= PHY_IS_INTERNAL,
323b560a58cSFlorian Fainelli 	.config_init	= bcm7xxx_28nm_config_init,
324b560a58cSFlorian Fainelli 	.config_aneg	= genphy_config_aneg,
325b560a58cSFlorian Fainelli 	.read_status	= genphy_read_status,
3264fd14e0bSFlorian Fainelli 	.resume		= bcm7xxx_28nm_afe_config_init,
327b560a58cSFlorian Fainelli 	.driver		= { .owner = THIS_MODULE },
328b560a58cSFlorian Fainelli }, {
329b560a58cSFlorian Fainelli 	.phy_id		= PHY_BCM_OUI_4,
330b560a58cSFlorian Fainelli 	.phy_id_mask	= 0xffff0000,
331b560a58cSFlorian Fainelli 	.name		= "Broadcom BCM7XXX 40nm",
332b560a58cSFlorian Fainelli 	.features	= PHY_GBIT_FEATURES |
333b560a58cSFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
334b560a58cSFlorian Fainelli 	.flags		= PHY_IS_INTERNAL,
335b560a58cSFlorian Fainelli 	.config_init	= bcm7xxx_config_init,
336b560a58cSFlorian Fainelli 	.config_aneg	= genphy_config_aneg,
337b560a58cSFlorian Fainelli 	.read_status	= genphy_read_status,
338b560a58cSFlorian Fainelli 	.suspend	= bcm7xxx_suspend,
339b560a58cSFlorian Fainelli 	.resume		= bcm7xxx_config_init,
340b560a58cSFlorian Fainelli 	.driver		= { .owner = THIS_MODULE },
341b560a58cSFlorian Fainelli }, {
342b560a58cSFlorian Fainelli 	.phy_id		= PHY_BCM_OUI_5,
343b560a58cSFlorian Fainelli 	.phy_id_mask	= 0xffffff00,
344b560a58cSFlorian Fainelli 	.name		= "Broadcom BCM7XXX 65nm",
345b560a58cSFlorian Fainelli 	.features	= PHY_BASIC_FEATURES |
346b560a58cSFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
347b560a58cSFlorian Fainelli 	.flags		= PHY_IS_INTERNAL,
348b560a58cSFlorian Fainelli 	.config_init	= bcm7xxx_dummy_config_init,
349b560a58cSFlorian Fainelli 	.config_aneg	= genphy_config_aneg,
350b560a58cSFlorian Fainelli 	.read_status	= genphy_read_status,
351b560a58cSFlorian Fainelli 	.suspend	= bcm7xxx_suspend,
352b560a58cSFlorian Fainelli 	.resume		= bcm7xxx_config_init,
353b560a58cSFlorian Fainelli 	.driver		= { .owner = THIS_MODULE },
354b560a58cSFlorian Fainelli } };
355b560a58cSFlorian Fainelli 
356b560a58cSFlorian Fainelli static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
357b560a58cSFlorian Fainelli 	{ PHY_ID_BCM7366, 0xfffffff0, },
358b560a58cSFlorian Fainelli 	{ PHY_ID_BCM7439, 0xfffffff0, },
359b560a58cSFlorian Fainelli 	{ PHY_ID_BCM7445, 0xfffffff0, },
360b560a58cSFlorian Fainelli 	{ PHY_BCM_OUI_4, 0xffff0000 },
361b560a58cSFlorian Fainelli 	{ PHY_BCM_OUI_5, 0xffffff00 },
362b560a58cSFlorian Fainelli 	{ }
363b560a58cSFlorian Fainelli };
364b560a58cSFlorian Fainelli 
365b560a58cSFlorian Fainelli static int __init bcm7xxx_phy_init(void)
366b560a58cSFlorian Fainelli {
367b560a58cSFlorian Fainelli 	return phy_drivers_register(bcm7xxx_driver,
368b560a58cSFlorian Fainelli 			ARRAY_SIZE(bcm7xxx_driver));
369b560a58cSFlorian Fainelli }
370b560a58cSFlorian Fainelli 
371b560a58cSFlorian Fainelli static void __exit bcm7xxx_phy_exit(void)
372b560a58cSFlorian Fainelli {
373b560a58cSFlorian Fainelli 	phy_drivers_unregister(bcm7xxx_driver,
374b560a58cSFlorian Fainelli 			ARRAY_SIZE(bcm7xxx_driver));
375b560a58cSFlorian Fainelli }
376b560a58cSFlorian Fainelli 
377b560a58cSFlorian Fainelli module_init(bcm7xxx_phy_init);
378b560a58cSFlorian Fainelli module_exit(bcm7xxx_phy_exit);
379b560a58cSFlorian Fainelli 
380b560a58cSFlorian Fainelli MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl);
381b560a58cSFlorian Fainelli 
382b560a58cSFlorian Fainelli MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver");
383b560a58cSFlorian Fainelli MODULE_LICENSE("GPL");
384b560a58cSFlorian Fainelli MODULE_AUTHOR("Broadcom Corporation");
385