Commit 77f4f622 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 2e4e4410 d8ebfed3
...@@ -376,6 +376,9 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds) ...@@ -376,6 +376,9 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
SWITCH_TOP_REV_MASK; SWITCH_TOP_REV_MASK;
priv->hw_params.core_rev = (rev & SF2_REV_MASK); priv->hw_params.core_rev = (rev & SF2_REV_MASK);
rev = reg_readl(priv, REG_PHY_REVISION);
priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK;
pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n", pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n",
priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff, priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,
priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff, 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,6 +402,18 @@ static int bcm_sf2_sw_set_addr(struct dsa_switch *ds, u8 *addr)
return 0; return 0;
} }
static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
/* The BCM7xxx PHY driver expects to find the integrated PHY revision
* in bits 15:8 and the patch level in bits 7:0 which is exactly what
* the REG_PHY_REVISION register layout is.
*/
return priv->hw_params.gphy_rev;
}
static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr, static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr,
int regnum, u16 val) int regnum, u16 val)
{ {
...@@ -597,6 +612,7 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = { ...@@ -597,6 +612,7 @@ static struct dsa_switch_driver bcm_sf2_switch_driver = {
.probe = bcm_sf2_sw_probe, .probe = bcm_sf2_sw_probe,
.setup = bcm_sf2_sw_setup, .setup = bcm_sf2_sw_setup,
.set_addr = bcm_sf2_sw_set_addr, .set_addr = bcm_sf2_sw_set_addr,
.get_phy_flags = bcm_sf2_sw_get_phy_flags,
.phy_read = bcm_sf2_sw_phy_read, .phy_read = bcm_sf2_sw_phy_read,
.phy_write = bcm_sf2_sw_phy_write, .phy_write = bcm_sf2_sw_phy_write,
.get_strings = bcm_sf2_sw_get_strings, .get_strings = bcm_sf2_sw_get_strings,
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
struct bcm_sf2_hw_params { struct bcm_sf2_hw_params {
u16 top_rev; u16 top_rev;
u16 core_rev; u16 core_rev;
u16 gphy_rev;
u32 num_gphy; u32 num_gphy;
u8 num_acb_queue; u8 num_acb_queue;
u8 num_rgmii; u8 num_rgmii;
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#define SWITCH_TOP_REV_MASK 0xffff #define SWITCH_TOP_REV_MASK 0xffff
#define REG_PHY_REVISION 0x1C #define REG_PHY_REVISION 0x1C
#define PHY_REVISION_MASK 0xffff
#define REG_SPHY_CNTRL 0x2C #define REG_SPHY_CNTRL 0x2C
#define IDDQ_BIAS (1 << 0) #define IDDQ_BIAS (1 << 0)
......
...@@ -2432,6 +2432,13 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv) ...@@ -2432,6 +2432,13 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
dev_info(&priv->pdev->dev, "GENET " GENET_VER_FMT, dev_info(&priv->pdev->dev, "GENET " GENET_VER_FMT,
major, (reg >> 16) & 0x0f, reg & 0xffff); major, (reg >> 16) & 0x0f, reg & 0xffff);
/* Store the integrated PHY revision for the MDIO probing function
* to pass this information to the PHY driver. The PHY driver expects
* to find the PHY major revision in bits 15:8 while the GENET register
* stores that information in bits 7:0, account for that.
*/
priv->gphy_rev = (reg & 0xffff) << 8;
#ifdef CONFIG_PHYS_ADDR_T_64BIT #ifdef CONFIG_PHYS_ADDR_T_64BIT
if (!(params->flags & GENET_HAS_40BITS)) if (!(params->flags & GENET_HAS_40BITS))
pr_warn("GENET does not support 40-bits PA\n"); pr_warn("GENET does not support 40-bits PA\n");
......
...@@ -545,6 +545,7 @@ struct bcmgenet_priv { ...@@ -545,6 +545,7 @@ struct bcmgenet_priv {
struct phy_device *phydev; struct phy_device *phydev;
struct device_node *phy_dn; struct device_node *phy_dn;
struct mii_bus *mii_bus; struct mii_bus *mii_bus;
u16 gphy_rev;
/* PHY device variables */ /* PHY device variables */
int old_duplex; int old_duplex;
......
...@@ -296,7 +296,7 @@ static int bcmgenet_mii_probe(struct net_device *dev) ...@@ -296,7 +296,7 @@ static int bcmgenet_mii_probe(struct net_device *dev)
struct bcmgenet_priv *priv = netdev_priv(dev); struct bcmgenet_priv *priv = netdev_priv(dev);
struct device_node *dn = priv->pdev->dev.of_node; struct device_node *dn = priv->pdev->dev.of_node;
struct phy_device *phydev; struct phy_device *phydev;
unsigned int phy_flags; u32 phy_flags;
int ret; int ret;
if (priv->phydev) { if (priv->phydev) {
...@@ -315,8 +315,11 @@ static int bcmgenet_mii_probe(struct net_device *dev) ...@@ -315,8 +315,11 @@ static int bcmgenet_mii_probe(struct net_device *dev)
priv->phy_dn = of_node_get(dn); priv->phy_dn = of_node_get(dn);
} }
phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup, 0, /* Communicate the integrated PHY revision */
priv->phy_interface); phy_flags = priv->gphy_rev;
phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup,
phy_flags, priv->phy_interface);
if (!phydev) { if (!phydev) {
pr_err("could not attach to PHY\n"); pr_err("could not attach to PHY\n");
return -ENODEV; return -ENODEV;
...@@ -338,15 +341,6 @@ static int bcmgenet_mii_probe(struct net_device *dev) ...@@ -338,15 +341,6 @@ static int bcmgenet_mii_probe(struct net_device *dev)
return ret; return ret;
} }
phy_flags = PHY_BRCM_100MBPS_WAR;
/* workarounds are only needed for 100Mpbs PHYs, and
* never on GENET V1 hardware
*/
if ((phydev->supported & PHY_GBIT_FEATURES) || GENET_IS_V1(priv))
phy_flags = 0;
phydev->dev_flags |= phy_flags;
phydev->advertising = phydev->supported; phydev->advertising = phydev->supported;
/* The internal PHY has its link interrupts routed to the /* The internal PHY has its link interrupts routed to the
......
...@@ -196,13 +196,22 @@ static int bcm7xxx_eee_enable(struct phy_device *phydev) ...@@ -196,13 +196,22 @@ static int bcm7xxx_eee_enable(struct phy_device *phydev)
static int bcm7xxx_28nm_config_init(struct phy_device *phydev) static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
{ {
int ret; u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags);
int ret = 0;
ret = bcm7445_config_init(phydev); dev_info(&phydev->dev, "PHY revision: 0x%02x, patch: %d\n", rev, patch);
if (ret)
return ret;
switch (rev) {
case 0xa0:
case 0xb0:
ret = bcm7445_config_init(phydev);
break;
default:
ret = bcm7xxx_28nm_afe_config_init(phydev); ret = bcm7xxx_28nm_afe_config_init(phydev);
break;
}
if (ret) if (ret)
return ret; return ret;
...@@ -257,8 +266,8 @@ static int bcm7xxx_config_init(struct phy_device *phydev) ...@@ -257,8 +266,8 @@ static int bcm7xxx_config_init(struct phy_device *phydev)
phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO); phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO);
phy_read(phydev, MII_BCM7XXX_AUX_MODE); phy_read(phydev, MII_BCM7XXX_AUX_MODE);
/* Workaround only required for 100Mbits/sec */ /* Workaround only required for 100Mbits/sec capable PHYs */
if (!(phydev->dev_flags & PHY_BRCM_100MBPS_WAR)) if (phydev->supported & PHY_GBIT_FEATURES)
return 0; return 0;
/* set shadow mode 2 */ /* set shadow mode 2 */
......
...@@ -224,6 +224,8 @@ struct phy_device *of_phy_connect(struct net_device *dev, ...@@ -224,6 +224,8 @@ struct phy_device *of_phy_connect(struct net_device *dev,
if (!phy) if (!phy)
return NULL; return NULL;
phy->dev_flags = flags;
return phy_connect_direct(dev, phy, hndlr, iface) ? NULL : phy; return phy_connect_direct(dev, phy, hndlr, iface) ? NULL : phy;
} }
EXPORT_SYMBOL(of_phy_connect); EXPORT_SYMBOL(of_phy_connect);
......
...@@ -40,7 +40,8 @@ ...@@ -40,7 +40,8 @@
#define PHY_BRCM_CLEAR_RGMII_MODE 0x00004000 #define PHY_BRCM_CLEAR_RGMII_MODE 0x00004000
#define PHY_BRCM_DIS_TXCRXC_NOENRGY 0x00008000 #define PHY_BRCM_DIS_TXCRXC_NOENRGY 0x00008000
/* Broadcom BCM7xxx specific workarounds */ /* Broadcom BCM7xxx specific workarounds */
#define PHY_BRCM_100MBPS_WAR 0x00010000 #define PHY_BRCM_7XXX_REV(x) (((x) >> 8) & 0xff)
#define PHY_BRCM_7XXX_PATCH(x) ((x) & 0xff)
#define PHY_BCM_FLAGS_VALID 0x80000000 #define PHY_BCM_FLAGS_VALID 0x80000000
/* Broadcom BCM54XX register definitions, common to most Broadcom PHYs */ /* Broadcom BCM54XX register definitions, common to most Broadcom PHYs */
......
...@@ -181,6 +181,7 @@ struct dsa_switch_driver { ...@@ -181,6 +181,7 @@ struct dsa_switch_driver {
char *(*probe)(struct device *host_dev, int sw_addr); char *(*probe)(struct device *host_dev, int sw_addr);
int (*setup)(struct dsa_switch *ds); int (*setup)(struct dsa_switch *ds);
int (*set_addr)(struct dsa_switch *ds, u8 *addr); int (*set_addr)(struct dsa_switch *ds, u8 *addr);
u32 (*get_phy_flags)(struct dsa_switch *ds, int port);
/* /*
* Access to the switch's PHY registers. * Access to the switch's PHY registers.
......
...@@ -371,6 +371,7 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p, ...@@ -371,6 +371,7 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
struct dsa_chip_data *cd = ds->pd; struct dsa_chip_data *cd = ds->pd;
struct device_node *phy_dn, *port_dn; struct device_node *phy_dn, *port_dn;
bool phy_is_fixed = false; bool phy_is_fixed = false;
u32 phy_flags = 0;
int ret; int ret;
port_dn = cd->port_dn[p->port]; port_dn = cd->port_dn[p->port];
...@@ -390,9 +391,12 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p, ...@@ -390,9 +391,12 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
phy_dn = port_dn; phy_dn = port_dn;
} }
if (ds->drv->get_phy_flags)
phy_flags = ds->drv->get_phy_flags(ds, p->port);
if (phy_dn) if (phy_dn)
p->phy = of_phy_connect(slave_dev, phy_dn, p->phy = of_phy_connect(slave_dev, phy_dn,
dsa_slave_adjust_link, 0, dsa_slave_adjust_link, phy_flags,
p->phy_interface); p->phy_interface);
if (p->phy && phy_is_fixed) if (p->phy && phy_is_fixed)
...@@ -480,6 +484,9 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent, ...@@ -480,6 +484,9 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
netif_carrier_off(slave_dev); netif_carrier_off(slave_dev);
if (p->phy != NULL) { if (p->phy != NULL) {
if (ds->drv->get_phy_flags(ds, port))
p->phy->dev_flags |= ds->drv->get_phy_flags(ds, port);
phy_attach(slave_dev, dev_name(&p->phy->dev), phy_attach(slave_dev, dev_name(&p->phy->dev),
PHY_INTERFACE_MODE_GMII); PHY_INTERFACE_MODE_GMII);
......
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