+// 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
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) {
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;
}
memcpy((void *)data_start, packet, length);
+ if (length < ETH_ZLEN) {
+ memset(&((char *)data_start)[length], 0, ETH_ZLEN - length);
+ length = ETH_ZLEN;
+ }
/* Flush data to be sent */
flush_dcache_range(data_start, data_end);
#if defined(CONFIG_DW_ALTDESCRIPTOR)
desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST;
- desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) &
- DESC_TXCTRL_SIZE1MASK;
+ desc_p->dmamac_cntl = (desc_p->dmamac_cntl & ~DESC_TXCTRL_SIZE1MASK) |
+ ((length << DESC_TXCTRL_SIZE1SHFT) &
+ DESC_TXCTRL_SIZE1MASK);
desc_p->txrx_status &= ~(DESC_TXSTS_MSK);
desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA;
#else
- desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) &
- DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST |
- DESC_TXCTRL_TXFIRST;
+ desc_p->dmamac_cntl = (desc_p->dmamac_cntl & ~DESC_TXCTRL_SIZE1MASK) |
+ ((length << DESC_TXCTRL_SIZE1SHFT) &
+ DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST |
+ DESC_TXCTRL_TXFIRST;
desc_p->txrx_status = DESC_TXSTS_OWNBYDMA;
#endif
static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
{
struct phy_device *phydev;
- int mask = 0xffffffff, ret;
+ int phy_addr = -1, ret;
#ifdef CONFIG_PHY_ADDR
- mask = 1 << CONFIG_PHY_ADDR;
+ phy_addr = CONFIG_PHY_ADDR;
#endif
- phydev = phy_find_by_mask(priv->bus, mask, priv->interface);
+ phydev = phy_connect(priv->bus, phy_addr, dev, priv->interface);
if (!phydev)
return -ENODEV;
- phy_connect_dev(phydev, dev);
-
phydev->supported &= PHY_GBIT_FEATURES;
if (priv->max_speed) {
ret = phy_set_supported(phydev, priv->max_speed);
struct dw_eth_dev *priv = dev_get_priv(dev);
u32 iobase = pdata->iobase;
ulong ioaddr;
- int ret;
+ int ret, err;
+ struct reset_ctl_bulk reset_bulk;
+#ifdef CONFIG_CLK
+ int i, 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
/*
priv->interface = pdata->phy_interface;
priv->max_speed = pdata->max_speed;
- dw_mdio_init(dev->name, dev);
+ ret = dw_mdio_init(dev->name, dev);
+ if (ret) {
+ err = ret;
+ goto mdio_err;
+ }
priv->bus = miiphy_get_dev_by_name(dev->name);
ret = dw_phy_init(priv, dev);
debug("%s, ret=%d\n", __func__, ret);
+ if (!ret)
+ return 0;
- return ret;
+ /* continue here for cleanup if no PHY found */
+ err = ret;
+ mdio_unregister(priv->bus);
+ mdio_free(priv->bus);
+mdio_err:
+
+#ifdef CONFIG_CLK
+clk_err:
+ ret = clk_release_all(priv->clocks, priv->clock_count);
+ if (ret)
+ pr_err("failed to disable all clocks\n");
+
+#endif
+ return err;
}
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 = {
#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) {
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;
}
{ .compatible = "allwinner,sun7i-a20-gmac" },
{ .compatible = "altr,socfpga-stmmac" },
{ .compatible = "amlogic,meson6-dwmac" },
+ { .compatible = "amlogic,meson-gx-dwmac" },
+ { .compatible = "amlogic,meson-gxbb-dwmac" },
+ { .compatible = "amlogic,meson-axg-dwmac" },
+ { .compatible = "st,stm32-dwmac" },
{ }
};