common: Drop linux/delay.h from common header
[oweals/u-boot.git] / drivers / net / macb.c
index fe370bf728975321d7cdb09a943d9290977fb044..424ca59707f2d5549dda2d6998e6cabb1720c5f1 100644 (file)
@@ -1,11 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (C) 2005-2006 Atmel Corporation
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 #include <common.h>
 #include <clk.h>
+#include <cpu_func.h>
 #include <dm.h>
+#include <log.h>
+#include <linux/delay.h>
 
 /*
  * The u-boot networking stack is a little weird.  It seems like the
@@ -38,7 +40,7 @@
 
 #include <linux/mii.h>
 #include <asm/io.h>
-#include <asm/dma-mapping.h>
+#include <linux/dma-mapping.h>
 #include <asm/arch/clk.h>
 #include <linux/errno.h>
 
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#define MACB_RX_BUFFER_SIZE            4096
-#define MACB_RX_RING_SIZE              (MACB_RX_BUFFER_SIZE / 128)
+/*
+ * These buffer sizes must be power of 2 and divisible
+ * by RX_BUFFER_MULTIPLE
+ */
+#define MACB_RX_BUFFER_SIZE            128
+#define GEM_RX_BUFFER_SIZE             2048
+#define RX_BUFFER_MULTIPLE             64
+
+#define MACB_RX_RING_SIZE              32
 #define MACB_TX_RING_SIZE              16
+
 #define MACB_TX_TIMEOUT                1000
 #define MACB_AUTONEG_TIMEOUT   5000000
 
@@ -78,31 +88,16 @@ struct macb_dma_desc {
 #define MACB_RX_DMA_DESC_SIZE  (DMA_DESC_BYTES(MACB_RX_RING_SIZE))
 #define MACB_TX_DUMMY_DMA_DESC_SIZE    (DMA_DESC_BYTES(1))
 
-#define RXADDR_USED            0x00000001
-#define RXADDR_WRAP            0x00000002
-
 #define RXBUF_FRMLEN_MASK      0x00000fff
-#define RXBUF_FRAME_START      0x00004000
-#define RXBUF_FRAME_END                0x00008000
-#define RXBUF_TYPEID_MATCH     0x00400000
-#define RXBUF_ADDR4_MATCH      0x00800000
-#define RXBUF_ADDR3_MATCH      0x01000000
-#define RXBUF_ADDR2_MATCH      0x02000000
-#define RXBUF_ADDR1_MATCH      0x04000000
-#define RXBUF_BROADCAST                0x80000000
-
 #define TXBUF_FRMLEN_MASK      0x000007ff
-#define TXBUF_FRAME_END                0x00008000
-#define TXBUF_NOCRC            0x00010000
-#define TXBUF_EXHAUSTED                0x08000000
-#define TXBUF_UNDERRUN         0x10000000
-#define TXBUF_MAXRETRY         0x20000000
-#define TXBUF_WRAP             0x40000000
-#define TXBUF_USED             0x80000000
 
 struct macb_device {
        void                    *regs;
 
+       bool                    is_big_endian;
+
+       const struct macb_config *config;
+
        unsigned int            rx_tail;
        unsigned int            tx_head;
        unsigned int            tx_tail;
@@ -113,6 +108,7 @@ struct macb_device {
        void                    *tx_buffer;
        struct macb_dma_desc    *rx_ring;
        struct macb_dma_desc    *tx_ring;
+       size_t                  rx_buffer_size;
 
        unsigned long           rx_buffer_dma;
        unsigned long           rx_ring_dma;
@@ -138,13 +134,20 @@ struct macb_device {
        phy_interface_t         phy_interface;
 #endif
 };
+
+struct macb_config {
+       unsigned int            dma_burst_length;
+
+       int                     (*clk_init)(struct udevice *dev, ulong rate);
+};
+
 #ifndef CONFIG_DM_ETH
 #define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
 #endif
 
 static int macb_is_gem(struct macb_device *macb)
 {
-       return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2;
+       return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) >= 0x2;
 }
 
 #ifndef cpu_is_sama5d2
@@ -164,7 +167,8 @@ static int gem_is_gigabit_capable(struct macb_device *macb)
        return macb_is_gem(macb) && !cpu_is_sama5d2() && !cpu_is_sama5d4();
 }
 
-static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
+static void macb_mdio_write(struct macb_device *macb, u8 phy_adr, u8 reg,
+                           u16 value)
 {
        unsigned long netctl;
        unsigned long netstat;
@@ -176,7 +180,7 @@ static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
 
        frame = (MACB_BF(SOF, 1)
                 | MACB_BF(RW, 1)
-                | MACB_BF(PHYA, macb->phy_addr)
+                | MACB_BF(PHYA, phy_adr)
                 | MACB_BF(REGA, reg)
                 | MACB_BF(CODE, 2)
                 | MACB_BF(DATA, value));
@@ -191,7 +195,7 @@ static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
        macb_writel(macb, NCR, netctl);
 }
 
-static u16 macb_mdio_read(struct macb_device *macb, u8 reg)
+static u16 macb_mdio_read(struct macb_device *macb, u8 phy_adr, u8 reg)
 {
        unsigned long netctl;
        unsigned long netstat;
@@ -203,7 +207,7 @@ static u16 macb_mdio_read(struct macb_device *macb, u8 reg)
 
        frame = (MACB_BF(SOF, 1)
                 | MACB_BF(RW, 2)
-                | MACB_BF(PHYA, macb->phy_addr)
+                | MACB_BF(PHYA, phy_adr)
                 | MACB_BF(REGA, reg)
                 | MACB_BF(CODE, 2));
        macb_writel(macb, MAN, frame);
@@ -239,11 +243,8 @@ int macb_miiphy_read(struct mii_dev *bus, int phy_adr, int devad, int reg)
        struct macb_device *macb = to_macb(dev);
 #endif
 
-       if (macb->phy_addr != phy_adr)
-               return -1;
-
        arch_get_mdio_control(bus->name);
-       value = macb_mdio_read(macb, reg);
+       value = macb_mdio_read(macb, phy_adr, reg);
 
        return value;
 }
@@ -259,11 +260,8 @@ int macb_miiphy_write(struct mii_dev *bus, int phy_adr, int devad, int reg,
        struct macb_device *macb = to_macb(dev);
 #endif
 
-       if (macb->phy_addr != phy_adr)
-               return -1;
-
        arch_get_mdio_control(bus->name);
-       macb_mdio_write(macb, reg, value);
+       macb_mdio_write(macb, phy_adr, reg, value);
 
        return 0;
 }
@@ -296,13 +294,15 @@ static inline void macb_flush_ring_desc(struct macb_device *macb, bool rx)
 static inline void macb_flush_rx_buffer(struct macb_device *macb)
 {
        flush_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma +
-                          ALIGN(MACB_RX_BUFFER_SIZE, PKTALIGN));
+                          ALIGN(macb->rx_buffer_size * MACB_RX_RING_SIZE,
+                                PKTALIGN));
 }
 
 static inline void macb_invalidate_rx_buffer(struct macb_device *macb)
 {
        invalidate_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma +
-                               ALIGN(MACB_RX_BUFFER_SIZE, PKTALIGN));
+                               ALIGN(macb->rx_buffer_size * MACB_RX_RING_SIZE,
+                                     PKTALIGN));
 }
 
 #if defined(CONFIG_CMD_NET)
@@ -317,9 +317,9 @@ static int _macb_send(struct macb_device *macb, const char *name, void *packet,
        paddr = dma_map_single(packet, length, DMA_TO_DEVICE);
 
        ctrl = length & TXBUF_FRMLEN_MASK;
-       ctrl |= TXBUF_FRAME_END;
+       ctrl |= MACB_BIT(TX_LAST);
        if (tx_head == (MACB_TX_RING_SIZE - 1)) {
-               ctrl |= TXBUF_WRAP;
+               ctrl |= MACB_BIT(TX_WRAP);
                macb->tx_head = 0;
        } else {
                macb->tx_head++;
@@ -329,8 +329,6 @@ static int _macb_send(struct macb_device *macb, const char *name, void *packet,
        macb->tx_ring[tx_head].addr = paddr;
        barrier();
        macb_flush_ring_desc(macb, TX);
-       /* Do we need check paddr and length is dcache line aligned? */
-       flush_dcache_range(paddr, paddr + ALIGN(length, ARCH_DMA_MINALIGN));
        macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART));
 
        /*
@@ -341,17 +339,17 @@ static int _macb_send(struct macb_device *macb, const char *name, void *packet,
                barrier();
                macb_invalidate_ring_desc(macb, TX);
                ctrl = macb->tx_ring[tx_head].ctrl;
-               if (ctrl & TXBUF_USED)
+               if (ctrl & MACB_BIT(TX_USED))
                        break;
                udelay(1);
        }
 
-       dma_unmap_single(packet, length, paddr);
+       dma_unmap_single(paddr, length, DMA_TO_DEVICE);
 
        if (i <= MACB_TX_TIMEOUT) {
-               if (ctrl & TXBUF_UNDERRUN)
+               if (ctrl & MACB_BIT(TX_UNDERRUN))
                        printf("%s: TX underrun\n", name);
-               if (ctrl & TXBUF_EXHAUSTED)
+               if (ctrl & MACB_BIT(TX_BUF_EXHAUSTED))
                        printf("%s: TX buffers exhausted in mid frame\n", name);
        } else {
                printf("%s: TX timeout\n", name);
@@ -370,14 +368,14 @@ static void reclaim_rx_buffers(struct macb_device *macb,
 
        macb_invalidate_ring_desc(macb, RX);
        while (i > new_tail) {
-               macb->rx_ring[i].addr &= ~RXADDR_USED;
+               macb->rx_ring[i].addr &= ~MACB_BIT(RX_USED);
                i++;
                if (i > MACB_RX_RING_SIZE)
                        i = 0;
        }
 
        while (i < new_tail) {
-               macb->rx_ring[i].addr &= ~RXADDR_USED;
+               macb->rx_ring[i].addr &= ~MACB_BIT(RX_USED);
                i++;
        }
 
@@ -397,26 +395,27 @@ static int _macb_recv(struct macb_device *macb, uchar **packetp)
        for (;;) {
                macb_invalidate_ring_desc(macb, RX);
 
-               if (!(macb->rx_ring[next_rx_tail].addr & RXADDR_USED))
+               if (!(macb->rx_ring[next_rx_tail].addr & MACB_BIT(RX_USED)))
                        return -EAGAIN;
 
                status = macb->rx_ring[next_rx_tail].ctrl;
-               if (status & RXBUF_FRAME_START) {
+               if (status & MACB_BIT(RX_SOF)) {
                        if (next_rx_tail != macb->rx_tail)
                                reclaim_rx_buffers(macb, next_rx_tail);
                        macb->wrapped = false;
                }
 
-               if (status & RXBUF_FRAME_END) {
-                       buffer = macb->rx_buffer + 128 * macb->rx_tail;
+               if (status & MACB_BIT(RX_EOF)) {
+                       buffer = macb->rx_buffer +
+                               macb->rx_buffer_size * macb->rx_tail;
                        length = status & RXBUF_FRMLEN_MASK;
 
                        macb_invalidate_rx_buffer(macb);
                        if (macb->wrapped) {
                                unsigned int headlen, taillen;
 
-                               headlen = 128 * (MACB_RX_RING_SIZE
-                                                - macb->rx_tail);
+                               headlen = macb->rx_buffer_size *
+                                       (MACB_RX_RING_SIZE - macb->rx_tail);
                                taillen = length - headlen;
                                memcpy((void *)net_rx_packets[0],
                                       buffer, headlen);
@@ -447,13 +446,13 @@ static void macb_phy_reset(struct macb_device *macb, const char *name)
        u16 status, adv;
 
        adv = ADVERTISE_CSMA | ADVERTISE_ALL;
-       macb_mdio_write(macb, MII_ADVERTISE, adv);
+       macb_mdio_write(macb, macb->phy_addr, MII_ADVERTISE, adv);
        printf("%s: Starting autonegotiation...\n", name);
-       macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE
+       macb_mdio_write(macb, macb->phy_addr, MII_BMCR, (BMCR_ANENABLE
                                         | BMCR_ANRESTART));
 
        for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) {
-               status = macb_mdio_read(macb, MII_BMSR);
+               status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR);
                if (status & BMSR_ANEGCOMPLETE)
                        break;
                udelay(100);
@@ -474,7 +473,7 @@ static int macb_phy_find(struct macb_device *macb, const char *name)
        /* Search for PHY... */
        for (i = 0; i < 32; i++) {
                macb->phy_addr = i;
-               phy_id = macb_mdio_read(macb, MII_PHYSID1);
+               phy_id = macb_mdio_read(macb, macb->phy_addr, MII_PHYSID1);
                if (phy_id != 0xffff) {
                        printf("%s: PHY present at %d\n", name, i);
                        return 0;
@@ -489,15 +488,86 @@ static int macb_phy_find(struct macb_device *macb, const char *name)
 
 /**
  * macb_linkspd_cb - Linkspeed change callback function
- * @regs:      Base Register of MACB devices
+ * @dev/@regs: MACB udevice (DM version) or
+ *             Base Register of MACB devices (non-DM version)
  * @speed:     Linkspeed
  * Returns 0 when operation success and negative errno number
  * when operation failed.
  */
+#ifdef CONFIG_DM_ETH
+static int macb_sifive_clk_init(struct udevice *dev, ulong rate)
+{
+       fdt_addr_t addr;
+       void *gemgxl_regs;
+
+       addr = dev_read_addr_index(dev, 1);
+       if (addr == FDT_ADDR_T_NONE)
+               return -ENODEV;
+
+       gemgxl_regs = (void __iomem *)addr;
+       if (!gemgxl_regs)
+               return -ENODEV;
+
+       /*
+        * SiFive GEMGXL TX clock operation mode:
+        *
+        * 0 = GMII mode. Use 125 MHz gemgxlclk from PRCI in TX logic
+        *     and output clock on GMII output signal GTX_CLK
+        * 1 = MII mode. Use MII input signal TX_CLK in TX logic
+        */
+       writel(rate != 125000000, gemgxl_regs);
+       return 0;
+}
+
+int __weak macb_linkspd_cb(struct udevice *dev, unsigned int speed)
+{
+#ifdef CONFIG_CLK
+       struct macb_device *macb = dev_get_priv(dev);
+       struct clk tx_clk;
+       ulong rate;
+       int ret;
+
+       switch (speed) {
+       case _10BASET:
+               rate = 2500000;         /* 2.5 MHz */
+               break;
+       case _100BASET:
+               rate = 25000000;        /* 25 MHz */
+               break;
+       case _1000BASET:
+               rate = 125000000;       /* 125 MHz */
+               break;
+       default:
+               /* does not change anything */
+               return 0;
+       }
+
+       if (macb->config->clk_init)
+               return macb->config->clk_init(dev, rate);
+
+       /*
+        * "tx_clk" is an optional clock source for MACB.
+        * Ignore if it does not exist in DT.
+        */
+       ret = clk_get_by_name(dev, "tx_clk", &tx_clk);
+       if (ret)
+               return 0;
+
+       if (tx_clk.dev) {
+               ret = clk_set_rate(&tx_clk, rate);
+               if (ret)
+                       return ret;
+       }
+#endif
+
+       return 0;
+}
+#else
 int __weak macb_linkspd_cb(void *regs, unsigned int speed)
 {
        return 0;
 }
+#endif
 
 #ifdef CONFIG_DM_ETH
 static int macb_phy_init(struct udevice *dev, const char *name)
@@ -521,7 +591,7 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
                return ret;
 
        /* Check if the PHY is up to snuff... */
-       phy_id = macb_mdio_read(macb, MII_PHYSID1);
+       phy_id = macb_mdio_read(macb, macb->phy_addr, MII_PHYSID1);
        if (phy_id == 0xffff) {
                printf("%s: No PHY present\n", name);
                return -ENODEV;
@@ -544,15 +614,21 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
        phy_config(macb->phydev);
 #endif
 
-       status = macb_mdio_read(macb, MII_BMSR);
+       status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR);
        if (!(status & BMSR_LSTATUS)) {
                /* Try to re-negotiate if we don't have link already. */
                macb_phy_reset(macb, name);
 
                for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) {
-                       status = macb_mdio_read(macb, MII_BMSR);
-                       if (status & BMSR_LSTATUS)
+                       status = macb_mdio_read(macb, macb->phy_addr, MII_BMSR);
+                       if (status & BMSR_LSTATUS) {
+                               /*
+                                * Delay a bit after the link is established,
+                                * so that the next xfer does not fail
+                                */
+                               mdelay(10);
                                break;
+                       }
                        udelay(100);
                }
        }
@@ -565,10 +641,12 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
 
        /* First check for GMAC and that it is GiB capable */
        if (gem_is_gigabit_capable(macb)) {
-               lpa = macb_mdio_read(macb, MII_STAT1000);
+               lpa = macb_mdio_read(macb, macb->phy_addr, MII_STAT1000);
 
-               if (lpa & (LPA_1000FULL | LPA_1000HALF)) {
-                       duplex = ((lpa & LPA_1000FULL) ? 1 : 0);
+               if (lpa & (LPA_1000FULL | LPA_1000HALF | LPA_1000XFULL |
+                                       LPA_1000XHALF)) {
+                       duplex = ((lpa & (LPA_1000FULL | LPA_1000XFULL)) ?
+                                       1 : 0);
 
                        printf("%s: link up, 1000Mbps %s-duplex (lpa: 0x%04x)\n",
                               name,
@@ -584,7 +662,11 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
 
                        macb_writel(macb, NCFGR, ncfgr);
 
+#ifdef CONFIG_DM_ETH
+                       ret = macb_linkspd_cb(dev, _1000BASET);
+#else
                        ret = macb_linkspd_cb(macb->regs, _1000BASET);
+#endif
                        if (ret)
                                return ret;
 
@@ -593,8 +675,8 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
        }
 
        /* fall back for EMAC checking */
-       adv = macb_mdio_read(macb, MII_ADVERTISE);
-       lpa = macb_mdio_read(macb, MII_LPA);
+       adv = macb_mdio_read(macb, macb->phy_addr, MII_ADVERTISE);
+       lpa = macb_mdio_read(macb, macb->phy_addr, MII_LPA);
        media = mii_nway_result(lpa & adv);
        speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
                 ? 1 : 0);
@@ -609,9 +691,17 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
        ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE));
        if (speed) {
                ncfgr |= MACB_BIT(SPD);
+#ifdef CONFIG_DM_ETH
+               ret = macb_linkspd_cb(dev, _100BASET);
+#else
                ret = macb_linkspd_cb(macb->regs, _100BASET);
+#endif
        } else {
+#ifdef CONFIG_DM_ETH
+               ret = macb_linkspd_cb(dev, _10BASET);
+#else
                ret = macb_linkspd_cb(macb->regs, _10BASET);
+#endif
        }
 
        if (ret)
@@ -637,7 +727,7 @@ static int gmac_init_multi_queues(struct macb_device *macb)
                if (queue_mask & (1 << i))
                        num_queues++;
 
-       macb->dummy_desc->ctrl = TXBUF_USED;
+       macb->dummy_desc->ctrl = MACB_BIT(TX_USED);
        macb->dummy_desc->addr = 0;
        flush_dcache_range(macb->dummy_desc_dma, macb->dummy_desc_dma +
                        ALIGN(MACB_TX_DUMMY_DMA_DESC_SIZE, PKTALIGN));
@@ -648,6 +738,31 @@ static int gmac_init_multi_queues(struct macb_device *macb)
        return 0;
 }
 
+static void gmac_configure_dma(struct macb_device *macb)
+{
+       u32 buffer_size;
+       u32 dmacfg;
+
+       buffer_size = macb->rx_buffer_size / RX_BUFFER_MULTIPLE;
+       dmacfg = gem_readl(macb, DMACFG) & ~GEM_BF(RXBS, -1L);
+       dmacfg |= GEM_BF(RXBS, buffer_size);
+
+       if (macb->config->dma_burst_length)
+               dmacfg = GEM_BFINS(FBLDO,
+                                  macb->config->dma_burst_length, dmacfg);
+
+       dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
+       dmacfg &= ~GEM_BIT(ENDIA_PKT);
+
+       if (macb->is_big_endian)
+               dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */
+       else
+               dmacfg &= ~GEM_BIT(ENDIA_DESC);
+
+       dmacfg &= ~GEM_BIT(ADDR64);
+       gem_writel(macb, DMACFG, dmacfg);
+}
+
 #ifdef CONFIG_DM_ETH
 static int _macb_init(struct udevice *dev, const char *name)
 #else
@@ -670,10 +785,10 @@ static int _macb_init(struct macb_device *macb, const char *name)
        paddr = macb->rx_buffer_dma;
        for (i = 0; i < MACB_RX_RING_SIZE; i++) {
                if (i == (MACB_RX_RING_SIZE - 1))
-                       paddr |= RXADDR_WRAP;
+                       paddr |= MACB_BIT(RX_WRAP);
                macb->rx_ring[i].addr = paddr;
                macb->rx_ring[i].ctrl = 0;
-               paddr += 128;
+               paddr += macb->rx_buffer_size;
        }
        macb_flush_ring_desc(macb, RX);
        macb_flush_rx_buffer(macb);
@@ -681,9 +796,10 @@ static int _macb_init(struct macb_device *macb, const char *name)
        for (i = 0; i < MACB_TX_RING_SIZE; i++) {
                macb->tx_ring[i].addr = 0;
                if (i == (MACB_TX_RING_SIZE - 1))
-                       macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP;
+                       macb->tx_ring[i].ctrl = MACB_BIT(TX_USED) |
+                               MACB_BIT(TX_WRAP);
                else
-                       macb->tx_ring[i].ctrl = TXBUF_USED;
+                       macb->tx_ring[i].ctrl = MACB_BIT(TX_USED);
        }
        macb_flush_ring_desc(macb, TX);
 
@@ -693,13 +809,15 @@ static int _macb_init(struct macb_device *macb, const char *name)
        macb->next_rx_tail = 0;
 
 #ifdef CONFIG_MACB_ZYNQ
-       macb_writel(macb, DMACFG, MACB_ZYNQ_GEM_DMACR_INIT);
+       gem_writel(macb, DMACFG, MACB_ZYNQ_GEM_DMACR_INIT);
 #endif
 
        macb_writel(macb, RBQP, macb->rx_ring_dma);
        macb_writel(macb, TBQP, macb->tx_ring_dma);
 
        if (macb_is_gem(macb)) {
+               /* Initialize DMA properties */
+               gmac_configure_dma(macb);
                /* Check the multi queue and initialize the queue for tx */
                gmac_init_multi_queues(macb);
 
@@ -712,14 +830,21 @@ static int _macb_init(struct macb_device *macb, const char *name)
 #ifdef CONFIG_DM_ETH
                if ((macb->phy_interface == PHY_INTERFACE_MODE_RMII) ||
                    (macb->phy_interface == PHY_INTERFACE_MODE_RGMII))
-                       gem_writel(macb, UR, GEM_BIT(RGMII));
+                       gem_writel(macb, USRIO, GEM_BIT(RGMII));
                else
-                       gem_writel(macb, UR, 0);
+                       gem_writel(macb, USRIO, 0);
+
+               if (macb->phy_interface == PHY_INTERFACE_MODE_SGMII) {
+                       unsigned int ncfgr = macb_readl(macb, NCFGR);
+
+                       ncfgr |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
+                       macb_writel(macb, NCFGR, ncfgr);
+               }
 #else
 #if defined(CONFIG_RGMII) || defined(CONFIG_RMII)
-               gem_writel(macb, UR, GEM_BIT(RGMII));
+               gem_writel(macb, USRIO, GEM_BIT(RGMII));
 #else
-               gem_writel(macb, UR, 0);
+               gem_writel(macb, USRIO, 0);
 #endif
 #endif
        } else {
@@ -841,8 +966,12 @@ static u32 gem_mdc_clk_div(int id, struct macb_device *macb)
                config = GEM_BF(CLK, GEM_CLK_DIV48);
        else if (macb_hz < 160000000)
                config = GEM_BF(CLK, GEM_CLK_DIV64);
-       else
+       else if (macb_hz < 240000000)
                config = GEM_BF(CLK, GEM_CLK_DIV96);
+       else if (macb_hz < 320000000)
+               config = GEM_BF(CLK, GEM_CLK_DIV128);
+       else
+               config = GEM_BF(CLK, GEM_CLK_DIV224);
 
        return config;
 }
@@ -870,8 +999,14 @@ static void _macb_eth_initialize(struct macb_device *macb)
        int id = 0;     /* This is not used by functions we call */
        u32 ncfgr;
 
+       if (macb_is_gem(macb))
+               macb->rx_buffer_size = GEM_RX_BUFFER_SIZE;
+       else
+               macb->rx_buffer_size = MACB_RX_BUFFER_SIZE;
+
        /* TODO: we need check the rx/tx_ring_dma is dcache line aligned */
-       macb->rx_buffer = dma_alloc_coherent(MACB_RX_BUFFER_SIZE,
+       macb->rx_buffer = dma_alloc_coherent(macb->rx_buffer_size *
+                                            MACB_RX_RING_SIZE,
                                             &macb->rx_buffer_dma);
        macb->rx_ring = dma_alloc_coherent(MACB_RX_DMA_DESC_SIZE,
                                           &macb->rx_ring_dma);
@@ -1062,14 +1197,13 @@ static int macb_enable_clk(struct udevice *dev)
                return -EINVAL;
 
        /*
-        * Zynq clock driver didn't support for enable or disable
-        * clock. Hence, clk_enable() didn't apply for Zynq
+        * If clock driver didn't support enable or disable then
+        * we get -ENOSYS from clk_enable(). To handle this, we
+        * don't fail for ret == -ENOSYS.
         */
-#ifndef CONFIG_MACB_ZYNQ
        ret = clk_enable(&clk);
-       if (ret)
+       if (ret && ret != -ENOSYS)
                return ret;
-#endif
 
        clk_rate = clk_get_rate(&clk);
        if (!clk_rate)
@@ -1081,12 +1215,17 @@ static int macb_enable_clk(struct udevice *dev)
 }
 #endif
 
+static const struct macb_config default_gem_config = {
+       .dma_burst_length = 16,
+       .clk_init = NULL,
+};
+
 static int macb_eth_probe(struct udevice *dev)
 {
        struct eth_pdata *pdata = dev_get_platdata(dev);
        struct macb_device *macb = dev_get_priv(dev);
        const char *phy_mode;
-       __maybe_unused int ret;
+       int ret;
 
        phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode",
                               NULL);
@@ -1099,6 +1238,12 @@ static int macb_eth_probe(struct udevice *dev)
 
        macb->regs = (void *)pdata->iobase;
 
+       macb->is_big_endian = (cpu_to_be32(0x12345678) == 0x12345678);
+
+       macb->config = (struct macb_config *)dev_get_driver_data(dev);
+       if (!macb->config)
+               macb->config = &default_gem_config;
+
 #ifdef CONFIG_CLK
        ret = macb_enable_clk(dev);
        if (ret)
@@ -1152,18 +1297,33 @@ static int macb_eth_ofdata_to_platdata(struct udevice *dev)
 {
        struct eth_pdata *pdata = dev_get_platdata(dev);
 
-       pdata->iobase = devfdt_get_addr(dev);
+       pdata->iobase = (phys_addr_t)dev_remap_addr(dev);
+       if (!pdata->iobase)
+               return -EINVAL;
 
        return macb_late_eth_ofdata_to_platdata(dev);
 }
 
+static const struct macb_config sama5d4_config = {
+       .dma_burst_length = 4,
+       .clk_init = NULL,
+};
+
+static const struct macb_config sifive_config = {
+       .dma_burst_length = 16,
+       .clk_init = macb_sifive_clk_init,
+};
+
 static const struct udevice_id macb_eth_ids[] = {
        { .compatible = "cdns,macb" },
        { .compatible = "cdns,at91sam9260-macb" },
+       { .compatible = "cdns,sam9x60-macb" },
        { .compatible = "atmel,sama5d2-gem" },
        { .compatible = "atmel,sama5d3-gem" },
-       { .compatible = "atmel,sama5d4-gem" },
+       { .compatible = "atmel,sama5d4-gem", .data = (ulong)&sama5d4_config },
        { .compatible = "cdns,zynq-gem" },
+       { .compatible = "sifive,fu540-c000-gem",
+         .data = (ulong)&sifive_config },
        { }
 };