common: Move hang() to the same header as panic()
[oweals/u-boot.git] / drivers / net / mcffec.c
index ebcbed941a5d2acafd57d032bdefbac1568ea8d5..8caf0ba6b1ca3b3dbbabff2b6de37901aa5e50f8 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2000-2004
  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
@@ -5,19 +6,20 @@
  * (C) Copyright 2007 Freescale Semiconductor, Inc.
  * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
  *
- * SPDX-License-Identifier:    GPL-2.0+
+ * Conversion to DM
+ * (C) 2019 Angelo Dureghello <angelo.dureghello@timesys.com>
  */
 
 #include <common.h>
+#include <env.h>
+#include <hang.h>
 #include <malloc.h>
-
 #include <command.h>
 #include <net.h>
-#include <netdev.h>
 #include <miiphy.h>
-
 #include <asm/fec.h>
 #include <asm/immap.h>
+#include <linux/mii.h>
 
 #undef ET_DEBUG
 #undef MII_DEBUG
@@ -26,7 +28,6 @@
 #define DBUF_LENGTH            1520
 #define TX_BUF_CNT             2
 #define PKT_MAXBUF_SIZE                1518
-#define PKT_MINBUF_SIZE                64
 #define PKT_MAXBLR_SIZE                1520
 #define LAST_PKTBUFSRX         PKTBUFSRX - 1
 #define BD_ENET_RX_W_E         (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY)
 
 DECLARE_GLOBAL_DATA_PTR;
 
-struct fec_info_s fec_info[] = {
-#ifdef CONFIG_SYS_FEC0_IOBASE
-       {
-        0,                     /* index */
-        CONFIG_SYS_FEC0_IOBASE,        /* io base */
-        CONFIG_SYS_FEC0_PINMUX,        /* gpio pin muxing */
-        CONFIG_SYS_FEC0_MIIBASE,       /* mii base */
-        -1,                    /* phy_addr */
-        0,                     /* duplex and speed */
-        0,                     /* phy name */
-        0,                     /* phyname init */
-        0,                     /* RX BD */
-        0,                     /* TX BD */
-        0,                     /* rx Index */
-        0,                     /* tx Index */
-        0,                     /* tx buffer */
-        0,                     /* initialized flag */
-        (struct fec_info_s *)-1,
-        },
-#endif
-#ifdef CONFIG_SYS_FEC1_IOBASE
-       {
-        1,                     /* index */
-        CONFIG_SYS_FEC1_IOBASE,        /* io base */
-        CONFIG_SYS_FEC1_PINMUX,        /* gpio pin muxing */
-        CONFIG_SYS_FEC1_MIIBASE,       /* mii base */
-        -1,                    /* phy_addr */
-        0,                     /* duplex and speed */
-        0,                     /* phy name */
-        0,                     /* phy name init */
+static void init_eth_info(struct fec_info_s *info)
+{
 #ifdef CONFIG_SYS_FEC_BUF_USE_SRAM
-        (cbd_t *)DBUF_LENGTH,  /* RX BD */
+       static u32 tmp;
+
+       if (info->index == 0)
+               tmp = CONFIG_SYS_INIT_RAM_ADDR + 0x1000;
+       else
+               info->rxbd = (cbd_t *)DBUF_LENGTH;
+
+       /* setup Receive and Transmit buffer descriptor */
+       info->rxbd = (cbd_t *)((u32)info->rxbd + tmp);
+       tmp = (u32)info->rxbd;
+       info->txbd =
+           (cbd_t *)((u32)info->txbd + tmp +
+           (PKTBUFSRX * sizeof(cbd_t)));
+       tmp = (u32)info->txbd;
+       info->txbuf =
+           (char *)((u32)info->txbuf + tmp +
+           (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t)));
+       tmp = (u32)info->txbuf;
 #else
-        0,                     /* RX BD */
+       info->rxbd =
+           (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE,
+                              (PKTBUFSRX * sizeof(cbd_t)));
+       info->txbd =
+           (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE,
+                              (TX_BUF_CNT * sizeof(cbd_t)));
+       info->txbuf =
+           (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH);
 #endif
-        0,                     /* TX BD */
-        0,                     /* rx Index */
-        0,                     /* tx Index */
-        0,                     /* tx buffer */
-        0,                     /* initialized flag */
-        (struct fec_info_s *)-1,
-        }
+
+#ifdef ET_DEBUG
+       printf("rxbd %x txbd %x\n", (int)info->rxbd, (int)info->txbd);
 #endif
-};
+       info->phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32);
+}
+
+static void fec_reset(struct fec_info_s *info)
+{
+       volatile fec_t *fecp = (fec_t *)(info->iobase);
+       int i;
+
+       fecp->ecr = FEC_ECR_RESET;
+       for (i = 0; (fecp->ecr & FEC_ECR_RESET) && (i < FEC_RESET_DELAY); ++i)
+               udelay(1);
 
-int fec_recv(struct eth_device *dev);
-int fec_init(struct eth_device *dev, bd_t * bd);
-void fec_halt(struct eth_device *dev);
-void fec_reset(struct eth_device *dev);
+       if (i == FEC_RESET_DELAY)
+               printf("FEC_RESET_DELAY timeout\n");
+}
 
-void setFecDuplexSpeed(volatile fec_t * fecp, bd_t * bd, int dup_spd)
+static void set_fec_duplex_speed(volatile fec_t *fecp, int dup_spd)
 {
+       bd_t *bd = gd->bd;
+
        if ((dup_spd >> 16) == FULL) {
                /* Set maximum frame length */
                fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) | FEC_RCR_MII_MODE |
@@ -117,138 +121,11 @@ void setFecDuplexSpeed(volatile fec_t * fecp, bd_t * bd, int dup_spd)
        }
 }
 
-static int fec_send(struct eth_device *dev, void *packet, int length)
-{
-       struct fec_info_s *info = dev->priv;
-       volatile fec_t *fecp = (fec_t *) (info->iobase);
-       int j, rc;
-       u16 phyStatus;
-
-       miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phyStatus);
-
-       /* section 16.9.23.3
-        * Wait for ready
-        */
-       j = 0;
-       while ((info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_READY) &&
-              (j < MCFFEC_TOUT_LOOP)) {
-               udelay(1);
-               j++;
-       }
-       if (j >= MCFFEC_TOUT_LOOP) {
-               printf("TX not ready\n");
-       }
-
-       info->txbd[info->txIdx].cbd_bufaddr = (uint) packet;
-       info->txbd[info->txIdx].cbd_datlen = length;
-       info->txbd[info->txIdx].cbd_sc |= BD_ENET_TX_RDY_LST;
-
-       /* Activate transmit Buffer Descriptor polling */
-       fecp->tdar = 0x01000000;        /* Descriptor polling active    */
-
-#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM
-       /*
-        * FEC unable to initial transmit data packet.
-        * A nop will ensure the descriptor polling active completed.
-        * CF Internal RAM has shorter cycle access than DRAM. If use
-        * DRAM as Buffer descriptor and data, a nop is a must.
-        * Affect only V2 and V3.
-        */
-       __asm__ ("nop");
-
-#endif
-
-#ifdef CONFIG_SYS_UNIFY_CACHE
-       icache_invalid();
-#endif
-
-       j = 0;
-       while ((info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_READY) &&
-              (j < MCFFEC_TOUT_LOOP)) {
-               udelay(1);
-               j++;
-       }
-       if (j >= MCFFEC_TOUT_LOOP) {
-               printf("TX timeout\n");
-       }
-
 #ifdef ET_DEBUG
-       printf("%s[%d] %s: cycles: %d    status: %x  retry cnt: %d\n",
-              __FILE__, __LINE__, __FUNCTION__, j,
-              info->txbd[info->txIdx].cbd_sc,
-              (info->txbd[info->txIdx].cbd_sc & 0x003C) >> 2);
-#endif
-
-       /* return only status bits */
-       rc = (info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_STATS);
-       info->txIdx = (info->txIdx + 1) % TX_BUF_CNT;
-
-       return rc;
-}
-
-int fec_recv(struct eth_device *dev)
+static void dbg_fec_regs(struct udevice *dev)
 {
        struct fec_info_s *info = dev->priv;
-       volatile fec_t *fecp = (fec_t *) (info->iobase);
-       int length;
-
-       for (;;) {
-#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM
-#endif
-#ifdef CONFIG_SYS_UNIFY_CACHE
-               icache_invalid();
-#endif
-               /* section 16.9.23.2 */
-               if (info->rxbd[info->rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
-                       length = -1;
-                       break;  /* nothing received - leave for() loop */
-               }
-
-               length = info->rxbd[info->rxIdx].cbd_datlen;
-
-               if (info->rxbd[info->rxIdx].cbd_sc & 0x003f) {
-                       printf("%s[%d] err: %x\n",
-                              __FUNCTION__, __LINE__,
-                              info->rxbd[info->rxIdx].cbd_sc);
-#ifdef ET_DEBUG
-                       printf("%s[%d] err: %x\n",
-                              __FUNCTION__, __LINE__,
-                              info->rxbd[info->rxIdx].cbd_sc);
-#endif
-               } else {
-
-                       length -= 4;
-                       /* Pass the packet up to the protocol layers. */
-                       net_process_received_packet(net_rx_packets[info->rxIdx],
-                                                   length);
-
-                       fecp->eir |= FEC_EIR_RXF;
-               }
-
-               /* Give the buffer back to the FEC. */
-               info->rxbd[info->rxIdx].cbd_datlen = 0;
-
-               /* wrap around buffer index when necessary */
-               if (info->rxIdx == LAST_PKTBUFSRX) {
-                       info->rxbd[PKTBUFSRX - 1].cbd_sc = BD_ENET_RX_W_E;
-                       info->rxIdx = 0;
-               } else {
-                       info->rxbd[info->rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
-                       info->rxIdx++;
-               }
-
-               /* Try to fill Buffer Descriptors */
-               fecp->rdar = 0x01000000;        /* Descriptor polling active    */
-       }
-
-       return length;
-}
-
-#ifdef ET_DEBUG
-void dbgFecRegs(struct eth_device *dev)
-{
-       struct fec_info_s *info = dev->priv;
-       volatile fec_t *fecp = (fec_t *) (info->iobase);
+       volatile fec_t *fecp = (fec_t *)(info->iobase);
 
        printf("=====\n");
        printf("ievent       %x - %x\n", (int)&fecp->eir, fecp->eir);
@@ -395,28 +272,27 @@ void dbgFecRegs(struct eth_device *dev)
 }
 #endif
 
-int fec_init(struct eth_device *dev, bd_t * bd)
+int mcffec_init(struct udevice *dev)
 {
        struct fec_info_s *info = dev->priv;
        volatile fec_t *fecp = (fec_t *) (info->iobase);
-       int i;
+       int rval, i;
        uchar ea[6];
 
-       fecpin_setclear(dev, 1);
-
-       fec_reset(dev);
+       fecpin_setclear(info, 1);
+       fec_reset(info);
 
 #if defined(CONFIG_CMD_MII) || defined (CONFIG_MII) || \
        defined (CONFIG_SYS_DISCOVER_PHY)
 
        mii_init();
 
-       setFecDuplexSpeed(fecp, bd, info->dup_spd);
+       set_fec_duplex_speed(fecp, info->dup_spd);
 #else
 #ifndef CONFIG_SYS_DISCOVER_PHY
-       setFecDuplexSpeed(fecp, bd, (FECDUPLEX << 16) | FECSPEED);
-#endif                         /* ifndef CONFIG_SYS_DISCOVER_PHY */
-#endif                         /* CONFIG_CMD_MII || CONFIG_MII */
+       set_fec_duplex_speed(fecp, (FECDUPLEX << 16) | FECSPEED);
+#endif /* ifndef CONFIG_SYS_DISCOVER_PHY */
+#endif /* CONFIG_CMD_MII || CONFIG_MII */
 
        /* We use strictly polling mode only */
        fecp->eimr = 0;
@@ -425,34 +301,20 @@ int fec_init(struct eth_device *dev, bd_t * bd)
        fecp->eir = 0xffffffff;
 
        /* Set station address   */
-       if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE) {
-#ifdef CONFIG_SYS_FEC1_IOBASE
-               volatile fec_t *fecp1 = (fec_t *) (CONFIG_SYS_FEC1_IOBASE);
-               eth_env_get_enetaddr("eth1addr", ea);
-               fecp1->palr =
-                   (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
-               fecp1->paur = (ea[4] << 24) | (ea[5] << 16);
-#endif
-               eth_env_get_enetaddr("ethaddr", ea);
-               fecp->palr =
-                   (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
-               fecp->paur = (ea[4] << 24) | (ea[5] << 16);
-       } else {
-#ifdef CONFIG_SYS_FEC0_IOBASE
-               volatile fec_t *fecp0 = (fec_t *) (CONFIG_SYS_FEC0_IOBASE);
-               eth_env_get_enetaddr("ethaddr", ea);
-               fecp0->palr =
-                   (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
-               fecp0->paur = (ea[4] << 24) | (ea[5] << 16);
-#endif
-#ifdef CONFIG_SYS_FEC1_IOBASE
-               eth_env_get_enetaddr("eth1addr", ea);
-               fecp->palr =
-                   (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
-               fecp->paur = (ea[4] << 24) | (ea[5] << 16);
-#endif
+       if (info->index == 0)
+               rval = eth_env_get_enetaddr("ethaddr", ea);
+       else
+               rval = eth_env_get_enetaddr("eth1addr", ea);
+
+       if (!rval) {
+               puts("Please set a valid MAC address\n");
+               return -EINVAL;
        }
 
+       fecp->palr =
+           (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]);
+       fecp->paur = (ea[4] << 24) | (ea[5] << 16);
+
        /* Clear unicast address hash table */
        fecp->iaur = 0;
        fecp->ialr = 0;
@@ -467,8 +329,8 @@ int fec_init(struct eth_device *dev, bd_t * bd)
        /*
         * Setup Buffers and Buffer Descriptors
         */
-       info->rxIdx = 0;
-       info->txIdx = 0;
+       info->rx_idx = 0;
+       info->tx_idx = 0;
 
        /*
         * Setup Receiver Buffer Descriptors (13.14.24.18)
@@ -501,119 +363,256 @@ int fec_init(struct eth_device *dev, bd_t * bd)
        /* Now enable the transmit and receive processing */
        fecp->ecr |= FEC_ECR_ETHER_EN;
 
-       /* And last, try to fill Rx Buffer Descriptors */
-       fecp->rdar = 0x01000000;        /* Descriptor polling active    */
+       /* And last, try to fill Rx Buffer Descriptors
+        * Descriptor polling active
+        */
+       fecp->rdar = 0x01000000;
 
-       return 1;
+       return 0;
 }
 
-void fec_reset(struct eth_device *dev)
+static int mcffec_send(struct udevice *dev, void *packet, int length)
 {
        struct fec_info_s *info = dev->priv;
-       volatile fec_t *fecp = (fec_t *) (info->iobase);
-       int i;
+       volatile fec_t *fecp = (fec_t *)info->iobase;
+       int j, rc;
+       u16 phy_status;
 
-       fecp->ecr = FEC_ECR_RESET;
-       for (i = 0; (fecp->ecr & FEC_ECR_RESET) && (i < FEC_RESET_DELAY); ++i) {
+       miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phy_status);
+
+       /* section 16.9.23.3
+        * Wait for ready
+        */
+       j = 0;
+       while ((info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_READY) &&
+              (j < info->to_loop)) {
                udelay(1);
+               j++;
        }
-       if (i == FEC_RESET_DELAY) {
-               printf("FEC_RESET_DELAY timeout\n");
+       if (j >= info->to_loop)
+               printf("TX not ready\n");
+
+       info->txbd[info->tx_idx].cbd_bufaddr = (uint)packet;
+       info->txbd[info->tx_idx].cbd_datlen = length;
+       info->txbd[info->tx_idx].cbd_sc |= BD_ENET_TX_RDY_LST;
+
+       /* Activate transmit Buffer Descriptor polling */
+       fecp->tdar = 0x01000000;        /* Descriptor polling active    */
+
+#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM
+       /*
+        * FEC unable to initial transmit data packet.
+        * A nop will ensure the descriptor polling active completed.
+        * CF Internal RAM has shorter cycle access than DRAM. If use
+        * DRAM as Buffer descriptor and data, a nop is a must.
+        * Affect only V2 and V3.
+        */
+       __asm__ ("nop");
+#endif
+
+#ifdef CONFIG_SYS_UNIFY_CACHE
+       icache_invalid();
+#endif
+
+       j = 0;
+       while ((info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_READY) &&
+              (j < info->to_loop)) {
+               udelay(1);
+               j++;
        }
+       if (j >= info->to_loop)
+               printf("TX timeout\n");
+
+#ifdef ET_DEBUG
+       printf("%s[%d] %s: cycles: %d    status: %x  retry cnt: %d\n",
+              __FILE__, __LINE__, __func__, j,
+              info->txbd[info->tx_idx].cbd_sc,
+              (info->txbd[info->tx_idx].cbd_sc & 0x003C) >> 2);
+#endif
+
+       /* return only status bits */
+       rc = (info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_STATS);
+       info->tx_idx = (info->tx_idx + 1) % TX_BUF_CNT;
+
+       return rc;
 }
 
-void fec_halt(struct eth_device *dev)
+static int mcffec_recv(struct udevice *dev, int flags, uchar **packetp)
 {
        struct fec_info_s *info = dev->priv;
+       volatile fec_t *fecp = (fec_t *)info->iobase;
+       int length = -1;
+
+       for (;;) {
+#ifdef CONFIG_SYS_UNIFY_CACHE
+               icache_invalid();
+#endif
+               /* If nothing received - leave for() loop */
+               if (info->rxbd[info->rx_idx].cbd_sc & BD_ENET_RX_EMPTY)
+                       break;
 
-       fec_reset(dev);
+               length = info->rxbd[info->rx_idx].cbd_datlen;
 
-       fecpin_setclear(dev, 0);
+               if (info->rxbd[info->rx_idx].cbd_sc & 0x003f) {
+                       printf("%s[%d] err: %x\n",
+                              __func__, __LINE__,
+                              info->rxbd[info->rx_idx].cbd_sc);
+               } else {
+                       length -= 4;
+
+                       /*
+                        * Pass the buffer ptr up to the protocol layers.
+                        */
+                       *packetp = net_rx_packets[info->rx_idx];
+
+                       fecp->eir |= FEC_EIR_RXF;
+               }
+
+               /* Give the buffer back to the FEC. */
+               info->rxbd[info->rx_idx].cbd_datlen = 0;
+
+               /* wrap around buffer index when necessary */
+               if (info->rx_idx == LAST_PKTBUFSRX) {
+                       info->rxbd[PKTBUFSRX - 1].cbd_sc = BD_ENET_RX_W_E;
+                       info->rx_idx = 0;
+               } else {
+                       info->rxbd[info->rx_idx].cbd_sc = BD_ENET_RX_EMPTY;
+                       info->rx_idx++;
+               }
+
+               /* Try to fill Buffer Descriptors
+                * Descriptor polling active
+                */
+               fecp->rdar = 0x01000000;
+       }
+
+       return length;
+}
+
+static void mcffec_halt(struct udevice *dev)
+{
+       struct fec_info_s *info = dev->priv;
+
+       fec_reset(info);
+       fecpin_setclear(info, 0);
+
+       info->rx_idx = 0;
+       info->tx_idx = 0;
 
-       info->rxIdx = info->txIdx = 0;
        memset(info->rxbd, 0, PKTBUFSRX * sizeof(cbd_t));
        memset(info->txbd, 0, TX_BUF_CNT * sizeof(cbd_t));
        memset(info->txbuf, 0, DBUF_LENGTH);
 }
 
-int mcffec_initialize(bd_t * bis)
+static const struct eth_ops mcffec_ops = {
+       .start  = mcffec_init,
+       .send   = mcffec_send,
+       .recv   = mcffec_recv,
+       .stop   = mcffec_halt,
+};
+
+/*
+ * Boot sequence, called just after mcffec_ofdata_to_platdata,
+ * as DM way, it replaces old mcffec_initialize.
+ */
+static int mcffec_probe(struct udevice *dev)
 {
-       struct eth_device *dev;
-       int i;
-#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM
-       u32 tmp = CONFIG_SYS_INIT_RAM_ADDR + 0x1000;
-#endif
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+       struct fec_info_s *info = dev->priv;
+       int node = dev_of_offset(dev);
+       int retval, fec_idx;
+       const u32 *val;
 
-       for (i = 0; i < ARRAY_SIZE(fec_info); i++) {
+       info->index = dev->seq;
+       info->iobase = pdata->iobase;
+       info->phy_addr = -1;
 
-               dev =
-                   (struct eth_device *)memalign(CONFIG_SYS_CACHELINE_SIZE,
-                                                 sizeof *dev);
-               if (dev == NULL)
-                       hang();
+       val = fdt_getprop(gd->fdt_blob, node, "mii-base", NULL);
+       if (val) {
+               u32 fec_iobase;
 
-               memset(dev, 0, sizeof(*dev));
+               fec_idx = fdt32_to_cpu(*val);
+               if (fec_idx == info->index) {
+                       fec_iobase = info->iobase;
+               } else {
+                       printf("mii base != base address, fec_idx %d\n",
+                              fec_idx);
+                       retval = fec_get_base_addr(fec_idx, &fec_iobase);
+                       if (retval)
+                               return retval;
+               }
+               info->miibase = fec_iobase;
+       }
 
-               sprintf(dev->name, "FEC%d", fec_info[i].index);
+       val = fdt_getprop(gd->fdt_blob, node, "phy-addr", NULL);
+       if (val)
+               info->phy_addr = fdt32_to_cpu(*val);
 
-               dev->priv = &fec_info[i];
-               dev->init = fec_init;
-               dev->halt = fec_halt;
-               dev->send = fec_send;
-               dev->recv = fec_recv;
+       val = fdt_getprop(gd->fdt_blob, node, "timeout-loop", NULL);
+       if (val)
+               info->to_loop = fdt32_to_cpu(*val);
 
-               /* setup Receive and Transmit buffer descriptor */
-#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM
-               fec_info[i].rxbd = (cbd_t *)((u32)fec_info[i].rxbd + tmp);
-               tmp = (u32)fec_info[i].rxbd;
-               fec_info[i].txbd =
-                   (cbd_t *)((u32)fec_info[i].txbd + tmp +
-                   (PKTBUFSRX * sizeof(cbd_t)));
-               tmp = (u32)fec_info[i].txbd;
-               fec_info[i].txbuf =
-                   (char *)((u32)fec_info[i].txbuf + tmp +
-                   (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t)));
-               tmp = (u32)fec_info[i].txbuf;
-#else
-               fec_info[i].rxbd =
-                   (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE,
-                                      (PKTBUFSRX * sizeof(cbd_t)));
-               fec_info[i].txbd =
-                   (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE,
-                                      (TX_BUF_CNT * sizeof(cbd_t)));
-               fec_info[i].txbuf =
-                   (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH);
-#endif
+       init_eth_info(info);
 
-#ifdef ET_DEBUG
-               printf("rxbd %x txbd %x\n",
-                      (int)fec_info[i].rxbd, (int)fec_info[i].txbd);
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+       info->bus = mdio_alloc();
+       if (!info->bus)
+               return -ENOMEM;
+       strcpy(info->bus->name, dev->name);
+       info->bus->read = mcffec_miiphy_read;
+       info->bus->write = mcffec_miiphy_write;
+
+       retval = mdio_register(info->bus);
+       if (retval < 0)
+               return retval;
 #endif
 
-               fec_info[i].phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32);
+       return 0;
+}
 
-               eth_register(dev);
+static int mcffec_remove(struct udevice *dev)
+{
+       struct fec_info_s *priv = dev_get_priv(dev);
 
-#if 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 = mcffec_miiphy_read;
-               mdiodev->write = mcffec_miiphy_write;
-
-               retval = mdio_register(mdiodev);
-               if (retval < 0)
-                       return retval;
-#endif
-               if (i > 0)
-                       fec_info[i - 1].next = &fec_info[i];
-       }
-       fec_info[i - 1].next = &fec_info[0];
+       mdio_unregister(priv->bus);
+       mdio_free(priv->bus);
+
+       return 0;
+}
 
-       /* default speed */
-       bis->bi_ethspeed = 10;
+/*
+ * Boot sequence, called 1st
+ */
+static int mcffec_ofdata_to_platdata(struct udevice *dev)
+{
+       struct eth_pdata *pdata = dev_get_platdata(dev);
+       const u32 *val;
+
+       pdata->iobase = (phys_addr_t)devfdt_get_addr(dev);
+       /* Default to 10Mbit/s */
+       pdata->max_speed = 10;
+
+       val = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
+                         "max-speed", NULL);
+       if (val)
+               pdata->max_speed = fdt32_to_cpu(*val);
 
        return 0;
 }
+
+static const struct udevice_id mcffec_ids[] = {
+       { .compatible = "fsl,mcf-fec" },
+       { }
+};
+
+U_BOOT_DRIVER(mcffec) = {
+       .name   = "mcffec",
+       .id     = UCLASS_ETH,
+       .of_match = mcffec_ids,
+       .ofdata_to_platdata = mcffec_ofdata_to_platdata,
+       .probe  = mcffec_probe,
+       .remove = mcffec_remove,
+       .ops    = &mcffec_ops,
+       .priv_auto_alloc_size = sizeof(struct fec_info_s),
+       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};