aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-09-19 16:27:13 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-19 16:27:13 -0400
commit77f4f6220a98f4f3eb08be10230d7e8c604aa2b8 (patch)
tree76f44de1599ba25217e24f3905732010260e0df2
parent2e4e44107176d552f8bb1bb76053e850e3809841 (diff)
parentd8ebfed3f11b62ebc192af3cab64d835ff047e74 (diff)
Merge branch 'fec-next'
Florian Fainelli says: ==================== net: phy: Broadcom BCM7xxx PHY workaround update This patch sets the change to of_phy_connect() that you have seen before, this time with the full context of why it is useful and applicable here. Due to some design decision, the internal PHY on Broadcom BCM7xxx chips is not entirely self contained and does not report its internal revision through MII_PHYSID2, that is left to external PHY designs. This forces us to get the PHY revision from the GENET and SF2 switch drivers because those two peripherals integrate such a PHY and do contain the PHY revision in their registers. The approach taken here is hopefully easy to extend to similar needs for other chips/ as well. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/dsa/bcm_sf2.c16
-rw-r--r--drivers/net/dsa/bcm_sf2.h1
-rw-r--r--drivers/net/dsa/bcm_sf2_regs.h1
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c7
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.h1
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c18
-rw-r--r--drivers/net/phy/bcm7xxx.c25
-rw-r--r--drivers/of/of_mdio.c2
-rw-r--r--include/linux/brcmphy.h3
-rw-r--r--include/net/dsa.h1
-rw-r--r--net/dsa/slave.c9
11 files changed, 62 insertions, 22 deletions
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 02d7db320d90..a97ba2548ea5 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -376,6 +376,9 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
376 SWITCH_TOP_REV_MASK; 376 SWITCH_TOP_REV_MASK;
377 priv->hw_params.core_rev = (rev & SF2_REV_MASK); 377 priv->hw_params.core_rev = (rev & SF2_REV_MASK);
378 378
379 rev = reg_readl(priv, REG_PHY_REVISION);
380 priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK;
381
379 pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n", 382 pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n",
380 priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff, 383 priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,
381 priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff, 384 priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,
@@ -399,6 +402,18 @@ static int bcm_sf2_sw_set_addr(struct dsa_switch *ds, u8 *addr)
399 return 0; 402 return 0;
400} 403}
401 404
405static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port)
406{
407 struct bcm_sf2_priv *priv = ds_to_priv(ds);
408
409 /* The BCM7xxx PHY driver expects to find the integrated PHY revision
410 * in bits 15:8 and the patch level in bits 7:0 which is exactly what
411 * the REG_PHY_REVISION register layout is.
412 */
413
414 return priv->hw_params.gphy_rev;
415}
416
402static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr, 417static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr,
403 int regnum, u16 val) 418 int regnum, u16 val)
404{ 419{
@@ -597,6 +612,7 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
597 .probe = bcm_sf2_sw_probe, 612 .probe = bcm_sf2_sw_probe,
598 .setup = bcm_sf2_sw_setup, 613 .setup = bcm_sf2_sw_setup,
599 .set_addr = bcm_sf2_sw_set_addr, 614 .set_addr = bcm_sf2_sw_set_addr,
615 .get_phy_flags = bcm_sf2_sw_get_phy_flags,
600 .phy_read = bcm_sf2_sw_phy_read, 616 .phy_read = bcm_sf2_sw_phy_read,
601 .phy_write = bcm_sf2_sw_phy_write, 617 .phy_write = bcm_sf2_sw_phy_write,
602 .get_strings = bcm_sf2_sw_get_strings, 618 .get_strings = bcm_sf2_sw_get_strings,
diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
index 260bab313e58..d3bd52dc40d2 100644
--- a/drivers/net/dsa/bcm_sf2.h
+++ b/drivers/net/dsa/bcm_sf2.h
@@ -26,6 +26,7 @@
26struct bcm_sf2_hw_params { 26struct bcm_sf2_hw_params {
27 u16 top_rev; 27 u16 top_rev;
28 u16 core_rev; 28 u16 core_rev;
29 u16 gphy_rev;
29 u32 num_gphy; 30 u32 num_gphy;
30 u8 num_acb_queue; 31 u8 num_acb_queue;
31 u8 num_rgmii; 32 u8 num_rgmii;
diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h
index 885c231b03b5..c65f138c777f 100644
--- a/drivers/net/dsa/bcm_sf2_regs.h
+++ b/drivers/net/dsa/bcm_sf2_regs.h
@@ -25,6 +25,7 @@
25#define SWITCH_TOP_REV_MASK 0xffff 25#define SWITCH_TOP_REV_MASK 0xffff
26 26
27#define REG_PHY_REVISION 0x1C 27#define REG_PHY_REVISION 0x1C
28#define PHY_REVISION_MASK 0xffff
28 29
29#define REG_SPHY_CNTRL 0x2C 30#define REG_SPHY_CNTRL 0x2C
30#define IDDQ_BIAS (1 << 0) 31#define IDDQ_BIAS (1 << 0)
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 3f9d4de8173c..a12c65604f9d 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2432,6 +2432,13 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
2432 dev_info(&priv->pdev->dev, "GENET " GENET_VER_FMT, 2432 dev_info(&priv->pdev->dev, "GENET " GENET_VER_FMT,
2433 major, (reg >> 16) & 0x0f, reg & 0xffff); 2433 major, (reg >> 16) & 0x0f, reg & 0xffff);
2434 2434
2435 /* Store the integrated PHY revision for the MDIO probing function
2436 * to pass this information to the PHY driver. The PHY driver expects
2437 * to find the PHY major revision in bits 15:8 while the GENET register
2438 * stores that information in bits 7:0, account for that.
2439 */
2440 priv->gphy_rev = (reg & 0xffff) << 8;
2441
2435#ifdef CONFIG_PHYS_ADDR_T_64BIT 2442#ifdef CONFIG_PHYS_ADDR_T_64BIT
2436 if (!(params->flags & GENET_HAS_40BITS)) 2443 if (!(params->flags & GENET_HAS_40BITS))
2437 pr_warn("GENET does not support 40-bits PA\n"); 2444 pr_warn("GENET does not support 40-bits PA\n");
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index c862d0666771..ad95fe57ebcd 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -545,6 +545,7 @@ struct bcmgenet_priv {
545 struct phy_device *phydev; 545 struct phy_device *phydev;
546 struct device_node *phy_dn; 546 struct device_node *phy_dn;
547 struct mii_bus *mii_bus; 547 struct mii_bus *mii_bus;
548 u16 gphy_rev;
548 549
549 /* PHY device variables */ 550 /* PHY device variables */
550 int old_duplex; 551 int old_duplex;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index c88f7ae99636..75b26cbaa7c1 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -296,7 +296,7 @@ static int bcmgenet_mii_probe(struct net_device *dev)
296 struct bcmgenet_priv *priv = netdev_priv(dev); 296 struct bcmgenet_priv *priv = netdev_priv(dev);
297 struct device_node *dn = priv->pdev->dev.of_node; 297 struct device_node *dn = priv->pdev->dev.of_node;
298 struct phy_device *phydev; 298 struct phy_device *phydev;
299 unsigned int phy_flags; 299 u32 phy_flags;
300 int ret; 300 int ret;
301 301
302 if (priv->phydev) { 302 if (priv->phydev) {
@@ -315,8 +315,11 @@ static int bcmgenet_mii_probe(struct net_device *dev)
315 priv->phy_dn = of_node_get(dn); 315 priv->phy_dn = of_node_get(dn);
316 } 316 }
317 317
318 phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup, 0, 318 /* Communicate the integrated PHY revision */
319 priv->phy_interface); 319 phy_flags = priv->gphy_rev;
320
321 phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup,
322 phy_flags, priv->phy_interface);
320 if (!phydev) { 323 if (!phydev) {
321 pr_err("could not attach to PHY\n"); 324 pr_err("could not attach to PHY\n");
322 return -ENODEV; 325 return -ENODEV;
@@ -338,15 +341,6 @@ static int bcmgenet_mii_probe(struct net_device *dev)
338 return ret; 341 return ret;
339 } 342 }
340 343
341 phy_flags = PHY_BRCM_100MBPS_WAR;
342
343 /* workarounds are only needed for 100Mpbs PHYs, and
344 * never on GENET V1 hardware
345 */
346 if ((phydev->supported & PHY_GBIT_FEATURES) || GENET_IS_V1(priv))
347 phy_flags = 0;
348
349 phydev->dev_flags |= phy_flags;
350 phydev->advertising = phydev->supported; 344 phydev->advertising = phydev->supported;
351 345
352 /* The internal PHY has its link interrupts routed to the 346 /* The internal PHY has its link interrupts routed to the
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index 09dd6e1dc6e1..daae69950925 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -196,13 +196,22 @@ static int bcm7xxx_eee_enable(struct phy_device *phydev)
196 196
197static int bcm7xxx_28nm_config_init(struct phy_device *phydev) 197static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
198{ 198{
199 int ret; 199 u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
200 200 u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags);
201 ret = bcm7445_config_init(phydev); 201 int ret = 0;
202 if (ret) 202
203 return ret; 203 dev_info(&phydev->dev, "PHY revision: 0x%02x, patch: %d\n", rev, patch);
204
205 switch (rev) {
206 case 0xa0:
207 case 0xb0:
208 ret = bcm7445_config_init(phydev);
209 break;
210 default:
211 ret = bcm7xxx_28nm_afe_config_init(phydev);
212 break;
213 }
204 214
205 ret = bcm7xxx_28nm_afe_config_init(phydev);
206 if (ret) 215 if (ret)
207 return ret; 216 return ret;
208 217
@@ -257,8 +266,8 @@ static int bcm7xxx_config_init(struct phy_device *phydev)
257 phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO); 266 phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO);
258 phy_read(phydev, MII_BCM7XXX_AUX_MODE); 267 phy_read(phydev, MII_BCM7XXX_AUX_MODE);
259 268
260 /* Workaround only required for 100Mbits/sec */ 269 /* Workaround only required for 100Mbits/sec capable PHYs */
261 if (!(phydev->dev_flags & PHY_BRCM_100MBPS_WAR)) 270 if (phydev->supported & PHY_GBIT_FEATURES)
262 return 0; 271 return 0;
263 272
264 /* set shadow mode 2 */ 273 /* set shadow mode 2 */
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 401b2453da45..a85d80012993 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -224,6 +224,8 @@ struct phy_device *of_phy_connect(struct net_device *dev,
224 if (!phy) 224 if (!phy)
225 return NULL; 225 return NULL;
226 226
227 phy->dev_flags = flags;
228
227 return phy_connect_direct(dev, phy, hndlr, iface) ? NULL : phy; 229 return phy_connect_direct(dev, phy, hndlr, iface) ? NULL : phy;
228} 230}
229EXPORT_SYMBOL(of_phy_connect); 231EXPORT_SYMBOL(of_phy_connect);
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
index 5bd35cc0d471..3f626fe48c9a 100644
--- a/include/linux/brcmphy.h
+++ b/include/linux/brcmphy.h
@@ -40,7 +40,8 @@
40#define PHY_BRCM_CLEAR_RGMII_MODE 0x00004000 40#define PHY_BRCM_CLEAR_RGMII_MODE 0x00004000
41#define PHY_BRCM_DIS_TXCRXC_NOENRGY 0x00008000 41#define PHY_BRCM_DIS_TXCRXC_NOENRGY 0x00008000
42/* Broadcom BCM7xxx specific workarounds */ 42/* Broadcom BCM7xxx specific workarounds */
43#define PHY_BRCM_100MBPS_WAR 0x00010000 43#define PHY_BRCM_7XXX_REV(x) (((x) >> 8) & 0xff)
44#define PHY_BRCM_7XXX_PATCH(x) ((x) & 0xff)
44#define PHY_BCM_FLAGS_VALID 0x80000000 45#define PHY_BCM_FLAGS_VALID 0x80000000
45 46
46/* Broadcom BCM54XX register definitions, common to most Broadcom PHYs */ 47/* Broadcom BCM54XX register definitions, common to most Broadcom PHYs */
diff --git a/include/net/dsa.h b/include/net/dsa.h
index c779e9bba1b3..e020b8a12b7d 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -181,6 +181,7 @@ struct dsa_switch_driver {
181 char *(*probe)(struct device *host_dev, int sw_addr); 181 char *(*probe)(struct device *host_dev, int sw_addr);
182 int (*setup)(struct dsa_switch *ds); 182 int (*setup)(struct dsa_switch *ds);
183 int (*set_addr)(struct dsa_switch *ds, u8 *addr); 183 int (*set_addr)(struct dsa_switch *ds, u8 *addr);
184 u32 (*get_phy_flags)(struct dsa_switch *ds, int port);
184 185
185 /* 186 /*
186 * Access to the switch's PHY registers. 187 * Access to the switch's PHY registers.
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 90c9689ed362..a7997265019a 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -371,6 +371,7 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
371 struct dsa_chip_data *cd = ds->pd; 371 struct dsa_chip_data *cd = ds->pd;
372 struct device_node *phy_dn, *port_dn; 372 struct device_node *phy_dn, *port_dn;
373 bool phy_is_fixed = false; 373 bool phy_is_fixed = false;
374 u32 phy_flags = 0;
374 int ret; 375 int ret;
375 376
376 port_dn = cd->port_dn[p->port]; 377 port_dn = cd->port_dn[p->port];
@@ -390,9 +391,12 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
390 phy_dn = port_dn; 391 phy_dn = port_dn;
391 } 392 }
392 393
394 if (ds->drv->get_phy_flags)
395 phy_flags = ds->drv->get_phy_flags(ds, p->port);
396
393 if (phy_dn) 397 if (phy_dn)
394 p->phy = of_phy_connect(slave_dev, phy_dn, 398 p->phy = of_phy_connect(slave_dev, phy_dn,
395 dsa_slave_adjust_link, 0, 399 dsa_slave_adjust_link, phy_flags,
396 p->phy_interface); 400 p->phy_interface);
397 401
398 if (p->phy && phy_is_fixed) 402 if (p->phy && phy_is_fixed)
@@ -480,6 +484,9 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
480 netif_carrier_off(slave_dev); 484 netif_carrier_off(slave_dev);
481 485
482 if (p->phy != NULL) { 486 if (p->phy != NULL) {
487 if (ds->drv->get_phy_flags(ds, port))
488 p->phy->dev_flags |= ds->drv->get_phy_flags(ds, port);
489
483 phy_attach(slave_dev, dev_name(&p->phy->dev), 490 phy_attach(slave_dev, dev_name(&p->phy->dev),
484 PHY_INTERFACE_MODE_GMII); 491 PHY_INTERFACE_MODE_GMII);
485 492