diff options
| -rw-r--r-- | arch/powerpc/sysdev/fsl_soc.c | 26 | ||||
| -rw-r--r-- | drivers/net/gianfar.c | 7 | ||||
| -rw-r--r-- | drivers/net/gianfar_mii.c | 21 | ||||
| -rw-r--r-- | drivers/net/gianfar_mii.h | 3 | ||||
| -rw-r--r-- | include/linux/fsl_devices.h | 3 |
5 files changed, 59 insertions, 1 deletions
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 01b884b25696..26ecb96f9731 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c | |||
| @@ -223,6 +223,8 @@ static int gfar_mdio_of_init_one(struct device_node *np) | |||
| 223 | if (ret) | 223 | if (ret) |
| 224 | return ret; | 224 | return ret; |
| 225 | 225 | ||
| 226 | /* The gianfar device will try to use the same ID created below to find | ||
| 227 | * this bus, to coordinate register access (since they share). */ | ||
| 226 | mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", | 228 | mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", |
| 227 | res.start&0xfffff, &res, 1); | 229 | res.start&0xfffff, &res, 1); |
| 228 | if (IS_ERR(mdio_dev)) | 230 | if (IS_ERR(mdio_dev)) |
| @@ -394,6 +396,30 @@ static int __init gfar_of_init(void) | |||
| 394 | of_node_put(mdio); | 396 | of_node_put(mdio); |
| 395 | } | 397 | } |
| 396 | 398 | ||
| 399 | /* Get MDIO bus controlled by this eTSEC, if any. Normally only | ||
| 400 | * eTSEC 1 will control an MDIO bus, not necessarily the same | ||
| 401 | * bus that its PHY is on ('mdio' above), so we can't just use | ||
| 402 | * that. What we do is look for a gianfar mdio device that has | ||
| 403 | * overlapping registers with this device. That's really the | ||
| 404 | * whole point, to find the device sharing our registers to | ||
| 405 | * coordinate access with it. | ||
| 406 | */ | ||
| 407 | for_each_compatible_node(mdio, NULL, "fsl,gianfar-mdio") { | ||
| 408 | if (of_address_to_resource(mdio, 0, &res)) | ||
| 409 | continue; | ||
| 410 | |||
| 411 | if (res.start >= r[0].start && res.end <= r[0].end) { | ||
| 412 | /* Get the ID the mdio bus platform device was | ||
| 413 | * registered with. gfar_data.bus_id is | ||
| 414 | * different because it's for finding a PHY, | ||
| 415 | * while this is for finding a MII bus. | ||
| 416 | */ | ||
| 417 | gfar_data.mdio_bus = res.start&0xfffff; | ||
| 418 | of_node_put(mdio); | ||
| 419 | break; | ||
| 420 | } | ||
| 421 | } | ||
| 422 | |||
| 397 | ret = | 423 | ret = |
| 398 | platform_device_add_data(gfar_dev, &gfar_data, | 424 | platform_device_add_data(gfar_dev, &gfar_data, |
| 399 | sizeof(struct | 425 | sizeof(struct |
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 64b201134fdb..249541a1814b 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
| @@ -586,6 +586,10 @@ static void gfar_configure_serdes(struct net_device *dev) | |||
| 586 | struct gfar_mii __iomem *regs = | 586 | struct gfar_mii __iomem *regs = |
| 587 | (void __iomem *)&priv->regs->gfar_mii_regs; | 587 | (void __iomem *)&priv->regs->gfar_mii_regs; |
| 588 | int tbipa = gfar_read(&priv->regs->tbipa); | 588 | int tbipa = gfar_read(&priv->regs->tbipa); |
| 589 | struct mii_bus *bus = gfar_get_miibus(priv); | ||
| 590 | |||
| 591 | if (bus) | ||
| 592 | mutex_lock(&bus->mdio_lock); | ||
| 589 | 593 | ||
| 590 | /* Single clk mode, mii mode off(for serdes communication) */ | 594 | /* Single clk mode, mii mode off(for serdes communication) */ |
| 591 | gfar_local_mdio_write(regs, tbipa, MII_TBICON, TBICON_CLK_SELECT); | 595 | gfar_local_mdio_write(regs, tbipa, MII_TBICON, TBICON_CLK_SELECT); |
| @@ -596,6 +600,9 @@ static void gfar_configure_serdes(struct net_device *dev) | |||
| 596 | 600 | ||
| 597 | gfar_local_mdio_write(regs, tbipa, MII_BMCR, BMCR_ANENABLE | | 601 | gfar_local_mdio_write(regs, tbipa, MII_BMCR, BMCR_ANENABLE | |
| 598 | BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000); | 602 | BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000); |
| 603 | |||
| 604 | if (bus) | ||
| 605 | mutex_unlock(&bus->mdio_lock); | ||
| 599 | } | 606 | } |
| 600 | 607 | ||
| 601 | static void init_registers(struct net_device *dev) | 608 | static void init_registers(struct net_device *dev) |
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index bf73eea98010..0e2595d24933 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c | |||
| @@ -269,6 +269,27 @@ static struct device_driver gianfar_mdio_driver = { | |||
| 269 | .remove = gfar_mdio_remove, | 269 | .remove = gfar_mdio_remove, |
| 270 | }; | 270 | }; |
| 271 | 271 | ||
| 272 | static int match_mdio_bus(struct device *dev, void *data) | ||
| 273 | { | ||
| 274 | const struct gfar_private *priv = data; | ||
| 275 | const struct platform_device *pdev = to_platform_device(dev); | ||
| 276 | |||
| 277 | return !strcmp(pdev->name, gianfar_mdio_driver.name) && | ||
| 278 | pdev->id == priv->einfo->mdio_bus; | ||
| 279 | } | ||
| 280 | |||
| 281 | /* Given a gfar_priv structure, find the mii_bus controlled by this device (not | ||
| 282 | * necessarily the same as the bus the gfar's PHY is on), if one exists. | ||
| 283 | * Normally only the first gianfar controls a mii_bus. */ | ||
| 284 | struct mii_bus *gfar_get_miibus(const struct gfar_private *priv) | ||
| 285 | { | ||
| 286 | /*const*/ struct device *d; | ||
| 287 | |||
| 288 | d = bus_find_device(gianfar_mdio_driver.bus, NULL, (void *)priv, | ||
| 289 | match_mdio_bus); | ||
| 290 | return d ? dev_get_drvdata(d) : NULL; | ||
| 291 | } | ||
| 292 | |||
| 272 | int __init gfar_mdio_init(void) | 293 | int __init gfar_mdio_init(void) |
| 273 | { | 294 | { |
| 274 | return driver_register(&gianfar_mdio_driver); | 295 | return driver_register(&gianfar_mdio_driver); |
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h index 2af28b16a0e2..02dc970ca1ff 100644 --- a/drivers/net/gianfar_mii.h +++ b/drivers/net/gianfar_mii.h | |||
| @@ -18,6 +18,8 @@ | |||
| 18 | #ifndef __GIANFAR_MII_H | 18 | #ifndef __GIANFAR_MII_H |
| 19 | #define __GIANFAR_MII_H | 19 | #define __GIANFAR_MII_H |
| 20 | 20 | ||
| 21 | struct gfar_private; /* forward ref */ | ||
| 22 | |||
| 21 | #define MIIMIND_BUSY 0x00000001 | 23 | #define MIIMIND_BUSY 0x00000001 |
| 22 | #define MIIMIND_NOTVALID 0x00000004 | 24 | #define MIIMIND_NOTVALID 0x00000004 |
| 23 | 25 | ||
| @@ -44,6 +46,7 @@ int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); | |||
| 44 | int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, | 46 | int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, |
| 45 | int regnum, u16 value); | 47 | int regnum, u16 value); |
| 46 | int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum); | 48 | int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum); |
| 49 | struct mii_bus *gfar_get_miibus(const struct gfar_private *priv); | ||
| 47 | int __init gfar_mdio_init(void); | 50 | int __init gfar_mdio_init(void); |
| 48 | void gfar_mdio_exit(void); | 51 | void gfar_mdio_exit(void); |
| 49 | #endif /* GIANFAR_PHY_H */ | 52 | #endif /* GIANFAR_PHY_H */ |
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 4e625e0094c8..708bab58d8d0 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h | |||
| @@ -49,7 +49,8 @@ struct gianfar_platform_data { | |||
| 49 | u32 device_flags; | 49 | u32 device_flags; |
| 50 | /* board specific information */ | 50 | /* board specific information */ |
| 51 | u32 board_flags; | 51 | u32 board_flags; |
| 52 | char bus_id[MII_BUS_ID_SIZE]; | 52 | int mdio_bus; /* Bus controlled by us */ |
| 53 | char bus_id[MII_BUS_ID_SIZE]; /* Bus PHY is on */ | ||
| 53 | u32 phy_id; | 54 | u32 phy_id; |
| 54 | u8 mac_addr[6]; | 55 | u8 mac_addr[6]; |
| 55 | phy_interface_t interface; | 56 | phy_interface_t interface; |
