WS cleanup: remove SPACE(s) followed by TAB
[platform/kernel/u-boot.git] / drivers / net / calxedaxgmac.c
index 00e26c2..eb1e2a7 100644 (file)
@@ -1,24 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * 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 <net.h>
 #include <linux/compiler.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <asm/io.h>
+#include <dm.h>
+#include <dm/device-internal.h>        /* for dev_set_priv() */
 
 #define TX_NUM_DESC                    1
 #define RX_NUM_DESC                    32
@@ -221,6 +214,18 @@ struct xgmac_dma_desc {
        __le32 res[3];
 };
 
+static struct xgmac_regs *xgmac_get_regs(struct eth_pdata *pdata)
+{
+       /*
+        * We use PHYS_64BIT on Highbank, so phys_addr_t is bigger than
+        * a pointer. U-Boot doesn't use LPAE (not even the MMU on highbank),
+        * so we can't access anything above 4GB.
+        * We have a check in the probe function below the ensure this,
+        * so casting to a 32-bit pointer type is fine here.
+        */
+       return (struct xgmac_regs *)(uintptr_t)pdata->iobase;
+}
+
 /* XGMAC Descriptor Access Helpers */
 static inline void desc_set_buf_len(struct xgmac_dma_desc *p, u32 buf_sz)
 {
@@ -313,8 +318,6 @@ struct calxeda_eth_dev {
 
        u32 tx_currdesc;
        u32 rx_currdesc;
-
-       struct eth_device *dev;
 } __aligned(32);
 
 /*
@@ -322,10 +325,10 @@ struct calxeda_eth_dev {
  * advanced descriptors.
  */
 
-static void init_rx_desc(struct calxeda_eth_dev *priv)
+static void init_rx_desc(struct eth_pdata *pdata, struct calxeda_eth_dev *priv)
 {
        struct xgmac_dma_desc *rxdesc = priv->rx_chain;
-       struct xgmac_regs *regs = (struct xgmac_regs *)priv->dev->iobase;
+       struct xgmac_regs *regs = xgmac_get_regs(pdata);
        void *rxbuffer = priv->rxbuffer;
        int i;
 
@@ -339,17 +342,16 @@ static void init_rx_desc(struct calxeda_eth_dev *priv)
        }
 }
 
-static void init_tx_desc(struct calxeda_eth_dev *priv)
+static void init_tx_desc(struct eth_pdata *pdata, struct calxeda_eth_dev *priv)
 {
-       struct xgmac_regs *regs = (struct xgmac_regs *)priv->dev->iobase;
+       struct xgmac_regs *regs = xgmac_get_regs(pdata);
 
        desc_init_tx_desc(priv->tx_chain, TX_NUM_DESC);
        writel((ulong)priv->tx_chain, &regs->txdesclist);
 }
 
-static int xgmac_reset(struct eth_device *dev)
+static int xgmac_reset(struct xgmac_regs *regs)
 {
-       struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
        int timeout = MAC_TIMEOUT;
        u32 value;
 
@@ -365,27 +367,28 @@ static int xgmac_reset(struct eth_device *dev)
        return timeout;
 }
 
-static void xgmac_hwmacaddr(struct eth_device *dev)
+static void xgmac_hwmacaddr(struct eth_pdata *pdata)
 {
-       struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
+       struct xgmac_regs *regs = xgmac_get_regs(pdata);
        u32 macaddr[2];
 
-       memcpy(macaddr, dev->enetaddr, 6);
+       memcpy(macaddr, pdata->enetaddr, ARP_HLEN);
        writel(macaddr[1], &regs->macaddr[0].hi);
        writel(macaddr[0], &regs->macaddr[0].lo);
 }
 
-static int xgmac_init(struct eth_device *dev, bd_t * bis)
+static int xgmac_eth_start(struct udevice *dev)
 {
-       struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
-       struct calxeda_eth_dev *priv = dev->priv;
-       int value;
+       struct eth_pdata *pdata = dev_get_plat(dev);
+       struct xgmac_regs *regs = xgmac_get_regs(pdata);
+       struct calxeda_eth_dev *priv = dev_get_priv(dev);
+       u32 value;
 
-       if (xgmac_reset(dev) < 0)
-               return -1;
+       if (xgmac_reset(regs) < 0)
+               return -ETIMEDOUT;
 
        /* set the hardware MAC address */
-       xgmac_hwmacaddr(dev);
+       xgmac_hwmacaddr(pdata);
 
        /* set the AXI bus modes */
        value = XGMAC_DMA_BUSMODE_ATDS |
@@ -400,7 +403,7 @@ static int xgmac_init(struct eth_device *dev, bd_t * bis)
        /* 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;
+               XGMAC_CORE_OMR_EFC | XGMAC_CORE_OMR_TSF;
        writel(value, &regs->core_opmode);
 
        /* enable pause frames */
@@ -410,8 +413,8 @@ static int xgmac_init(struct eth_device *dev, bd_t * bis)
        writel(value, &regs->flow_control);
 
        /* Initialize the descriptor chains */
-       init_rx_desc(priv);
-       init_tx_desc(priv);
+       init_rx_desc(pdata, priv);
+       init_tx_desc(pdata, priv);
 
        /* must set to 0, or when started up will cause issues */
        priv->tx_currdesc = 0;
@@ -434,15 +437,16 @@ static int xgmac_init(struct eth_device *dev, bd_t * bis)
        return 0;
 }
 
-static int xgmac_tx(struct eth_device *dev, volatile void *packet, int length)
+static int xgmac_tx(struct udevice *dev, void *packet, int length)
 {
-       struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
-       struct calxeda_eth_dev *priv = dev->priv;
+       struct calxeda_eth_dev *priv = dev_get_priv(dev);
+       struct eth_pdata *pdata = dev_get_plat(dev);
+       struct xgmac_regs *regs = xgmac_get_regs(pdata);
        u32 currdesc = priv->tx_currdesc;
        struct xgmac_dma_desc *txdesc = &priv->tx_chain[currdesc];
        int timeout;
 
-       desc_set_buf_addr_and_size(txdesc, (void *)packet, length);
+       desc_set_buf_addr_and_size(txdesc, packet, length);
        desc_set_tx_owner(txdesc, TXDESC_FIRST_SEG |
                TXDESC_LAST_SEG | TXDESC_CRC_EN_APPEND);
 
@@ -462,35 +466,45 @@ static int xgmac_tx(struct eth_device *dev, volatile void *packet, int length)
        return 0;
 }
 
-static int xgmac_rx(struct eth_device *dev)
+static int xgmac_rx(struct udevice *dev, int flags, uchar **packetp)
 {
-       struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
-       struct calxeda_eth_dev *priv = dev->priv;
+       struct calxeda_eth_dev *priv = dev_get_priv(dev);
        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 */
+               return -EAGAIN; /* the MAC is still chewing on it */
 
        length = desc_get_rx_frame_len(rxdesc);
+       *packetp = desc_get_buf_addr(rxdesc);
+
+       priv->rx_currdesc = (currdesc + 1) & (RX_NUM_DESC - 1);
+
+       return length;
+}
 
-       NetReceive((volatile unsigned char *)desc_get_buf_addr(rxdesc), length);
+static int xgmac_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+       struct eth_pdata *pdata = dev_get_plat(dev);
+       struct xgmac_regs *regs = xgmac_get_regs(pdata);
+       struct calxeda_eth_dev *priv = dev_get_priv(dev);
+       u32 rxdesc = ((char *)packet - priv->rxbuffer) / ETH_BUF_SZ;
+       struct xgmac_dma_desc *p = &priv->rx_chain[rxdesc];
 
        /* set descriptor back to owned by XGMAC */
-       desc_set_rx_owner(rxdesc);
+       desc_set_rx_owner(p);
        writel(1, &regs->rxpoll);
 
-       priv->rx_currdesc = (currdesc + 1) & (RX_NUM_DESC - 1);
-
-       return length;
+       return 0;
 }
 
-static void xgmac_halt(struct eth_device *dev)
+static void xgmac_eth_stop(struct udevice *dev)
 {
-       struct xgmac_regs *regs = (struct xgmac_regs *)dev->iobase;
-       struct calxeda_eth_dev *priv = dev->priv;
+       struct calxeda_eth_dev *priv = dev_get_priv(dev);
+       struct eth_pdata *pdata = dev_get_plat(dev);
+       struct xgmac_regs *regs = xgmac_get_regs(pdata);
        int value;
 
        /* Disable TX/RX */
@@ -508,47 +522,88 @@ static void xgmac_halt(struct eth_device *dev)
        priv->rx_currdesc = 0;
 }
 
-int calxedaxgmac_initialize(u32 id, ulong base_addr)
+/*
+ * Changing the MAC address is not a good idea, as the fabric would
+ * need to know about this as well (it does not learn MAC addresses).
+ */
+static int xgmac_eth_write_hwaddr(struct udevice *dev)
+{
+       return -ENOSYS;
+}
+
+static int xgmac_eth_read_rom_hwaddr(struct udevice *dev)
 {
-       struct eth_device *dev;
-       struct calxeda_eth_dev *priv;
-       struct xgmac_regs *regs;
+       struct eth_pdata *pdata = dev_get_plat(dev);
+       struct xgmac_regs *regs = xgmac_get_regs(pdata);
        u32 macaddr[2];
 
-       regs = (struct xgmac_regs *)base_addr;
+       /* The MAC address is already configured, so read it from registers. */
+       macaddr[1] = readl(&regs->macaddr[0].hi);
+       macaddr[0] = readl(&regs->macaddr[0].lo);
+       memcpy(pdata->enetaddr, macaddr, ARP_HLEN);
 
-       /* check hardware version */
-       if (readl(&regs->version) != 0x1012)
-               return -1;
+       return 0;
+}
 
-       dev = malloc(sizeof(*dev));
-       if (!dev)
-               return 0;
-       memset(dev, 0, sizeof(*dev));
+static int xgmac_ofdata_to_platdata(struct udevice *dev)
+{
+       struct eth_pdata *pdata = dev_get_plat(dev);
+       struct calxeda_eth_dev *priv;
 
        /* Structure must be aligned, because it contains the descriptors */
        priv = memalign(32, sizeof(*priv));
-       if (!priv) {
-               free(dev);
-               return 0;
+       if (!priv)
+               return -ENOMEM;
+       dev_set_priv(dev, priv);
+
+       pdata->iobase = devfdt_get_addr(dev);
+       if (pdata->iobase == FDT_ADDR_T_NONE) {
+               printf("%s: Cannot find XGMAC base address\n", __func__);
+               return -EINVAL;
+       }
+       if (pdata->iobase >= (1ULL << 32)) {
+               printf("%s: MMIO base address cannot be above 4GB\n", __func__);
+               return -EINVAL;
        }
 
-       dev->iobase = (int)base_addr;
-       dev->priv = priv;
-       priv->dev = dev;
-       sprintf(dev->name, "xgmac%d", id);
+       return 0;
+}
 
-       /* The MAC address is already configured, so read it from registers. */
-       macaddr[1] = readl(&regs->macaddr[0].hi);
-       macaddr[0] = readl(&regs->macaddr[0].lo);
-       memcpy(dev->enetaddr, macaddr, 6);
+static int xgmac_eth_probe(struct udevice *dev)
+{
+       struct eth_pdata *pdata = dev_get_plat(dev);
+       struct xgmac_regs *regs = xgmac_get_regs(pdata);
 
-       dev->init = xgmac_init;
-       dev->send = xgmac_tx;
-       dev->recv = xgmac_rx;
-       dev->halt = xgmac_halt;
+       /* check hardware version */
+       if (readl(&regs->version) != 0x1012)
+               return -ENODEV;
 
-       eth_register(dev);
+       xgmac_eth_read_rom_hwaddr(dev);
 
-       return 1;
+       return 0;
 }
+
+static const struct eth_ops xgmac_eth_ops = {
+       .start          = xgmac_eth_start,
+       .send           = xgmac_tx,
+       .recv           = xgmac_rx,
+       .free_pkt       = xgmac_free_pkt,
+       .stop           = xgmac_eth_stop,
+       .write_hwaddr   = xgmac_eth_write_hwaddr,
+       .read_rom_hwaddr = xgmac_eth_read_rom_hwaddr,
+};
+
+static const struct udevice_id xgmac_eth_ids[] = {
+       { .compatible = "calxeda,hb-xgmac" },
+       { }
+};
+
+U_BOOT_DRIVER(eth_xgmac) = {
+       .name           = "eth_xgmac",
+       .id             = UCLASS_ETH,
+       .of_match       = xgmac_eth_ids,
+       .of_to_plat     = xgmac_ofdata_to_platdata,
+       .probe          = xgmac_eth_probe,
+       .ops            = &xgmac_eth_ops,
+       .plat_auto      = sizeof(struct eth_pdata),
+};