From: Moritz Fischer <m...@kernel.org>

This allows 'fixed-link' direct MAC connections to be declared
in devicetree.

Signed-off-by: Moritz Fischer <m...@kernel.org>
Cc: Nicolas Ferre <nicolas.fe...@microchip.com>
---
 drivers/net/ethernet/cadence/macb.c | 61 ++++++++++++++++++++++++++++++++++---
 drivers/net/ethernet/cadence/macb.h |  1 +
 2 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/cadence/macb.c 
b/drivers/net/ethernet/cadence/macb.c
index 30606b1..af443a8 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -469,6 +469,34 @@ static int macb_mii_probe(struct net_device *dev)
        return 0;
 }
 
+static int macb_fixed_init(struct macb *bp)
+{
+       struct phy_device *phydev;
+
+       phydev = of_phy_connect(bp->dev, bp->phy_node,
+                               &macb_handle_link_change, 0,
+                               bp->phy_interface);
+       if (!phydev)
+               return -ENODEV;
+
+       /* mask with MAC supported features */
+       if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)
+               phydev->supported &= PHY_GBIT_FEATURES;
+       else
+               phydev->supported &= PHY_BASIC_FEATURES;
+
+       if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF)
+               phydev->supported &= ~SUPPORTED_1000baseT_Half;
+
+       phydev->advertising = phydev->supported;
+
+       bp->link = 0;
+       bp->speed = 0;
+       bp->duplex = -1;
+
+       return 0;
+}
+
 static int macb_mii_init(struct macb *bp)
 {
        struct macb_platform_data *pdata;
@@ -3245,6 +3273,7 @@ static int macb_probe(struct platform_device *pdev)
        const char *mac;
        struct macb *bp;
        int err;
+       bool fixed_link = false;
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        mem = devm_ioremap_resource(&pdev->dev, regs);
@@ -3342,8 +3371,18 @@ static int macb_probe(struct platform_device *pdev)
                macb_get_hwaddr(bp);
 
        /* Power up the PHY if there is a GPIO reset */
-       phy_node =  of_get_next_available_child(np, NULL);
-       if (phy_node) {
+       phy_node = of_parse_phandle(np, "phy-handle", 0);
+       if (!phy_node && of_phy_is_fixed_link(np)) {
+               err = of_phy_register_fixed_link(np);
+               if (err < 0) {
+                       dev_err(&pdev->dev, "broken fixed-link specification");
+                       goto failed_phy;
+               }
+               /* in case of a fixed PHY, the DT node is the ethernet MAC */
+               phy_node = of_node_get(np);
+               bp->phy_node = phy_node;
+               fixed_link = true;
+       } else {
                int gpio = of_get_named_gpio(phy_node, "reset-gpios", 0);
 
                if (gpio_is_valid(gpio)) {
@@ -3369,7 +3408,10 @@ static int macb_probe(struct platform_device *pdev)
        if (err)
                goto err_out_free_netdev;
 
-       err = macb_mii_init(bp);
+       if (!fixed_link)
+               err = macb_mii_init(bp);
+       else
+               err = macb_fixed_init(bp);
        if (err)
                goto err_out_free_netdev;
 
@@ -3400,6 +3442,9 @@ static int macb_probe(struct platform_device *pdev)
        if (bp->reset_gpio)
                gpiod_set_value(bp->reset_gpio, 0);
 
+failed_phy:
+       of_node_put(phy_node);
+
 err_out_free_netdev:
        free_netdev(dev);
 
@@ -3423,9 +3468,14 @@ static int macb_remove(struct platform_device *pdev)
                bp = netdev_priv(dev);
                if (dev->phydev)
                        phy_disconnect(dev->phydev);
-               mdiobus_unregister(bp->mii_bus);
+
+               if (!bp->phy_node)
+                       mdiobus_unregister(bp->mii_bus);
+
                dev->phydev = NULL;
-               mdiobus_free(bp->mii_bus);
+
+               if (!bp->phy_node)
+                       mdiobus_free(bp->mii_bus);
 
                /* Shutdown the PHY if there is a GPIO reset */
                if (bp->reset_gpio)
@@ -3435,6 +3485,7 @@ static int macb_remove(struct platform_device *pdev)
                clk_disable_unprepare(bp->tx_clk);
                clk_disable_unprepare(bp->hclk);
                clk_disable_unprepare(bp->pclk);
+               of_node_put(bp->phy_node);
                clk_disable_unprepare(bp->rx_clk);
                free_netdev(dev);
        }
diff --git a/drivers/net/ethernet/cadence/macb.h 
b/drivers/net/ethernet/cadence/macb.h
index 234a49e..d9a9b6f 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -931,6 +931,7 @@ struct macb {
        struct macb_or_gem_ops  macbgem_ops;
 
        struct mii_bus          *mii_bus;
+       struct device_node      *phy_node;
        int                     link;
        int                     speed;
        int                     duplex;
-- 
2.7.4

Reply via email to