| .. | .. |
|---|
| 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 | }; |
|---|