@@ -0,0 +1,544 @@
+/* MOXA ART Ethernet (RTL8201CP) driver.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * Based on code from
+ * Moxa Technology Co., Ltd. <www.moxa.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <linux/ethtool.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/crc32.h>
+#include <linux/crc32c.h>
+
+#include "moxart_ether.h"
+
+static inline unsigned long moxart_emac_read(struct net_device *ndev,
+ unsigned int reg)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ return readl(priv->base + reg);
+}
+
+static inline void moxart_emac_write(struct net_device *ndev,
+ unsigned int reg, unsigned long value)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ writel(value, priv->base + reg);
+}
+
+static void moxart_update_mac_address(struct net_device *ndev)
+{
+ moxart_emac_write(ndev, MAC_MADR_REG_OFFSET,
+ ((ndev->dev_addr[0] << 8) | (ndev->dev_addr[1])));
+ moxart_emac_write(ndev, MAC_MADR_REG_OFFSET + 4,
+ ((ndev->dev_addr[2] << 24) |
+ (ndev->dev_addr[3] << 16) |
+ (ndev->dev_addr[4] << 8) |
+ (ndev->dev_addr[5])));
+}
+
+static int moxart_set_mac_address(struct net_device *ndev, void *addr)
+{
+ struct sockaddr *address = addr;
+
+ if (!is_valid_ether_addr(address->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(ndev->dev_addr, address->sa_data, ndev->addr_len);
+ moxart_update_mac_address(ndev);
+
+ return 0;
+}
+
+static void moxart_mac_free_memory(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ if (priv->virt_tx_desc_baseaddr)
+ dma_free_coherent(NULL, sizeof(struct tx_desc_t)*TX_DESC_NUM,
+ priv->virt_tx_desc_baseaddr,
+ priv->phy_tx_desc_baseaddr);
+ if (priv->virt_rx_desc_baseaddr)
+ dma_free_coherent(NULL, sizeof(struct rx_desc_t)*RX_DESC_NUM,
+ priv->virt_rx_desc_baseaddr,
+ priv->phy_rx_desc_baseaddr);
+ if (priv->virt_tx_buf_baseaddr)
+ dma_free_coherent(NULL, TX_BUF_SIZE*TX_DESC_NUM,
+ priv->virt_tx_buf_baseaddr,
+ priv->phy_tx_buf_baseaddr);
+ if (priv->virt_rx_buf_baseaddr)
+ dma_free_coherent(NULL, RX_BUF_SIZE*RX_DESC_NUM,
+ priv->virt_rx_buf_baseaddr,
+ priv->phy_rx_buf_baseaddr);
+}
+
+static void moxart_mac_reset(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ writel(SW_RST, priv->base + MACCR_REG_OFFSET);
+ while (readl(priv->base + MACCR_REG_OFFSET) & SW_RST)
+ mdelay(10);
+
+ writel(0, priv->base + IMR_REG_OFFSET);
+
+ priv->maccr = RX_BROADPKT | FULLDUP | CRC_APD | RX_FTL;
+}
+
+static void moxart_mac_enable(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ writel(0x00001010, priv->base + ITC_REG_OFFSET);
+ writel(0x00000001, priv->base + APTC_REG_OFFSET);
+ writel(0x00000390, priv->base + DBLAC_REG_OFFSET);
+
+ writel(RPKT_FINISH_M, priv->base + IMR_REG_OFFSET);
+ priv->maccr |= (RCV_EN | XMT_EN | RDMA_EN | XDMA_EN);
+ writel(priv->maccr, priv->base + MACCR_REG_OFFSET);
+}
+
+static void moxart_mac_setup_desc_ring(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ struct tx_desc_t *txdesc;
+ struct rx_desc_t *rxdesc;
+ unsigned char *virtbuf;
+ unsigned int phybuf;
+ int i;
+
+ virtbuf = priv->virt_tx_buf_baseaddr;
+ phybuf = priv->phy_tx_buf_baseaddr;
+ for (i = 0; i < TX_DESC_NUM; i++,
+ virtbuf += TX_BUF_SIZE, phybuf += TX_BUF_SIZE) {
+ txdesc = &priv->virt_tx_desc_baseaddr[i];
+ memset(txdesc, 0, sizeof(struct tx_desc_t));
+ txdesc->txdes2.phy_tx_buf_baseaddr = phybuf;
+ txdesc->txdes2.virt_tx_buf_baseaddr = virtbuf;
+ }
+ priv->virt_tx_desc_baseaddr[TX_DESC_NUM - 1].txdes1.ubit.edotr = 1;
+ priv->tx_desc_now = 0;
+
+ virtbuf = priv->virt_rx_buf_baseaddr;
+ phybuf = priv->phy_rx_buf_baseaddr;
+ for (i = 0; i < RX_DESC_NUM; i++,
+ virtbuf += RX_BUF_SIZE, phybuf += RX_BUF_SIZE) {
+ rxdesc = &priv->virt_rx_desc_baseaddr[i];
+ memset(rxdesc, 0, sizeof(struct rx_desc_t));
+ rxdesc->rxdes0.ubit.rx_dma_own = 1;
+ rxdesc->rxdes1.ubit.rx_buf_size = RX_BUF_SIZE;
+ rxdesc->rxdes2.phy_rx_buf_baseaddr = phybuf;
+ rxdesc->rxdes2.virt_rx_buf_baseaddr = virtbuf;
+ }
+ priv->virt_rx_desc_baseaddr[RX_DESC_NUM - 1].rxdes1.ubit.edorr = 1;
+ priv->rx_desc_now = 0;
+
+ /* reset the MAC controler TX/RX desciptor base address */
+ writel(priv->phy_tx_desc_baseaddr, priv->base + TXR_BADR_REG_OFFSET);
+ writel(priv->phy_rx_desc_baseaddr, priv->base + RXR_BADR_REG_OFFSET);
+}
+
+static int moxart_mac_open(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ return -EADDRNOTAVAIL;
+
+ spin_lock_irq(&priv->txlock);
+ moxart_mac_reset(ndev);
+ moxart_update_mac_address(ndev);
+ moxart_mac_setup_desc_ring(ndev);
+ moxart_mac_enable(ndev);
+ spin_unlock_irq(&priv->txlock);
+ netif_start_queue(ndev);
+
+ netdev_dbg(ndev, "%s: IMR=0x%x, MACCR=0x%x\n",
+ __func__, readl(priv->base + IMR_REG_OFFSET),
+ readl(priv->base + MACCR_REG_OFFSET));
+
+ return 0;
+}
+
+static int moxart_mac_stop(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ netif_stop_queue(ndev);
+ spin_lock_irq(&priv->txlock);
+
+ /* disable all interrupts */
+ writel(0, priv->base + IMR_REG_OFFSET);
+
+ /* disable all functions */
+ writel(0, priv->base + MACCR_REG_OFFSET);
+
+ spin_unlock_irq(&priv->txlock);
+
+ return 0;
+}
+
+static void moxart_mac_recv(struct work_struct *ptr)
+{
+ struct net_device *ndev = (struct net_device *) ptr;
+ struct moxart_mac_priv_t *priv = netdev_priv((struct net_device *)ptr);
+ struct rx_desc_t *rxdesc;
+ struct sk_buff *skb;
+ unsigned int ui, len;
+ int rxnow = priv->rx_desc_now;
+ int loops = RX_DESC_NUM;
+
+repeat_recv:
+ rxdesc = &priv->virt_rx_desc_baseaddr[rxnow];
+ ui = rxdesc->rxdes0.ui;
+
+ if (ui & RXDMA_OWN)
+ return;
+
+ if (ui & (RX_ERR | CRC_ERR | FTL | RUNT | RX_ODD_NB)) {
+ netdev_err(ndev, "%s: packet error\n", __func__);
+ priv->stats.rx_dropped++;
+ priv->stats.rx_errors++;
+ goto recv_finish;
+ }
+
+ len = ui & RFL_MASK;
+
+ if (len > RX_BUF_SIZE)
+ len = RX_BUF_SIZE;
+
+ skb = dev_alloc_skb(len + 2);
+ if (skb == NULL) {
+ netdev_err(ndev, "%s: dev_alloc_skb failed\n", __func__);
+ priv->stats.rx_dropped++;
+ goto recv_finish;
+ }
+
+ skb_reserve(skb, 2);
+ skb->dev = ndev;
+ memcpy(skb_put(skb, len), rxdesc->rxdes2.virt_rx_buf_baseaddr, len);
+ netif_rx(skb);
+ skb->protocol = eth_type_trans(skb, ndev);
+ ndev->last_rx = jiffies;
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += len;
+ if (ui & MULTICAST_RXDES0)
+ priv->stats.multicast++;
+
+recv_finish:
+ rxdesc->rxdes0.ui = RXDMA_OWN;
+ rxnow++;
+ rxnow &= RX_DESC_NUM_MASK;
+ priv->rx_desc_now = rxnow;
+ if (loops-- > 0)
+ goto repeat_recv;
+}
+
+static irqreturn_t moxart_mac_interrupt(int irq, void *dev_id)
+{
+ struct net_device *ndev = (struct net_device *) dev_id;
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ unsigned int ists = readl(priv->base + ISR_REG_OFFSET);
+
+ if (ists & RPKT_FINISH)
+ moxart_mac_recv((void *) ndev);
+
+ return IRQ_HANDLED;
+}
+
+static int moxart_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ struct tx_desc_t *txdesc;
+ int len;
+ int txnow = priv->tx_desc_now;
+
+ spin_lock_irq(&priv->txlock);
+ txdesc = &priv->virt_tx_desc_baseaddr[txnow];
+ if (txdesc->txdes0.ubit.tx_dma_own) {
+ netdev_err(ndev, "%s: no TX space for packet\n", __func__);
+ priv->stats.tx_dropped++;
+ goto xmit_final;
+ }
+
+ len = skb->len > TX_BUF_SIZE ? TX_BUF_SIZE : skb->len;
+ memcpy(txdesc->txdes2.virt_tx_buf_baseaddr, skb->data, len);
+
+ if (skb->len < ETH_ZLEN) {
+ memset(&txdesc->txdes2.virt_tx_buf_baseaddr[skb->len],
+ 0, ETH_ZLEN - skb->len);
+ len = ETH_ZLEN;
+ }
+
+ txdesc->txdes1.ubit.lts = 1;
+ txdesc->txdes1.ubit.fts = 1;
+ txdesc->txdes1.ubit.tx2_fic = 0;
+ txdesc->txdes1.ubit.tx_ic = 0;
+ txdesc->txdes1.ubit.tx_buf_size = len;
+ txdesc->txdes0.ui = TXDMA_OWN;
+
+ /* start to send packet */
+ writel(0xffffffff, priv->base + TXPD_REG_OFFSET);
+
+ txnow++;
+ txnow &= TX_DESC_NUM_MASK;
+ priv->tx_desc_now = txnow;
+ ndev->trans_start = jiffies;
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += len;
+
+xmit_final:
+ spin_unlock_irq(&priv->txlock);
+ dev_kfree_skb_any(skb);
+
+ return NETDEV_TX_OK;
+}
+
+static struct net_device_stats *moxart_mac_get_stats(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ int desc = priv->rx_desc_now;
+
+ desc++;
+ desc &= RX_DESC_NUM_MASK;
+
+ return &priv->stats;
+}
+
+static void moxart_mac_setmulticast(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ struct netdev_hw_addr *ha;
+ int crc_val;
+
+ netdev_for_each_mc_addr(ha, ndev) {
+ crc_val = crc32_le(~0, ha->addr, ETH_ALEN);
+ crc_val = (crc_val >> 26) & 0x3f;
+ if (crc_val >= 32) {
+ writel(readl(priv->base + MATH1_REG_OFFSET) |
+ (1UL << (crc_val - 32)),
+ priv->base + MATH1_REG_OFFSET);
+ } else {
+ writel(readl(priv->base + MATH0_REG_OFFSET) |
+ (1UL << crc_val),
+ priv->base + MATH0_REG_OFFSET);
+ }
+ }
+}
+
+static void moxart_mac_set_rx_mode(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+
+ spin_lock_irq(&priv->txlock);
+
+ (ndev->flags & IFF_PROMISC) ? (priv->maccr |= RCV_ALL) :
+ (priv->maccr &= ~RCV_ALL);
+
+ (ndev->flags & IFF_ALLMULTI) ? (priv->maccr |= RX_MULTIPKT) :
+ (priv->maccr &= ~RX_MULTIPKT);
+
+ if ((ndev->flags & IFF_MULTICAST) && netdev_mc_count(ndev)) {
+ priv->maccr |= HT_MULTI_EN;
+ moxart_mac_setmulticast(ndev);
+ } else {
+ priv->maccr &= ~HT_MULTI_EN;
+ }
+
+ writel(priv->maccr, priv->base + MACCR_REG_OFFSET);
+
+ spin_unlock_irq(&priv->txlock);
+}
+
+static struct net_device_ops moxart_netdev_ops = {
+ .ndo_open = moxart_mac_open,
+ .ndo_stop = moxart_mac_stop,
+ .ndo_start_xmit = moxart_mac_start_xmit,
+ .ndo_get_stats = moxart_mac_get_stats,
+ .ndo_set_rx_mode = moxart_mac_set_rx_mode,
+ .ndo_set_mac_address = moxart_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+static void moxart_get_mac_address(struct net_device *ndev)
+{
+ struct moxart_mac_priv_t *priv = netdev_priv(ndev);
+ int i;
+
+ for (i = 0; i <= 5; i++)
+ ndev->dev_addr[i] = readb(priv->flash_base + i);
+}
+
+static int moxart_mac_probe(struct platform_device *pdev)
+{
+ struct device *p_dev = &pdev->dev;
+ struct device_node *node = p_dev->of_node;
+ struct net_device *ndev;
+ struct moxart_mac_priv_t *priv;
+ struct resource *res;
+ unsigned int irq;
+ void *tmp;
+
+ ndev = alloc_etherdev(sizeof(struct moxart_mac_priv_t));
+ if (!ndev)
+ return -ENOMEM;
+
+ irq = irq_of_parse_and_map(node, 0);
+
+ priv = netdev_priv(ndev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ndev->base_addr = res->start;
+ priv->base = devm_ioremap_resource(p_dev, res);
+ if (IS_ERR(priv->base)) {
+ dev_err(p_dev, "%s: devm_ioremap_resource res_mac failed\n",
+ __func__);
+ goto init_fail;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+ /* the flash driver (physmap_of) requests the same region
+ * so use ioremap instead of devm_ioremap_resource
+ */
+ priv->flash_base = ioremap(res->start, resource_size(res));
+ if (IS_ERR(priv->flash_base)) {
+ dev_err(p_dev, "%s: devm_ioremap_resource res_flash failed\n",
+ __func__);
+ goto init_fail;
+ }
+
+ spin_lock_init(&priv->txlock);
+
+ tmp = dma_alloc_coherent(NULL, sizeof(struct tx_desc_t) * TX_DESC_NUM,
+ (dma_addr_t *) &priv->phy_tx_desc_baseaddr,
+ GFP_DMA | GFP_KERNEL);
+ priv->virt_tx_desc_baseaddr = (struct tx_desc_t *) tmp;
+ if (priv->virt_tx_desc_baseaddr == NULL ||
+ (priv->phy_tx_desc_baseaddr & 0x0f)) {
+ netdev_err(ndev, "TX descriptor alloc failed\n");
+ goto init_fail;
+ }
+
+ tmp = dma_alloc_coherent(NULL, sizeof(struct rx_desc_t) * RX_DESC_NUM,
+ (dma_addr_t *)&priv->phy_rx_desc_baseaddr,
+ GFP_DMA | GFP_KERNEL);
+ priv->virt_rx_desc_baseaddr = (struct rx_desc_t *) tmp;
+ if (priv->virt_rx_desc_baseaddr == NULL ||
+ (priv->phy_rx_desc_baseaddr & 0x0f)) {
+ netdev_err(ndev, "RX descriptor alloc failed\n");
+ goto init_fail;
+ }
+
+ tmp = dma_alloc_coherent(NULL, TX_BUF_SIZE * TX_DESC_NUM,
+ (dma_addr_t *)&priv->phy_tx_buf_baseaddr,
+ GFP_DMA | GFP_KERNEL);
+ priv->virt_tx_buf_baseaddr = (unsigned char *) tmp;
+ if (priv->virt_tx_buf_baseaddr == NULL ||
+ (priv->phy_tx_buf_baseaddr & 0x03)) {
+ netdev_err(ndev, "TX buffer alloc failed\n");
+ goto init_fail;
+ }
+
+ tmp = dma_alloc_coherent(NULL, RX_BUF_SIZE * RX_DESC_NUM,
+ (dma_addr_t *)&priv->phy_rx_buf_baseaddr,
+ GFP_DMA | GFP_KERNEL);
+ priv->virt_rx_buf_baseaddr = (unsigned char *) tmp;
+ if (priv->virt_rx_buf_baseaddr == NULL ||
+ (priv->phy_rx_buf_baseaddr & 0x03)) {
+ netdev_err(ndev, "RX buffer alloc failed\n");
+ goto init_fail;
+ }
+
+ platform_set_drvdata(pdev, ndev);
+
+ ether_setup(ndev);
+ ndev->netdev_ops = &moxart_netdev_ops;
+ ndev->priv_flags |= IFF_UNICAST_FLT;
+
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ moxart_get_mac_address(ndev);
+ moxart_update_mac_address(ndev);
+
+ if (register_netdev(ndev)) {
+ free_netdev(ndev);
+ goto init_fail;
+ }
+
+ ndev->irq = irq;
+
+ if (devm_request_irq(p_dev, irq, moxart_mac_interrupt, 0,
+ pdev->name, ndev)) {
+ netdev_err(ndev, "%s: devm_request_irq failed\n", __func__);
+ free_netdev(ndev);
+ return -EBUSY;
+ }
+
+ netdev_dbg(ndev, "%s: IRQ=%d address=%02x:%02x:%02x:%02x:%02x:%02x\n",
+ __func__, ndev->irq,
+ ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
+ ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+
+ return 0;
+
+init_fail:
+ netdev_err(ndev, "%s: init failed\n", __func__);
+ moxart_mac_free_memory(ndev);
+
+ return -ENOMEM;
+}
+
+static int moxart_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+
+ unregister_netdev(ndev);
+ free_irq(ndev->irq, ndev);
+ moxart_mac_free_memory(ndev);
+ platform_set_drvdata(pdev, NULL);
+ free_netdev(ndev);
+
+ return 0;
+}
+
+static const struct of_device_id moxart_mac_match[] = {
+ { .compatible = "moxa,moxart-mac" },
+ { }
+};
+
+struct __initdata platform_driver moxart_mac_driver = {
+ .probe = moxart_mac_probe,
+ .remove = moxart_remove,
+ .driver = {
+ .name = "moxart-ethernet",
+ .owner = THIS_MODULE,
+ .of_match_table = moxart_mac_match,
+ },
+};
+module_platform_driver(moxart_mac_driver);
+
+MODULE_DESCRIPTION("MOXART RTL8201CP Ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>");
+@@ -0,0 +1,525 @@
+/* MOXA ART Ethernet (RTL8201CP) driver.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * Based on code from
+ * Moxa Technology Co., Ltd. <www.moxa.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _MOXART_ETHERNET_H
+#define _MOXART_ETHERNET_H
+
+#define TX_DESC_NUM 64
+#define TX_DESC_NUM_MASK (TX_DESC_NUM-1)
+#define RX_DESC_NUM 64
+#define RX_DESC_NUM_MASK (RX_DESC_NUM-1)
+#define TX_BUF_SIZE 1600
+#define RX_BUF_SIZE 1600
+
+struct tx_desc_t {
+ union {
+#define TXDMA_OWN BIT(31)
+#define TXPKT_EXSCOL BIT(1)
+#define TXPKT_LATECOL BIT(0)
+ unsigned int ui;
+
+ struct {
+ /* is aborted due to late collision */
+ unsigned int tx_pkt_late_col:1;
+
+ /* is aborted after 16 collisions */
+ unsigned int rx_pkt_exs_col:1;
+
+ unsigned int reserved1:29;
+
+ /* is owned by the MAC controller */
+ unsigned int tx_dma_own:1;
+ } ubit;
+ } txdes0;
+
+ union {
+#define EDOTR BIT(31)
+#define TXIC BIT(30)
+#define TX2FIC BIT(29)
+#define FTS BIT(28)
+#define LTS BIT(27)
+#define TXBUF_SIZE_MASK 0x7ff
+#define TXBUF_SIZE_MAX (TXBUF_SIZE_MASK+1)
+ unsigned int ui;
+
+ struct {
+ /* transmit buffer size in byte */
+ unsigned int tx_buf_size:11;
+
+ unsigned int reserved2:16;
+
+ /* is the last descriptor of a Tx packet */
+ unsigned int lts:1;
+
+ /* is the first descriptor of a Tx packet */
+ unsigned int fts:1;
+
+ /* transmit to FIFO interrupt on completion */
+ unsigned int tx2_fic:1;
+
+ /* transmit interrupt on completion */
+ unsigned int tx_ic:1;
+
+ /* end descriptor of transmit ring */
+ unsigned int edotr:1;
+ } ubit;
+ } txdes1;
+
+ struct {
+ /* transmit buffer physical base address */
+ unsigned int phy_tx_buf_baseaddr;
+
+ /* transmit buffer virtual base address */
+ unsigned char *virt_tx_buf_baseaddr;
+ } txdes2;
+};
+
+struct rx_desc_t {
+ union {
+#define RXDMA_OWN BIT(31)
+#define FRS BIT(29)
+#define LRS BIT(28)
+#define RX_ODD_NB BIT(22)
+#define RUNT BIT(21)
+#define FTL BIT(20)
+#define CRC_ERR BIT(19)
+#define RX_ERR BIT(18)
+#define BROADCAST_RXDES0 BIT(17)
+#define MULTICAST_RXDES0 BIT(16)
+#define RFL_MASK 0x7ff
+#define RFL_MAX (RFL_MASK+1)
+ unsigned int ui;
+
+ struct {
+ /* receive frame length */
+ unsigned int recv_frame_len:11;
+ unsigned int reserved1:5;
+
+ /* multicast frame */
+ unsigned int multicast:1;
+
+ /* broadcast frame */
+ unsigned int broadcast:1;
+ unsigned int rx_err:1; /* receive error */
+ unsigned int crc_err:1; /* CRC error */
+ unsigned int ftl:1; /* frame too long */
+
+ /* runt packet, less than 64 bytes */
+ unsigned int runt:1;
+
+ /* receive odd nibbles */
+ unsigned int rx_odd_nb:1;
+ unsigned int reserved2:5;
+
+ /* last receive segment descriptor */
+ unsigned int lrs:1;
+
+ /* first receive segment descriptor */
+ unsigned int frs:1;
+
+ unsigned int reserved3:1;
+ unsigned int rx_dma_own:1; /* RXDMA onwership */
+ } ubit;
+ } rxdes0;
+
+ union {
+#define EDORR BIT(31)
+#define RXBUF_SIZE_MASK 0x7ff
+#define RXBUF_SIZE_MAX (RXBUF_SIZE_MASK+1)
+ unsigned int ui;
+
+ struct {
+ /* receive buffer size */
+ unsigned int rx_buf_size:11;
+
+ unsigned int reserved4:20;
+
+ /* end descriptor of receive ring */
+ unsigned int edorr:1;
+ } ubit;
+ } rxdes1;
+
+ struct {
+ /* receive buffer physical base address */
+ unsigned int phy_rx_buf_baseaddr;
+
+ /* receive buffer virtual base address */
+ unsigned char *virt_rx_buf_baseaddr;
+ } rxdes2;
+};
+
+struct mac_control_reg_t {
+
+/* RXDMA has received packets into RX buffer successfully */
+#define RPKT_FINISH BIT(0)
+/* receive buffer unavailable */
+#define NORXBUF BIT(1)
+/* TXDMA has moved data into the TX FIFO */
+#define XPKT_FINISH BIT(2)
+/* transmit buffer unavailable */
+#define NOTXBUF BIT(3)
+/* packets transmitted to ethernet successfully */
+#define XPKT_OK_INT_STS BIT(4)
+/* packets transmitted to ethernet lost due to late
+ * collision or excessive collision
+ */
+#define XPKT_LOST_INT_STS BIT(5)
+/* packets received into RX FIFO successfully */
+#define RPKT_SAV BIT(6)
+/* received packet lost due to RX FIFO full */
+#define RPKT_LOST_INT_STS BIT(7)
+#define AHB_ERR BIT(8) /* AHB error */
+#define PHYSTS_CHG BIT(9) /* PHY link status change */
+ unsigned int isr; /* interrupt status, 0x0 */
+
+#define RPKT_FINISH_M BIT(0) /* interrupt mask of ISR[0] */
+#define NORXBUF_M BIT(1) /* interrupt mask of ISR[1] */
+#define XPKT_FINISH_M BIT(2) /* interrupt mask of ISR[2] */
+#define NOTXBUF_M BIT(3) /* interrupt mask of ISR[3] */
+#define XPKT_OK_M BIT(4) /* interrupt mask of ISR[4] */
+#define XPKT_LOST_M BIT(5) /* interrupt mask of ISR[5] */
+#define RPKT_SAV_M BIT(6) /* interrupt mask of ISR[6] */
+#define RPKT_LOST_M BIT(7) /* interrupt mask of ISR[7] */
+#define AHB_ERR_M BIT(8) /* interrupt mask of ISR[8] */
+#define PHYSTS_CHG_M BIT(9) /* interrupt mask of ISR[9] */
+ unsigned int imr; /* interrupt mask, 0x4 */
+
+/* the most significant 2 bytes of MAC address */
+#define MAC_MADR_MASK 0xffff
+ /* MAC most significant address, 0x8 */
+ unsigned int mac_madr;
+
+ /* MAC least significant address, 0xc */
+ unsigned int mac_ldar;
+
+ /* multicast address hash table 0, 0x10 */
+ unsigned int matht0;
+
+ /* multicast address hash table 1, 0x14 */
+ unsigned int matht1;
+
+ /* transmit poll demand, 0x18 */
+ unsigned int txpd;
+
+ /* receive poll demand, 0x1c */
+ unsigned int rxpd;
+
+ /* transmit ring base address, 0x20 */
+ unsigned int txr_badr;
+
+ /* receive ring base address, 0x24 */
+ unsigned int rxr_badr;
+
+/* defines the period of TX cycle time */
+#define TXINT_TIME_SEL BIT(15)
+#define TXINT_THR_MASK 0x7000
+#define TXINT_CNT_MASK 0xf00
+/* defines the period of RX cycle time */
+#define RXINT_TIME_SEL BIT(7)
+#define RXINT_THR_MASK 0x70
+#define RXINT_CNT_MASK 0xF
+ /* interrupt timer control, 0x28 */
+ unsigned int itc;
+
+/* defines the period of TX poll time */
+#define TXPOLL_TIME_SEL BIT(12)
+#define TXPOLL_CNT_MASK 0xf00
+#define TXPOLL_CNT_SHIFT_BIT 8
+/* defines the period of RX poll time */
+#define RXPOLL_TIME_SEL BIT(4)
+#define RXPOLL_CNT_MASK 0xF
+#define RXPOLL_CNT_SHIFT_BIT 0
+ /* automatic polling timer control, 0x2c */
+ unsigned int aptc;
+
+/* enable RX FIFO threshold arbitration */
+#define RX_THR_EN BIT(9)
+#define RXFIFO_HTHR_MASK 0x1c0
+#define RXFIFO_LTHR_MASK 0x38
+/* use INCR16 burst command in AHB bus */
+#define INCR16_EN BIT(2)
+/* use INCR8 burst command in AHB bus */
+#define INCR8_EN BIT(1)
+/* use INCR4 burst command in AHB bus */
+#define INCR4_EN BIT(0)
+ /* DMA burst length and arbitration control, 0x30 */
+ unsigned int dblac;
+
+ unsigned int reserved1[21]; /* 0x34 - 0x84 */
+
+#define RX_BROADPKT BIT(17) /* receive boradcast packet */
+/* receive all multicast packet */
+#define RX_MULTIPKT BIT(16)
+#define FULLDUP BIT(15) /* full duplex */
+/* append CRC to transmitted packet */
+#define CRC_APD BIT(14)
+/* do not check incoming packet's destination address */
+#define RCV_ALL BIT(12)
+/* store incoming packet even if its length is great than 1518 bytes */
+#define RX_FTL BIT(11)
+/* store incoming packet even if its length is less than 64 bytes */
+#define RX_RUNT BIT(10)
+/* enable storing incoming packet if the packet passes hash table
+ * address filtering and is a multicast packet
+ */
+#define HT_MULTI_EN BIT(9)
+#define RCV_EN BIT(8) /* receiver enable */
+/* enable packet reception when transmitting packet in half duplex mode */
+#define ENRX_IN_HALFTX BIT(6)
+#define XMT_EN BIT(5) /* transmitter enable */
+/* disable CRC check when receiving packets */
+#define CRC_DIS BIT(4)
+#define LOOP_EN BIT(3) /* internal loop-back */
+/* software reset, last 64 AHB bus clocks */
+#define SW_RST BIT(2)
+#define RDMA_EN BIT(1) /* enable receive DMA chan */
+#define XDMA_EN BIT(0) /* enable transmit DMA chan */
+ unsigned int maccr; /* MAC control, 0x88 */
+
+#define COL_EXCEED BIT(11) /* collisions exceeds 16 */
+/* transmitter detects late collision */
+#define LATE_COL BIT(10)
+/* packet transmitted to ethernet lost due to late collision
+ * or excessive collision
+ */
+#define XPKT_LOST BIT(9)
+/* packets transmitted to ethernet successfully */
+#define XPKT_OK BIT(8)
+/* receiver detects a runt packet */
+#define RUNT_MAC_STS BIT(7)
+/* receiver detects a frame that is too long */
+#define FTL_MAC_STS BIT(6)
+#define CRC_ERR_MAC_STS BIT(5)
+/* received packets list due to RX FIFO full */
+#define RPKT_LOST BIT(4)
+/* packets received into RX FIFO successfully */
+#define RPKT_SAVE BIT(3)
+/* incoming packet dropped due to collision */
+#define COL BIT(2)
+#define MCPU_BROADCAST BIT(1)
+#define MCPU_MULTICAST BIT(0)
+ unsigned int macsr; /* MAC status, 0x8c */
+
+/* initialize a write sequence to PHY by setting this bit to 1
+ * this bit would be auto cleared after the write operation is finished.
+ */
+#define MIIWR BIT(27)
+#define MIIRD BIT(26)
+#define REGAD_MASK 0x3e00000
+#define PHYAD_MASK 0x1f0000
+#define MIIRDATA_MASK 0xffff
+ unsigned int phycr; /* PHY control, 0x90 */
+
+#define MIIWDATA_MASK 0xffff
+ unsigned int phywdata; /* PHY write data, 0x94 */
+
+#define PAUSE_TIME_MASK 0xffff0000
+#define FC_HIGH_MASK 0xf000
+#define FC_LOW_MASK 0xf00
+#define RX_PAUSE BIT(4) /* receive pause frame */
+/* packet transmission is paused due to receive */
+#define TXPAUSED BIT(3)
+ /* pause frame */
+/* enable flow control threshold mode. */
+#define FCTHR_EN BIT(2)
+#define TX_PAUSE BIT(1) /* transmit pause frame */
+#define FC_EN BIT(0) /* flow control mode enable */
+ unsigned int fcr; /* flow control, 0x98 */
+
+#define BK_LOW_MASK 0xf00
+#define BKJAM_LEN_MASK 0xf0
+#define BK_MODE BIT(1) /* back pressure address mode */
+#define BK_EN BIT(0) /* back pressure mode enable */
+ unsigned int bpr; /* back pressure, 0x9c */
+
+ unsigned int reserved2[9]; /* 0xa0 - 0xc0 */
+
+#define TEST_SEED_MASK 0x3fff
+ unsigned int ts; /* test seed, 0xc4 */
+
+#define TXD_REQ BIT(31) /* TXDMA request */
+#define RXD_REQ BIT(30) /* RXDMA request */
+#define DARB_TXGNT BIT(29) /* TXDMA grant */
+#define DARB_RXGNT BIT(28) /* RXDMA grant */
+#define TXFIFO_EMPTY BIT(27) /* TX FIFO is empty */
+#define RXFIFO_EMPTY BIT(26) /* RX FIFO is empty */
+#define TXDMA2_SM_MASK 0x7000
+#define TXDMA1_SM_MASK 0xf00
+#define RXDMA2_SM_MASK 0x70
+#define RXDMA1_SM_MASK 0xF
+ unsigned int dmafifos; /* DMA/FIFO state, 0xc8 */
+
+#define SINGLE_PKT BIT(26) /* single packet mode */
+/* automatic polling timer test mode */
+#define PTIMER_TEST BIT(25)
+#define ITIMER_TEST BIT(24) /* interrupt timer test mode */
+#define TEST_SEED_SEL BIT(22) /* test seed select */
+#define SEED_SEL BIT(21) /* seed select */
+#define TEST_MODE BIT(20) /* transmission test mode */
+#define TEST_TIME_MASK 0xffc00
+#define TEST_EXCEL_MASK 0x3e0
+ unsigned int tm; /* test mode, 0xcc */
+
+ unsigned int reserved3; /* 0xd0 */
+
+#define TX_MCOL_MASK 0xffff0000
+#define TX_MCOL_SHIFT_BIT 16
+#define TX_SCOL_MASK 0xffff
+#define TX_SCOL_SHIFT_BIT 0
+ /* TX_MCOL and TX_SCOL counter, 0xd4 */
+ unsigned int txmcol_xscol;
+
+#define RPF_MASK 0xffff0000
+#define RPF_SHIFT_BIT 16
+#define AEP_MASK 0xffff
+#define AEP_SHIFT_BIT 0
+ unsigned int rpf_aep; /* RPF and AEP counter, 0xd8 */
+
+#define XM_MASK 0xffff0000
+#define XM_SHIFT_BIT 16
+#define PG_MASK 0xffff
+#define PG_SHIFT_BIT 0
+ unsigned int xm_pg; /* XM and PG counter, 0xdc */
+
+#define RUNT_CNT_MASK 0xffff0000
+#define RUNT_CNT_SHIFT_BIT 16
+#define TLCC_MASK 0xffff
+#define TLCC_SHIFT_BIT 0
+ /* RUNT_CNT and TLCC counter, 0xe0 */
+ unsigned int runtcnt_tlcc;
+
+#define CRCER_CNT_MASK 0xffff0000
+#define CRCER_CNT_SHIFT_BIT 16
+#define FTL_CNT_MASK 0xffff
+#define FTL_CNT_SHIFT_BIT 0
+ /* CRCER_CNT and FTL_CNT counter, 0xe4 */
+ unsigned int crcercnt_ftlcnt;
+
+#define RLC_MASK 0xffff0000
+#define RLC_SHIFT_BIT 16
+#define RCC_MASK 0xffff
+#define RCC_SHIFT_BIT 0
+ unsigned int rlc_rcc; /* RLC and RCC counter, 0xe8 */
+
+ unsigned int broc; /* BROC counter, 0xec */
+ unsigned int mulca; /* MULCA counter, 0xf0 */
+ unsigned int rp; /* RP counter, 0xf4 */
+ unsigned int xp; /* XP counter, 0xf8 */
+};
+
+#define ISR_REG_OFFSET 0x0
+#define IMR_REG_OFFSET 0x4
+#define MAC_MADR_REG_OFFSET 0x8
+#define MAC_LADR_REG_OFFSET 0xC
+#define MATH0_REG_OFFSET 0x10
+#define MATH1_REG_OFFSET 0x14
+#define TXPD_REG_OFFSET 0x18
+#define RXPD_REG_OFFSET 0x1C
+#define TXR_BADR_REG_OFFSET 0x20
+#define RXR_BADR_REG_OFFSET 0x24
+#define ITC_REG_OFFSET 0x28
+#define APTC_REG_OFFSET 0x2C
+#define DBLAC_REG_OFFSET 0x30
+#define MACCR_REG_OFFSET 0x88
+#define MACSR_REG_OFFSET 0x8C
+#define PHYCR_REG_OFFSET 0x90
+#define PHYWDATA_REG_OFFSET 0x94
+#define FCR_REG_OFFSET 0x98
+#define BPR_REG_OFFSET 0x9C
+#define TS_REG_OFFSET 0xC4
+#define DMAFIFOS_REG_OFFSET 0xC8
+#define TM_REG_OFFSET 0xCC
+#define TX_MCOL_TX_SCOL_REG_OFFSET 0xD4
+#define RPF_AEP_REG_OFFSET 0xD8
+#define XM_PG_REG_OFFSET 0xDC
+#define RUNT_CNT_TLCC_REG_OFFSET 0xE0
+#define CRCER_CNT_FTL_CNT_REG_OFFSET 0xE4
+#define RLC_RCC_REG_OFFSET 0xE8
+#define BROC_REG_OFFSET 0xEC
+#define MULCA_REG_OFFSET 0xF0
+#define RP_REG_OFFSET 0xF4
+#define XP_REG_OFFSET 0xF8
+#define PHY_CNTL_REG 0x0
+#define PHY_STATUS_REG 0x1
+#define PHY_ID_REG1 0x2
+#define PHY_ID_REG2 0x3
+#define PHY_ANA_REG 0x4
+#define PHY_ANLPAR_REG 0x5
+#define PHY_ANE_REG 0x6
+#define PHY_ECNTL_REG1 0x10
+#define PHY_QPDS_REG 0x11
+#define PHY_10BOP_REG 0x12
+#define PHY_ECNTL_REG2 0x13
+#define FTMAC100_REG_PHY_WRITE 0x8000000
+#define FTMAC100_REG_PHY_READ 0x4000000
+
+/* PHY Status register */
+#define AN_COMPLETE 0x20
+
+#define LINK_STATUS 0x4
+
+struct moxart_mac_priv_t {
+ void __iomem *base;
+ void __iomem *flash_base;
+
+ /* Tx descriptor physical base address */
+ unsigned int phy_tx_desc_baseaddr;
+
+ /* Tx descriptor virtual base address */
+ struct tx_desc_t *virt_tx_desc_baseaddr;
+
+ /* Rx descriptor physical base address */
+ unsigned int phy_rx_desc_baseaddr;
+
+ /* Rx descriptor virtual base address */
+ struct rx_desc_t *virt_rx_desc_baseaddr;
+
+ /* Tx buffer physical base address */
+ unsigned int phy_tx_buf_baseaddr;
+
+ /* Tx buffer virtual base address */
+ unsigned char *virt_tx_buf_baseaddr;
+
+ /* Rx buffer physical base address */
+ unsigned int phy_rx_buf_baseaddr;
+
+ /* Rx buffer virtual base address */
+ unsigned char *virt_rx_buf_baseaddr;
+
+ /* Tx descriptor now first used index */
+ int tx_desc_now;
+
+ /* Rx descriptor now first used index */
+ int rx_desc_now;
+
+ /* OS about the ethernet statistics */
+ struct net_device_stats stats;
+
+ spinlock_t txlock;
+ spinlock_t rxlock;
+
+ /* store the maccr control register value */
+ unsigned int maccr;
+
+ struct work_struct rqueue;
+};
+
+#if TX_BUF_SIZE >= TXBUF_SIZE_MAX
+#error MOXA ART Ethernet device driver Tx buffer size too large !
+#endif
+#if RX_BUF_SIZE >= RXBUF_SIZE_MAX
+#error MOXA ART Ethernet device driver Rx buffer size too large !
+#endif
+
+#endif