fixup! net: cirrus: add DT support for Cirrus EP93xx ep93xx/v6.3-rc6-v1-wip2
authorNikita Shubin <nikita.shubin@maquefel.me>
Tue, 2 May 2023 11:57:04 +0000 (14:57 +0300)
committerNikita Shubin <nikita.shubin@maquefel.me>
Tue, 2 May 2023 11:57:04 +0000 (14:57 +0300)
drivers/net/ethernet/cirrus/ep93xx_eth.c

index b156cc75daad6c4d7f03f418b53f73e879674aa0..ec3d15c9a3c3f5121e6b9214099b198630688c84 100644 (file)
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
-#include <linux/mii.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_platform.h>
+#include <linux/of_mdio.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/phy.h>
 
 #include <linux/platform_data/eth-ep93xx.h>
 
@@ -172,7 +174,11 @@ struct ep93xx_priv
        struct net_device       *dev;
        struct napi_struct      napi;
 
-       struct mii_if_info      mii;
+       struct phy_device *phy_dev;
+       struct device_node *phy_node;
+
+       struct mii_bus *mii_bus;
+
        u8                      mdc_divisor;
 };
 
@@ -183,9 +189,9 @@ struct ep93xx_priv
 #define wrw(ep, off, val)      __raw_writew((val), (ep)->base_addr + (off))
 #define wrl(ep, off, val)      __raw_writel((val), (ep)->base_addr + (off))
 
-static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg)
+static int ep93xx_mdio_read(struct mii_bus *bus, int phy_id, int reg)
 {
-       struct ep93xx_priv *ep = netdev_priv(dev);
+       struct ep93xx_priv *ep = bus->priv;
        int data;
        int i;
 
@@ -207,9 +213,9 @@ static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg)
        return data;
 }
 
-static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data)
+static int ep93xx_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
 {
-       struct ep93xx_priv *ep = netdev_priv(dev);
+       struct ep93xx_priv *ep = bus->priv;
        int i;
 
        wrl(ep, REG_MIIDATA, data);
@@ -221,8 +227,12 @@ static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int d
                msleep(1);
        }
 
-       if (i == 10)
+       if (i == 10) {
                pr_info("mdio write timed out\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
 }
 
 static int ep93xx_rx(struct net_device *dev, int budget)
@@ -551,7 +561,7 @@ static int ep93xx_start_hw(struct net_device *dev)
        wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9));
 
        /* Does the PHY support preamble suppress?  */
-       if ((ep93xx_mdio_read(dev, ep->mii.phy_id, MII_BMSR) & 0x0040) != 0)
+       if ((phy_read(ep->phy_dev, MII_BMSR) & 0x0040) != 0)
                wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9) | (1 << 8));
 
        /* Receive descriptor ring.  */
@@ -683,10 +693,17 @@ static int ep93xx_close(struct net_device *dev)
 
 static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-       struct ep93xx_priv *ep = netdev_priv(dev);
-       struct mii_ioctl_data *data = if_mii(ifr);
-
-       return generic_mii_ioctl(&ep->mii, data, cmd, NULL);
+       if (!dev->phydev || !netif_running(dev))
+               return -EINVAL;
+
+       switch (cmd) {
+       case SIOCGMIIPHY:
+       case SIOCGMIIREG:
+       case SIOCSMIIREG:
+               return phy_mii_ioctl(dev->phydev, ifr, cmd);
+       default:
+               return -EOPNOTSUPP;
+       }
 }
 
 static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
@@ -694,41 +711,11 @@ static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
        strscpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
 }
 
-static int ep93xx_get_link_ksettings(struct net_device *dev,
-                                    struct ethtool_link_ksettings *cmd)
-{
-       struct ep93xx_priv *ep = netdev_priv(dev);
-
-       mii_ethtool_get_link_ksettings(&ep->mii, cmd);
-
-       return 0;
-}
-
-static int ep93xx_set_link_ksettings(struct net_device *dev,
-                                    const struct ethtool_link_ksettings *cmd)
-{
-       struct ep93xx_priv *ep = netdev_priv(dev);
-       return mii_ethtool_set_link_ksettings(&ep->mii, cmd);
-}
-
-static int ep93xx_nway_reset(struct net_device *dev)
-{
-       struct ep93xx_priv *ep = netdev_priv(dev);
-       return mii_nway_restart(&ep->mii);
-}
-
-static u32 ep93xx_get_link(struct net_device *dev)
-{
-       struct ep93xx_priv *ep = netdev_priv(dev);
-       return mii_link_ok(&ep->mii);
-}
-
 static const struct ethtool_ops ep93xx_ethtool_ops = {
        .get_drvinfo            = ep93xx_get_drvinfo,
-       .nway_reset             = ep93xx_nway_reset,
-       .get_link               = ep93xx_get_link,
-       .get_link_ksettings     = ep93xx_get_link_ksettings,
-       .set_link_ksettings     = ep93xx_set_link_ksettings,
+       .get_link               = ethtool_op_get_link,
+       .get_link_ksettings     = phy_ethtool_get_link_ksettings,
+       .set_link_ksettings     = phy_ethtool_set_link_ksettings,
 };
 
 static const struct net_device_ops ep93xx_netdev_ops = {
@@ -758,6 +745,76 @@ static struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data)
        return dev;
 }
 
+static int ep93xx_mdio_setup(struct ep93xx_priv *ep, struct device *dev)
+{
+       struct mii_bus *bus;
+       struct resource res;
+       struct device_node *np = of_get_parent(ep->phy_node);
+       struct device_node *npp;
+       int rc, ret;
+
+       /* Don't register the MDIO bus if the phy_node or its parent node
+        * can't be found.
+        */
+       if (!np) {
+               dev_err(dev, "Failed to register mdio bus.\n");
+               return -ENODEV;
+       }
+
+       npp = of_get_parent(np);
+       ret = of_address_to_resource(npp, 0, &res);
+       of_node_put(npp);
+       if (ret) {
+               dev_err(dev, "%s resource error!\n",
+                       dev->of_node->full_name);
+               of_node_put(np);
+               return ret;
+       }
+
+       if (ep->dev->mem_start != res.start) {
+               struct phy_device *phydev;
+
+               phydev = of_phy_find_device(ep->phy_node);
+               if (!phydev)
+                       dev_info(dev,
+                                "MDIO of the phy is not registered yet\n");
+               else
+                       put_device(&phydev->mdio.dev);
+               of_node_put(np);
+               return 0;
+       }
+
+       bus = mdiobus_alloc();
+       if (!bus) {
+               dev_err(dev, "Failed to allocate mdiobus\n");
+               of_node_put(np);
+               return -ENOMEM;
+       }
+
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
+                (unsigned long long)res.start);
+       bus->priv = ep;
+       bus->name = "Cirrus ep93xx MDIO";
+       bus->read = ep93xx_mdio_read;
+       bus->write = ep93xx_mdio_write;
+       bus->parent = dev;
+
+       rc = of_mdiobus_register(bus, np);
+       of_node_put(np);
+       if (rc) {
+               dev_err(dev, "Failed to register mdio bus.\n");
+               goto err_register;
+       }
+
+       ep->mii_bus = bus;
+
+       return 0;
+
+err_register:
+       mdiobus_free(bus);
+       return rc;      
+
+}
 
 static int ep93xx_eth_remove(struct platform_device *pdev)
 {
@@ -823,10 +880,8 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
                        if (!data)
                                return -ENOMEM;
 
-                       if (of_property_read_bool(np, "copy_addr")) {
-                               memcpy_fromio(data->dev_addr, base_addr + 0x50, 6);
-                               dev_info(&pdev->dev, "MAC=%pM\n", data->dev_addr);
-                       }
+                       memcpy_fromio(data->dev_addr, base_addr + 0x50, 6);
+                       dev_info(&pdev->dev, "MAC=%pM\n", data->dev_addr);
 
                        if (of_property_read_u32(np, "phy_id", &phy_id)) {
                                dev_err(&pdev->dev, "Failed to parse \"phy_id\"\n");
@@ -862,13 +917,8 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
 
        ep->base_addr = base_addr;
        ep->irq = irq;
-
-       ep->mii.phy_id = data->phy_id;
-       ep->mii.phy_id_mask = 0x1f;
-       ep->mii.reg_num_mask = 0x1f;
-       ep->mii.dev = dev;
-       ep->mii.mdio_read = ep93xx_mdio_read;
-       ep->mii.mdio_write = ep93xx_mdio_write;
+       ep->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
+       ep93xx_mdio_setup(ep, &pdev->dev);
        ep->mdc_divisor = 40;   /* Max HCLK 100 MHz, min MDIO clk 2.5 MHz.  */
 
        if (is_zero_ether_addr(dev->dev_addr))