.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
---|
1 | 2 | /* |
---|
2 | 3 | * drivers/net/phy/broadcom.c |
---|
3 | 4 | * |
---|
.. | .. |
---|
7 | 8 | * Copyright (c) 2006 Maciej W. Rozycki |
---|
8 | 9 | * |
---|
9 | 10 | * Inspired by code written by Amy Fong. |
---|
10 | | - * |
---|
11 | | - * This program is free software; you can redistribute it and/or |
---|
12 | | - * modify it under the terms of the GNU General Public License |
---|
13 | | - * as published by the Free Software Foundation; either version |
---|
14 | | - * 2 of the License, or (at your option) any later version. |
---|
15 | 11 | */ |
---|
16 | 12 | |
---|
17 | 13 | #include "bcm-phy-lib.h" |
---|
| 14 | +#include <linux/delay.h> |
---|
18 | 15 | #include <linux/module.h> |
---|
19 | 16 | #include <linux/phy.h> |
---|
20 | 17 | #include <linux/brcmphy.h> |
---|
.. | .. |
---|
30 | 27 | MODULE_AUTHOR("Maciej W. Rozycki"); |
---|
31 | 28 | MODULE_LICENSE("GPL"); |
---|
32 | 29 | |
---|
33 | | -static int bcm54210e_config_init(struct phy_device *phydev) |
---|
34 | | -{ |
---|
35 | | - int val; |
---|
36 | | - |
---|
37 | | - val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); |
---|
38 | | - val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; |
---|
39 | | - val |= MII_BCM54XX_AUXCTL_MISC_WREN; |
---|
40 | | - bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, val); |
---|
41 | | - |
---|
42 | | - val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL); |
---|
43 | | - val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN; |
---|
44 | | - bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); |
---|
45 | | - |
---|
46 | | - if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) { |
---|
47 | | - val = phy_read(phydev, MII_CTRL1000); |
---|
48 | | - val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER; |
---|
49 | | - phy_write(phydev, MII_CTRL1000, val); |
---|
50 | | - } |
---|
51 | | - |
---|
52 | | - return 0; |
---|
53 | | -} |
---|
54 | | - |
---|
55 | | -static int bcm54612e_config_init(struct phy_device *phydev) |
---|
56 | | -{ |
---|
57 | | - int reg; |
---|
58 | | - |
---|
59 | | - /* Clear TX internal delay unless requested. */ |
---|
60 | | - if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) && |
---|
61 | | - (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) { |
---|
62 | | - /* Disable TXD to GTXCLK clock delay (default set) */ |
---|
63 | | - /* Bit 9 is the only field in shadow register 00011 */ |
---|
64 | | - bcm_phy_write_shadow(phydev, 0x03, 0); |
---|
65 | | - } |
---|
66 | | - |
---|
67 | | - /* Clear RX internal delay unless requested. */ |
---|
68 | | - if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) && |
---|
69 | | - (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) { |
---|
70 | | - reg = bcm54xx_auxctl_read(phydev, |
---|
71 | | - MII_BCM54XX_AUXCTL_SHDWSEL_MISC); |
---|
72 | | - /* Disable RXD to RXC delay (default set) */ |
---|
73 | | - reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; |
---|
74 | | - /* Clear shadow selector field */ |
---|
75 | | - reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK; |
---|
76 | | - bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, |
---|
77 | | - MII_BCM54XX_AUXCTL_MISC_WREN | reg); |
---|
78 | | - } |
---|
79 | | - |
---|
80 | | - /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ |
---|
81 | | - if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { |
---|
82 | | - int err; |
---|
83 | | - |
---|
84 | | - reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); |
---|
85 | | - err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0, |
---|
86 | | - BCM54612E_LED4_CLK125OUT_EN | reg); |
---|
87 | | - |
---|
88 | | - if (err < 0) |
---|
89 | | - return err; |
---|
90 | | - } |
---|
91 | | - |
---|
92 | | - return 0; |
---|
93 | | -} |
---|
94 | | - |
---|
95 | | -static int bcm5481x_config(struct phy_device *phydev) |
---|
| 30 | +static int bcm54xx_config_clock_delay(struct phy_device *phydev) |
---|
96 | 31 | { |
---|
97 | 32 | int rc, val; |
---|
98 | 33 | |
---|
.. | .. |
---|
131 | 66 | return rc; |
---|
132 | 67 | |
---|
133 | 68 | return 0; |
---|
| 69 | +} |
---|
| 70 | + |
---|
| 71 | +static int bcm54210e_config_init(struct phy_device *phydev) |
---|
| 72 | +{ |
---|
| 73 | + int val; |
---|
| 74 | + |
---|
| 75 | + bcm54xx_config_clock_delay(phydev); |
---|
| 76 | + |
---|
| 77 | + if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) { |
---|
| 78 | + val = phy_read(phydev, MII_CTRL1000); |
---|
| 79 | + val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER; |
---|
| 80 | + phy_write(phydev, MII_CTRL1000, val); |
---|
| 81 | + } |
---|
| 82 | + |
---|
| 83 | + return 0; |
---|
| 84 | +} |
---|
| 85 | + |
---|
| 86 | +static int bcm54612e_config_init(struct phy_device *phydev) |
---|
| 87 | +{ |
---|
| 88 | + int reg; |
---|
| 89 | + |
---|
| 90 | + bcm54xx_config_clock_delay(phydev); |
---|
| 91 | + |
---|
| 92 | + /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ |
---|
| 93 | + if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { |
---|
| 94 | + int err; |
---|
| 95 | + |
---|
| 96 | + reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); |
---|
| 97 | + err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0, |
---|
| 98 | + BCM54612E_LED4_CLK125OUT_EN | reg); |
---|
| 99 | + |
---|
| 100 | + if (err < 0) |
---|
| 101 | + return err; |
---|
| 102 | + } |
---|
| 103 | + |
---|
| 104 | + return 0; |
---|
| 105 | +} |
---|
| 106 | + |
---|
| 107 | +static int bcm54616s_config_init(struct phy_device *phydev) |
---|
| 108 | +{ |
---|
| 109 | + int rc, val; |
---|
| 110 | + |
---|
| 111 | + if (phydev->interface != PHY_INTERFACE_MODE_SGMII && |
---|
| 112 | + phydev->interface != PHY_INTERFACE_MODE_1000BASEX) |
---|
| 113 | + return 0; |
---|
| 114 | + |
---|
| 115 | + /* Ensure proper interface mode is selected. */ |
---|
| 116 | + /* Disable RGMII mode */ |
---|
| 117 | + val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); |
---|
| 118 | + if (val < 0) |
---|
| 119 | + return val; |
---|
| 120 | + val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN; |
---|
| 121 | + val |= MII_BCM54XX_AUXCTL_MISC_WREN; |
---|
| 122 | + rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, |
---|
| 123 | + val); |
---|
| 124 | + if (rc < 0) |
---|
| 125 | + return rc; |
---|
| 126 | + |
---|
| 127 | + /* Select 1000BASE-X register set (primary SerDes) */ |
---|
| 128 | + val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); |
---|
| 129 | + if (val < 0) |
---|
| 130 | + return val; |
---|
| 131 | + val |= BCM54XX_SHD_MODE_1000BX; |
---|
| 132 | + rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val); |
---|
| 133 | + if (rc < 0) |
---|
| 134 | + return rc; |
---|
| 135 | + |
---|
| 136 | + /* Power down SerDes interface */ |
---|
| 137 | + rc = phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN); |
---|
| 138 | + if (rc < 0) |
---|
| 139 | + return rc; |
---|
| 140 | + |
---|
| 141 | + /* Select proper interface mode */ |
---|
| 142 | + val &= ~BCM54XX_SHD_INTF_SEL_MASK; |
---|
| 143 | + val |= phydev->interface == PHY_INTERFACE_MODE_SGMII ? |
---|
| 144 | + BCM54XX_SHD_INTF_SEL_SGMII : |
---|
| 145 | + BCM54XX_SHD_INTF_SEL_GBIC; |
---|
| 146 | + rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val); |
---|
| 147 | + if (rc < 0) |
---|
| 148 | + return rc; |
---|
| 149 | + |
---|
| 150 | + /* Power up SerDes interface */ |
---|
| 151 | + rc = phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN); |
---|
| 152 | + if (rc < 0) |
---|
| 153 | + return rc; |
---|
| 154 | + |
---|
| 155 | + /* Select copper register set */ |
---|
| 156 | + val &= ~BCM54XX_SHD_MODE_1000BX; |
---|
| 157 | + rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val); |
---|
| 158 | + if (rc < 0) |
---|
| 159 | + return rc; |
---|
| 160 | + |
---|
| 161 | + /* Power up copper interface */ |
---|
| 162 | + return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN); |
---|
134 | 163 | } |
---|
135 | 164 | |
---|
136 | 165 | /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */ |
---|
.. | .. |
---|
222 | 251 | /* Abort if we are using an untested phy. */ |
---|
223 | 252 | if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 && |
---|
224 | 253 | BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 && |
---|
225 | | - BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M) |
---|
| 254 | + BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M && |
---|
| 255 | + BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 && |
---|
| 256 | + BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) |
---|
226 | 257 | return; |
---|
227 | 258 | |
---|
228 | 259 | val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3); |
---|
.. | .. |
---|
241 | 272 | clk125en = false; |
---|
242 | 273 | } else { |
---|
243 | 274 | if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) { |
---|
244 | | - /* Here, bit 0 _enables_ CLK125 when set */ |
---|
245 | | - val &= ~BCM54XX_SHD_SCR3_DEF_CLK125; |
---|
| 275 | + if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) { |
---|
| 276 | + /* Here, bit 0 _enables_ CLK125 when set */ |
---|
| 277 | + val &= ~BCM54XX_SHD_SCR3_DEF_CLK125; |
---|
| 278 | + } |
---|
246 | 279 | clk125en = false; |
---|
247 | 280 | } |
---|
248 | 281 | } |
---|
.. | .. |
---|
252 | 285 | else |
---|
253 | 286 | val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; |
---|
254 | 287 | |
---|
255 | | - if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) |
---|
256 | | - val |= BCM54XX_SHD_SCR3_TRDDAPD; |
---|
| 288 | + if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) { |
---|
| 289 | + if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 || |
---|
| 290 | + BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811) |
---|
| 291 | + val |= BCM54810_SHD_SCR3_TRDDAPD; |
---|
| 292 | + else |
---|
| 293 | + val |= BCM54XX_SHD_SCR3_TRDDAPD; |
---|
| 294 | + } |
---|
257 | 295 | |
---|
258 | 296 | if (orig != val) |
---|
259 | 297 | bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val); |
---|
.. | .. |
---|
300 | 338 | (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE)) |
---|
301 | 339 | bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0); |
---|
302 | 340 | |
---|
303 | | - if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) || |
---|
304 | | - (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) || |
---|
305 | | - (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) |
---|
306 | | - bcm54xx_adjust_rxrefclk(phydev); |
---|
| 341 | + bcm54xx_adjust_rxrefclk(phydev); |
---|
307 | 342 | |
---|
308 | | - if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E) { |
---|
| 343 | + switch (BRCM_PHY_MODEL(phydev)) { |
---|
| 344 | + case PHY_ID_BCM50610: |
---|
| 345 | + case PHY_ID_BCM50610M: |
---|
| 346 | + err = bcm54xx_config_clock_delay(phydev); |
---|
| 347 | + break; |
---|
| 348 | + case PHY_ID_BCM54210E: |
---|
309 | 349 | err = bcm54210e_config_init(phydev); |
---|
310 | | - if (err) |
---|
311 | | - return err; |
---|
312 | | - } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) { |
---|
| 350 | + break; |
---|
| 351 | + case PHY_ID_BCM54612E: |
---|
313 | 352 | err = bcm54612e_config_init(phydev); |
---|
314 | | - if (err) |
---|
315 | | - return err; |
---|
316 | | - } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) { |
---|
| 353 | + break; |
---|
| 354 | + case PHY_ID_BCM54616S: |
---|
| 355 | + err = bcm54616s_config_init(phydev); |
---|
| 356 | + break; |
---|
| 357 | + case PHY_ID_BCM54810: |
---|
317 | 358 | /* For BCM54810, we need to disable BroadR-Reach function */ |
---|
318 | 359 | val = bcm_phy_read_exp(phydev, |
---|
319 | 360 | BCM54810_EXP_BROADREACH_LRE_MISC_CTL); |
---|
.. | .. |
---|
321 | 362 | err = bcm_phy_write_exp(phydev, |
---|
322 | 363 | BCM54810_EXP_BROADREACH_LRE_MISC_CTL, |
---|
323 | 364 | val); |
---|
| 365 | + break; |
---|
| 366 | + } |
---|
| 367 | + if (err) |
---|
| 368 | + return err; |
---|
| 369 | + |
---|
| 370 | + bcm54xx_phydsp_config(phydev); |
---|
| 371 | + |
---|
| 372 | + /* Encode link speed into LED1 and LED3 pair (green/amber). |
---|
| 373 | + * Also flash these two LEDs on activity. This means configuring |
---|
| 374 | + * them for MULTICOLOR and encoding link/activity into them. |
---|
| 375 | + */ |
---|
| 376 | + val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) | |
---|
| 377 | + BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1); |
---|
| 378 | + bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val); |
---|
| 379 | + |
---|
| 380 | + val = BCM_LED_MULTICOLOR_IN_PHASE | |
---|
| 381 | + BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) | |
---|
| 382 | + BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT); |
---|
| 383 | + bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val); |
---|
| 384 | + |
---|
| 385 | + return 0; |
---|
| 386 | +} |
---|
| 387 | + |
---|
| 388 | +static int bcm54xx_resume(struct phy_device *phydev) |
---|
| 389 | +{ |
---|
| 390 | + int ret; |
---|
| 391 | + |
---|
| 392 | + /* Writes to register other than BMCR would be ignored |
---|
| 393 | + * unless we clear the PDOWN bit first |
---|
| 394 | + */ |
---|
| 395 | + ret = genphy_resume(phydev); |
---|
| 396 | + if (ret < 0) |
---|
| 397 | + return ret; |
---|
| 398 | + |
---|
| 399 | + /* Upon exiting power down, the PHY remains in an internal reset state |
---|
| 400 | + * for 40us |
---|
| 401 | + */ |
---|
| 402 | + fsleep(40); |
---|
| 403 | + |
---|
| 404 | + return bcm54xx_config_init(phydev); |
---|
| 405 | +} |
---|
| 406 | + |
---|
| 407 | +static int bcm54810_read_mmd(struct phy_device *phydev, int devnum, u16 regnum) |
---|
| 408 | +{ |
---|
| 409 | + return -EOPNOTSUPP; |
---|
| 410 | +} |
---|
| 411 | + |
---|
| 412 | +static int bcm54810_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, |
---|
| 413 | + u16 val) |
---|
| 414 | +{ |
---|
| 415 | + return -EOPNOTSUPP; |
---|
| 416 | +} |
---|
| 417 | + |
---|
| 418 | +static int bcm54811_config_init(struct phy_device *phydev) |
---|
| 419 | +{ |
---|
| 420 | + int err, reg; |
---|
| 421 | + |
---|
| 422 | + /* Disable BroadR-Reach function. */ |
---|
| 423 | + reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL); |
---|
| 424 | + reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; |
---|
| 425 | + err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL, |
---|
| 426 | + reg); |
---|
| 427 | + if (err < 0) |
---|
| 428 | + return err; |
---|
| 429 | + |
---|
| 430 | + err = bcm54xx_config_init(phydev); |
---|
| 431 | + |
---|
| 432 | + /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ |
---|
| 433 | + if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { |
---|
| 434 | + reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); |
---|
| 435 | + err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0, |
---|
| 436 | + BCM54612E_LED4_CLK125OUT_EN | reg); |
---|
324 | 437 | if (err < 0) |
---|
325 | 438 | return err; |
---|
326 | 439 | } |
---|
327 | 440 | |
---|
328 | | - bcm54xx_phydsp_config(phydev); |
---|
329 | | - |
---|
330 | | - return 0; |
---|
| 441 | + return err; |
---|
331 | 442 | } |
---|
332 | 443 | |
---|
333 | 444 | static int bcm5482_config_init(struct phy_device *phydev) |
---|
.. | .. |
---|
374 | 485 | /* |
---|
375 | 486 | * Select 1000BASE-X register set (primary SerDes) |
---|
376 | 487 | */ |
---|
377 | | - reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE); |
---|
378 | | - bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE, |
---|
379 | | - reg | BCM5482_SHD_MODE_1000BX); |
---|
| 488 | + reg = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); |
---|
| 489 | + bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, |
---|
| 490 | + reg | BCM54XX_SHD_MODE_1000BX); |
---|
380 | 491 | |
---|
381 | 492 | /* |
---|
382 | 493 | * LED1=ACTIVITYLED, LED3=LINKSPD[2] |
---|
.. | .. |
---|
425 | 536 | struct device_node *np = phydev->mdio.dev.of_node; |
---|
426 | 537 | int ret; |
---|
427 | 538 | |
---|
428 | | - /* Aneg firsly. */ |
---|
| 539 | + /* Aneg firstly. */ |
---|
429 | 540 | ret = genphy_config_aneg(phydev); |
---|
430 | 541 | |
---|
431 | 542 | /* Then we can set up the delay. */ |
---|
432 | | - bcm5481x_config(phydev); |
---|
| 543 | + bcm54xx_config_clock_delay(phydev); |
---|
433 | 544 | |
---|
434 | 545 | if (of_property_read_bool(np, "enet-phy-lane-swap")) { |
---|
435 | 546 | /* Lane Swap - Undocumented register...magic! */ |
---|
.. | .. |
---|
440 | 551 | } |
---|
441 | 552 | |
---|
442 | 553 | return ret; |
---|
| 554 | +} |
---|
| 555 | + |
---|
| 556 | +static int bcm54616s_probe(struct phy_device *phydev) |
---|
| 557 | +{ |
---|
| 558 | + int val; |
---|
| 559 | + |
---|
| 560 | + val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); |
---|
| 561 | + if (val < 0) |
---|
| 562 | + return val; |
---|
| 563 | + |
---|
| 564 | + /* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0] |
---|
| 565 | + * is 01b, and the link between PHY and its link partner can be |
---|
| 566 | + * either 1000Base-X or 100Base-FX. |
---|
| 567 | + * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX |
---|
| 568 | + * support is still missing as of now. |
---|
| 569 | + */ |
---|
| 570 | + if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) { |
---|
| 571 | + val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL); |
---|
| 572 | + if (val < 0) |
---|
| 573 | + return val; |
---|
| 574 | + |
---|
| 575 | + /* Bit 0 of the SerDes 100-FX Control register, when set |
---|
| 576 | + * to 1, sets the MII/RGMII -> 100BASE-FX configuration. |
---|
| 577 | + * When this bit is set to 0, it sets the GMII/RGMII -> |
---|
| 578 | + * 1000BASE-X configuration. |
---|
| 579 | + */ |
---|
| 580 | + if (!(val & BCM54616S_100FX_MODE)) |
---|
| 581 | + phydev->dev_flags |= PHY_BCM_FLAGS_MODE_1000BX; |
---|
| 582 | + |
---|
| 583 | + phydev->port = PORT_FIBRE; |
---|
| 584 | + } |
---|
| 585 | + |
---|
| 586 | + return 0; |
---|
| 587 | +} |
---|
| 588 | + |
---|
| 589 | +static int bcm54616s_config_aneg(struct phy_device *phydev) |
---|
| 590 | +{ |
---|
| 591 | + int ret; |
---|
| 592 | + |
---|
| 593 | + /* Aneg firstly. */ |
---|
| 594 | + if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) |
---|
| 595 | + ret = genphy_c37_config_aneg(phydev); |
---|
| 596 | + else |
---|
| 597 | + ret = genphy_config_aneg(phydev); |
---|
| 598 | + |
---|
| 599 | + /* Then we can set up the delay. */ |
---|
| 600 | + bcm54xx_config_clock_delay(phydev); |
---|
| 601 | + |
---|
| 602 | + return ret; |
---|
| 603 | +} |
---|
| 604 | + |
---|
| 605 | +static int bcm54616s_read_status(struct phy_device *phydev) |
---|
| 606 | +{ |
---|
| 607 | + int err; |
---|
| 608 | + |
---|
| 609 | + if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) |
---|
| 610 | + err = genphy_c37_read_status(phydev); |
---|
| 611 | + else |
---|
| 612 | + err = genphy_read_status(phydev); |
---|
| 613 | + |
---|
| 614 | + return err; |
---|
443 | 615 | } |
---|
444 | 616 | |
---|
445 | 617 | static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) |
---|
.. | .. |
---|
460 | 632 | /* Reset the PHY to bring it to a known state. */ |
---|
461 | 633 | err = phy_write(phydev, MII_BMCR, BMCR_RESET); |
---|
462 | 634 | if (err < 0) |
---|
| 635 | + return err; |
---|
| 636 | + |
---|
| 637 | + /* The datasheet indicates the PHY needs up to 1us to complete a reset, |
---|
| 638 | + * build some slack here. |
---|
| 639 | + */ |
---|
| 640 | + usleep_range(1000, 2000); |
---|
| 641 | + |
---|
| 642 | + /* The PHY requires 65 MDC clock cycles to complete a write operation |
---|
| 643 | + * and turnaround the line properly. |
---|
| 644 | + * |
---|
| 645 | + * We ignore -EIO here as the MDIO controller (e.g.: mdio-bcm-unimac) |
---|
| 646 | + * may flag the lack of turn-around as a read failure. This is |
---|
| 647 | + * particularly true with this combination since the MDIO controller |
---|
| 648 | + * only used 64 MDC cycles. This is not a critical failure in this |
---|
| 649 | + * specific case and it has no functional impact otherwise, so we let |
---|
| 650 | + * that one go through. If there is a genuine bus error, the next read |
---|
| 651 | + * of MII_BRCM_FET_INTREG will error out. |
---|
| 652 | + */ |
---|
| 653 | + err = phy_read(phydev, MII_BMCR); |
---|
| 654 | + if (err < 0 && err != -EIO) |
---|
463 | 655 | return err; |
---|
464 | 656 | |
---|
465 | 657 | reg = phy_read(phydev, MII_BRCM_FET_INTREG); |
---|
.. | .. |
---|
588 | 780 | .phy_id = PHY_ID_BCM5411, |
---|
589 | 781 | .phy_id_mask = 0xfffffff0, |
---|
590 | 782 | .name = "Broadcom BCM5411", |
---|
591 | | - .features = PHY_GBIT_FEATURES, |
---|
592 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 783 | + /* PHY_GBIT_FEATURES */ |
---|
593 | 784 | .config_init = bcm54xx_config_init, |
---|
594 | 785 | .ack_interrupt = bcm_phy_ack_intr, |
---|
595 | 786 | .config_intr = bcm_phy_config_intr, |
---|
.. | .. |
---|
597 | 788 | .phy_id = PHY_ID_BCM5421, |
---|
598 | 789 | .phy_id_mask = 0xfffffff0, |
---|
599 | 790 | .name = "Broadcom BCM5421", |
---|
600 | | - .features = PHY_GBIT_FEATURES, |
---|
601 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 791 | + /* PHY_GBIT_FEATURES */ |
---|
602 | 792 | .config_init = bcm54xx_config_init, |
---|
603 | 793 | .ack_interrupt = bcm_phy_ack_intr, |
---|
604 | 794 | .config_intr = bcm_phy_config_intr, |
---|
.. | .. |
---|
606 | 796 | .phy_id = PHY_ID_BCM54210E, |
---|
607 | 797 | .phy_id_mask = 0xfffffff0, |
---|
608 | 798 | .name = "Broadcom BCM54210E", |
---|
609 | | - .features = PHY_GBIT_FEATURES, |
---|
610 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 799 | + /* PHY_GBIT_FEATURES */ |
---|
611 | 800 | .config_init = bcm54xx_config_init, |
---|
612 | 801 | .ack_interrupt = bcm_phy_ack_intr, |
---|
613 | 802 | .config_intr = bcm_phy_config_intr, |
---|
.. | .. |
---|
615 | 804 | .phy_id = PHY_ID_BCM5461, |
---|
616 | 805 | .phy_id_mask = 0xfffffff0, |
---|
617 | 806 | .name = "Broadcom BCM5461", |
---|
618 | | - .features = PHY_GBIT_FEATURES, |
---|
619 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 807 | + /* PHY_GBIT_FEATURES */ |
---|
620 | 808 | .config_init = bcm54xx_config_init, |
---|
621 | 809 | .ack_interrupt = bcm_phy_ack_intr, |
---|
622 | 810 | .config_intr = bcm_phy_config_intr, |
---|
.. | .. |
---|
624 | 812 | .phy_id = PHY_ID_BCM54612E, |
---|
625 | 813 | .phy_id_mask = 0xfffffff0, |
---|
626 | 814 | .name = "Broadcom BCM54612E", |
---|
627 | | - .features = PHY_GBIT_FEATURES, |
---|
628 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 815 | + /* PHY_GBIT_FEATURES */ |
---|
629 | 816 | .config_init = bcm54xx_config_init, |
---|
630 | 817 | .ack_interrupt = bcm_phy_ack_intr, |
---|
631 | 818 | .config_intr = bcm_phy_config_intr, |
---|
.. | .. |
---|
633 | 820 | .phy_id = PHY_ID_BCM54616S, |
---|
634 | 821 | .phy_id_mask = 0xfffffff0, |
---|
635 | 822 | .name = "Broadcom BCM54616S", |
---|
636 | | - .features = PHY_GBIT_FEATURES, |
---|
637 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 823 | + /* PHY_GBIT_FEATURES */ |
---|
| 824 | + .soft_reset = genphy_soft_reset, |
---|
638 | 825 | .config_init = bcm54xx_config_init, |
---|
| 826 | + .config_aneg = bcm54616s_config_aneg, |
---|
639 | 827 | .ack_interrupt = bcm_phy_ack_intr, |
---|
640 | 828 | .config_intr = bcm_phy_config_intr, |
---|
| 829 | + .read_status = bcm54616s_read_status, |
---|
| 830 | + .probe = bcm54616s_probe, |
---|
641 | 831 | }, { |
---|
642 | 832 | .phy_id = PHY_ID_BCM5464, |
---|
643 | 833 | .phy_id_mask = 0xfffffff0, |
---|
644 | 834 | .name = "Broadcom BCM5464", |
---|
645 | | - .features = PHY_GBIT_FEATURES, |
---|
646 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 835 | + /* PHY_GBIT_FEATURES */ |
---|
647 | 836 | .config_init = bcm54xx_config_init, |
---|
648 | 837 | .ack_interrupt = bcm_phy_ack_intr, |
---|
649 | 838 | .config_intr = bcm_phy_config_intr, |
---|
| 839 | + .suspend = genphy_suspend, |
---|
| 840 | + .resume = genphy_resume, |
---|
650 | 841 | }, { |
---|
651 | 842 | .phy_id = PHY_ID_BCM5481, |
---|
652 | 843 | .phy_id_mask = 0xfffffff0, |
---|
653 | 844 | .name = "Broadcom BCM5481", |
---|
654 | | - .features = PHY_GBIT_FEATURES, |
---|
655 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 845 | + /* PHY_GBIT_FEATURES */ |
---|
656 | 846 | .config_init = bcm54xx_config_init, |
---|
657 | 847 | .config_aneg = bcm5481_config_aneg, |
---|
658 | 848 | .ack_interrupt = bcm_phy_ack_intr, |
---|
.. | .. |
---|
661 | 851 | .phy_id = PHY_ID_BCM54810, |
---|
662 | 852 | .phy_id_mask = 0xfffffff0, |
---|
663 | 853 | .name = "Broadcom BCM54810", |
---|
664 | | - .features = PHY_GBIT_FEATURES, |
---|
665 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 854 | + /* PHY_GBIT_FEATURES */ |
---|
| 855 | + .read_mmd = bcm54810_read_mmd, |
---|
| 856 | + .write_mmd = bcm54810_write_mmd, |
---|
666 | 857 | .config_init = bcm54xx_config_init, |
---|
667 | 858 | .config_aneg = bcm5481_config_aneg, |
---|
668 | 859 | .ack_interrupt = bcm_phy_ack_intr, |
---|
669 | 860 | .config_intr = bcm_phy_config_intr, |
---|
| 861 | + .suspend = genphy_suspend, |
---|
| 862 | + .resume = bcm54xx_resume, |
---|
| 863 | +}, { |
---|
| 864 | + .phy_id = PHY_ID_BCM54811, |
---|
| 865 | + .phy_id_mask = 0xfffffff0, |
---|
| 866 | + .name = "Broadcom BCM54811", |
---|
| 867 | + /* PHY_GBIT_FEATURES */ |
---|
| 868 | + .config_init = bcm54811_config_init, |
---|
| 869 | + .config_aneg = bcm5481_config_aneg, |
---|
| 870 | + .ack_interrupt = bcm_phy_ack_intr, |
---|
| 871 | + .config_intr = bcm_phy_config_intr, |
---|
| 872 | + .suspend = genphy_suspend, |
---|
| 873 | + .resume = bcm54xx_resume, |
---|
670 | 874 | }, { |
---|
671 | 875 | .phy_id = PHY_ID_BCM5482, |
---|
672 | 876 | .phy_id_mask = 0xfffffff0, |
---|
673 | 877 | .name = "Broadcom BCM5482", |
---|
674 | | - .features = PHY_GBIT_FEATURES, |
---|
675 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 878 | + /* PHY_GBIT_FEATURES */ |
---|
676 | 879 | .config_init = bcm5482_config_init, |
---|
677 | 880 | .read_status = bcm5482_read_status, |
---|
678 | 881 | .ack_interrupt = bcm_phy_ack_intr, |
---|
.. | .. |
---|
681 | 884 | .phy_id = PHY_ID_BCM50610, |
---|
682 | 885 | .phy_id_mask = 0xfffffff0, |
---|
683 | 886 | .name = "Broadcom BCM50610", |
---|
684 | | - .features = PHY_GBIT_FEATURES, |
---|
685 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 887 | + /* PHY_GBIT_FEATURES */ |
---|
686 | 888 | .config_init = bcm54xx_config_init, |
---|
687 | 889 | .ack_interrupt = bcm_phy_ack_intr, |
---|
688 | 890 | .config_intr = bcm_phy_config_intr, |
---|
.. | .. |
---|
690 | 892 | .phy_id = PHY_ID_BCM50610M, |
---|
691 | 893 | .phy_id_mask = 0xfffffff0, |
---|
692 | 894 | .name = "Broadcom BCM50610M", |
---|
693 | | - .features = PHY_GBIT_FEATURES, |
---|
694 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 895 | + /* PHY_GBIT_FEATURES */ |
---|
695 | 896 | .config_init = bcm54xx_config_init, |
---|
696 | 897 | .ack_interrupt = bcm_phy_ack_intr, |
---|
697 | 898 | .config_intr = bcm_phy_config_intr, |
---|
.. | .. |
---|
699 | 900 | .phy_id = PHY_ID_BCM57780, |
---|
700 | 901 | .phy_id_mask = 0xfffffff0, |
---|
701 | 902 | .name = "Broadcom BCM57780", |
---|
702 | | - .features = PHY_GBIT_FEATURES, |
---|
703 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 903 | + /* PHY_GBIT_FEATURES */ |
---|
704 | 904 | .config_init = bcm54xx_config_init, |
---|
705 | 905 | .ack_interrupt = bcm_phy_ack_intr, |
---|
706 | 906 | .config_intr = bcm_phy_config_intr, |
---|
.. | .. |
---|
708 | 908 | .phy_id = PHY_ID_BCMAC131, |
---|
709 | 909 | .phy_id_mask = 0xfffffff0, |
---|
710 | 910 | .name = "Broadcom BCMAC131", |
---|
711 | | - .features = PHY_BASIC_FEATURES, |
---|
712 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 911 | + /* PHY_BASIC_FEATURES */ |
---|
713 | 912 | .config_init = brcm_fet_config_init, |
---|
714 | 913 | .ack_interrupt = brcm_fet_ack_interrupt, |
---|
715 | 914 | .config_intr = brcm_fet_config_intr, |
---|
.. | .. |
---|
717 | 916 | .phy_id = PHY_ID_BCM5241, |
---|
718 | 917 | .phy_id_mask = 0xfffffff0, |
---|
719 | 918 | .name = "Broadcom BCM5241", |
---|
720 | | - .features = PHY_BASIC_FEATURES, |
---|
721 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 919 | + /* PHY_BASIC_FEATURES */ |
---|
722 | 920 | .config_init = brcm_fet_config_init, |
---|
723 | 921 | .ack_interrupt = brcm_fet_ack_interrupt, |
---|
724 | 922 | .config_intr = brcm_fet_config_intr, |
---|
.. | .. |
---|
727 | 925 | .phy_id_mask = 0xfffffff0, |
---|
728 | 926 | .name = "Broadcom BCM5395", |
---|
729 | 927 | .flags = PHY_IS_INTERNAL, |
---|
730 | | - .features = PHY_GBIT_FEATURES, |
---|
| 928 | + /* PHY_GBIT_FEATURES */ |
---|
731 | 929 | .get_sset_count = bcm_phy_get_sset_count, |
---|
732 | 930 | .get_strings = bcm_phy_get_strings, |
---|
733 | 931 | .get_stats = bcm53xx_phy_get_stats, |
---|
734 | 932 | .probe = bcm53xx_phy_probe, |
---|
735 | 933 | }, { |
---|
| 934 | + .phy_id = PHY_ID_BCM53125, |
---|
| 935 | + .phy_id_mask = 0xfffffff0, |
---|
| 936 | + .name = "Broadcom BCM53125", |
---|
| 937 | + .flags = PHY_IS_INTERNAL, |
---|
| 938 | + /* PHY_GBIT_FEATURES */ |
---|
| 939 | + .get_sset_count = bcm_phy_get_sset_count, |
---|
| 940 | + .get_strings = bcm_phy_get_strings, |
---|
| 941 | + .get_stats = bcm53xx_phy_get_stats, |
---|
| 942 | + .probe = bcm53xx_phy_probe, |
---|
| 943 | + .config_init = bcm54xx_config_init, |
---|
| 944 | + .ack_interrupt = bcm_phy_ack_intr, |
---|
| 945 | + .config_intr = bcm_phy_config_intr, |
---|
| 946 | +}, { |
---|
736 | 947 | .phy_id = PHY_ID_BCM89610, |
---|
737 | 948 | .phy_id_mask = 0xfffffff0, |
---|
738 | 949 | .name = "Broadcom BCM89610", |
---|
739 | | - .features = PHY_GBIT_FEATURES, |
---|
740 | | - .flags = PHY_HAS_INTERRUPT, |
---|
| 950 | + /* PHY_GBIT_FEATURES */ |
---|
741 | 951 | .config_init = bcm54xx_config_init, |
---|
742 | 952 | .ack_interrupt = bcm_phy_ack_intr, |
---|
743 | 953 | .config_intr = bcm_phy_config_intr, |
---|
.. | .. |
---|
755 | 965 | { PHY_ID_BCM5464, 0xfffffff0 }, |
---|
756 | 966 | { PHY_ID_BCM5481, 0xfffffff0 }, |
---|
757 | 967 | { PHY_ID_BCM54810, 0xfffffff0 }, |
---|
| 968 | + { PHY_ID_BCM54811, 0xfffffff0 }, |
---|
758 | 969 | { PHY_ID_BCM5482, 0xfffffff0 }, |
---|
759 | 970 | { PHY_ID_BCM50610, 0xfffffff0 }, |
---|
760 | 971 | { PHY_ID_BCM50610M, 0xfffffff0 }, |
---|
.. | .. |
---|
762 | 973 | { PHY_ID_BCMAC131, 0xfffffff0 }, |
---|
763 | 974 | { PHY_ID_BCM5241, 0xfffffff0 }, |
---|
764 | 975 | { PHY_ID_BCM5395, 0xfffffff0 }, |
---|
| 976 | + { PHY_ID_BCM53125, 0xfffffff0 }, |
---|
765 | 977 | { PHY_ID_BCM89610, 0xfffffff0 }, |
---|
766 | 978 | { } |
---|
767 | 979 | }; |
---|