Merge tag 'u-boot-imx-20191009' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
[oweals/u-boot.git] / drivers / net / macb.c
index dc6aa6deda8347db6bdf41a4c610af8996df6472..1a532b0e5a4f603a75deca3edb51fc7c389a7c75 100644 (file)
 
 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
 
@@ -82,7 +90,10 @@ struct macb_dma_desc {
 
 struct macb_device {
        void                    *regs;
-       unsigned int            dma_burst_length;
+
+       bool                    is_big_endian;
+
+       const struct macb_config *config;
 
        unsigned int            rx_tail;
        unsigned int            tx_head;
@@ -94,6 +105,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;
@@ -122,6 +134,8 @@ struct macb_device {
 
 struct macb_config {
        unsigned int            dma_burst_length;
+
+       int                     (*clk_init)(struct udevice *dev, ulong rate);
 };
 
 #ifndef CONFIG_DM_ETH
@@ -282,13 +296,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)
@@ -394,15 +410,16 @@ static int _macb_recv(struct macb_device *macb, uchar **packetp)
                }
 
                if (status & MACB_BIT(RX_EOF)) {
-                       buffer = macb->rx_buffer + 128 * macb->rx_tail;
+                       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);
@@ -482,21 +499,38 @@ static int macb_phy_find(struct macb_device *macb, const char *name)
  * 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;
 
-       /*
-        * "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;
-
        switch (speed) {
        case _10BASET:
                rate = 2500000;         /* 2.5 MHz */
@@ -512,6 +546,17 @@ int __weak macb_linkspd_cb(struct udevice *dev, unsigned int speed)
                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)
@@ -600,7 +645,7 @@ 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_LPA);
+               lpa = macb_mdio_read(macb, MII_STAT1000);
 
                if (lpa & (LPA_1000FULL | LPA_1000HALF | LPA_1000XFULL |
                                        LPA_1000XHALF)) {
@@ -697,6 +742,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
@@ -722,7 +792,7 @@ static int _macb_init(struct macb_device *macb, const char *name)
                        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);
@@ -750,6 +820,8 @@ static int _macb_init(struct macb_device *macb, const char *name)
        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);
 
@@ -931,8 +1003,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);
@@ -1143,15 +1221,15 @@ static int macb_enable_clk(struct udevice *dev)
 
 static const struct macb_config default_gem_config = {
        .dma_burst_length = 16,
+       .clk_init = NULL,
 };
 
 static int macb_eth_probe(struct udevice *dev)
 {
-       const struct macb_config *macb_config;
        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);
@@ -1164,11 +1242,12 @@ static int macb_eth_probe(struct udevice *dev)
 
        macb->regs = (void *)pdata->iobase;
 
-       macb_config = (struct macb_config *)dev_get_driver_data(dev);
-       if (!macb_config)
-               macb_config = &default_gem_config;
+       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;
 
-       macb->dma_burst_length = macb_config->dma_burst_length;
 #ifdef CONFIG_CLK
        ret = macb_enable_clk(dev);
        if (ret)
@@ -1231,15 +1310,24 @@ static int macb_eth_ofdata_to_platdata(struct udevice *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", .data = (ulong)&sama5d4_config },
        { .compatible = "cdns,zynq-gem" },
+       { .compatible = "sifive,fu540-c000-gem",
+         .data = (ulong)&sifive_config },
        { }
 };