• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *	drivers/net/phy/broadcom.c
4  *
5  *	Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
6  *	transceivers.
7  *
8  *	Copyright (c) 2006  Maciej W. Rozycki
9  *
10  *	Inspired by code written by Amy Fong.
11  */
12 
13 #include "bcm-phy-lib.h"
14 #include <linux/module.h>
15 #include <linux/phy.h>
16 #include <linux/brcmphy.h>
17 #include <linux/of.h>
18 
19 #define BRCM_PHY_MODEL(phydev) \
20 	((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
21 
22 #define BRCM_PHY_REV(phydev) \
23 	((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
24 
25 MODULE_DESCRIPTION("Broadcom PHY driver");
26 MODULE_AUTHOR("Maciej W. Rozycki");
27 MODULE_LICENSE("GPL");
28 
bcm54xx_config_clock_delay(struct phy_device * phydev)29 static int bcm54xx_config_clock_delay(struct phy_device *phydev)
30 {
31 	int rc, val;
32 
33 	/* handling PHY's internal RX clock delay */
34 	val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
35 	val |= MII_BCM54XX_AUXCTL_MISC_WREN;
36 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
37 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
38 		/* Disable RGMII RXC-RXD skew */
39 		val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
40 	}
41 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
42 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
43 		/* Enable RGMII RXC-RXD skew */
44 		val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
45 	}
46 	rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
47 				  val);
48 	if (rc < 0)
49 		return rc;
50 
51 	/* handling PHY's internal TX clock delay */
52 	val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
53 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
54 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
55 		/* Disable internal TX clock delay */
56 		val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
57 	}
58 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
59 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
60 		/* Enable internal TX clock delay */
61 		val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN;
62 	}
63 	rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
64 	if (rc < 0)
65 		return rc;
66 
67 	return 0;
68 }
69 
bcm54210e_config_init(struct phy_device * phydev)70 static int bcm54210e_config_init(struct phy_device *phydev)
71 {
72 	int val;
73 
74 	bcm54xx_config_clock_delay(phydev);
75 
76 	if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) {
77 		val = phy_read(phydev, MII_CTRL1000);
78 		val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
79 		phy_write(phydev, MII_CTRL1000, val);
80 	}
81 
82 	return 0;
83 }
84 
bcm54612e_config_init(struct phy_device * phydev)85 static int bcm54612e_config_init(struct phy_device *phydev)
86 {
87 	int reg;
88 
89 	bcm54xx_config_clock_delay(phydev);
90 
91 	/* Enable CLK125 MUX on LED4 if ref clock is enabled. */
92 	if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
93 		int err;
94 
95 		reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
96 		err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
97 					BCM54612E_LED4_CLK125OUT_EN | reg);
98 
99 		if (err < 0)
100 			return err;
101 	}
102 
103 	return 0;
104 }
105 
bcm54616s_config_init(struct phy_device * phydev)106 static int bcm54616s_config_init(struct phy_device *phydev)
107 {
108 	int rc, val;
109 
110 	if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
111 	    phydev->interface != PHY_INTERFACE_MODE_1000BASEX)
112 		return 0;
113 
114 	/* Ensure proper interface mode is selected. */
115 	/* Disable RGMII mode */
116 	val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
117 	if (val < 0)
118 		return val;
119 	val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN;
120 	val |= MII_BCM54XX_AUXCTL_MISC_WREN;
121 	rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
122 				  val);
123 	if (rc < 0)
124 		return rc;
125 
126 	/* Select 1000BASE-X register set (primary SerDes) */
127 	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
128 	if (val < 0)
129 		return val;
130 	val |= BCM54XX_SHD_MODE_1000BX;
131 	rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
132 	if (rc < 0)
133 		return rc;
134 
135 	/* Power down SerDes interface */
136 	rc = phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
137 	if (rc < 0)
138 		return rc;
139 
140 	/* Select proper interface mode */
141 	val &= ~BCM54XX_SHD_INTF_SEL_MASK;
142 	val |= phydev->interface == PHY_INTERFACE_MODE_SGMII ?
143 		BCM54XX_SHD_INTF_SEL_SGMII :
144 		BCM54XX_SHD_INTF_SEL_GBIC;
145 	rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
146 	if (rc < 0)
147 		return rc;
148 
149 	/* Power up SerDes interface */
150 	rc = phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
151 	if (rc < 0)
152 		return rc;
153 
154 	/* Select copper register set */
155 	val &= ~BCM54XX_SHD_MODE_1000BX;
156 	rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
157 	if (rc < 0)
158 		return rc;
159 
160 	/* Power up copper interface */
161 	return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
162 }
163 
164 /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
bcm50610_a0_workaround(struct phy_device * phydev)165 static int bcm50610_a0_workaround(struct phy_device *phydev)
166 {
167 	int err;
168 
169 	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
170 				MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
171 				MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
172 	if (err < 0)
173 		return err;
174 
175 	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
176 				MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
177 	if (err < 0)
178 		return err;
179 
180 	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
181 				MII_BCM54XX_EXP_EXP75_VDACCTRL);
182 	if (err < 0)
183 		return err;
184 
185 	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
186 				MII_BCM54XX_EXP_EXP96_MYST);
187 	if (err < 0)
188 		return err;
189 
190 	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
191 				MII_BCM54XX_EXP_EXP97_MYST);
192 
193 	return err;
194 }
195 
bcm54xx_phydsp_config(struct phy_device * phydev)196 static int bcm54xx_phydsp_config(struct phy_device *phydev)
197 {
198 	int err, err2;
199 
200 	/* Enable the SMDSP clock */
201 	err = bcm54xx_auxctl_write(phydev,
202 				   MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
203 				   MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
204 				   MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
205 	if (err < 0)
206 		return err;
207 
208 	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
209 	    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
210 		/* Clear bit 9 to fix a phy interop issue. */
211 		err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
212 					MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
213 		if (err < 0)
214 			goto error;
215 
216 		if (phydev->drv->phy_id == PHY_ID_BCM50610) {
217 			err = bcm50610_a0_workaround(phydev);
218 			if (err < 0)
219 				goto error;
220 		}
221 	}
222 
223 	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
224 		int val;
225 
226 		val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
227 		if (val < 0)
228 			goto error;
229 
230 		val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
231 		err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
232 	}
233 
234 error:
235 	/* Disable the SMDSP clock */
236 	err2 = bcm54xx_auxctl_write(phydev,
237 				    MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
238 				    MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
239 
240 	/* Return the first error reported. */
241 	return err ? err : err2;
242 }
243 
bcm54xx_adjust_rxrefclk(struct phy_device * phydev)244 static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
245 {
246 	u32 orig;
247 	int val;
248 	bool clk125en = true;
249 
250 	/* Abort if we are using an untested phy. */
251 	if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
252 	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
253 	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M &&
254 	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 &&
255 	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811)
256 		return;
257 
258 	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
259 	if (val < 0)
260 		return;
261 
262 	orig = val;
263 
264 	if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
265 	     BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
266 	    BRCM_PHY_REV(phydev) >= 0x3) {
267 		/*
268 		 * Here, bit 0 _disables_ CLK125 when set.
269 		 * This bit is set by default.
270 		 */
271 		clk125en = false;
272 	} else {
273 		if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
274 			if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) {
275 				/* Here, bit 0 _enables_ CLK125 when set */
276 				val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
277 			}
278 			clk125en = false;
279 		}
280 	}
281 
282 	if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
283 		val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
284 	else
285 		val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
286 
287 	if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) {
288 		if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 ||
289 		    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811)
290 			val |= BCM54810_SHD_SCR3_TRDDAPD;
291 		else
292 			val |= BCM54XX_SHD_SCR3_TRDDAPD;
293 	}
294 
295 	if (orig != val)
296 		bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
297 
298 	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
299 	if (val < 0)
300 		return;
301 
302 	orig = val;
303 
304 	if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
305 		val |= BCM54XX_SHD_APD_EN;
306 	else
307 		val &= ~BCM54XX_SHD_APD_EN;
308 
309 	if (orig != val)
310 		bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
311 }
312 
bcm54xx_config_init(struct phy_device * phydev)313 static int bcm54xx_config_init(struct phy_device *phydev)
314 {
315 	int reg, err, val;
316 
317 	reg = phy_read(phydev, MII_BCM54XX_ECR);
318 	if (reg < 0)
319 		return reg;
320 
321 	/* Mask interrupts globally.  */
322 	reg |= MII_BCM54XX_ECR_IM;
323 	err = phy_write(phydev, MII_BCM54XX_ECR, reg);
324 	if (err < 0)
325 		return err;
326 
327 	/* Unmask events we are interested in.  */
328 	reg = ~(MII_BCM54XX_INT_DUPLEX |
329 		MII_BCM54XX_INT_SPEED |
330 		MII_BCM54XX_INT_LINK);
331 	err = phy_write(phydev, MII_BCM54XX_IMR, reg);
332 	if (err < 0)
333 		return err;
334 
335 	if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
336 	     BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
337 	    (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
338 		bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
339 
340 	bcm54xx_adjust_rxrefclk(phydev);
341 
342 	switch (BRCM_PHY_MODEL(phydev)) {
343 	case PHY_ID_BCM50610:
344 	case PHY_ID_BCM50610M:
345 		err = bcm54xx_config_clock_delay(phydev);
346 		break;
347 	case PHY_ID_BCM54210E:
348 		err = bcm54210e_config_init(phydev);
349 		break;
350 	case PHY_ID_BCM54612E:
351 		err = bcm54612e_config_init(phydev);
352 		break;
353 	case PHY_ID_BCM54616S:
354 		err = bcm54616s_config_init(phydev);
355 		break;
356 	case PHY_ID_BCM54810:
357 		/* For BCM54810, we need to disable BroadR-Reach function */
358 		val = bcm_phy_read_exp(phydev,
359 				       BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
360 		val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
361 		err = bcm_phy_write_exp(phydev,
362 					BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
363 					val);
364 		break;
365 	}
366 	if (err)
367 		return err;
368 
369 	bcm54xx_phydsp_config(phydev);
370 
371 	/* Encode link speed into LED1 and LED3 pair (green/amber).
372 	 * Also flash these two LEDs on activity. This means configuring
373 	 * them for MULTICOLOR and encoding link/activity into them.
374 	 */
375 	val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
376 		BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
377 	bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
378 
379 	val = BCM_LED_MULTICOLOR_IN_PHASE |
380 		BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
381 		BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
382 	bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
383 
384 	return 0;
385 }
386 
bcm54xx_resume(struct phy_device * phydev)387 static int bcm54xx_resume(struct phy_device *phydev)
388 {
389 	int ret;
390 
391 	/* Writes to register other than BMCR would be ignored
392 	 * unless we clear the PDOWN bit first
393 	 */
394 	ret = genphy_resume(phydev);
395 	if (ret < 0)
396 		return ret;
397 
398 	/* Upon exiting power down, the PHY remains in an internal reset state
399 	 * for 40us
400 	 */
401 	fsleep(40);
402 
403 	return bcm54xx_config_init(phydev);
404 }
405 
bcm54811_config_init(struct phy_device * phydev)406 static int bcm54811_config_init(struct phy_device *phydev)
407 {
408 	int err, reg;
409 
410 	/* Disable BroadR-Reach function. */
411 	reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
412 	reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
413 	err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
414 				reg);
415 	if (err < 0)
416 		return err;
417 
418 	err = bcm54xx_config_init(phydev);
419 
420 	/* Enable CLK125 MUX on LED4 if ref clock is enabled. */
421 	if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
422 		reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
423 		err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
424 					BCM54612E_LED4_CLK125OUT_EN | reg);
425 		if (err < 0)
426 			return err;
427 	}
428 
429 	return err;
430 }
431 
bcm5482_config_init(struct phy_device * phydev)432 static int bcm5482_config_init(struct phy_device *phydev)
433 {
434 	int err, reg;
435 
436 	err = bcm54xx_config_init(phydev);
437 
438 	if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
439 		/*
440 		 * Enable secondary SerDes and its use as an LED source
441 		 */
442 		reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD);
443 		bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD,
444 				     reg |
445 				     BCM5482_SHD_SSD_LEDM |
446 				     BCM5482_SHD_SSD_EN);
447 
448 		/*
449 		 * Enable SGMII slave mode and auto-detection
450 		 */
451 		reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
452 		err = bcm_phy_read_exp(phydev, reg);
453 		if (err < 0)
454 			return err;
455 		err = bcm_phy_write_exp(phydev, reg, err |
456 					BCM5482_SSD_SGMII_SLAVE_EN |
457 					BCM5482_SSD_SGMII_SLAVE_AD);
458 		if (err < 0)
459 			return err;
460 
461 		/*
462 		 * Disable secondary SerDes powerdown
463 		 */
464 		reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
465 		err = bcm_phy_read_exp(phydev, reg);
466 		if (err < 0)
467 			return err;
468 		err = bcm_phy_write_exp(phydev, reg,
469 					err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
470 		if (err < 0)
471 			return err;
472 
473 		/*
474 		 * Select 1000BASE-X register set (primary SerDes)
475 		 */
476 		reg = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
477 		bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE,
478 				     reg | BCM54XX_SHD_MODE_1000BX);
479 
480 		/*
481 		 * LED1=ACTIVITYLED, LED3=LINKSPD[2]
482 		 * (Use LED1 as secondary SerDes ACTIVITY LED)
483 		 */
484 		bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1,
485 			BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
486 			BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
487 
488 		/*
489 		 * Auto-negotiation doesn't seem to work quite right
490 		 * in this mode, so we disable it and force it to the
491 		 * right speed/duplex setting.  Only 'link status'
492 		 * is important.
493 		 */
494 		phydev->autoneg = AUTONEG_DISABLE;
495 		phydev->speed = SPEED_1000;
496 		phydev->duplex = DUPLEX_FULL;
497 	}
498 
499 	return err;
500 }
501 
bcm5482_read_status(struct phy_device * phydev)502 static int bcm5482_read_status(struct phy_device *phydev)
503 {
504 	int err;
505 
506 	err = genphy_read_status(phydev);
507 
508 	if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
509 		/*
510 		 * Only link status matters for 1000Base-X mode, so force
511 		 * 1000 Mbit/s full-duplex status
512 		 */
513 		if (phydev->link) {
514 			phydev->speed = SPEED_1000;
515 			phydev->duplex = DUPLEX_FULL;
516 		}
517 	}
518 
519 	return err;
520 }
521 
bcm5481_config_aneg(struct phy_device * phydev)522 static int bcm5481_config_aneg(struct phy_device *phydev)
523 {
524 	struct device_node *np = phydev->mdio.dev.of_node;
525 	int ret;
526 
527 	/* Aneg firstly. */
528 	ret = genphy_config_aneg(phydev);
529 
530 	/* Then we can set up the delay. */
531 	bcm54xx_config_clock_delay(phydev);
532 
533 	if (of_property_read_bool(np, "enet-phy-lane-swap")) {
534 		/* Lane Swap - Undocumented register...magic! */
535 		ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
536 					0x11B);
537 		if (ret < 0)
538 			return ret;
539 	}
540 
541 	return ret;
542 }
543 
bcm54616s_probe(struct phy_device * phydev)544 static int bcm54616s_probe(struct phy_device *phydev)
545 {
546 	int val;
547 
548 	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
549 	if (val < 0)
550 		return val;
551 
552 	/* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0]
553 	 * is 01b, and the link between PHY and its link partner can be
554 	 * either 1000Base-X or 100Base-FX.
555 	 * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX
556 	 * support is still missing as of now.
557 	 */
558 	if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) {
559 		val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL);
560 		if (val < 0)
561 			return val;
562 
563 		/* Bit 0 of the SerDes 100-FX Control register, when set
564 		 * to 1, sets the MII/RGMII -> 100BASE-FX configuration.
565 		 * When this bit is set to 0, it sets the GMII/RGMII ->
566 		 * 1000BASE-X configuration.
567 		 */
568 		if (!(val & BCM54616S_100FX_MODE))
569 			phydev->dev_flags |= PHY_BCM_FLAGS_MODE_1000BX;
570 
571 		phydev->port = PORT_FIBRE;
572 	}
573 
574 	return 0;
575 }
576 
bcm54616s_config_aneg(struct phy_device * phydev)577 static int bcm54616s_config_aneg(struct phy_device *phydev)
578 {
579 	int ret;
580 
581 	/* Aneg firstly. */
582 	if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX)
583 		ret = genphy_c37_config_aneg(phydev);
584 	else
585 		ret = genphy_config_aneg(phydev);
586 
587 	/* Then we can set up the delay. */
588 	bcm54xx_config_clock_delay(phydev);
589 
590 	return ret;
591 }
592 
bcm54616s_read_status(struct phy_device * phydev)593 static int bcm54616s_read_status(struct phy_device *phydev)
594 {
595 	int err;
596 
597 	if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX)
598 		err = genphy_c37_read_status(phydev);
599 	else
600 		err = genphy_read_status(phydev);
601 
602 	return err;
603 }
604 
brcm_phy_setbits(struct phy_device * phydev,int reg,int set)605 static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
606 {
607 	int val;
608 
609 	val = phy_read(phydev, reg);
610 	if (val < 0)
611 		return val;
612 
613 	return phy_write(phydev, reg, val | set);
614 }
615 
brcm_fet_config_init(struct phy_device * phydev)616 static int brcm_fet_config_init(struct phy_device *phydev)
617 {
618 	int reg, err, err2, brcmtest;
619 
620 	/* Reset the PHY to bring it to a known state. */
621 	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
622 	if (err < 0)
623 		return err;
624 
625 	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
626 	if (reg < 0)
627 		return reg;
628 
629 	/* Unmask events we are interested in and mask interrupts globally. */
630 	reg = MII_BRCM_FET_IR_DUPLEX_EN |
631 	      MII_BRCM_FET_IR_SPEED_EN |
632 	      MII_BRCM_FET_IR_LINK_EN |
633 	      MII_BRCM_FET_IR_ENABLE |
634 	      MII_BRCM_FET_IR_MASK;
635 
636 	err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
637 	if (err < 0)
638 		return err;
639 
640 	/* Enable shadow register access */
641 	brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
642 	if (brcmtest < 0)
643 		return brcmtest;
644 
645 	reg = brcmtest | MII_BRCM_FET_BT_SRE;
646 
647 	err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
648 	if (err < 0)
649 		return err;
650 
651 	/* Set the LED mode */
652 	reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
653 	if (reg < 0) {
654 		err = reg;
655 		goto done;
656 	}
657 
658 	reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
659 	reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
660 
661 	err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
662 	if (err < 0)
663 		goto done;
664 
665 	/* Enable auto MDIX */
666 	err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
667 				       MII_BRCM_FET_SHDW_MC_FAME);
668 	if (err < 0)
669 		goto done;
670 
671 	if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
672 		/* Enable auto power down */
673 		err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
674 					       MII_BRCM_FET_SHDW_AS2_APDE);
675 	}
676 
677 done:
678 	/* Disable shadow register access */
679 	err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
680 	if (!err)
681 		err = err2;
682 
683 	return err;
684 }
685 
brcm_fet_ack_interrupt(struct phy_device * phydev)686 static int brcm_fet_ack_interrupt(struct phy_device *phydev)
687 {
688 	int reg;
689 
690 	/* Clear pending interrupts.  */
691 	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
692 	if (reg < 0)
693 		return reg;
694 
695 	return 0;
696 }
697 
brcm_fet_config_intr(struct phy_device * phydev)698 static int brcm_fet_config_intr(struct phy_device *phydev)
699 {
700 	int reg, err;
701 
702 	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
703 	if (reg < 0)
704 		return reg;
705 
706 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
707 		reg &= ~MII_BRCM_FET_IR_MASK;
708 	else
709 		reg |= MII_BRCM_FET_IR_MASK;
710 
711 	err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
712 	return err;
713 }
714 
715 struct bcm53xx_phy_priv {
716 	u64	*stats;
717 };
718 
bcm53xx_phy_probe(struct phy_device * phydev)719 static int bcm53xx_phy_probe(struct phy_device *phydev)
720 {
721 	struct bcm53xx_phy_priv *priv;
722 
723 	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
724 	if (!priv)
725 		return -ENOMEM;
726 
727 	phydev->priv = priv;
728 
729 	priv->stats = devm_kcalloc(&phydev->mdio.dev,
730 				   bcm_phy_get_sset_count(phydev), sizeof(u64),
731 				   GFP_KERNEL);
732 	if (!priv->stats)
733 		return -ENOMEM;
734 
735 	return 0;
736 }
737 
bcm53xx_phy_get_stats(struct phy_device * phydev,struct ethtool_stats * stats,u64 * data)738 static void bcm53xx_phy_get_stats(struct phy_device *phydev,
739 				  struct ethtool_stats *stats, u64 *data)
740 {
741 	struct bcm53xx_phy_priv *priv = phydev->priv;
742 
743 	bcm_phy_get_stats(phydev, priv->stats, stats, data);
744 }
745 
746 static struct phy_driver broadcom_drivers[] = {
747 {
748 	.phy_id		= PHY_ID_BCM5411,
749 	.phy_id_mask	= 0xfffffff0,
750 	.name		= "Broadcom BCM5411",
751 	/* PHY_GBIT_FEATURES */
752 	.config_init	= bcm54xx_config_init,
753 	.ack_interrupt	= bcm_phy_ack_intr,
754 	.config_intr	= bcm_phy_config_intr,
755 }, {
756 	.phy_id		= PHY_ID_BCM5421,
757 	.phy_id_mask	= 0xfffffff0,
758 	.name		= "Broadcom BCM5421",
759 	/* PHY_GBIT_FEATURES */
760 	.config_init	= bcm54xx_config_init,
761 	.ack_interrupt	= bcm_phy_ack_intr,
762 	.config_intr	= bcm_phy_config_intr,
763 }, {
764 	.phy_id		= PHY_ID_BCM54210E,
765 	.phy_id_mask	= 0xfffffff0,
766 	.name		= "Broadcom BCM54210E",
767 	/* PHY_GBIT_FEATURES */
768 	.config_init	= bcm54xx_config_init,
769 	.ack_interrupt	= bcm_phy_ack_intr,
770 	.config_intr	= bcm_phy_config_intr,
771 }, {
772 	.phy_id		= PHY_ID_BCM5461,
773 	.phy_id_mask	= 0xfffffff0,
774 	.name		= "Broadcom BCM5461",
775 	/* PHY_GBIT_FEATURES */
776 	.config_init	= bcm54xx_config_init,
777 	.ack_interrupt	= bcm_phy_ack_intr,
778 	.config_intr	= bcm_phy_config_intr,
779 }, {
780 	.phy_id		= PHY_ID_BCM54612E,
781 	.phy_id_mask	= 0xfffffff0,
782 	.name		= "Broadcom BCM54612E",
783 	/* PHY_GBIT_FEATURES */
784 	.config_init	= bcm54xx_config_init,
785 	.ack_interrupt	= bcm_phy_ack_intr,
786 	.config_intr	= bcm_phy_config_intr,
787 }, {
788 	.phy_id		= PHY_ID_BCM54616S,
789 	.phy_id_mask	= 0xfffffff0,
790 	.name		= "Broadcom BCM54616S",
791 	/* PHY_GBIT_FEATURES */
792 	.soft_reset     = genphy_soft_reset,
793 	.config_init	= bcm54xx_config_init,
794 	.config_aneg	= bcm54616s_config_aneg,
795 	.ack_interrupt	= bcm_phy_ack_intr,
796 	.config_intr	= bcm_phy_config_intr,
797 	.read_status	= bcm54616s_read_status,
798 	.probe		= bcm54616s_probe,
799 }, {
800 	.phy_id		= PHY_ID_BCM5464,
801 	.phy_id_mask	= 0xfffffff0,
802 	.name		= "Broadcom BCM5464",
803 	/* PHY_GBIT_FEATURES */
804 	.config_init	= bcm54xx_config_init,
805 	.ack_interrupt	= bcm_phy_ack_intr,
806 	.config_intr	= bcm_phy_config_intr,
807 	.suspend	= genphy_suspend,
808 	.resume		= genphy_resume,
809 }, {
810 	.phy_id		= PHY_ID_BCM5481,
811 	.phy_id_mask	= 0xfffffff0,
812 	.name		= "Broadcom BCM5481",
813 	/* PHY_GBIT_FEATURES */
814 	.config_init	= bcm54xx_config_init,
815 	.config_aneg	= bcm5481_config_aneg,
816 	.ack_interrupt	= bcm_phy_ack_intr,
817 	.config_intr	= bcm_phy_config_intr,
818 }, {
819 	.phy_id         = PHY_ID_BCM54810,
820 	.phy_id_mask    = 0xfffffff0,
821 	.name           = "Broadcom BCM54810",
822 	/* PHY_GBIT_FEATURES */
823 	.config_init    = bcm54xx_config_init,
824 	.config_aneg    = bcm5481_config_aneg,
825 	.ack_interrupt  = bcm_phy_ack_intr,
826 	.config_intr    = bcm_phy_config_intr,
827 	.suspend	= genphy_suspend,
828 	.resume		= bcm54xx_resume,
829 }, {
830 	.phy_id         = PHY_ID_BCM54811,
831 	.phy_id_mask    = 0xfffffff0,
832 	.name           = "Broadcom BCM54811",
833 	/* PHY_GBIT_FEATURES */
834 	.config_init    = bcm54811_config_init,
835 	.config_aneg    = bcm5481_config_aneg,
836 	.ack_interrupt  = bcm_phy_ack_intr,
837 	.config_intr    = bcm_phy_config_intr,
838 	.suspend	= genphy_suspend,
839 	.resume		= bcm54xx_resume,
840 }, {
841 	.phy_id		= PHY_ID_BCM5482,
842 	.phy_id_mask	= 0xfffffff0,
843 	.name		= "Broadcom BCM5482",
844 	/* PHY_GBIT_FEATURES */
845 	.config_init	= bcm5482_config_init,
846 	.read_status	= bcm5482_read_status,
847 	.ack_interrupt	= bcm_phy_ack_intr,
848 	.config_intr	= bcm_phy_config_intr,
849 }, {
850 	.phy_id		= PHY_ID_BCM50610,
851 	.phy_id_mask	= 0xfffffff0,
852 	.name		= "Broadcom BCM50610",
853 	/* PHY_GBIT_FEATURES */
854 	.config_init	= bcm54xx_config_init,
855 	.ack_interrupt	= bcm_phy_ack_intr,
856 	.config_intr	= bcm_phy_config_intr,
857 }, {
858 	.phy_id		= PHY_ID_BCM50610M,
859 	.phy_id_mask	= 0xfffffff0,
860 	.name		= "Broadcom BCM50610M",
861 	/* PHY_GBIT_FEATURES */
862 	.config_init	= bcm54xx_config_init,
863 	.ack_interrupt	= bcm_phy_ack_intr,
864 	.config_intr	= bcm_phy_config_intr,
865 }, {
866 	.phy_id		= PHY_ID_BCM57780,
867 	.phy_id_mask	= 0xfffffff0,
868 	.name		= "Broadcom BCM57780",
869 	/* PHY_GBIT_FEATURES */
870 	.config_init	= bcm54xx_config_init,
871 	.ack_interrupt	= bcm_phy_ack_intr,
872 	.config_intr	= bcm_phy_config_intr,
873 }, {
874 	.phy_id		= PHY_ID_BCMAC131,
875 	.phy_id_mask	= 0xfffffff0,
876 	.name		= "Broadcom BCMAC131",
877 	/* PHY_BASIC_FEATURES */
878 	.config_init	= brcm_fet_config_init,
879 	.ack_interrupt	= brcm_fet_ack_interrupt,
880 	.config_intr	= brcm_fet_config_intr,
881 }, {
882 	.phy_id		= PHY_ID_BCM5241,
883 	.phy_id_mask	= 0xfffffff0,
884 	.name		= "Broadcom BCM5241",
885 	/* PHY_BASIC_FEATURES */
886 	.config_init	= brcm_fet_config_init,
887 	.ack_interrupt	= brcm_fet_ack_interrupt,
888 	.config_intr	= brcm_fet_config_intr,
889 }, {
890 	.phy_id		= PHY_ID_BCM5395,
891 	.phy_id_mask	= 0xfffffff0,
892 	.name		= "Broadcom BCM5395",
893 	.flags		= PHY_IS_INTERNAL,
894 	/* PHY_GBIT_FEATURES */
895 	.get_sset_count	= bcm_phy_get_sset_count,
896 	.get_strings	= bcm_phy_get_strings,
897 	.get_stats	= bcm53xx_phy_get_stats,
898 	.probe		= bcm53xx_phy_probe,
899 }, {
900 	.phy_id		= PHY_ID_BCM53125,
901 	.phy_id_mask	= 0xfffffff0,
902 	.name		= "Broadcom BCM53125",
903 	.flags		= PHY_IS_INTERNAL,
904 	/* PHY_GBIT_FEATURES */
905 	.get_sset_count	= bcm_phy_get_sset_count,
906 	.get_strings	= bcm_phy_get_strings,
907 	.get_stats	= bcm53xx_phy_get_stats,
908 	.probe		= bcm53xx_phy_probe,
909 	.config_init	= bcm54xx_config_init,
910 	.ack_interrupt	= bcm_phy_ack_intr,
911 	.config_intr	= bcm_phy_config_intr,
912 }, {
913 	.phy_id         = PHY_ID_BCM89610,
914 	.phy_id_mask    = 0xfffffff0,
915 	.name           = "Broadcom BCM89610",
916 	/* PHY_GBIT_FEATURES */
917 	.config_init    = bcm54xx_config_init,
918 	.ack_interrupt  = bcm_phy_ack_intr,
919 	.config_intr    = bcm_phy_config_intr,
920 } };
921 
922 module_phy_driver(broadcom_drivers);
923 
924 static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
925 	{ PHY_ID_BCM5411, 0xfffffff0 },
926 	{ PHY_ID_BCM5421, 0xfffffff0 },
927 	{ PHY_ID_BCM54210E, 0xfffffff0 },
928 	{ PHY_ID_BCM5461, 0xfffffff0 },
929 	{ PHY_ID_BCM54612E, 0xfffffff0 },
930 	{ PHY_ID_BCM54616S, 0xfffffff0 },
931 	{ PHY_ID_BCM5464, 0xfffffff0 },
932 	{ PHY_ID_BCM5481, 0xfffffff0 },
933 	{ PHY_ID_BCM54810, 0xfffffff0 },
934 	{ PHY_ID_BCM54811, 0xfffffff0 },
935 	{ PHY_ID_BCM5482, 0xfffffff0 },
936 	{ PHY_ID_BCM50610, 0xfffffff0 },
937 	{ PHY_ID_BCM50610M, 0xfffffff0 },
938 	{ PHY_ID_BCM57780, 0xfffffff0 },
939 	{ PHY_ID_BCMAC131, 0xfffffff0 },
940 	{ PHY_ID_BCM5241, 0xfffffff0 },
941 	{ PHY_ID_BCM5395, 0xfffffff0 },
942 	{ PHY_ID_BCM53125, 0xfffffff0 },
943 	{ PHY_ID_BCM89610, 0xfffffff0 },
944 	{ }
945 };
946 
947 MODULE_DEVICE_TABLE(mdio, broadcom_tbl);
948