Skip to content

Commit c544fcb

Browse files
committed
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: David S. Miller <[email protected]>
2 parents 966df6d + b5d007e commit c544fcb

File tree

4 files changed

+104
-21
lines changed

4 files changed

+104
-21
lines changed

drivers/net/phy/broadcom.c

Lines changed: 87 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,64 @@ static int bcm54612e_config_init(struct phy_device *phydev)
103103
return 0;
104104
}
105105

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+
106164
/* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
107165
static int bcm50610_a0_workaround(struct phy_device *phydev)
108166
{
@@ -283,40 +341,49 @@ static int bcm54xx_config_init(struct phy_device *phydev)
283341

284342
bcm54xx_adjust_rxrefclk(phydev);
285343

286-
if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E) {
344+
switch (BRCM_PHY_MODEL(phydev)) {
345+
case PHY_ID_BCM54210E:
287346
err = bcm54210e_config_init(phydev);
288-
if (err)
289-
return err;
290-
} else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) {
347+
break;
348+
case PHY_ID_BCM54612E:
291349
err = bcm54612e_config_init(phydev);
292-
if (err)
293-
return err;
294-
} else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
350+
break;
351+
case PHY_ID_BCM54616S:
352+
err = bcm54616s_config_init(phydev);
353+
break;
354+
case PHY_ID_BCM54810:
295355
/* For BCM54810, we need to disable BroadR-Reach function */
296356
val = bcm_phy_read_exp(phydev,
297357
BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
298358
val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
299359
err = bcm_phy_write_exp(phydev,
300360
BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
301361
val);
302-
if (err < 0)
303-
return err;
362+
break;
304363
}
364+
if (err)
365+
return err;
305366

306367
bcm54xx_phydsp_config(phydev);
307368

308-
/* Encode link speed into LED1 and LED3 pair (green/amber).
369+
/* For non-SFP setups, encode link speed into LED1 and LED3 pair
370+
* (green/amber).
309371
* Also flash these two LEDs on activity. This means configuring
310372
* them for MULTICOLOR and encoding link/activity into them.
373+
* Don't do this for devices on an SFP module, since some of these
374+
* use the LED outputs to control the SFP LOS signal, and changing
375+
* these settings will cause LOS to malfunction.
311376
*/
312-
val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
313-
BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
314-
bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
315-
316-
val = BCM_LED_MULTICOLOR_IN_PHASE |
317-
BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
318-
BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
319-
bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
377+
if (!phy_on_sfp(phydev)) {
378+
val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
379+
BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
380+
bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val);
381+
382+
val = BCM_LED_MULTICOLOR_IN_PHASE |
383+
BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
384+
BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
385+
bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
386+
}
320387

321388
return 0;
322389
}
@@ -390,7 +457,7 @@ struct bcm54616s_phy_priv {
390457
static int bcm54616s_probe(struct phy_device *phydev)
391458
{
392459
struct bcm54616s_phy_priv *priv;
393-
int val, intf_sel;
460+
int val;
394461

395462
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
396463
if (!priv)
@@ -408,8 +475,7 @@ static int bcm54616s_probe(struct phy_device *phydev)
408475
* RGMII-1000Base-X is properly supported, but RGMII-100Base-FX
409476
* support is still missing as of now.
410477
*/
411-
intf_sel = (val & BCM54XX_SHD_INTF_SEL_MASK) >> 1;
412-
if (intf_sel == 1) {
478+
if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) {
413479
val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL);
414480
if (val < 0)
415481
return val;

drivers/net/phy/phy_device.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,8 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
13771377

13781378
if (phydev->sfp_bus_attached)
13791379
dev->sfp_bus = phydev->sfp_bus;
1380+
else if (dev->sfp_bus)
1381+
phydev->is_on_sfp_module = true;
13801382
}
13811383

13821384
/* Some Ethernet drivers try to connect to a PHY device before

include/linux/brcmphy.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129

130130
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x07
131131
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN 0x0010
132+
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN 0x0080
132133
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN 0x0100
133134
#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200
134135
#define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000
@@ -216,6 +217,9 @@
216217
/* 11111: Mode Control Register */
217218
#define BCM54XX_SHD_MODE 0x1f
218219
#define BCM54XX_SHD_INTF_SEL_MASK GENMASK(2, 1) /* INTERF_SEL[1:0] */
220+
#define BCM54XX_SHD_INTF_SEL_RGMII 0x02
221+
#define BCM54XX_SHD_INTF_SEL_SGMII 0x04
222+
#define BCM54XX_SHD_INTF_SEL_GBIC 0x06
219223
#define BCM54XX_SHD_MODE_1000BX BIT(0) /* Enable 1000-X registers */
220224

221225
/*

include/linux/phy.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ struct macsec_ops;
492492
* @sysfs_links: Internal boolean tracking sysfs symbolic links setup/removal.
493493
* @loopback_enabled: Set true if this PHY has been loopbacked successfully.
494494
* @downshifted_rate: Set true if link speed has been downshifted.
495+
* @is_on_sfp_module: Set true if PHY is located on an SFP module.
495496
* @state: State of the PHY for management purposes
496497
* @dev_flags: Device-specific flags used by the PHY driver.
497498
* @irq: IRQ number of the PHY's interrupt (-1 if none)
@@ -565,6 +566,7 @@ struct phy_device {
565566
unsigned sysfs_links:1;
566567
unsigned loopback_enabled:1;
567568
unsigned downshifted_rate:1;
569+
unsigned is_on_sfp_module:1;
568570

569571
unsigned autoneg:1;
570572
/* The most recently read link state */
@@ -1296,6 +1298,15 @@ static inline bool phy_is_internal(struct phy_device *phydev)
12961298
return phydev->is_internal;
12971299
}
12981300

1301+
/**
1302+
* phy_on_sfp - Convenience function for testing if a PHY is on an SFP module
1303+
* @phydev: the phy_device struct
1304+
*/
1305+
static inline bool phy_on_sfp(struct phy_device *phydev)
1306+
{
1307+
return phydev->is_on_sfp_module;
1308+
}
1309+
12991310
/**
13001311
* phy_interface_mode_is_rgmii - Convenience function for testing if a
13011312
* PHY interface mode is RGMII (all variants)

0 commit comments

Comments
 (0)