Skip to content

Commit a577ca6

Browse files
chunkeeydavem330
authored andcommitted
net: emac: add support for device-tree based PHY discovery and setup
This patch adds glue-code that allows the EMAC driver to interface with the existing dt-supported PHYs in drivers/net/phy. Because currently, the emac driver maintains a small library of supported phys for in a private phy.c file located in the drivers directory. The support is limited to mostly single ethernet transceiver like the: CIS8201, BCM5248, ET1011C, Marvell 88E1111 and 88E1112, AR8035. However, routers like the Netgear WNDR4700 and Cisco Meraki MX60(W) have a 5-port switch (AR8327N) attached to the EMAC. The switch chip is supported by the qca8k mdio driver, which uses the generic phy library. Another reason is that PHYLIB also supports the BCM54610, which was used for the Western Digital My Book Live. This will now also make EMAC select PHYLIB. Signed-off-by: Christian Lamparter <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ca78d31 commit a577ca6

File tree

3 files changed

+252
-7
lines changed

3 files changed

+252
-7
lines changed

drivers/net/ethernet/ibm/emac/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ config IBM_EMAC
22
tristate "IBM EMAC Ethernet support"
33
depends on PPC_DCR
44
select CRC32
5+
select PHYLIB
56
help
67
This driver supports the IBM EMAC family of Ethernet controllers
78
typically found on 4xx embedded PowerPC chips, but also on the

drivers/net/ethernet/ibm/emac/core.c

Lines changed: 247 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <linux/of_address.h>
4343
#include <linux/of_irq.h>
4444
#include <linux/of_net.h>
45+
#include <linux/of_mdio.h>
4546
#include <linux/slab.h>
4647

4748
#include <asm/processor.h>
@@ -2420,6 +2421,219 @@ static int emac_read_uint_prop(struct device_node *np, const char *name,
24202421
return 0;
24212422
}
24222423

2424+
static void emac_adjust_link(struct net_device *ndev)
2425+
{
2426+
struct emac_instance *dev = netdev_priv(ndev);
2427+
struct phy_device *phy = dev->phy_dev;
2428+
2429+
dev->phy.autoneg = phy->autoneg;
2430+
dev->phy.speed = phy->speed;
2431+
dev->phy.duplex = phy->duplex;
2432+
dev->phy.pause = phy->pause;
2433+
dev->phy.asym_pause = phy->asym_pause;
2434+
dev->phy.advertising = phy->advertising;
2435+
}
2436+
2437+
static int emac_mii_bus_read(struct mii_bus *bus, int addr, int regnum)
2438+
{
2439+
int ret = emac_mdio_read(bus->priv, addr, regnum);
2440+
/* This is a workaround for powered down ports/phys.
2441+
* In the wild, this was seen on the Cisco Meraki MX60(W).
2442+
* This hardware disables ports as part of the handoff
2443+
* procedure. Accessing the ports will lead to errors
2444+
* (-ETIMEDOUT, -EREMOTEIO) that do more harm than good.
2445+
*/
2446+
return ret < 0 ? 0xffff : ret;
2447+
}
2448+
2449+
static int emac_mii_bus_write(struct mii_bus *bus, int addr,
2450+
int regnum, u16 val)
2451+
{
2452+
emac_mdio_write(bus->priv, addr, regnum, val);
2453+
return 0;
2454+
}
2455+
2456+
static int emac_mii_bus_reset(struct mii_bus *bus)
2457+
{
2458+
struct emac_instance *dev = netdev_priv(bus->priv);
2459+
2460+
return emac_reset(dev);
2461+
}
2462+
2463+
static int emac_mdio_setup_aneg(struct mii_phy *phy, u32 advertise)
2464+
{
2465+
struct net_device *ndev = phy->dev;
2466+
struct emac_instance *dev = netdev_priv(ndev);
2467+
2468+
dev->phy.autoneg = AUTONEG_ENABLE;
2469+
dev->phy.speed = SPEED_1000;
2470+
dev->phy.duplex = DUPLEX_FULL;
2471+
dev->phy.advertising = advertise;
2472+
phy->autoneg = AUTONEG_ENABLE;
2473+
phy->speed = dev->phy.speed;
2474+
phy->duplex = dev->phy.duplex;
2475+
phy->advertising = advertise;
2476+
return phy_start_aneg(dev->phy_dev);
2477+
}
2478+
2479+
static int emac_mdio_setup_forced(struct mii_phy *phy, int speed, int fd)
2480+
{
2481+
struct net_device *ndev = phy->dev;
2482+
struct emac_instance *dev = netdev_priv(ndev);
2483+
2484+
dev->phy.autoneg = AUTONEG_DISABLE;
2485+
dev->phy.speed = speed;
2486+
dev->phy.duplex = fd;
2487+
phy->autoneg = AUTONEG_DISABLE;
2488+
phy->speed = speed;
2489+
phy->duplex = fd;
2490+
return phy_start_aneg(dev->phy_dev);
2491+
}
2492+
2493+
static int emac_mdio_poll_link(struct mii_phy *phy)
2494+
{
2495+
struct net_device *ndev = phy->dev;
2496+
struct emac_instance *dev = netdev_priv(ndev);
2497+
int res;
2498+
2499+
res = phy_read_status(dev->phy_dev);
2500+
if (res) {
2501+
dev_err(&dev->ofdev->dev, "link update failed (%d).", res);
2502+
return ethtool_op_get_link(ndev);
2503+
}
2504+
2505+
return dev->phy_dev->link;
2506+
}
2507+
2508+
static int emac_mdio_read_link(struct mii_phy *phy)
2509+
{
2510+
struct net_device *ndev = phy->dev;
2511+
struct emac_instance *dev = netdev_priv(ndev);
2512+
int res;
2513+
2514+
res = phy_read_status(dev->phy_dev);
2515+
if (res)
2516+
return res;
2517+
2518+
dev->phy.speed = phy->speed;
2519+
dev->phy.duplex = phy->duplex;
2520+
dev->phy.pause = phy->pause;
2521+
dev->phy.asym_pause = phy->asym_pause;
2522+
return 0;
2523+
}
2524+
2525+
static int emac_mdio_init_phy(struct mii_phy *phy)
2526+
{
2527+
struct net_device *ndev = phy->dev;
2528+
struct emac_instance *dev = netdev_priv(ndev);
2529+
2530+
phy_start(dev->phy_dev);
2531+
dev->phy.autoneg = phy->autoneg;
2532+
dev->phy.speed = phy->speed;
2533+
dev->phy.duplex = phy->duplex;
2534+
dev->phy.advertising = phy->advertising;
2535+
dev->phy.pause = phy->pause;
2536+
dev->phy.asym_pause = phy->asym_pause;
2537+
2538+
return phy_init_hw(dev->phy_dev);
2539+
}
2540+
2541+
static const struct mii_phy_ops emac_dt_mdio_phy_ops = {
2542+
.init = emac_mdio_init_phy,
2543+
.setup_aneg = emac_mdio_setup_aneg,
2544+
.setup_forced = emac_mdio_setup_forced,
2545+
.poll_link = emac_mdio_poll_link,
2546+
.read_link = emac_mdio_read_link,
2547+
};
2548+
2549+
static int emac_dt_mdio_probe(struct emac_instance *dev)
2550+
{
2551+
struct device_node *mii_np;
2552+
int res;
2553+
2554+
mii_np = of_get_child_by_name(dev->ofdev->dev.of_node, "mdio");
2555+
if (!mii_np) {
2556+
dev_err(&dev->ofdev->dev, "no mdio definition found.");
2557+
return -ENODEV;
2558+
}
2559+
2560+
if (!of_device_is_available(mii_np)) {
2561+
res = -ENODEV;
2562+
goto put_node;
2563+
}
2564+
2565+
dev->mii_bus = devm_mdiobus_alloc(&dev->ofdev->dev);
2566+
if (!dev->mii_bus) {
2567+
res = -ENOMEM;
2568+
goto put_node;
2569+
}
2570+
2571+
dev->mii_bus->priv = dev->ndev;
2572+
dev->mii_bus->parent = dev->ndev->dev.parent;
2573+
dev->mii_bus->name = "emac_mdio";
2574+
dev->mii_bus->read = &emac_mii_bus_read;
2575+
dev->mii_bus->write = &emac_mii_bus_write;
2576+
dev->mii_bus->reset = &emac_mii_bus_reset;
2577+
snprintf(dev->mii_bus->id, MII_BUS_ID_SIZE, "%s", dev->ofdev->name);
2578+
res = of_mdiobus_register(dev->mii_bus, mii_np);
2579+
if (res) {
2580+
dev_err(&dev->ofdev->dev, "cannot register MDIO bus %s (%d)",
2581+
dev->mii_bus->name, res);
2582+
}
2583+
2584+
put_node:
2585+
of_node_put(mii_np);
2586+
return res;
2587+
}
2588+
2589+
static int emac_dt_phy_connect(struct emac_instance *dev,
2590+
struct device_node *phy_handle)
2591+
{
2592+
int res;
2593+
2594+
dev->phy.def = devm_kzalloc(&dev->ofdev->dev, sizeof(*dev->phy.def),
2595+
GFP_KERNEL);
2596+
if (!dev->phy.def)
2597+
return -ENOMEM;
2598+
2599+
dev->phy_dev = of_phy_connect(dev->ndev, phy_handle, &emac_adjust_link,
2600+
0, dev->phy_mode);
2601+
if (!dev->phy_dev) {
2602+
dev_err(&dev->ofdev->dev, "failed to connect to PHY.\n");
2603+
return -ENODEV;
2604+
}
2605+
2606+
dev->phy.def->phy_id = dev->phy_dev->drv->phy_id;
2607+
dev->phy.def->phy_id_mask = dev->phy_dev->drv->phy_id_mask;
2608+
dev->phy.def->name = dev->phy_dev->drv->name;
2609+
dev->phy.def->ops = &emac_dt_mdio_phy_ops;
2610+
dev->phy.features = dev->phy_dev->supported;
2611+
dev->phy.address = dev->phy_dev->mdio.addr;
2612+
dev->phy.mode = dev->phy_dev->interface;
2613+
return 0;
2614+
}
2615+
2616+
static int emac_dt_phy_probe(struct emac_instance *dev)
2617+
{
2618+
struct device_node *np = dev->ofdev->dev.of_node;
2619+
struct device_node *phy_handle;
2620+
int res = 0;
2621+
2622+
phy_handle = of_parse_phandle(np, "phy-handle", 0);
2623+
2624+
if (phy_handle) {
2625+
res = emac_dt_mdio_probe(dev);
2626+
if (!res) {
2627+
res = emac_dt_phy_connect(dev, phy_handle);
2628+
if (res)
2629+
mdiobus_unregister(dev->mii_bus);
2630+
}
2631+
}
2632+
2633+
of_node_put(phy_handle);
2634+
return res;
2635+
}
2636+
24232637
static int emac_init_phy(struct emac_instance *dev)
24242638
{
24252639
struct device_node *np = dev->ofdev->dev.of_node;
@@ -2430,15 +2644,12 @@ static int emac_init_phy(struct emac_instance *dev)
24302644
dev->phy.dev = ndev;
24312645
dev->phy.mode = dev->phy_mode;
24322646

2433-
/* PHY-less configuration.
2434-
* XXX I probably should move these settings to the dev tree
2435-
*/
2436-
if (dev->phy_address == 0xffffffff && dev->phy_map == 0xffffffff) {
2647+
/* PHY-less configuration. */
2648+
if ((dev->phy_address == 0xffffffff && dev->phy_map == 0xffffffff) ||
2649+
of_phy_is_fixed_link(np)) {
24372650
emac_reset(dev);
24382651

2439-
/* PHY-less configuration.
2440-
* XXX I probably should move these settings to the dev tree
2441-
*/
2652+
/* PHY-less configuration. */
24422653
dev->phy.address = -1;
24432654
dev->phy.features = SUPPORTED_MII;
24442655
if (emac_phy_supports_gige(dev->phy_mode))
@@ -2447,6 +2658,16 @@ static int emac_init_phy(struct emac_instance *dev)
24472658
dev->phy.features |= SUPPORTED_100baseT_Full;
24482659
dev->phy.pause = 1;
24492660

2661+
if (of_phy_is_fixed_link(np)) {
2662+
int res = emac_dt_mdio_probe(dev);
2663+
2664+
if (!res) {
2665+
res = of_phy_register_fixed_link(np);
2666+
if (res)
2667+
mdiobus_unregister(dev->mii_bus);
2668+
}
2669+
return res;
2670+
}
24502671
return 0;
24512672
}
24522673

@@ -2490,6 +2711,18 @@ static int emac_init_phy(struct emac_instance *dev)
24902711

24912712
emac_configure(dev);
24922713

2714+
if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) {
2715+
int res = emac_dt_phy_probe(dev);
2716+
2717+
mutex_unlock(&emac_phy_map_lock);
2718+
if (!res)
2719+
goto init_phy;
2720+
2721+
dev_err(&dev->ofdev->dev, "failed to attach dt phy (%d).\n",
2722+
res);
2723+
return res;
2724+
}
2725+
24932726
if (dev->phy_address != 0xffffffff)
24942727
phy_map = ~(1 << dev->phy_address);
24952728

@@ -2517,6 +2750,7 @@ static int emac_init_phy(struct emac_instance *dev)
25172750
return -ENXIO;
25182751
}
25192752

2753+
init_phy:
25202754
/* Init PHY */
25212755
if (dev->phy.def->ops->init)
25222756
dev->phy.def->ops->init(&dev->phy);
@@ -2988,6 +3222,12 @@ static int emac_remove(struct platform_device *ofdev)
29883222
if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
29893223
zmii_detach(dev->zmii_dev, dev->zmii_port);
29903224

3225+
if (dev->phy_dev)
3226+
phy_disconnect(dev->phy_dev);
3227+
3228+
if (dev->mii_bus)
3229+
mdiobus_unregister(dev->mii_bus);
3230+
29913231
busy_phy_map &= ~(1 << dev->phy.address);
29923232
DBG(dev, "busy_phy_map now %#x" NL, busy_phy_map);
29933233

drivers/net/ethernet/ibm/emac/core.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ struct emac_instance {
199199
struct emac_instance *mdio_instance;
200200
struct mutex mdio_lock;
201201

202+
/* Device-tree based phy configuration */
203+
struct mii_bus *mii_bus;
204+
struct phy_device *phy_dev;
205+
202206
/* ZMII infos if any */
203207
u32 zmii_ph;
204208
u32 zmii_port;

0 commit comments

Comments
 (0)