From: Rob Herring <rob.herr...@calxeda.com>

This adds ethernet driver for Calxeda xgmac found on Highbank SOC.

Signed-off-by: Rob Herring <rob.herr...@calxeda.com>
---
 README                     |    6 +
 drivers/net/Makefile       |    1 +
 drivers/net/calxedaxgmac.c |  552 ++++++++++++++++++++++++++++++++++++++++++++
 include/netdev.h           |    1 +
 4 files changed, 560 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/calxedaxgmac.c

diff --git a/README b/README
index fda0190..43a48ed 100644
--- a/README
+++ b/README
@@ -1003,6 +1003,12 @@ The following options need to be configured:
                        If this defined, the driver is quiet.
                        The driver doen't show link status messages.
 
+               CONFIG_CALXEDA_XGMAC
+               Support for the Calxeda XGMAC adapter
+                       CONFIG_CALXEDA_XGMAC_BASE
+                       Define this to hold the physical address
+                       of the device (I/O space)
+
                CONFIG_DRIVER_LAN91C96
                Support for SMSC's LAN91C96 chips.
 
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index d3df82e..f4f7ea3 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -31,6 +31,7 @@ COBJS-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
 COBJS-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
 COBJS-$(CONFIG_DRIVER_AX88180) += ax88180.o
 COBJS-$(CONFIG_BFIN_MAC) += bfin_mac.o
+COBJS-$(CONFIG_CALXEDA_XGMAC) += calxedaxgmac.o
 COBJS-$(CONFIG_CS8900) += cs8900.o
 COBJS-$(CONFIG_TULIP) += dc2114x.o
 COBJS-$(CONFIG_DESIGNWARE_ETH) += designware.o
diff --git a/drivers/net/calxedaxgmac.c b/drivers/net/calxedaxgmac.c
new file mode 100644
index 0000000..6429d9a
--- /dev/null
+++ b/drivers/net/calxedaxgmac.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright 2010-2011 Calxeda, Inc.
+ *
+ * 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 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, see <http://www.gnu.org/licenses/>.
+ */
+#include <common.h>
+#include <malloc.h>
+#include <linux/err.h>
+#include <asm/io.h>
+
+#define TX_NUM_DESC                    1
+#define RX_NUM_DESC                    32
+
+#define MAC_TIMEOUT                    (5*CONFIG_SYS_HZ)
+
+#define ETH_BUF_SZ                     2048
+#define TX_BUF_SZ                      (ETH_BUF_SZ * TX_NUM_DESC)
+#define RX_BUF_SZ                      (ETH_BUF_SZ * RX_NUM_DESC)
+
+#define RXSTART                                0x00000002
+#define TXSTART                                0x00002000
+
+#define RXENABLE                       0x00000004
+#define TXENABLE                       0x00000008
+
+#define XGMAC_CONTROL_SPD              0x40000000
+#define XGMAC_CONTROL_SPD_MASK         0x60000000
+#define XGMAC_CONTROL_SARC             0x10000000
+#define XGMAC_CONTROL_SARK_MASK                0x18000000
+#define XGMAC_CONTROL_CAR              0x04000000
+#define XGMAC_CONTROL_CAR_MASK         0x06000000
+#define XGMAC_CONTROL_CAR_SHIFT                25
+#define XGMAC_CONTROL_DP               0x01000000
+#define XGMAC_CONTROL_WD               0x00800000
+#define XGMAC_CONTROL_JD               0x00400000
+#define XGMAC_CONTROL_JE               0x00100000
+#define XGMAC_CONTROL_LM               0x00001000
+#define XGMAC_CONTROL_IPC              0x00000400
+#define XGMAC_CONTROL_ACS              0x00000080
+#define XGMAC_CONTROL_DDIC             0x00000010
+#define XGMAC_CONTROL_TE               0x00000008
+#define XGMAC_CONTROL_RE               0x00000004
+
+#define XGMAC_DMA_BUSMODE_RESET                0x00000001
+#define XGMAC_DMA_BUSMODE_DSL          0x00000004
+#define XGMAC_DMA_BUSMODE_DSL_MASK     0x0000007c
+#define XGMAC_DMA_BUSMODE_DSL_SHIFT    2
+#define XGMAC_DMA_BUSMODE_ATDS         0x00000080
+#define XGMAC_DMA_BUSMODE_PBL_MASK     0x00003f00
+#define XGMAC_DMA_BUSMODE_PBL_SHIFT    8
+#define XGMAC_DMA_BUSMODE_FB           0x00010000
+#define XGMAC_DMA_BUSMODE_USP          0x00800000
+#define XGMAC_DMA_BUSMODE_8PBL         0x01000000
+#define XGMAC_DMA_BUSMODE_AAL          0x02000000
+
+#define XGMAC_DMA_AXIMODE_ENLPI                0x80000000
+#define XGMAC_DMA_AXIMODE_MGK          0x40000000
+#define XGMAC_DMA_AXIMODE_WROSR                0x00100000
+#define XGMAC_DMA_AXIMODE_WROSR_MASK   0x00F00000
+#define XGMAC_DMA_AXIMODE_WROSR_SHIFT  20
+#define XGMAC_DMA_AXIMODE_RDOSR                0x00010000
+#define XGMAC_DMA_AXIMODE_RDOSR_MASK   0x000F0000
+#define XGMAC_DMA_AXIMODE_RDOSR_SHIFT  16
+#define XGMAC_DMA_AXIMODE_AAL          0x00001000
+#define XGMAC_DMA_AXIMODE_BLEN256      0x00000080
+#define XGMAC_DMA_AXIMODE_BLEN128      0x00000040
+#define XGMAC_DMA_AXIMODE_BLEN64       0x00000020
+#define XGMAC_DMA_AXIMODE_BLEN32       0x00000010
+#define XGMAC_DMA_AXIMODE_BLEN16       0x00000008
+#define XGMAC_DMA_AXIMODE_BLEN8                0x00000004
+#define XGMAC_DMA_AXIMODE_BLEN4                0x00000002
+#define XGMAC_DMA_AXIMODE_UNDEF                0x00000001
+
+#define XGMAC_CORE_OMR_RTC_SHIFT       3
+#define XGMAC_CORE_OMR_RTC_MASK                0x00000018
+#define XGMAC_CORE_OMR_RTC             0x00000010
+#define XGMAC_CORE_OMR_RSF             0x00000020
+#define XGMAC_CORE_OMR_DT              0x00000040
+#define XGMAC_CORE_OMR_FEF             0x00000080
+#define XGMAC_CORE_OMR_EFC             0x00000100
+#define XGMAC_CORE_OMR_RFA_SHIFT       9
+#define XGMAC_CORE_OMR_RFA_MASK                0x00000E00
+#define XGMAC_CORE_OMR_RFD_SHIFT       12
+#define XGMAC_CORE_OMR_RFD_MASK                0x00007000
+#define XGMAC_CORE_OMR_TTC_SHIFT       16
+#define XGMAC_CORE_OMR_TTC_MASK                0x00030000
+#define XGMAC_CORE_OMR_TTC             0x00020000
+#define XGMAC_CORE_OMR_FTF             0x00100000
+#define XGMAC_CORE_OMR_TSF             0x00200000
+
+#define FIFO_MINUS_1K                  0x0
+#define FIFO_MINUS_2K                  0x1
+#define FIFO_MINUS_3K                  0x2
+#define FIFO_MINUS_4K                  0x3
+#define FIFO_MINUS_6K                  0x4
+#define FIFO_MINUS_8K                  0x5
+#define FIFO_MINUS_12K                 0x6
+#define FIFO_MINUS_16K                 0x7
+
+#define XGMAC_CORE_FLOW_PT_SHIFT       16
+#define XGMAC_CORE_FLOW_PT_MASK                0xFFFF0000
+#define XGMAC_CORE_FLOW_PT             0x00010000
+#define XGMAC_CORE_FLOW_DZQP           0x00000080
+#define XGMAC_CORE_FLOW_PLT_SHIFT      4
+#define XGMAC_CORE_FLOW_PLT_MASK       0x00000030
+#define XGMAC_CORE_FLOW_PLT            0x00000010
+#define XGMAC_CORE_FLOW_UP             0x00000008
+#define XGMAC_CORE_FLOW_RFE            0x00000004
+#define XGMAC_CORE_FLOW_TFE            0x00000002
+#define XGMAC_CORE_FLOW_FCB            0x00000001
+
+#define XGMAC_CORE_CONFIG              0x00000000
+#define XGMAC_CORE_FRAMEFILTER         0x00000004
+#define XGMAC_CORE_FLOW                        0x00000018
+#define XGMAC_CORE_VLANTAG             0x0000001C
+#define XGMAC_CORE_VERSION             0x00000020
+#define XGMAC_CORE_VLANINCLUDE         0x00000024
+#define XGMAC_CORE_LPICONTROL          0x00000028
+#define XGMAC_CORE_LPITIMERS           0x0000002C
+#define XGMAC_CORE_PACESTRETCH         0x00000030
+#define XGMAC_CORE_VLANHASH            0x00000034
+#define XGMAC_CORE_DEBUG               0x00000038
+#define XGMAC_CORE_INT                 0x0000003C
+#define XGMAC_CORE_MACADDR0HI          0x00000040
+#define XGMAC_CORE_MACADDR0LO          0x00000044
+#define XGMAC_CORE_OMR                 0x00000400
+
+#define XGMAC_DMA_BUSMODE              0x00000f00
+#define XGMAC_DMA_TXPOLL               0x00000f04
+#define XGMAC_DMA_RXPOLL               0x00000f08
+#define XGMAC_DMA_RXDESCLIST           0x00000f0C
+#define XGMAC_DMA_TXDESCLIST           0x00000f10
+#define XGMAC_DMA_STATUS               0x00000f14
+#define XGMAC_DMA_OMR                  0x00000f18
+#define XGMAC_DMA_INTENABLE            0x00000f1C
+#define XGMAC_DMA_MISSEDFRAME          0x00000f20
+#define XGMAC_DMA_RXWATCHDOG           0x00000f24
+#define XGMAC_DMA_AXIMODE              0x00000f28
+#define XGMAC_DMA_AXISTATUS            0x00000f2C
+#define XGMAC_DMA_CURTXDESC            0x00000f48
+#define XGMAC_DMA_CURRXDESC            0x00000f4C
+#define XGMAC_DMA_CURTXBUF             0x00000f50
+#define XGMAC_DMA_CURRXBUF             0x00000f54
+
+/* XGMAC Descriptor Defines */
+#define MAX_DESC_BUF_SZ                        (0x2000 - 8)
+
+#define RXDESC_EXT_STATUS              0x00000001
+#define RXDESC_CRC_ERR                 0x00000002
+#define RXDESC_RX_ERR                  0x00000008
+#define RXDESC_RX_WDOG                 0x00000010
+#define RXDESC_FRAME_TYPE              0x00000020
+#define RXDESC_GIANT_FRAME             0x00000080
+#define RXDESC_LAST_SEG                        0x00000100
+#define RXDESC_FIRST_SEG               0x00000200
+#define RXDESC_VLAN_FRAME              0x00000400
+#define RXDESC_OVERFLOW_ERR            0x00000800
+#define RXDESC_LENGTH_ERR              0x00001000
+#define RXDESC_SA_FILTER_FAIL          0x00002000
+#define RXDESC_DESCRIPTOR_ERR          0x00004000
+#define RXDESC_ERROR_SUMMARY           0x00008000
+#define RXDESC_FRAME_LEN_OFFSET                16
+#define RXDESC_FRAME_LEN_MASK          0x3fff0000
+#define RXDESC_DA_FILTER_FAIL          0x40000000
+
+#define RXDESC1_END_RING               0x00008000
+
+#define RXDESC_IP_PAYLOAD_MASK         0x00000003
+#define RXDESC_IP_PAYLOAD_UDP          0x00000001
+#define RXDESC_IP_PAYLOAD_TCP          0x00000002
+#define RXDESC_IP_PAYLOAD_ICMP         0x00000003
+#define RXDESC_IP_HEADER_ERR           0x00000008
+#define RXDESC_IP_PAYLOAD_ERR          0x00000010
+#define RXDESC_IPV4_PACKET             0x00000040
+#define RXDESC_IPV6_PACKET             0x00000080
+#define TXDESC_UNDERFLOW_ERR           0x00000001
+#define TXDESC_JABBER_TIMEOUT          0x00000002
+#define TXDESC_LOCAL_FAULT             0x00000004
+#define TXDESC_REMOTE_FAULT            0x00000008
+#define TXDESC_VLAN_FRAME              0x00000010
+#define TXDESC_FRAME_FLUSHED           0x00000020
+#define TXDESC_IP_HEADER_ERR           0x00000040
+#define TXDESC_PAYLOAD_CSUM_ERR                0x00000080
+#define TXDESC_ERROR_SUMMARY           0x00008000
+#define TXDESC_SA_CTRL_INSERT          0x00040000
+#define TXDESC_SA_CTRL_REPLACE         0x00080000
+#define TXDESC_2ND_ADDR_CHAINED                0x00100000
+#define TXDESC_END_RING                        0x00200000
+#define TXDESC_CSUM_IP                 0x00400000
+#define TXDESC_CSUM_IP_PAYLD           0x00800000
+#define TXDESC_CSUM_ALL                        0x00C00000
+#define TXDESC_CRC_EN_REPLACE          0x01000000
+#define TXDESC_CRC_EN_APPEND           0x02000000
+#define TXDESC_DISABLE_PAD             0x04000000
+#define TXDESC_FIRST_SEG               0x10000000
+#define TXDESC_LAST_SEG                        0x20000000
+#define TXDESC_INTERRUPT               0x40000000
+
+#define DESC_OWN                       0x80000000
+#define DESC_BUFFER1_SZ_MASK           0x00001fff
+#define DESC_BUFFER2_SZ_MASK           0x1fff0000
+#define DESC_BUFFER2_SZ_OFFSET         16
+
+struct xgmac_dma_desc {
+       __le32 flags;
+       __le32 buf_size;
+       __le32 buf1_addr;               /* Buffer 1 Address Pointer */
+       __le32 buf2_addr;               /* Buffer 2 Address Pointer */
+       __le32 ext_status;
+       __le32 res[3];
+};
+
+/* XGMAC Descriptor Access Helpers */
+static inline void desc_set_buf_len(struct xgmac_dma_desc *p, u32 buf_sz)
+{
+       if (buf_sz > MAX_DESC_BUF_SZ)
+               p->buf_size = cpu_to_le32(MAX_DESC_BUF_SZ |
+                       (buf_sz - MAX_DESC_BUF_SZ) << DESC_BUFFER2_SZ_OFFSET);
+       else
+               p->buf_size = cpu_to_le32(buf_sz);
+}
+
+static inline int desc_get_buf_len(struct xgmac_dma_desc *p)
+{
+       u32 len = le32_to_cpu(p->buf_size);
+       return (len & DESC_BUFFER1_SZ_MASK) +
+               ((len & DESC_BUFFER2_SZ_MASK) >> DESC_BUFFER2_SZ_OFFSET);
+}
+
+static inline void desc_init_rx_desc(struct xgmac_dma_desc *p, int ring_size,
+                                    int buf_sz)
+{
+       struct xgmac_dma_desc *end = p + ring_size - 1;
+
+       memset(p, 0, sizeof(*p) * ring_size);
+
+       for (; p <= end; p++)
+               desc_set_buf_len(p, buf_sz);
+
+       end->buf_size |= cpu_to_le32(RXDESC1_END_RING);
+}
+
+static inline void desc_init_tx_desc(struct xgmac_dma_desc *p, u32 ring_size)
+{
+       memset(p, 0, sizeof(*p) * ring_size);
+       p[ring_size - 1].flags = cpu_to_le32(TXDESC_END_RING);
+}
+
+static inline int desc_get_owner(struct xgmac_dma_desc *p)
+{
+       return le32_to_cpu(p->flags) & DESC_OWN;
+}
+
+static inline void desc_set_rx_owner(struct xgmac_dma_desc *p)
+{
+       /* Clear all fields and set the owner */
+       p->flags = cpu_to_le32(DESC_OWN);
+}
+
+static inline void desc_set_tx_owner(struct xgmac_dma_desc *p, u32 flags)
+{
+       u32 tmpflags = le32_to_cpu(p->flags);
+       tmpflags &= TXDESC_END_RING;
+       tmpflags |= flags | DESC_OWN;
+       p->flags = cpu_to_le32(tmpflags);
+}
+
+static inline void *desc_get_buf_addr(struct xgmac_dma_desc *p)
+{
+       return (void *)le32_to_cpu(p->buf1_addr);
+}
+
+static inline void desc_set_buf_addr(struct xgmac_dma_desc *p,
+                                    void *paddr, int len)
+{
+       p->buf1_addr = cpu_to_le32(paddr);
+       if (len > MAX_DESC_BUF_SZ)
+               p->buf2_addr = cpu_to_le32(paddr + MAX_DESC_BUF_SZ);
+}
+
+static inline void desc_set_buf_addr_and_size(struct xgmac_dma_desc *p,
+                                             void *paddr, int len)
+{
+       desc_set_buf_len(p, len);
+       desc_set_buf_addr(p, paddr, len);
+}
+
+static inline int desc_get_rx_frame_len(struct xgmac_dma_desc *p)
+{
+       u32 data = le32_to_cpu(p->flags);
+       u32 len = (data & RXDESC_FRAME_LEN_MASK) >> RXDESC_FRAME_LEN_OFFSET;
+       if (data & RXDESC_FRAME_TYPE)
+               len -= 4;
+
+       return len;
+}
+
+struct calxeda_eth_dev {
+       struct xgmac_dma_desc rx_chain[RX_NUM_DESC];
+       struct xgmac_dma_desc tx_chain[TX_NUM_DESC];
+       char rxbuffer[RX_BUF_SZ];
+
+       u32 tx_currdesc;
+       u32 rx_currdesc;
+
+       struct eth_device *dev;
+} __attribute__((aligned(32)));
+
+/*
+ * Initialize a descriptor ring.  Calxeda XGMAC is configured to use
+ * advanced descriptors.
+ */
+
+static void init_rx_desc(struct calxeda_eth_dev *priv)
+{
+       struct xgmac_dma_desc *rxdesc = priv->rx_chain;
+       void *rxbuffer = priv->rxbuffer;
+       int i;
+
+       desc_init_rx_desc(rxdesc, RX_NUM_DESC, ETH_BUF_SZ);
+       writel((ulong)rxdesc, priv->dev->iobase + XGMAC_DMA_RXDESCLIST);
+
+       for (i = 0; i < RX_NUM_DESC; i++) {
+               desc_set_buf_addr(rxdesc + i, rxbuffer + (i * ETH_BUF_SZ),
+                                 ETH_BUF_SZ);
+               desc_set_rx_owner(rxdesc + i);
+       };
+}
+
+static void init_tx_desc(struct calxeda_eth_dev *priv)
+{
+       desc_init_tx_desc(priv->tx_chain, TX_NUM_DESC);
+       writel((ulong)priv->tx_chain, priv->dev->iobase + XGMAC_DMA_TXDESCLIST);
+}
+
+static int xgmac_reset(struct eth_device *dev)
+{
+       int timeout = MAC_TIMEOUT;
+       u32 value;
+
+       value = readl(dev->iobase + XGMAC_CORE_CONFIG) & XGMAC_CONTROL_SPD_MASK;
+
+       writel(XGMAC_DMA_BUSMODE_RESET, dev->iobase + XGMAC_DMA_BUSMODE);
+       while ((timeout-- >= 0) &&
+               (readl(dev->iobase + XGMAC_DMA_BUSMODE) & 
XGMAC_DMA_BUSMODE_RESET))
+               udelay(1);
+
+       writel(value, dev->iobase + XGMAC_CORE_CONFIG);
+
+       return timeout;
+}
+
+static void xgmac_hwmacaddr(struct eth_device *dev)
+{
+       u32 macaddr[2];
+
+       memcpy(macaddr, dev->enetaddr, 6);
+       writel(macaddr[1], dev->iobase + XGMAC_CORE_MACADDR0HI);
+       writel(macaddr[0], dev->iobase + XGMAC_CORE_MACADDR0LO);
+}
+
+static int xgmac_init(struct eth_device *dev, bd_t * bis)
+{
+       struct calxeda_eth_dev *priv = dev->priv;
+       int value;
+
+       /* check that there is a valid MAC address */
+       if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) == 0) {
+               printf("ERROR: ethaddr not set!\n");
+               return -1;
+       }
+
+       /* set the hardware MAC address */
+       xgmac_hwmacaddr(dev);
+
+       /* set the AXI bus modes */
+       value = XGMAC_DMA_BUSMODE_ATDS |
+               (16 << XGMAC_DMA_BUSMODE_PBL_SHIFT) |
+               XGMAC_DMA_BUSMODE_FB | XGMAC_DMA_BUSMODE_AAL;
+       writel(value, dev->iobase + XGMAC_DMA_BUSMODE);
+
+       value = XGMAC_DMA_AXIMODE_AAL | XGMAC_DMA_AXIMODE_BLEN16 |
+               XGMAC_DMA_AXIMODE_BLEN8 | XGMAC_DMA_AXIMODE_BLEN4;
+       writel(value, dev->iobase + XGMAC_DMA_AXIMODE);
+
+       /* set flow control parameters and store and forward mode */
+       value = (FIFO_MINUS_12K << XGMAC_CORE_OMR_RFD_SHIFT) |
+               (FIFO_MINUS_4K << XGMAC_CORE_OMR_RFA_SHIFT) |
+               XGMAC_CORE_OMR_EFC | XGMAC_CORE_OMR_TSF | XGMAC_CORE_OMR_RSF;
+       writel(value, dev->iobase + XGMAC_CORE_OMR);
+
+       /* enable pause frames */
+       value = (1024 << XGMAC_CORE_FLOW_PT_SHIFT) |
+               (1 << XGMAC_CORE_FLOW_PLT_SHIFT) |
+               XGMAC_CORE_FLOW_UP | XGMAC_CORE_FLOW_RFE | XGMAC_CORE_FLOW_TFE;
+       writel(value, dev->iobase + XGMAC_CORE_FLOW);
+
+       /* set default core values */
+       value = readl(dev->iobase + XGMAC_CORE_CONFIG);
+       value &= XGMAC_CONTROL_SPD_MASK;
+       value |= XGMAC_CONTROL_DDIC | XGMAC_CONTROL_ACS |
+               XGMAC_CONTROL_IPC | XGMAC_CONTROL_CAR;
+       writel(value, dev->iobase + XGMAC_CORE_CONFIG);
+
+       /* Initialize the descriptor chains */
+       init_rx_desc(priv);
+       init_tx_desc(priv);
+
+       /* must set to 0, or when started up will cause issues */
+       priv->tx_currdesc = 0;
+       priv->rx_currdesc = 0;
+
+       /* Everything is ready enable both mac and DMA */
+       value = readl(dev->iobase + XGMAC_CORE_CONFIG);
+       value |= RXENABLE | TXENABLE;
+       writel(value, dev->iobase + XGMAC_CORE_CONFIG);
+
+       value = readl(dev->iobase + XGMAC_DMA_OMR);
+       value |= RXSTART | TXSTART;
+       writel(value, dev->iobase + XGMAC_DMA_OMR);
+
+       return 0;
+}
+
+static int xgmac_tx(struct eth_device *dev, volatile void *packet, int length)
+{
+       struct calxeda_eth_dev *priv = dev->priv;
+       u32 currdesc = priv->tx_currdesc;
+       struct xgmac_dma_desc *txdesc = &priv->tx_chain[currdesc];
+       int timeout;
+
+       desc_set_buf_addr_and_size(txdesc, packet, length);
+       desc_set_tx_owner(txdesc, TXDESC_FIRST_SEG |
+               TXDESC_LAST_SEG | TXDESC_CRC_EN_APPEND);
+
+       /* write poll demand */
+       writel(1, dev->iobase + XGMAC_DMA_TXPOLL);
+
+       timeout = 1000000;
+       while (desc_get_owner(txdesc)) {
+               if (timeout-- < 0) {
+                       printf("xgmac: TX timeout\n");
+                       return -ETIMEDOUT;
+               }
+               udelay(1);
+       }
+
+       priv->tx_currdesc = (currdesc + 1) & (TX_NUM_DESC - 1);
+       return 0;
+}
+
+static int xgmac_rx(struct eth_device *dev)
+{
+       struct calxeda_eth_dev *priv = dev->priv;
+       u32 currdesc = priv->rx_currdesc;
+       struct xgmac_dma_desc *rxdesc = &priv->rx_chain[currdesc];
+       int length = 0;
+
+       /* check if the host has the desc */
+       if (desc_get_owner(rxdesc))
+               return -1; /* something bad happened */
+
+       length = desc_get_rx_frame_len(rxdesc);
+
+       NetReceive((volatile unsigned char *)desc_get_buf_addr(rxdesc), length);
+
+       /* set descriptor back to owned by XGMAC */
+       desc_set_rx_owner(rxdesc);
+       writel(1, dev->iobase + XGMAC_DMA_RXPOLL);
+
+       priv->rx_currdesc = (currdesc + 1) & (RX_NUM_DESC - 1);
+
+       return length;
+}
+
+static void xgmac_halt(struct eth_device *dev)
+{
+       struct calxeda_eth_dev *priv = dev->priv;
+       int value;
+
+       /* Disable TX/RX */
+       value = readl(dev->iobase + XGMAC_CORE_CONFIG);
+       value &= ~(RXENABLE | TXENABLE);
+       writel(value, dev->iobase + XGMAC_CORE_CONFIG);
+
+       /* Disable DMA */
+       value = readl(dev->iobase + XGMAC_DMA_OMR);
+       value &= ~(RXSTART | TXSTART);
+       writel(value, dev->iobase + XGMAC_DMA_OMR);
+
+       /* must set to 0, or when started up will cause issues */
+       priv->tx_currdesc = 0;
+       priv->rx_currdesc = 0;
+}
+
+int calxedaxgmac_initialize(u32 id, ulong base_addr)
+{
+       struct eth_device *dev;
+       struct calxeda_eth_dev *priv;
+       u32 macaddr[2];
+       char enetvar[32];
+
+       dev = malloc(sizeof(*dev));
+       if (!dev)
+               return -ENOMEM;
+       memset(dev, 0, sizeof(*dev));
+
+       /* Structure must be aligned, because it contains the descriptors */
+       priv = (struct calxeda_eth_dev *)memalign(32, sizeof(*priv));
+       if (!priv) {
+               free(dev);
+               return -ENOMEM;
+       }
+
+       dev->iobase = (int)base_addr;
+       dev->priv = priv;
+
+       /* check hardware version */
+       if (readl(dev->iobase + XGMAC_CORE_VERSION) != 0x1012)
+               return -EINVAL;
+
+       sprintf(dev->name, "xgmac%d", id);
+
+       macaddr[1] = readl(dev->iobase + XGMAC_CORE_MACADDR0HI);
+       macaddr[0] = readl(dev->iobase + XGMAC_CORE_MACADDR0LO);
+       memcpy(dev->enetaddr, macaddr, 6);
+       sprintf(enetvar, id ? "eth%daddr" : "ethaddr", id);
+       eth_setenv_enetaddr(enetvar, dev->enetaddr);
+
+       priv->dev = dev;
+
+       dev->init = xgmac_init;
+       dev->send = xgmac_tx;
+       dev->recv = xgmac_rx;
+       dev->halt = xgmac_halt;
+
+       if (xgmac_reset(dev) < 0)
+               return -1;
+
+       return eth_register(dev);
+}
diff --git a/include/netdev.h b/include/netdev.h
index 04d9f75..96e9f8f 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -48,6 +48,7 @@ int at91emac_register(bd_t *bis, unsigned long iobase);
 int au1x00_enet_initialize(bd_t*);
 int ax88180_initialize(bd_t *bis);
 int bfin_EMAC_initialize(bd_t *bis);
+int calxedaxgmac_initialize(u32 id, ulong base_addr);
 int cs8900_initialize(u8 dev_num, int base_addr);
 int davinci_emac_initialize(void);
 int dc21x4x_initialize(bd_t *bis);
-- 
1.7.5.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to