Commit c544fcb4 authored by David S. Miller's avatar David S. Miller

Merge branch 'broadcom-next'

Robert Hancock says:

====================
Broadcom PHY driver updates

Updates to the Broadcom PHY driver related to use with copper SFP modules.

Changed since v3:
-fixed kerneldoc error

Changed since v2:
-Create flag for PHY on SFP module and use that rather than accessing
 attached_dev directly in PHY driver

Changed since v1:
-Reversed conditional to reduce indentation
-Added missing setting of MII_BCM54XX_AUXCTL_MISC_WREN in
 MII_BCM54XX_AUXCTL_SHDWSEL_MISC register
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 966df6de b5d007e2
...@@ -103,6 +103,64 @@ static int bcm54612e_config_init(struct phy_device *phydev) ...@@ -103,6 +103,64 @@ static int bcm54612e_config_init(struct phy_device *phydev)
return 0; return 0;
} }
static int bcm54616s_config_init(struct phy_device *phydev)
{
int rc, val;
if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
phydev->interface != PHY_INTERFACE_MODE_1000BASEX)
return 0;
/* Ensure proper interface mode is selected. */
/* Disable RGMII mode */
val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
if (val < 0)
return val;
val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN;
val |= MII_BCM54XX_AUXCTL_MISC_WREN;
rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
val);
if (rc < 0)
return rc;
/* Select 1000BASE-X register set (primary SerDes) */
val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
if (val < 0)
return val;
val |= BCM54XX_SHD_MODE_1000BX;
rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
if (rc < 0)
return rc;
/* Power down SerDes interface */
rc = phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
if (rc < 0)
return rc;
/* Select proper interface mode */
val &= ~BCM54XX_SHD_INTF_SEL_MASK;
val |= phydev->interface == PHY_INTERFACE_MODE_SGMII ?
BCM54XX_SHD_INTF_SEL_SGMII :
BCM54XX_SHD_INTF_SEL_GBIC;
rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
if (rc < 0)
return rc;
/* Power up SerDes interface */
rc = phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
if (rc < 0)
return rc;
/* Select copper register set */
val &= ~BCM54XX_SHD_MODE_1000BX;
rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
if (rc < 0)
return rc;
/* Power up copper interface */
return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
}
/* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */ /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
static int bcm50610_a0_workaround(struct phy_device *phydev) static int bcm50610_a0_workaround(struct phy_device *phydev)
{ {
...@@ -283,15 +341,17 @@ static int bcm54xx_config_init(struct phy_device *phydev) ...@@ -283,15 +341,17 @@ static int bcm54xx_config_init(struct phy_device *phydev)
bcm54xx_adjust_rxrefclk(phydev); bcm54xx_adjust_rxrefclk(phydev);
if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E) { switch (BRCM_PHY_MODEL(phydev)) {
case PHY_ID_BCM54210E:
err = bcm54210e_config_init(phydev); err = bcm54210e_config_init(phydev);
if (err) break;
return err; case PHY_ID_BCM54612E:
} else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) {
err = bcm54612e_config_init(phydev); err = bcm54612e_config_init(phydev);
if (err) break;
return err; case PHY_ID_BCM54616S:
} else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) { err = bcm54616s_config_init(phydev);
break;
case PHY_ID_BCM54810:
/* For BCM54810, we need to disable BroadR-Reach function */ /* For BCM54810, we need to disable BroadR-Reach function */
val = bcm_phy_read_exp(phydev, val = bcm_phy_read_exp(phydev,
BCM54810_EXP_BROADREACH_LRE_MISC_CTL); BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
...@@ -299,16 +359,22 @@ static int bcm54xx_config_init(struct phy_device *phydev) ...@@ -299,16 +359,22 @@ static int bcm54xx_config_init(struct phy_device *phydev)
err = bcm_phy_write_exp(phydev, err = bcm_phy_write_exp(phydev,
BCM54810_EXP_BROADREACH_LRE_MISC_CTL, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
val); val);
if (err < 0) break;
return err;
} }
if (err)
return err;
bcm54xx_phydsp_config(phydev); bcm54xx_phydsp_config(phydev);
/* Encode link speed into LED1 and LED3 pair (green/amber). /* For non-SFP setups, encode link speed into LED1 and LED3 pair
* (green/amber).
* Also flash these two LEDs on activity. This means configuring * Also flash these two LEDs on activity. This means configuring
* them for MULTICOLOR and encoding link/activity into them. * them for MULTICOLOR and encoding link/activity into them.
* Don't do this for devices on an SFP module, since some of these
* use the LED outputs to control the SFP LOS signal, and changing
* these settings will cause LOS to malfunction.
*/ */
if (!phy_on_sfp(phydev)) {
val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) | val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1); BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val); bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
...@@ -317,6 +383,7 @@ static int bcm54xx_config_init(struct phy_device *phydev) ...@@ -317,6 +383,7 @@ static int bcm54xx_config_init(struct phy_device *phydev)
BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) | BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT); BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val); bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
}
return 0; return 0;
} }
...@@ -390,7 +457,7 @@ struct bcm54616s_phy_priv { ...@@ -390,7 +457,7 @@ struct bcm54616s_phy_priv {
static int bcm54616s_probe(struct phy_device *phydev) static int bcm54616s_probe(struct phy_device *phydev)
{ {
struct bcm54616s_phy_priv *priv; struct bcm54616s_phy_priv *priv;
int val, intf_sel; int val;
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
...@@ -408,8 +475,7 @@ static int bcm54616s_probe(struct phy_device *phydev) ...@@ -408,8 +475,7 @@ static int bcm54616s_probe(struct phy_device *phydev)
* RGMII-1000Base-X is properly supported, but RGMII-100Base-FX * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX
* support is still missing as of now. * support is still missing as of now.
*/ */
intf_sel = (val & BCM54XX_SHD_INTF_SEL_MASK) >> 1; if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) {
if (intf_sel == 1) {
val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL); val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL);
if (val < 0) if (val < 0)
return val; return val;
......
...@@ -1377,6 +1377,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, ...@@ -1377,6 +1377,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
if (phydev->sfp_bus_attached) if (phydev->sfp_bus_attached)
dev->sfp_bus = phydev->sfp_bus; dev->sfp_bus = phydev->sfp_bus;
else if (dev->sfp_bus)
phydev->is_on_sfp_module = true;
} }
/* Some Ethernet drivers try to connect to a PHY device before /* Some Ethernet drivers try to connect to a PHY device before
......
...@@ -129,6 +129,7 @@ ...@@ -129,6 +129,7 @@
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x07 #define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x07
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN 0x0010 #define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN 0x0010
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN 0x0080
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN 0x0100 #define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN 0x0100
#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200 #define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200
#define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000 #define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000
...@@ -216,6 +217,9 @@ ...@@ -216,6 +217,9 @@
/* 11111: Mode Control Register */ /* 11111: Mode Control Register */
#define BCM54XX_SHD_MODE 0x1f #define BCM54XX_SHD_MODE 0x1f
#define BCM54XX_SHD_INTF_SEL_MASK GENMASK(2, 1) /* INTERF_SEL[1:0] */ #define BCM54XX_SHD_INTF_SEL_MASK GENMASK(2, 1) /* INTERF_SEL[1:0] */
#define BCM54XX_SHD_INTF_SEL_RGMII 0x02
#define BCM54XX_SHD_INTF_SEL_SGMII 0x04
#define BCM54XX_SHD_INTF_SEL_GBIC 0x06
#define BCM54XX_SHD_MODE_1000BX BIT(0) /* Enable 1000-X registers */ #define BCM54XX_SHD_MODE_1000BX BIT(0) /* Enable 1000-X registers */
/* /*
......
...@@ -492,6 +492,7 @@ struct macsec_ops; ...@@ -492,6 +492,7 @@ struct macsec_ops;
* @sysfs_links: Internal boolean tracking sysfs symbolic links setup/removal. * @sysfs_links: Internal boolean tracking sysfs symbolic links setup/removal.
* @loopback_enabled: Set true if this PHY has been loopbacked successfully. * @loopback_enabled: Set true if this PHY has been loopbacked successfully.
* @downshifted_rate: Set true if link speed has been downshifted. * @downshifted_rate: Set true if link speed has been downshifted.
* @is_on_sfp_module: Set true if PHY is located on an SFP module.
* @state: State of the PHY for management purposes * @state: State of the PHY for management purposes
* @dev_flags: Device-specific flags used by the PHY driver. * @dev_flags: Device-specific flags used by the PHY driver.
* @irq: IRQ number of the PHY's interrupt (-1 if none) * @irq: IRQ number of the PHY's interrupt (-1 if none)
...@@ -565,6 +566,7 @@ struct phy_device { ...@@ -565,6 +566,7 @@ struct phy_device {
unsigned sysfs_links:1; unsigned sysfs_links:1;
unsigned loopback_enabled:1; unsigned loopback_enabled:1;
unsigned downshifted_rate:1; unsigned downshifted_rate:1;
unsigned is_on_sfp_module:1;
unsigned autoneg:1; unsigned autoneg:1;
/* The most recently read link state */ /* The most recently read link state */
...@@ -1296,6 +1298,15 @@ static inline bool phy_is_internal(struct phy_device *phydev) ...@@ -1296,6 +1298,15 @@ static inline bool phy_is_internal(struct phy_device *phydev)
return phydev->is_internal; return phydev->is_internal;
} }
/**
* phy_on_sfp - Convenience function for testing if a PHY is on an SFP module
* @phydev: the phy_device struct
*/
static inline bool phy_on_sfp(struct phy_device *phydev)
{
return phydev->is_on_sfp_module;
}
/** /**
* phy_interface_mode_is_rgmii - Convenience function for testing if a * phy_interface_mode_is_rgmii - Convenience function for testing if a
* PHY interface mode is RGMII (all variants) * PHY interface mode is RGMII (all variants)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment