summaryrefslogtreecommitdiffstats
path: root/drivers/net/phy
diff options
context:
space:
mode:
authorFlorian Fainelli <f.fainelli@gmail.com>2015-06-26 13:39:06 -0400
committerDavid S. Miller <davem@davemloft.net>2015-06-28 23:28:20 -0400
commitd8e704e461c217918cf236f49276e469580afbef (patch)
treef0bfdf7d131f89548fd07c506fe41440816656a3 /drivers/net/phy
parent7b635da86821005cd131369b7a4268df8067cc6c (diff)
net: phy: mdio-bcm-unimac: workaround initial read failures for integrated PHYs
All BCM7xxx integrated Gigabit PHYs have an issue in their MDIO management controller which will make the initial read or write to them to fail and return 0xffff. This is a real issue as the typical first thing we do is read from MII_PHYSID1 and MII_PHYSID2 from get_phy_id() to register a driver for these PHYs. Coupled with the workaround in drivers/net/phy/bcm7xxx.c, this workaround for the MDIO bus controller consists in scanning the list of PHYs to do this initial read workaround for as part of the MDIO bus reset routine which is invoked prior to mdiobus_scan(). Once we have a proper PHY driver/device registered, all workarounds are located there (e.g: power management suspend/resume calls). Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/mdio-bcm-unimac.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/net/phy/mdio-bcm-unimac.c b/drivers/net/phy/mdio-bcm-unimac.c
index fc7abc50b4f1..6a52a7f0fa0d 100644
--- a/drivers/net/phy/mdio-bcm-unimac.c
+++ b/drivers/net/phy/mdio-bcm-unimac.c
@@ -120,6 +120,48 @@ static int unimac_mdio_write(struct mii_bus *bus, int phy_id,
120 return 0; 120 return 0;
121} 121}
122 122
123/* Workaround for integrated BCM7xxx Gigabit PHYs which have a problem with
124 * their internal MDIO management controller making them fail to successfully
125 * be read from or written to for the first transaction. We insert a dummy
126 * BMSR read here to make sure that phy_get_device() and get_phy_id() can
127 * correctly read the PHY MII_PHYSID1/2 registers and successfully register a
128 * PHY device for this peripheral.
129 *
130 * Once the PHY driver is registered, we can workaround subsequent reads from
131 * there (e.g: during system-wide power management).
132 *
133 * bus->reset is invoked before mdiobus_scan during mdiobus_register and is
134 * therefore the right location to stick that workaround. Since we do not want
135 * to read from non-existing PHYs, we either use bus->phy_mask or do a manual
136 * Device Tree scan to limit the search area.
137 */
138static int unimac_mdio_reset(struct mii_bus *bus)
139{
140 struct device_node *np = bus->dev.of_node;
141 struct device_node *child;
142 u32 read_mask = 0;
143 int addr;
144
145 if (!np) {
146 read_mask = ~bus->phy_mask;
147 } else {
148 for_each_available_child_of_node(np, child) {
149 addr = of_mdio_parse_addr(&bus->dev, child);
150 if (addr < 0)
151 continue;
152
153 read_mask |= 1 << addr;
154 }
155 }
156
157 for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
158 if (read_mask & 1 << addr)
159 mdiobus_read(bus, addr, MII_BMSR);
160 }
161
162 return 0;
163}
164
123static int unimac_mdio_probe(struct platform_device *pdev) 165static int unimac_mdio_probe(struct platform_device *pdev)
124{ 166{
125 struct unimac_mdio_priv *priv; 167 struct unimac_mdio_priv *priv;
@@ -155,6 +197,7 @@ static int unimac_mdio_probe(struct platform_device *pdev)
155 bus->parent = &pdev->dev; 197 bus->parent = &pdev->dev;
156 bus->read = unimac_mdio_read; 198 bus->read = unimac_mdio_read;
157 bus->write = unimac_mdio_write; 199 bus->write = unimac_mdio_write;
200 bus->reset = unimac_mdio_reset;
158 snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name); 201 snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
159 202
160 bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); 203 bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);