]> git.sur5r.net Git - u-boot/blobdiff - drivers/net/designware.c
net: designware: Add reset ctrl to driver
[u-boot] / drivers / net / designware.c
index e207bc63b837fbc60db485642f49613bd8f6b1f9..19db0a8114ae8bc0c37766f294486ea64980ad0b 100644 (file)
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2010
  * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 /*
  */
 
 #include <common.h>
+#include <clk.h>
 #include <dm.h>
 #include <errno.h>
 #include <miiphy.h>
 #include <malloc.h>
 #include <pci.h>
+#include <reset.h>
 #include <linux/compiler.h>
 #include <linux/err.h>
+#include <linux/kernel.h>
 #include <asm/io.h>
+#include <power/regulator.h>
 #include "designware.h"
 
-DECLARE_GLOBAL_DATA_PTR;
-
 static int dw_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
 {
 #ifdef CONFIG_DM_ETH
@@ -280,6 +281,15 @@ int designware_eth_init(struct dw_eth_dev *priv, u8 *enetaddr)
 
        writel(readl(&dma_p->busmode) | DMAMAC_SRST, &dma_p->busmode);
 
+       /*
+        * When a MII PHY is used, we must set the PS bit for the DMA
+        * reset to succeed.
+        */
+       if (priv->phydev->interface == PHY_INTERFACE_MODE_MII)
+               writel(readl(&mac_p->conf) | MII_PORTSELECT, &mac_p->conf);
+       else
+               writel(readl(&mac_p->conf) & ~MII_PORTSELECT, &mac_p->conf);
+
        start = get_timer(0);
        while (readl(&dma_p->busmode) & DMAMAC_SRST) {
                if (get_timer(start) >= CONFIG_MACRESET_TIMEOUT) {
@@ -342,6 +352,8 @@ int designware_eth_enable(struct dw_eth_dev *priv)
        return 0;
 }
 
+#define ETH_ZLEN       60
+
 static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length)
 {
        struct eth_dma_regs *dma_p = priv->dma_regs_p;
@@ -368,6 +380,8 @@ static int _dw_eth_send(struct dw_eth_dev *priv, void *packet, int length)
                return -EPERM;
        }
 
+       length = max(length, ETH_ZLEN);
+
        memcpy((void *)data_start, packet, length);
 
        /* Flush data to be sent */
@@ -660,6 +674,58 @@ int designware_eth_probe(struct udevice *dev)
        u32 iobase = pdata->iobase;
        ulong ioaddr;
        int ret;
+       struct reset_ctl_bulk reset_bulk;
+#ifdef CONFIG_CLK
+       int i, err, clock_nb;
+
+       priv->clock_count = 0;
+       clock_nb = dev_count_phandle_with_args(dev, "clocks", "#clock-cells");
+       if (clock_nb > 0) {
+               priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk),
+                                           GFP_KERNEL);
+               if (!priv->clocks)
+                       return -ENOMEM;
+
+               for (i = 0; i < clock_nb; i++) {
+                       err = clk_get_by_index(dev, i, &priv->clocks[i]);
+                       if (err < 0)
+                               break;
+
+                       err = clk_enable(&priv->clocks[i]);
+                       if (err && err != -ENOSYS && err != -ENOTSUPP) {
+                               pr_err("failed to enable clock %d\n", i);
+                               clk_free(&priv->clocks[i]);
+                               goto clk_err;
+                       }
+                       priv->clock_count++;
+               }
+       } else if (clock_nb != -ENOENT) {
+               pr_err("failed to get clock phandle(%d)\n", clock_nb);
+               return clock_nb;
+       }
+#endif
+
+#if defined(CONFIG_DM_REGULATOR)
+       struct udevice *phy_supply;
+
+       ret = device_get_supply_regulator(dev, "phy-supply",
+                                         &phy_supply);
+       if (ret) {
+               debug("%s: No phy supply\n", dev->name);
+       } else {
+               ret = regulator_set_enable(phy_supply, true);
+               if (ret) {
+                       puts("Error enabling phy supply\n");
+                       return ret;
+               }
+       }
+#endif
+
+       ret = reset_get_bulk(dev, &reset_bulk);
+       if (ret)
+               dev_warn(dev, "Can't get reset: %d\n", ret);
+       else
+               reset_deassert_bulk(&reset_bulk);
 
 #ifdef CONFIG_DM_PCI
        /*
@@ -690,6 +756,15 @@ int designware_eth_probe(struct udevice *dev)
        debug("%s, ret=%d\n", __func__, ret);
 
        return ret;
+
+#ifdef CONFIG_CLK
+clk_err:
+       ret = clk_release_all(priv->clocks, priv->clock_count);
+       if (ret)
+               pr_err("failed to disable all clocks\n");
+
+       return err;
+#endif
 }
 
 static int designware_eth_remove(struct udevice *dev)
@@ -700,7 +775,11 @@ static int designware_eth_remove(struct udevice *dev)
        mdio_unregister(priv->bus);
        mdio_free(priv->bus);
 
+#ifdef CONFIG_CLK
+       return clk_release_all(priv->clocks, priv->clock_count);
+#else
        return 0;
+#endif
 }
 
 const struct eth_ops designware_eth_ops = {
@@ -720,15 +799,14 @@ int designware_eth_ofdata_to_platdata(struct udevice *dev)
 #endif
        struct eth_pdata *pdata = &dw_pdata->eth_pdata;
        const char *phy_mode;
-       const fdt32_t *cell;
 #ifdef CONFIG_DM_GPIO
        int reset_flags = GPIOD_IS_OUT;
 #endif
        int ret = 0;
 
-       pdata->iobase = dev_get_addr(dev);
+       pdata->iobase = dev_read_addr(dev);
        pdata->phy_interface = -1;
-       phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
+       phy_mode = dev_read_string(dev, "phy-mode");
        if (phy_mode)
                pdata->phy_interface = phy_get_interface_by_name(phy_mode);
        if (pdata->phy_interface == -1) {
@@ -736,21 +814,17 @@ int designware_eth_ofdata_to_platdata(struct udevice *dev)
                return -EINVAL;
        }
 
-       pdata->max_speed = 0;
-       cell = fdt_getprop(gd->fdt_blob, dev->of_offset, "max-speed", NULL);
-       if (cell)
-               pdata->max_speed = fdt32_to_cpu(*cell);
+       pdata->max_speed = dev_read_u32_default(dev, "max-speed", 0);
 
 #ifdef CONFIG_DM_GPIO
-       if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset,
-                           "snps,reset-active-low"))
+       if (dev_read_bool(dev, "snps,reset-active-low"))
                reset_flags |= GPIOD_ACTIVE_LOW;
 
        ret = gpio_request_by_name(dev, "snps,reset-gpio", 0,
                &priv->reset_gpio, reset_flags);
        if (ret == 0) {
-               ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
-                       "snps,reset-delays-us", dw_pdata->reset_delays, 3);
+               ret = dev_read_u32_array(dev, "snps,reset-delays-us",
+                                        dw_pdata->reset_delays, 3);
        } else if (ret == -ENOENT) {
                ret = 0;
        }
@@ -763,6 +837,7 @@ static const struct udevice_id designware_eth_ids[] = {
        { .compatible = "allwinner,sun7i-a20-gmac" },
        { .compatible = "altr,socfpga-stmmac" },
        { .compatible = "amlogic,meson6-dwmac" },
+       { .compatible = "amlogic,meson-gx-dwmac" },
        { .compatible = "st,stm32-dwmac" },
        { }
 };