arm: mach-k3: Enable dcache in SPL
[oweals/u-boot.git] / drivers / net / mvgbe.c
index 477bf5c1325cafc7d5a621e3b4163ecf396df67d..6d56360a202e09c2fa6ec9f50b337a97fe4eeaa9 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2009
  * Marvell Semiconductor <www.marvell.com>
@@ -8,40 +9,24 @@
  *
  * based on - Driver for MV64360X ethernet ports
  * Copyright (C) 2002 rabeeh@galileo.co.il
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
  */
 
 #include <common.h>
+#include <dm.h>
 #include <net.h>
 #include <malloc.h>
 #include <miiphy.h>
+#include <wait_bit.h>
 #include <asm/io.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 #include <asm/types.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
 #include <asm/arch/cpu.h>
 
-#if defined(CONFIG_KIRKWOOD)
-#include <asm/arch/kirkwood.h>
-#elif defined(CONFIG_ORION5X)
+#if defined(CONFIG_ARCH_KIRKWOOD)
+#include <asm/arch/soc.h>
+#elif defined(CONFIG_ARCH_ORION5X)
 #include <asm/arch/orion5x.h>
 #endif
 
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifndef CONFIG_MVGBE_PORTS
+# define CONFIG_MVGBE_PORTS {0, 0}
+#endif
+
 #define MV_PHY_ADR_REQUEST 0xee
 #define MVGBE_SMI_REG (((struct mvgbe_registers *)MVGBE0_BASE)->smi)
 
-/*
- * smi_reg_read - miiphy_read callback function.
- *
- * Returns 16bit phy register value, or 0xffff on error
- */
-static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
+#if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+static int smi_wait_ready(struct mvgbe_device *dmvgbe)
+{
+       int ret;
+
+       ret = wait_for_bit_le32(&MVGBE_SMI_REG, MVGBE_PHY_SMI_BUSY_MASK, false,
+                               MVGBE_PHY_SMI_TIMEOUT_MS, false);
+       if (ret) {
+               printf("Error: SMI busy timeout\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __mvgbe_mdio_read(struct mvgbe_device *dmvgbe, int phy_adr,
+                            int devad, int reg_ofs)
 {
-       struct eth_device *dev = eth_get_dev_by_name(devname);
-       struct mvgbe_device *dmvgbe = to_mvgbe(dev);
        struct mvgbe_registers *regs = dmvgbe->regs;
        u32 smi_reg;
        u32 timeout;
+       u16 data = 0;
 
        /* Phyadr read request */
        if (phy_adr == MV_PHY_ADR_REQUEST &&
                        reg_ofs == MV_PHY_ADR_REQUEST) {
                /* */
-               *data = (u16) (MVGBE_REG_RD(regs->phyadr) & PHYADR_MASK);
-               return 0;
+               data = (u16) (MVGBE_REG_RD(regs->phyadr) & PHYADR_MASK);
+               return data;
        }
        /* check parameters */
        if (phy_adr > PHYADR_MASK) {
                printf("Err..(%s) Invalid PHY address %d\n",
-                       __FUNCTION__, phy_adr);
+                       __func__, phy_adr);
                return -EFAULT;
        }
        if (reg_ofs > PHYREG_MASK) {
                printf("Err..(%s) Invalid register offset %d\n",
-                       __FUNCTION__, reg_ofs);
+                       __func__, reg_ofs);
                return -EFAULT;
        }
 
-       timeout = MVGBE_PHY_SMI_TIMEOUT;
        /* wait till the SMI is not busy */
-       do {
-               /* read smi register */
-               smi_reg = MVGBE_REG_RD(MVGBE_SMI_REG);
-               if (timeout-- == 0) {
-                       printf("Err..(%s) SMI busy timeout\n", __FUNCTION__);
-                       return -EFAULT;
-               }
-       } while (smi_reg & MVGBE_PHY_SMI_BUSY_MASK);
+       if (smi_wait_ready(dmvgbe) < 0)
+               return -EFAULT;
 
        /* fill the phy address and regiser offset and read opcode */
        smi_reg = (phy_adr << MVGBE_PHY_SMI_DEV_ADDR_OFFS)
@@ -111,7 +103,7 @@ static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
                smi_reg = MVGBE_REG_RD(MVGBE_SMI_REG);
                if (timeout-- == 0) {
                        printf("Err..(%s) SMI read ready timeout\n",
-                               __FUNCTION__);
+                               __func__);
                        return -EFAULT;
                }
        } while (!(smi_reg & MVGBE_PHY_SMI_READ_VALID_MASK));
@@ -120,27 +112,37 @@ static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data)
        for (timeout = 0; timeout < MVGBE_PHY_SMI_TIMEOUT; timeout++)
                ;
 
-       *data = (u16) (MVGBE_REG_RD(MVGBE_SMI_REG) & MVGBE_PHY_SMI_DATA_MASK);
+       data = (u16) (MVGBE_REG_RD(MVGBE_SMI_REG) & MVGBE_PHY_SMI_DATA_MASK);
 
-       debug("%s:(adr %d, off %d) value= %04x\n", __FUNCTION__, phy_adr,
-               reg_ofs, *data);
+       debug("%s:(adr %d, off %d) value= %04x\n", __func__, phy_adr, reg_ofs,
+             data);
 
-       return 0;
+       return data;
 }
 
 /*
- * smi_reg_write - imiiphy_write callback function.
+ * smi_reg_read - miiphy_read callback function.
  *
- * Returns 0 if write succeed, -EINVAL on bad parameters
- * -ETIME on timeout
+ * Returns 16bit phy register value, or -EFAULT on error
  */
-static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
+static int smi_reg_read(struct mii_dev *bus, int phy_adr, int devad,
+                       int reg_ofs)
 {
-       struct eth_device *dev = eth_get_dev_by_name(devname);
+#ifdef CONFIG_DM_ETH
+       struct mvgbe_device *dmvgbe = bus->priv;
+#else
+       struct eth_device *dev = eth_get_dev_by_name(bus->name);
        struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+#endif
+
+       return __mvgbe_mdio_read(dmvgbe, phy_adr, devad, reg_ofs);
+}
+
+static int __mvgbe_mdio_write(struct mvgbe_device *dmvgbe, int phy_adr,
+                             int devad, int reg_ofs, u16 data)
+{
        struct mvgbe_registers *regs = dmvgbe->regs;
        u32 smi_reg;
-       u32 timeout;
 
        /* Phyadr write request*/
        if (phy_adr == MV_PHY_ADR_REQUEST &&
@@ -151,24 +153,17 @@ static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
 
        /* check parameters */
        if (phy_adr > PHYADR_MASK) {
-               printf("Err..(%s) Invalid phy address\n", __FUNCTION__);
+               printf("Err..(%s) Invalid phy address\n", __func__);
                return -EINVAL;
        }
        if (reg_ofs > PHYREG_MASK) {
-               printf("Err..(%s) Invalid register offset\n", __FUNCTION__);
-               return -EINVAL;
+               printf("Err..(%s) Invalid register offset\n", __func__);
+               return -EFAULT;
        }
 
        /* wait till the SMI is not busy */
-       timeout = MVGBE_PHY_SMI_TIMEOUT;
-       do {
-               /* read smi register */
-               smi_reg = MVGBE_REG_RD(MVGBE_SMI_REG);
-               if (timeout-- == 0) {
-                       printf("Err..(%s) SMI busy timeout\n", __FUNCTION__);
-                       return -ETIME;
-               }
-       } while (smi_reg & MVGBE_PHY_SMI_BUSY_MASK);
+       if (smi_wait_ready(dmvgbe) < 0)
+               return -EFAULT;
 
        /* fill the phy addr and reg offset and write opcode and data */
        smi_reg = (data << MVGBE_PHY_SMI_DATA_OFFS);
@@ -182,6 +177,25 @@ static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
        return 0;
 }
 
+/*
+ * smi_reg_write - miiphy_write callback function.
+ *
+ * Returns 0 if write succeed, -EFAULT on error
+ */
+static int smi_reg_write(struct mii_dev *bus, int phy_adr, int devad,
+                        int reg_ofs, u16 data)
+{
+#ifdef CONFIG_DM_ETH
+       struct mvgbe_device *dmvgbe = bus->priv;
+#else
+       struct eth_device *dev = eth_get_dev_by_name(bus->name);
+       struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+#endif
+
+       return __mvgbe_mdio_write(dmvgbe, phy_adr, devad, reg_ofs, data);
+}
+#endif
+
 /* Stop and checks all queues */
 static void stop_queue(u32 * qreg)
 {
@@ -366,8 +380,9 @@ static int port_uc_addr(struct mvgbe_registers *regs, u8 uc_nibble,
 /*
  * port_uc_addr_set - This function Set the port Unicast address.
  */
-static void port_uc_addr_set(struct mvgbe_registers *regs, u8 * p_addr)
+static void port_uc_addr_set(struct mvgbe_device *dmvgbe, u8 *p_addr)
 {
+       struct mvgbe_registers *regs = dmvgbe->regs;
        u32 mac_h;
        u32 mac_l;
 
@@ -409,12 +424,14 @@ static void mvgbe_init_rx_desc_ring(struct mvgbe_device *dmvgbe)
        dmvgbe->p_rxdesc_curr = dmvgbe->p_rxdesc;
 }
 
-static int mvgbe_init(struct eth_device *dev)
+static int __mvgbe_init(struct mvgbe_device *dmvgbe, u8 *enetaddr,
+                       const char *name)
 {
-       struct mvgbe_device *dmvgbe = to_mvgbe(dev);
        struct mvgbe_registers *regs = dmvgbe->regs;
-#if (defined (CONFIG_MII) || defined (CONFIG_CMD_MII)) \
-        && defined (CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) &&  \
+       !defined(CONFIG_PHYLIB) &&                       \
+       !defined(CONFIG_DM_ETH) &&                       \
+       defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
        int i;
 #endif
        /* setup RX rings */
@@ -430,7 +447,7 @@ static int mvgbe_init(struct eth_device *dev)
 
        set_dram_access(regs);
        port_init_mac_tables(regs);
-       port_uc_addr_set(regs, dmvgbe->dev.enetaddr);
+       port_uc_addr_set(dmvgbe, enetaddr);
 
        /* Assign port configuration and command. */
        MVGBE_REG_WR(regs->pxc, PRT_CFG_VAL);
@@ -465,29 +482,39 @@ static int mvgbe_init(struct eth_device *dev)
        /* Enable port Rx. */
        MVGBE_REG_WR(regs->rqc, (1 << RXUQ));
 
-#if (defined (CONFIG_MII) || defined (CONFIG_CMD_MII)) \
-        && defined (CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \
+       !defined(CONFIG_PHYLIB) && \
+       !defined(CONFIG_DM_ETH) && \
+       defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
        /* Wait up to 5s for the link status */
        for (i = 0; i < 5; i++) {
                u16 phyadr;
 
-               miiphy_read(dev->name, MV_PHY_ADR_REQUEST,
+               miiphy_read(name, MV_PHY_ADR_REQUEST,
                                MV_PHY_ADR_REQUEST, &phyadr);
                /* Return if we get link up */
-               if (miiphy_link(dev->name, phyadr))
+               if (miiphy_link(name, phyadr))
                        return 0;
                udelay(1000000);
        }
 
-       printf("No link on %s\n", dev->name);
+       printf("No link on %s\n", name);
        return -1;
 #endif
        return 0;
 }
 
-static int mvgbe_halt(struct eth_device *dev)
+#ifndef CONFIG_DM_ETH
+static int mvgbe_init(struct eth_device *dev)
 {
        struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+
+       return __mvgbe_init(dmvgbe, dmvgbe->dev.enetaddr, dmvgbe->dev.name);
+}
+#endif
+
+static void __mvgbe_halt(struct mvgbe_device *dmvgbe)
+{
        struct mvgbe_registers *regs = dmvgbe->regs;
 
        /* Disable all gigE address decoder */
@@ -509,24 +536,42 @@ static int mvgbe_halt(struct eth_device *dev)
        MVGBE_REG_WR(regs->ice, 0);
        MVGBE_REG_WR(regs->pim, 0);
        MVGBE_REG_WR(regs->peim, 0);
+}
+
+#ifndef CONFIG_DM_ETH
+static int mvgbe_halt(struct eth_device *dev)
+{
+       struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+
+       __mvgbe_halt(dmvgbe);
 
        return 0;
 }
+#endif
+
+#ifdef CONFIG_DM_ETH
+static int mvgbe_write_hwaddr(struct udevice *dev)
+{
+       struct eth_pdata *pdata = dev_get_platdata(dev);
 
+       port_uc_addr_set(dev_get_priv(dev), pdata->enetaddr);
+
+       return 0;
+}
+#else
 static int mvgbe_write_hwaddr(struct eth_device *dev)
 {
        struct mvgbe_device *dmvgbe = to_mvgbe(dev);
-       struct mvgbe_registers *regs = dmvgbe->regs;
 
        /* Programs net device MAC address after initialization */
-       port_uc_addr_set(regs, dmvgbe->dev.enetaddr);
+       port_uc_addr_set(dmvgbe, dmvgbe->dev.enetaddr);
        return 0;
 }
+#endif
 
-static int mvgbe_send(struct eth_device *dev, void *dataptr,
-                     int datasize)
+static int __mvgbe_send(struct mvgbe_device *dmvgbe, void *dataptr,
+                       int datasize)
 {
-       struct mvgbe_device *dmvgbe = to_mvgbe(dev);
        struct mvgbe_registers *regs = dmvgbe->regs;
        struct mvgbe_txdesc *p_txdesc = dmvgbe->p_txdesc;
        void *p = (void *)dataptr;
@@ -571,7 +616,7 @@ static int mvgbe_send(struct eth_device *dev, void *dataptr,
                if ((cmd_sts & (MVGBE_ERROR_SUMMARY | MVGBE_TX_LAST_FRAME)) ==
                                (MVGBE_ERROR_SUMMARY | MVGBE_TX_LAST_FRAME) &&
                                cmd_sts & (MVGBE_UR_ERROR | MVGBE_RL_ERROR)) {
-                       printf("Err..(%s) in xmit packet\n", __FUNCTION__);
+                       printf("Err..(%s) in xmit packet\n", __func__);
                        return -1;
                }
                cmd_sts = readl(&p_txdesc->cmd_sts);
@@ -579,27 +624,39 @@ static int mvgbe_send(struct eth_device *dev, void *dataptr,
        return 0;
 }
 
-static int mvgbe_recv(struct eth_device *dev)
+#ifndef CONFIG_DM_ETH
+static int mvgbe_send(struct eth_device *dev, void *dataptr, int datasize)
 {
        struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+
+       return __mvgbe_send(dmvgbe, dataptr, datasize);
+}
+#endif
+
+static int __mvgbe_recv(struct mvgbe_device *dmvgbe, uchar **packetp)
+{
        struct mvgbe_rxdesc *p_rxdesc_curr = dmvgbe->p_rxdesc_curr;
        u32 cmd_sts;
        u32 timeout = 0;
        u32 rxdesc_curr_addr;
+       unsigned char *data;
+       int rx_bytes = 0;
+
+       *packetp = NULL;
 
        /* wait untill rx packet available or timeout */
        do {
                if (timeout < MVGBE_PHY_SMI_TIMEOUT)
                        timeout++;
                else {
-                       debug("%s time out...\n", __FUNCTION__);
+                       debug("%s time out...\n", __func__);
                        return -1;
                }
        } while (readl(&p_rxdesc_curr->cmd_sts) & MVGBE_BUFFER_OWNED_BY_DMA);
 
        if (p_rxdesc_curr->byte_cnt != 0) {
                debug("%s: Received %d byte Packet @ 0x%x (cmd_sts= %08x)\n",
-                       __FUNCTION__, (u32) p_rxdesc_curr->byte_cnt,
+                       __func__, (u32) p_rxdesc_curr->byte_cnt,
                        (u32) p_rxdesc_curr->buf_ptr,
                        (u32) p_rxdesc_curr->cmd_sts);
        }
@@ -616,21 +673,24 @@ static int mvgbe_recv(struct eth_device *dev)
                != (MVGBE_RX_FIRST_DESC | MVGBE_RX_LAST_DESC)) {
 
                printf("Err..(%s) Dropping packet spread on"
-                       " multiple descriptors\n", __FUNCTION__);
+                       " multiple descriptors\n", __func__);
 
        } else if (cmd_sts & MVGBE_ERROR_SUMMARY) {
 
                printf("Err..(%s) Dropping packet with errors\n",
-                       __FUNCTION__);
+                       __func__);
 
        } else {
                /* !!! call higher layer processing */
                debug("%s: Sending Received packet to"
-                       " upper layer (NetReceive)\n", __FUNCTION__);
+                     " upper layer (net_process_received_packet)\n",
+                     __func__);
+
+               data = (p_rxdesc_curr->buf_ptr + RX_BUF_OFFSET);
+               rx_bytes = (int)(p_rxdesc_curr->byte_cnt -
+                                                 RX_BUF_OFFSET);
 
-               /* let the upper layer handle the packet */
-               NetReceive((p_rxdesc_curr->buf_ptr + RX_BUF_OFFSET),
-                       (int)(p_rxdesc_curr->byte_cnt - RX_BUF_OFFSET));
+               *packetp = data;
        }
        /*
         * free these descriptors and point next in the ring
@@ -643,61 +703,146 @@ static int mvgbe_recv(struct eth_device *dev)
        rxdesc_curr_addr = (u32)&dmvgbe->p_rxdesc_curr;
        writel((unsigned)p_rxdesc_curr->nxtdesc_p, rxdesc_curr_addr);
 
+       return rx_bytes;
+}
+
+#ifndef CONFIG_DM_ETH
+static int mvgbe_recv(struct eth_device *dev)
+{
+       struct mvgbe_device *dmvgbe = to_mvgbe(dev);
+       uchar *packet;
+       int ret;
+
+       ret = __mvgbe_recv(dmvgbe, &packet);
+       if (ret < 0)
+               return ret;
+
+       net_process_received_packet(packet, ret);
+
        return 0;
 }
+#endif
 
-int mvgbe_initialize(bd_t *bis)
+#if defined(CONFIG_PHYLIB) || defined(CONFIG_DM_ETH)
+#if defined(CONFIG_DM_ETH)
+static struct phy_device *__mvgbe_phy_init(struct udevice *dev,
+                                          struct mii_dev *bus,
+                                          phy_interface_t phy_interface,
+                                          int phyid)
+#else
+static struct phy_device *__mvgbe_phy_init(struct eth_device *dev,
+                                          struct mii_dev *bus,
+                                          phy_interface_t phy_interface,
+                                          int phyid)
+#endif
 {
-       struct mvgbe_device *dmvgbe;
-       struct eth_device *dev;
-       int devnum;
-       u8 used_ports[MAX_MVGBE_DEVS] = CONFIG_MVGBE_PORTS;
+       struct phy_device *phydev;
 
-       for (devnum = 0; devnum < MAX_MVGBE_DEVS; devnum++) {
-               /*skip if port is configured not to use */
-               if (used_ports[devnum] == 0)
-                       continue;
+       /* Set phy address of the port */
+       miiphy_write(dev->name, MV_PHY_ADR_REQUEST, MV_PHY_ADR_REQUEST,
+                    phyid);
 
-               dmvgbe = malloc(sizeof(struct mvgbe_device));
+       phydev = phy_connect(bus, phyid, dev, phy_interface);
+       if (!phydev) {
+               printf("phy_connect failed\n");
+               return NULL;
+       }
 
-               if (!dmvgbe)
-                       goto error1;
+       phy_config(phydev);
+       phy_startup(phydev);
 
-               memset(dmvgbe, 0, sizeof(struct mvgbe_device));
+       return phydev;
+}
+#endif /* CONFIG_PHYLIB || CONFIG_DM_ETH */
 
-               dmvgbe->p_rxdesc =
-                       (struct mvgbe_rxdesc *)memalign(PKTALIGN,
-                       MV_RXQ_DESC_ALIGNED_SIZE*RINGSZ + 1);
+#if defined(CONFIG_PHYLIB) && !defined(CONFIG_DM_ETH)
+int mvgbe_phylib_init(struct eth_device *dev, int phyid)
+{
+       struct mii_dev *bus;
+       struct phy_device *phydev;
+       int ret;
+
+       bus = mdio_alloc();
+       if (!bus) {
+               printf("mdio_alloc failed\n");
+               return -ENOMEM;
+       }
+       bus->read = smi_reg_read;
+       bus->write = smi_reg_write;
+       strcpy(bus->name, dev->name);
+
+       ret = mdio_register(bus);
+       if (ret) {
+               printf("mdio_register failed\n");
+               free(bus);
+               return -ENOMEM;
+       }
 
-               if (!dmvgbe->p_rxdesc)
-                       goto error2;
+       phydev = __mvgbe_phy_init(dev, bus, PHY_INTERFACE_MODE_RGMII, phyid);
+       if (!phydev)
+               return -ENODEV;
 
-               dmvgbe->p_rxbuf = (u8 *) memalign(PKTALIGN,
-                       RINGSZ*PKTSIZE_ALIGN + 1);
+       return 0;
+}
+#endif
 
-               if (!dmvgbe->p_rxbuf)
-                       goto error3;
+static int mvgbe_alloc_buffers(struct mvgbe_device *dmvgbe)
+{
+       dmvgbe->p_rxdesc = memalign(PKTALIGN,
+                                   MV_RXQ_DESC_ALIGNED_SIZE * RINGSZ + 1);
+       if (!dmvgbe->p_rxdesc)
+               goto error1;
+
+       dmvgbe->p_rxbuf = memalign(PKTALIGN,
+                                  RINGSZ * PKTSIZE_ALIGN + 1);
+       if (!dmvgbe->p_rxbuf)
+               goto error2;
 
-               dmvgbe->p_aligned_txbuf = memalign(8, PKTSIZE_ALIGN);
+       dmvgbe->p_aligned_txbuf = memalign(8, PKTSIZE_ALIGN);
+       if (!dmvgbe->p_aligned_txbuf)
+               goto error3;
 
-               if (!dmvgbe->p_aligned_txbuf)
-                       goto error4;
+       dmvgbe->p_txdesc = memalign(PKTALIGN, sizeof(struct mvgbe_txdesc) + 1);
+       if (!dmvgbe->p_txdesc)
+               goto error4;
 
-               dmvgbe->p_txdesc = (struct mvgbe_txdesc *) memalign(
-                       PKTALIGN, sizeof(struct mvgbe_txdesc) + 1);
+       return 0;
 
-               if (!dmvgbe->p_txdesc) {
-                       free(dmvgbe->p_aligned_txbuf);
 error4:
-                       free(dmvgbe->p_rxbuf);
+       free(dmvgbe->p_aligned_txbuf);
 error3:
-                       free(dmvgbe->p_rxdesc);
+       free(dmvgbe->p_rxbuf);
 error2:
-                       free(dmvgbe);
+       free(dmvgbe->p_rxdesc);
 error1:
+       return -ENOMEM;
+}
+
+#ifndef CONFIG_DM_ETH
+int mvgbe_initialize(bd_t *bis)
+{
+       struct mvgbe_device *dmvgbe;
+       struct eth_device *dev;
+       int devnum;
+       int ret;
+       u8 used_ports[MAX_MVGBE_DEVS] = CONFIG_MVGBE_PORTS;
+
+       for (devnum = 0; devnum < MAX_MVGBE_DEVS; devnum++) {
+               /*skip if port is configured not to use */
+               if (used_ports[devnum] == 0)
+                       continue;
+
+               dmvgbe = malloc(sizeof(struct mvgbe_device));
+               if (!dmvgbe)
+                       return -ENOMEM;
+
+               memset(dmvgbe, 0, sizeof(struct mvgbe_device));
+               ret = mvgbe_alloc_buffers(dmvgbe);
+               if (ret) {
                        printf("Err.. %s Failed to allocate memory\n",
-                               __FUNCTION__);
-                       return -1;
+                               __func__);
+                       free(dmvgbe);
+                       return ret;
                }
 
                dev = &dmvgbe->dev;
@@ -716,7 +861,7 @@ error1:
 #endif
                default:        /* this should never happen */
                        printf("Err..(%s) Invalid device number %d\n",
-                               __FUNCTION__, devnum);
+                               __func__, devnum);
                        return -1;
                }
 
@@ -728,8 +873,20 @@ error1:
 
                eth_register(dev);
 
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
-               miiphy_register(dev->name, smi_reg_read, smi_reg_write);
+#if defined(CONFIG_PHYLIB)
+               mvgbe_phylib_init(dev, PHY_BASE_ADR + devnum);
+#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+               int retval;
+               struct mii_dev *mdiodev = mdio_alloc();
+               if (!mdiodev)
+                       return -ENOMEM;
+               strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
+               mdiodev->read = smi_reg_read;
+               mdiodev->write = smi_reg_write;
+
+               retval = mdio_register(mdiodev);
+               if (retval < 0)
+                       return retval;
                /* Set phy address of the port */
                miiphy_write(dev->name, MV_PHY_ADR_REQUEST,
                                MV_PHY_ADR_REQUEST, PHY_BASE_ADR + devnum);
@@ -737,3 +894,152 @@ error1:
        }
        return 0;
 }
+#endif
+
+#ifdef CONFIG_DM_ETH
+static int mvgbe_port_is_fixed_link(struct mvgbe_device *dmvgbe)
+{
+       return dmvgbe->phyaddr > PHY_MAX_ADDR;
+}
+
+static int mvgbe_start(struct udevice *dev)
+{
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+       struct mvgbe_device *dmvgbe = dev_get_priv(dev);
+       int ret;
+
+       ret = __mvgbe_init(dmvgbe, pdata->enetaddr, dev->name);
+       if (ret)
+               return ret;
+
+       if (!mvgbe_port_is_fixed_link(dmvgbe)) {
+               dmvgbe->phydev = __mvgbe_phy_init(dev, dmvgbe->bus,
+                                                 dmvgbe->phy_interface,
+                                                 dmvgbe->phyaddr);
+               if (!dmvgbe->phydev)
+                       return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int mvgbe_send(struct udevice *dev, void *packet, int length)
+{
+       struct mvgbe_device *dmvgbe = dev_get_priv(dev);
+
+       return __mvgbe_send(dmvgbe, packet, length);
+}
+
+static int mvgbe_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+       struct mvgbe_device *dmvgbe = dev_get_priv(dev);
+
+       return __mvgbe_recv(dmvgbe, packetp);
+}
+
+static void mvgbe_stop(struct udevice *dev)
+{
+       struct mvgbe_device *dmvgbe = dev_get_priv(dev);
+
+       __mvgbe_halt(dmvgbe);
+}
+
+static int mvgbe_probe(struct udevice *dev)
+{
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+       struct mvgbe_device *dmvgbe = dev_get_priv(dev);
+       struct mii_dev *bus;
+       int ret;
+
+       ret = mvgbe_alloc_buffers(dmvgbe);
+       if (ret)
+               return ret;
+
+       dmvgbe->regs = (void __iomem *)pdata->iobase;
+
+       bus  = mdio_alloc();
+       if (!bus) {
+               printf("Failed to allocate MDIO bus\n");
+               return -ENOMEM;
+       }
+
+       bus->read = smi_reg_read;
+       bus->write = smi_reg_write;
+       snprintf(bus->name, sizeof(bus->name), dev->name);
+       bus->priv = dmvgbe;
+       dmvgbe->bus = bus;
+
+       ret = mdio_register(bus);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static const struct eth_ops mvgbe_ops = {
+       .start          = mvgbe_start,
+       .send           = mvgbe_send,
+       .recv           = mvgbe_recv,
+       .stop           = mvgbe_stop,
+       .write_hwaddr   = mvgbe_write_hwaddr,
+};
+
+static int mvgbe_ofdata_to_platdata(struct udevice *dev)
+{
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+       struct mvgbe_device *dmvgbe = dev_get_priv(dev);
+       void *blob = (void *)gd->fdt_blob;
+       int node = dev_of_offset(dev);
+       const char *phy_mode;
+       int fl_node;
+       int pnode;
+       unsigned long addr;
+
+       pdata->iobase = devfdt_get_addr(dev);
+       pdata->phy_interface = -1;
+
+       pnode = fdt_node_offset_by_compatible(blob, node,
+                                             "marvell,kirkwood-eth-port");
+
+       /* Get phy-mode / phy_interface from DT */
+       phy_mode = fdt_getprop(gd->fdt_blob, pnode, "phy-mode", NULL);
+       if (phy_mode)
+               pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+       else
+               pdata->phy_interface = PHY_INTERFACE_MODE_GMII;
+
+       dmvgbe->phy_interface = pdata->phy_interface;
+
+       /* fetch 'fixed-link' property */
+       fl_node = fdt_subnode_offset(blob, pnode, "fixed-link");
+       if (fl_node != -FDT_ERR_NOTFOUND) {
+               /* set phy_addr to invalid value for fixed link */
+               dmvgbe->phyaddr = PHY_MAX_ADDR + 1;
+               dmvgbe->duplex = fdtdec_get_bool(blob, fl_node, "full-duplex");
+               dmvgbe->speed = fdtdec_get_int(blob, fl_node, "speed", 0);
+       } else {
+               /* Now read phyaddr from DT */
+               addr = fdtdec_lookup_phandle(blob, pnode, "phy-handle");
+               if (addr > 0)
+                       dmvgbe->phyaddr = fdtdec_get_int(blob, addr, "reg", 0);
+       }
+
+       return 0;
+}
+
+static const struct udevice_id mvgbe_ids[] = {
+       { .compatible = "marvell,kirkwood-eth" },
+       { }
+};
+
+U_BOOT_DRIVER(mvgbe) = {
+       .name   = "mvgbe",
+       .id     = UCLASS_ETH,
+       .of_match = mvgbe_ids,
+       .ofdata_to_platdata = mvgbe_ofdata_to_platdata,
+       .probe  = mvgbe_probe,
+       .ops    = &mvgbe_ops,
+       .priv_auto_alloc_size = sizeof(struct mvgbe_device),
+       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+#endif /* CONFIG_DM_ETH */