net: eqos: implement callbaks to get interface and set txclk rate
[oweals/u-boot.git] / drivers / net / dwc_eth_qos.c
index 455709338cea5d90a51e9db6db78dca7d5e9ee17..e4fc76cc06848d2ad82732499c8f73b3202fb838 100644 (file)
  */
 #include <common.h>
 #include <clk.h>
+#include <cpu_func.h>
 #include <dm.h>
 #include <errno.h>
+#include <malloc.h>
 #include <memalign.h>
 #include <miiphy.h>
 #include <net.h>
 #include <wait_bit.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
+#include <eth_phy.h>
+#ifdef CONFIG_ARCH_IMX8M
+#include <asm/arch/clock.h>
+#include <asm/mach-imx/sys_proto.h>
+#endif
 
 /* Core registers */
 
@@ -78,6 +85,7 @@ struct eqos_mac_regs {
 #define EQOS_MAC_CONFIGURATION_PS                      BIT(15)
 #define EQOS_MAC_CONFIGURATION_FES                     BIT(14)
 #define EQOS_MAC_CONFIGURATION_DM                      BIT(13)
+#define EQOS_MAC_CONFIGURATION_LM                      BIT(12)
 #define EQOS_MAC_CONFIGURATION_TE                      BIT(1)
 #define EQOS_MAC_CONFIGURATION_RE                      BIT(0)
 
@@ -99,11 +107,19 @@ struct eqos_mac_regs {
 #define EQOS_MAC_RXQ_CTRL2_PSRQ0_SHIFT                 0
 #define EQOS_MAC_RXQ_CTRL2_PSRQ0_MASK                  0xff
 
+#define EQOS_MAC_HW_FEATURE0_MMCSEL_SHIFT              8
+#define EQOS_MAC_HW_FEATURE0_HDSEL_SHIFT               2
+#define EQOS_MAC_HW_FEATURE0_GMIISEL_SHIFT             1
+#define EQOS_MAC_HW_FEATURE0_MIISEL_SHIFT              0
+
 #define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_SHIFT          6
 #define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_MASK           0x1f
 #define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_SHIFT          0
 #define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_MASK           0x1f
 
+#define EQOS_MAC_HW_FEATURE3_ASP_SHIFT                 28
+#define EQOS_MAC_HW_FEATURE3_ASP_MASK                  0x3
+
 #define EQOS_MAC_MDIO_ADDRESS_PA_SHIFT                 21
 #define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT                        16
 #define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT                 8
@@ -151,6 +167,8 @@ struct eqos_mtl_regs {
 #define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_MASK          0x3f
 #define EQOS_MTL_RXQ0_OPERATION_MODE_EHFC              BIT(7)
 #define EQOS_MTL_RXQ0_OPERATION_MODE_RSF               BIT(5)
+#define EQOS_MTL_RXQ0_OPERATION_MODE_FEP               BIT(4)
+#define EQOS_MTL_RXQ0_OPERATION_MODE_FUP               BIT(3)
 
 #define EQOS_MTL_RXQ0_DEBUG_PRXQ_SHIFT                 16
 #define EQOS_MTL_RXQ0_DEBUG_PRXQ_MASK                  0x7fff
@@ -304,6 +322,8 @@ struct eqos_priv {
        struct clk clk_slave_bus;
        struct mii_dev *mii;
        struct phy_device *phy;
+       int phyaddr;
+       u32 max_speed;
        void *descs;
        struct eqos_desc *tx_descs;
        struct eqos_desc *rx_descs;
@@ -363,7 +383,7 @@ static void eqos_inval_desc_tegra186(void *desc)
 #endif
 }
 
-static void eqos_inval_desc_stm32(void *desc)
+static void eqos_inval_desc_generic(void *desc)
 {
 #ifndef CONFIG_SYS_NONCACHED_MEMORY
        unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN);
@@ -381,7 +401,7 @@ static void eqos_flush_desc_tegra186(void *desc)
 #endif
 }
 
-static void eqos_flush_desc_stm32(void *desc)
+static void eqos_flush_desc_generic(void *desc)
 {
 #ifndef CONFIG_SYS_NONCACHED_MEMORY
        unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN);
@@ -400,7 +420,7 @@ static void eqos_inval_buffer_tegra186(void *buf, size_t size)
        invalidate_dcache_range(start, end);
 }
 
-static void eqos_inval_buffer_stm32(void *buf, size_t size)
+static void eqos_inval_buffer_generic(void *buf, size_t size)
 {
        unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN);
        unsigned long end = roundup((unsigned long)buf + size,
@@ -414,7 +434,7 @@ static void eqos_flush_buffer_tegra186(void *buf, size_t size)
        flush_cache((unsigned long)buf, size);
 }
 
-static void eqos_flush_buffer_stm32(void *buf, size_t size)
+static void eqos_flush_buffer_generic(void *buf, size_t size)
 {
        unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN);
        unsigned long end = roundup((unsigned long)buf + size,
@@ -517,6 +537,7 @@ static int eqos_mdio_write(struct mii_dev *bus, int mdio_addr, int mdio_devad,
 
 static int eqos_start_clks_tegra186(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
        struct eqos_priv *eqos = dev_get_priv(dev);
        int ret;
 
@@ -557,10 +578,12 @@ static int eqos_start_clks_tegra186(struct udevice *dev)
                pr_err("clk_enable(clk_tx) failed: %d", ret);
                goto err_disable_clk_ptp_ref;
        }
+#endif
 
        debug("%s: OK\n", __func__);
        return 0;
 
+#ifdef CONFIG_CLK
 err_disable_clk_ptp_ref:
        clk_disable(&eqos->clk_ptp_ref);
 err_disable_clk_rx:
@@ -572,10 +595,12 @@ err_disable_clk_slave_bus:
 err:
        debug("%s: FAILED: %d\n", __func__, ret);
        return ret;
+#endif
 }
 
 static int eqos_start_clks_stm32(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
        struct eqos_priv *eqos = dev_get_priv(dev);
        int ret;
 
@@ -606,10 +631,12 @@ static int eqos_start_clks_stm32(struct udevice *dev)
                        goto err_disable_clk_tx;
                }
        }
+#endif
 
        debug("%s: OK\n", __func__);
        return 0;
 
+#ifdef CONFIG_CLK
 err_disable_clk_tx:
        clk_disable(&eqos->clk_tx);
 err_disable_clk_rx:
@@ -619,10 +646,17 @@ err_disable_clk_master_bus:
 err:
        debug("%s: FAILED: %d\n", __func__, ret);
        return ret;
+#endif
+}
+
+static int eqos_start_clks_imx(struct udevice *dev)
+{
+       return 0;
 }
 
 static void eqos_stop_clks_tegra186(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
        struct eqos_priv *eqos = dev_get_priv(dev);
 
        debug("%s(dev=%p):\n", __func__, dev);
@@ -632,12 +666,14 @@ static void eqos_stop_clks_tegra186(struct udevice *dev)
        clk_disable(&eqos->clk_rx);
        clk_disable(&eqos->clk_master_bus);
        clk_disable(&eqos->clk_slave_bus);
+#endif
 
        debug("%s: OK\n", __func__);
 }
 
 static void eqos_stop_clks_stm32(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
        struct eqos_priv *eqos = dev_get_priv(dev);
 
        debug("%s(dev=%p):\n", __func__, dev);
@@ -647,10 +683,16 @@ static void eqos_stop_clks_stm32(struct udevice *dev)
        clk_disable(&eqos->clk_master_bus);
        if (clk_valid(&eqos->clk_ck))
                clk_disable(&eqos->clk_ck);
+#endif
 
        debug("%s: OK\n", __func__);
 }
 
+static void eqos_stop_clks_imx(struct udevice *dev)
+{
+       /* empty */
+}
+
 static int eqos_start_resets_tegra186(struct udevice *dev)
 {
        struct eqos_priv *eqos = dev_get_priv(dev);
@@ -691,6 +733,34 @@ static int eqos_start_resets_tegra186(struct udevice *dev)
 }
 
 static int eqos_start_resets_stm32(struct udevice *dev)
+{
+       struct eqos_priv *eqos = dev_get_priv(dev);
+       int ret;
+
+       debug("%s(dev=%p):\n", __func__, dev);
+       if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) {
+               ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1);
+               if (ret < 0) {
+                       pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d",
+                              ret);
+                       return ret;
+               }
+
+               udelay(2);
+
+               ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0);
+               if (ret < 0) {
+                       pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d",
+                              ret);
+                       return ret;
+               }
+       }
+       debug("%s: OK\n", __func__);
+
+       return 0;
+}
+
+static int eqos_start_resets_imx(struct udevice *dev)
 {
        return 0;
 }
@@ -706,6 +776,23 @@ static int eqos_stop_resets_tegra186(struct udevice *dev)
 }
 
 static int eqos_stop_resets_stm32(struct udevice *dev)
+{
+       struct eqos_priv *eqos = dev_get_priv(dev);
+       int ret;
+
+       if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) {
+               ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1);
+               if (ret < 0) {
+                       pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d",
+                              ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int eqos_stop_resets_imx(struct udevice *dev)
 {
        return 0;
 }
@@ -764,16 +851,38 @@ static int eqos_disable_calibration_tegra186(struct udevice *dev)
 
 static ulong eqos_get_tick_clk_rate_tegra186(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
        struct eqos_priv *eqos = dev_get_priv(dev);
 
        return clk_get_rate(&eqos->clk_slave_bus);
+#else
+       return 0;
+#endif
 }
 
 static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
        struct eqos_priv *eqos = dev_get_priv(dev);
 
        return clk_get_rate(&eqos->clk_master_bus);
+#else
+       return 0;
+#endif
+}
+
+__weak u32 imx_get_eqos_csr_clk(void)
+{
+       return 100 * 1000000;
+}
+__weak int imx_eqos_txclk_set_rate(unsigned long rate)
+{
+       return 0;
+}
+
+static ulong eqos_get_tick_clk_rate_imx(struct udevice *dev)
+{
+       return imx_get_eqos_csr_clk();
 }
 
 static int eqos_calibrate_pads_stm32(struct udevice *dev)
@@ -781,11 +890,21 @@ static int eqos_calibrate_pads_stm32(struct udevice *dev)
        return 0;
 }
 
+static int eqos_calibrate_pads_imx(struct udevice *dev)
+{
+       return 0;
+}
+
 static int eqos_disable_calibration_stm32(struct udevice *dev)
 {
        return 0;
 }
 
+static int eqos_disable_calibration_imx(struct udevice *dev)
+{
+       return 0;
+}
+
 static int eqos_set_full_duplex(struct udevice *dev)
 {
        struct eqos_priv *eqos = dev_get_priv(dev);
@@ -850,6 +969,7 @@ static int eqos_set_mii_speed_10(struct udevice *dev)
 
 static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
        struct eqos_priv *eqos = dev_get_priv(dev);
        ulong rate;
        int ret;
@@ -876,6 +996,7 @@ static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev)
                pr_err("clk_set_rate(tx_clk, %lu) failed: %d", rate, ret);
                return ret;
        }
+#endif
 
        return 0;
 }
@@ -885,6 +1006,38 @@ static int eqos_set_tx_clk_speed_stm32(struct udevice *dev)
        return 0;
 }
 
+static int eqos_set_tx_clk_speed_imx(struct udevice *dev)
+{
+       struct eqos_priv *eqos = dev_get_priv(dev);
+       ulong rate;
+       int ret;
+
+       debug("%s(dev=%p):\n", __func__, dev);
+
+       switch (eqos->phy->speed) {
+       case SPEED_1000:
+               rate = 125 * 1000 * 1000;
+               break;
+       case SPEED_100:
+               rate = 25 * 1000 * 1000;
+               break;
+       case SPEED_10:
+               rate = 2.5 * 1000 * 1000;
+               break;
+       default:
+               pr_err("invalid speed %d", eqos->phy->speed);
+               return -EINVAL;
+       }
+
+       ret = imx_eqos_txclk_set_rate(rate);
+       if (ret < 0) {
+               pr_err("imx (tx_clk, %lu) failed: %d", rate, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int eqos_adjust_link(struct udevice *dev)
 {
        struct eqos_priv *eqos = dev_get_priv(dev);
@@ -1044,12 +1197,28 @@ static int eqos_start(struct udevice *dev)
         * don't need to reconnect/reconfigure again
         */
        if (!eqos->phy) {
-               eqos->phy = phy_connect(eqos->mii, 0, dev,
+               int addr = -1;
+#ifdef CONFIG_DM_ETH_PHY
+               addr = eth_phy_get_addr(dev);
+#endif
+#ifdef DWC_NET_PHYADDR
+               addr = DWC_NET_PHYADDR;
+#endif
+               eqos->phy = phy_connect(eqos->mii, addr, dev,
                                        eqos->config->interface(dev));
                if (!eqos->phy) {
                        pr_err("phy_connect() failed");
                        goto err_stop_resets;
                }
+
+               if (eqos->max_speed) {
+                       ret = phy_set_supported(eqos->phy, eqos->max_speed);
+                       if (ret) {
+                               pr_err("phy_set_supported() failed: %d", ret);
+                               goto err_shutdown_phy;
+                       }
+               }
+
                ret = phy_config(eqos->phy);
                if (ret < 0) {
                        pr_err("phy_config() failed: %d", ret);
@@ -1075,6 +1244,7 @@ static int eqos_start(struct udevice *dev)
        }
 
        /* Configure MTL */
+       writel(0x60, &eqos->mtl_regs->txq0_quantum_weight - 0x100);
 
        /* Enable Store and Forward mode for TX */
        /* Program Tx operating mode */
@@ -1088,7 +1258,9 @@ static int eqos_start(struct udevice *dev)
 
        /* Enable Store and Forward mode for RX, since no jumbo frame */
        setbits_le32(&eqos->mtl_regs->rxq0_operation_mode,
-                    EQOS_MTL_RXQ0_OPERATION_MODE_RSF);
+                    EQOS_MTL_RXQ0_OPERATION_MODE_RSF |
+                    EQOS_MTL_RXQ0_OPERATION_MODE_FEP |
+                    EQOS_MTL_RXQ0_OPERATION_MODE_FUP);
 
        /* Transmit/Receive queue fifo size; use all RAM for 1 queue */
        val = readl(&eqos->mac_regs->hw_feature1);
@@ -1164,6 +1336,19 @@ static int eqos_start(struct udevice *dev)
                        eqos->config->config_mac <<
                        EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT);
 
+       clrsetbits_le32(&eqos->mac_regs->rxq_ctrl0,
+                       EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK <<
+                       EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT,
+                       0x2 <<
+                       EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT);
+
+       /* Multicast and Broadcast Queue Enable */
+       setbits_le32(&eqos->mac_regs->unused_0a4,
+                    0x00100000);
+       /* enable promise mode */
+       setbits_le32(&eqos->mac_regs->unused_004[1],
+                    0x1);
+
        /* Set TX flow control parameters */
        /* Set Pause Time */
        setbits_le32(&eqos->mac_regs->q0_tx_flow_ctrl,
@@ -1240,9 +1425,13 @@ static int eqos_start(struct udevice *dev)
                struct eqos_desc *rx_desc = &(eqos->rx_descs[i]);
                rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf +
                                             (i * EQOS_MAX_PACKET_SIZE));
-               rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
+               rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
+               mb();
+               eqos->config->ops->eqos_flush_desc(rx_desc);
+               eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf +
+                                               (i * EQOS_MAX_PACKET_SIZE),
+                                               EQOS_MAX_PACKET_SIZE);
        }
-       eqos->config->ops->eqos_flush_desc(eqos->descs);
 
        writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress);
        writel((ulong)eqos->tx_descs, &eqos->dma_regs->ch0_txdesc_list_address);
@@ -1255,14 +1444,12 @@ static int eqos_start(struct udevice *dev)
               &eqos->dma_regs->ch0_rxdesc_ring_length);
 
        /* Enable everything */
-
-       setbits_le32(&eqos->mac_regs->configuration,
-                    EQOS_MAC_CONFIGURATION_TE | EQOS_MAC_CONFIGURATION_RE);
-
        setbits_le32(&eqos->dma_regs->ch0_tx_control,
                     EQOS_DMA_CH0_TX_CONTROL_ST);
        setbits_le32(&eqos->dma_regs->ch0_rx_control,
                     EQOS_DMA_CH0_RX_CONTROL_SR);
+       setbits_le32(&eqos->mac_regs->configuration,
+                    EQOS_MAC_CONFIGURATION_TE | EQOS_MAC_CONFIGURATION_RE);
 
        /* TX tail pointer not written until we need to TX a packet */
        /*
@@ -1371,7 +1558,8 @@ static int eqos_send(struct udevice *dev, void *packet, int length)
        tx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_FD | EQOS_DESC3_LD | length;
        eqos->config->ops->eqos_flush_desc(tx_desc);
 
-       writel((ulong)(tx_desc + 1), &eqos->dma_regs->ch0_txdesc_tail_pointer);
+       writel((ulong)(&(eqos->tx_descs[eqos->tx_desc_idx])),
+               &eqos->dma_regs->ch0_txdesc_tail_pointer);
 
        for (i = 0; i < 1000000; i++) {
                eqos->config->ops->eqos_inval_desc(tx_desc);
@@ -1394,6 +1582,7 @@ static int eqos_recv(struct udevice *dev, int flags, uchar **packetp)
        debug("%s(dev=%p, flags=%x):\n", __func__, dev, flags);
 
        rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]);
+       eqos->config->ops->eqos_inval_desc(rx_desc);
        if (rx_desc->des3 & EQOS_DESC3_OWN) {
                debug("%s: RX packet not available\n", __func__);
                return -EAGAIN;
@@ -1425,7 +1614,14 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length)
                return -EINVAL;
        }
 
+       eqos->config->ops->eqos_inval_buffer(packet, length);
+
        rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]);
+
+       rx_desc->des0 = 0;
+       mb();
+       eqos->config->ops->eqos_flush_desc(rx_desc);
+       eqos->config->ops->eqos_inval_buffer(packet, length);
        rx_desc->des0 = (u32)(ulong)packet;
        rx_desc->des1 = 0;
        rx_desc->des2 = 0;
@@ -1434,7 +1630,7 @@ static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length)
         * writes to the rest of the descriptor too.
         */
        mb();
-       rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
+       rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
        eqos->config->ops->eqos_flush_desc(rx_desc);
 
        writel((ulong)rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer);
@@ -1488,6 +1684,9 @@ static int eqos_probe_resources_core(struct udevice *dev)
        }
        debug("%s: rx_pkt=%p\n", __func__, eqos->rx_pkt);
 
+       eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf,
+                       EQOS_MAX_PACKET_SIZE * EQOS_DESCRIPTORS_RX);
+
        debug("%s: OK\n", __func__);
        return 0;
 
@@ -1602,6 +1801,7 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
        struct eqos_priv *eqos = dev_get_priv(dev);
        int ret;
        phy_interface_t interface;
+       struct ofnode_phandle_args phandle_args;
 
        debug("%s(dev=%p):\n", __func__, dev);
 
@@ -1616,6 +1816,8 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
        if (ret)
                return -EINVAL;
 
+       eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0);
+
        ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus);
        if (ret) {
                pr_err("clk_get_by_name(master_bus) failed: %d", ret);
@@ -1639,6 +1841,24 @@ static int eqos_probe_resources_stm32(struct udevice *dev)
        if (ret)
                pr_warn("No phy clock provided %d", ret);
 
+       eqos->phyaddr = -1;
+       ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
+                                        &phandle_args);
+       if (!ret) {
+               /* search "reset-gpios" in phy node */
+               ret = gpio_request_by_name_nodev(phandle_args.node,
+                                                "reset-gpios", 0,
+                                                &eqos->phy_reset_gpio,
+                                                GPIOD_IS_OUT |
+                                                GPIOD_IS_OUT_ACTIVE);
+               if (ret)
+                       pr_warn("gpio_request_by_name(phy reset) not provided %d",
+                               ret);
+
+               eqos->phyaddr = ofnode_read_u32_default(phandle_args.node,
+                                                       "reg", -1);
+       }
+
        debug("%s: OK\n", __func__);
        return 0;
 
@@ -1672,17 +1892,52 @@ static phy_interface_t eqos_get_interface_tegra186(struct udevice *dev)
        return PHY_INTERFACE_MODE_MII;
 }
 
+static int eqos_probe_resources_imx(struct udevice *dev)
+{
+       struct eqos_priv *eqos = dev_get_priv(dev);
+       phy_interface_t interface;
+
+       debug("%s(dev=%p):\n", __func__, dev);
+
+       interface = eqos->config->interface(dev);
+
+       if (interface == PHY_INTERFACE_MODE_NONE) {
+               pr_err("Invalid PHY interface\n");
+               return -EINVAL;
+       }
+
+       debug("%s: OK\n", __func__);
+       return 0;
+}
+
+static phy_interface_t eqos_get_interface_imx(struct udevice *dev)
+{
+       const char *phy_mode;
+       phy_interface_t interface = PHY_INTERFACE_MODE_NONE;
+
+       debug("%s(dev=%p):\n", __func__, dev);
+
+       phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode",
+                              NULL);
+       if (phy_mode)
+               interface = phy_get_interface_by_name(phy_mode);
+
+       return interface;
+}
+
 static int eqos_remove_resources_tegra186(struct udevice *dev)
 {
        struct eqos_priv *eqos = dev_get_priv(dev);
 
        debug("%s(dev=%p):\n", __func__, dev);
 
+#ifdef CONFIG_CLK
        clk_free(&eqos->clk_tx);
        clk_free(&eqos->clk_ptp_ref);
        clk_free(&eqos->clk_rx);
        clk_free(&eqos->clk_slave_bus);
        clk_free(&eqos->clk_master_bus);
+#endif
        dm_gpio_free(dev, &eqos->phy_reset_gpio);
        reset_free(&eqos->reset_ctl);
 
@@ -1692,6 +1947,7 @@ static int eqos_remove_resources_tegra186(struct udevice *dev)
 
 static int eqos_remove_resources_stm32(struct udevice *dev)
 {
+#ifdef CONFIG_CLK
        struct eqos_priv *eqos = dev_get_priv(dev);
 
        debug("%s(dev=%p):\n", __func__, dev);
@@ -1701,11 +1957,20 @@ static int eqos_remove_resources_stm32(struct udevice *dev)
        clk_free(&eqos->clk_master_bus);
        if (clk_valid(&eqos->clk_ck))
                clk_free(&eqos->clk_ck);
+#endif
+
+       if (dm_gpio_is_valid(&eqos->phy_reset_gpio))
+               dm_gpio_free(dev, &eqos->phy_reset_gpio);
 
        debug("%s: OK\n", __func__);
        return 0;
 }
 
+static int eqos_remove_resources_imx(struct udevice *dev)
+{
+       return 0;
+}
+
 static int eqos_probe(struct udevice *dev)
 {
        struct eqos_priv *eqos = dev_get_priv(dev);
@@ -1738,23 +2003,32 @@ static int eqos_probe(struct udevice *dev)
                goto err_remove_resources_core;
        }
 
-       eqos->mii = mdio_alloc();
+#ifdef CONFIG_DM_ETH_PHY
+       eqos->mii = eth_phy_get_mdio_bus(dev);
+#endif
        if (!eqos->mii) {
-               pr_err("mdio_alloc() failed");
-               ret = -ENOMEM;
-               goto err_remove_resources_tegra;
-       }
-       eqos->mii->read = eqos_mdio_read;
-       eqos->mii->write = eqos_mdio_write;
-       eqos->mii->priv = eqos;
-       strcpy(eqos->mii->name, dev->name);
+               eqos->mii = mdio_alloc();
+               if (!eqos->mii) {
+                       pr_err("mdio_alloc() failed");
+                       ret = -ENOMEM;
+                       goto err_remove_resources_tegra;
+               }
+               eqos->mii->read = eqos_mdio_read;
+               eqos->mii->write = eqos_mdio_write;
+               eqos->mii->priv = eqos;
+               strcpy(eqos->mii->name, dev->name);
 
-       ret = mdio_register(eqos->mii);
-       if (ret < 0) {
-               pr_err("mdio_register() failed: %d", ret);
-               goto err_free_mdio;
+               ret = mdio_register(eqos->mii);
+               if (ret < 0) {
+                       pr_err("mdio_register() failed: %d", ret);
+                       goto err_free_mdio;
+               }
        }
 
+#ifdef CONFIG_DM_ETH_PHY
+       eth_phy_set_mdio_bus(dev, eqos->mii);
+#endif
+
        debug("%s: OK\n", __func__);
        return 0;
 
@@ -1822,10 +2096,10 @@ static const struct eqos_config eqos_tegra186_config = {
 };
 
 static struct eqos_ops eqos_stm32_ops = {
-       .eqos_inval_desc = eqos_inval_desc_stm32,
-       .eqos_flush_desc = eqos_flush_desc_stm32,
-       .eqos_inval_buffer = eqos_inval_buffer_stm32,
-       .eqos_flush_buffer = eqos_flush_buffer_stm32,
+       .eqos_inval_desc = eqos_inval_desc_generic,
+       .eqos_flush_desc = eqos_flush_desc_generic,
+       .eqos_inval_buffer = eqos_inval_buffer_generic,
+       .eqos_flush_buffer = eqos_flush_buffer_generic,
        .eqos_probe_resources = eqos_probe_resources_stm32,
        .eqos_remove_resources = eqos_remove_resources_stm32,
        .eqos_stop_resets = eqos_stop_resets_stm32,
@@ -1848,6 +2122,33 @@ static const struct eqos_config eqos_stm32_config = {
        .ops = &eqos_stm32_ops
 };
 
+static struct eqos_ops eqos_imx_ops = {
+       .eqos_inval_desc = eqos_inval_desc_generic,
+       .eqos_flush_desc = eqos_flush_desc_generic,
+       .eqos_inval_buffer = eqos_inval_buffer_generic,
+       .eqos_flush_buffer = eqos_flush_buffer_generic,
+       .eqos_probe_resources = eqos_probe_resources_imx,
+       .eqos_remove_resources = eqos_remove_resources_imx,
+       .eqos_stop_resets = eqos_stop_resets_imx,
+       .eqos_start_resets = eqos_start_resets_imx,
+       .eqos_stop_clks = eqos_stop_clks_imx,
+       .eqos_start_clks = eqos_start_clks_imx,
+       .eqos_calibrate_pads = eqos_calibrate_pads_imx,
+       .eqos_disable_calibration = eqos_disable_calibration_imx,
+       .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_imx,
+       .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_imx
+};
+
+struct eqos_config eqos_imx_config = {
+       .reg_access_always_ok = false,
+       .mdio_wait = 10000,
+       .swr_wait = 50,
+       .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
+       .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
+       .interface = eqos_get_interface_imx,
+       .ops = &eqos_imx_ops
+};
+
 static const struct udevice_id eqos_ids[] = {
        {
                .compatible = "nvidia,tegra186-eqos",
@@ -1857,6 +2158,10 @@ static const struct udevice_id eqos_ids[] = {
                .compatible = "snps,dwmac-4.20a",
                .data = (ulong)&eqos_stm32_config
        },
+       {
+               .compatible = "fsl,imx-eqos",
+               .data = (ulong)&eqos_imx_config
+       },
 
        { }
 };
@@ -1864,7 +2169,7 @@ static const struct udevice_id eqos_ids[] = {
 U_BOOT_DRIVER(eth_eqos) = {
        .name = "eth_eqos",
        .id = UCLASS_ETH,
-       .of_match = eqos_ids,
+       .of_match = of_match_ptr(eqos_ids),
        .probe = eqos_probe,
        .remove = eqos_remove,
        .ops = &eqos_ops,