]> git.sur5r.net Git - u-boot/blobdiff - drivers/net/mvpp2.c
net: mvpp2: Add RX and TX FIFO configuration for PPv2.2
[u-boot] / drivers / net / mvpp2.c
index c683fff53f86e7666fc6c10389d2680e774b8fd0..d0f20cc0f61f5d3dbc874734116cd22fa8498b4c 100644 (file)
@@ -6,7 +6,7 @@
  * Marcin Wojtas <mw@semihalf.com>
  *
  * U-Boot version:
- * Copyright (C) 2016 Stefan Roese <sr@denx.de>
+ * Copyright (C) 2016-2017 Stefan Roese <sr@denx.de>
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
@@ -397,7 +397,9 @@ do {                                                                        \
        (((index) < (q)->last_desc) ? ((index) + 1) : 0)
 
 /* SMI: 0xc0054 -> offset 0x54 to lms_base */
-#define MVPP2_SMI                              0x0054
+#define MVPP21_SMI                             0x0054
+/* PP2.2: SMI: 0x12a200 -> offset 0x1200 to iface_base */
+#define MVPP22_SMI                             0x1200
 #define     MVPP2_PHY_REG_MASK                 0x1f
 /* SMI register fields */
 #define     MVPP2_SMI_DATA_OFFS                        0       /* Data */
@@ -480,9 +482,23 @@ do {                                                                       \
 #define MVPP2_TX_DESC_ALIGN            (MVPP2_DESC_ALIGNED_SIZE - 1)
 
 /* RX FIFO constants */
-#define MVPP2_RX_FIFO_PORT_DATA_SIZE   0x2000
-#define MVPP2_RX_FIFO_PORT_ATTR_SIZE   0x80
-#define MVPP2_RX_FIFO_PORT_MIN_PKT     0x80
+#define MVPP21_RX_FIFO_PORT_DATA_SIZE          0x2000
+#define MVPP21_RX_FIFO_PORT_ATTR_SIZE          0x80
+#define MVPP22_RX_FIFO_10GB_PORT_DATA_SIZE     0x8000
+#define MVPP22_RX_FIFO_2_5GB_PORT_DATA_SIZE    0x2000
+#define MVPP22_RX_FIFO_1GB_PORT_DATA_SIZE      0x1000
+#define MVPP22_RX_FIFO_10GB_PORT_ATTR_SIZE     0x200
+#define MVPP22_RX_FIFO_2_5GB_PORT_ATTR_SIZE    0x80
+#define MVPP22_RX_FIFO_1GB_PORT_ATTR_SIZE      0x40
+#define MVPP2_RX_FIFO_PORT_MIN_PKT             0x80
+
+/* TX general registers */
+#define MVPP22_TX_FIFO_SIZE_REG(eth_tx_port)   (0x8860 + ((eth_tx_port) << 2))
+#define MVPP22_TX_FIFO_SIZE_MASK               0xf
+
+/* TX FIFO constants */
+#define MVPP2_TX_FIFO_DATA_SIZE_10KB           0xa
+#define MVPP2_TX_FIFO_DATA_SIZE_3KB            0x3
 
 /* RX buffer constants */
 #define MVPP2_SKB_SHINFO_SIZE \
@@ -745,6 +761,7 @@ struct mvpp2 {
        void __iomem *base;
        void __iomem *lms_base;
        void __iomem *iface_base;
+       void __iomem *mdio_base;
 
        /* List of pointers to port structures */
        struct mvpp2_port **port_list;
@@ -770,6 +787,8 @@ struct mvpp2 {
        unsigned int max_port_rxqs;
 
        struct mii_dev *bus;
+
+       int probe_done;
 };
 
 struct mvpp2_pcpu_stats {
@@ -1085,6 +1104,8 @@ static int rxq_number = MVPP2_DEFAULT_RXQ;
 /* Number of TXQs used by single port */
 static int txq_number = MVPP2_DEFAULT_TXQ;
 
+static int base_id;
+
 #define MVPP2_DRIVER_NAME "mvpp2"
 #define MVPP2_DRIVER_VERSION "1.0"
 
@@ -3920,10 +3941,35 @@ static void mvpp2_rx_fifo_init(struct mvpp2 *priv)
        int port;
 
        for (port = 0; port < MVPP2_MAX_PORTS; port++) {
-               mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(port),
-                           MVPP2_RX_FIFO_PORT_DATA_SIZE);
-               mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
-                           MVPP2_RX_FIFO_PORT_ATTR_SIZE);
+               if (priv->hw_version == MVPP22) {
+                       if (port == 0) {
+                               mvpp2_write(priv,
+                                           MVPP2_RX_DATA_FIFO_SIZE_REG(port),
+                                           MVPP22_RX_FIFO_10GB_PORT_DATA_SIZE);
+                               mvpp2_write(priv,
+                                           MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
+                                           MVPP22_RX_FIFO_10GB_PORT_ATTR_SIZE);
+                       } else if (port == 1) {
+                               mvpp2_write(priv,
+                                           MVPP2_RX_DATA_FIFO_SIZE_REG(port),
+                                           MVPP22_RX_FIFO_2_5GB_PORT_DATA_SIZE);
+                               mvpp2_write(priv,
+                                           MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
+                                           MVPP22_RX_FIFO_2_5GB_PORT_ATTR_SIZE);
+                       } else {
+                               mvpp2_write(priv,
+                                           MVPP2_RX_DATA_FIFO_SIZE_REG(port),
+                                           MVPP22_RX_FIFO_1GB_PORT_DATA_SIZE);
+                               mvpp2_write(priv,
+                                           MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
+                                           MVPP22_RX_FIFO_1GB_PORT_ATTR_SIZE);
+                       }
+               } else {
+                       mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(port),
+                                   MVPP21_RX_FIFO_PORT_DATA_SIZE);
+                       mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
+                                   MVPP21_RX_FIFO_PORT_ATTR_SIZE);
+               }
        }
 
        mvpp2_write(priv, MVPP2_RX_MIN_PKT_SIZE_REG,
@@ -3931,6 +3977,24 @@ static void mvpp2_rx_fifo_init(struct mvpp2 *priv)
        mvpp2_write(priv, MVPP2_RX_FIFO_INIT_REG, 0x1);
 }
 
+/* Initialize Tx FIFO's */
+static void mvpp2_tx_fifo_init(struct mvpp2 *priv)
+{
+       int port, val;
+
+       for (port = 0; port < MVPP2_MAX_PORTS; port++) {
+               /* Port 0 supports 10KB TX FIFO */
+               if (port == 0) {
+                       val = MVPP2_TX_FIFO_DATA_SIZE_10KB &
+                               MVPP22_TX_FIFO_SIZE_MASK;
+               } else {
+                       val = MVPP2_TX_FIFO_DATA_SIZE_3KB &
+                               MVPP22_TX_FIFO_SIZE_MASK;
+               }
+               mvpp2_write(priv, MVPP22_TX_FIFO_SIZE_REG(port), val);
+       }
+}
+
 static void mvpp2_axi_init(struct mvpp2 *priv)
 {
        u32 val, rdval, wrval;
@@ -4037,6 +4101,10 @@ static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv)
        /* Rx Fifo Init */
        mvpp2_rx_fifo_init(priv);
 
+       /* Tx Fifo Init */
+       if (priv->hw_version == MVPP22)
+               mvpp2_tx_fifo_init(priv);
+
        /* Reset Rx queue group interrupt configuration */
        for (i = 0; i < MVPP2_MAX_PORTS; i++) {
                if (priv->hw_version == MVPP21) {
@@ -4089,7 +4157,7 @@ static int smi_wait_ready(struct mvpp2 *priv)
        /* wait till the SMI is not busy */
        do {
                /* read smi register */
-               smi_reg = readl(priv->lms_base + MVPP2_SMI);
+               smi_reg = readl(priv->mdio_base);
                if (timeout-- == 0) {
                        printf("Error: SMI busy timeout\n");
                        return -EFAULT;
@@ -4131,14 +4199,14 @@ static int mpp2_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
                | MVPP2_SMI_OPCODE_READ;
 
        /* write the smi register */
-       writel(smi_reg, priv->lms_base + MVPP2_SMI);
+       writel(smi_reg, priv->mdio_base);
 
        /* wait till read value is ready */
        timeout = MVPP2_SMI_TIMEOUT;
 
        do {
                /* read smi register */
-               smi_reg = readl(priv->lms_base + MVPP2_SMI);
+               smi_reg = readl(priv->mdio_base);
                if (timeout-- == 0) {
                        printf("Err: SMI read ready timeout\n");
                        return -EFAULT;
@@ -4149,7 +4217,7 @@ static int mpp2_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
        for (timeout = 0; timeout < MVPP2_SMI_TIMEOUT; timeout++)
                ;
 
-       return readl(priv->lms_base + MVPP2_SMI) & MVPP2_SMI_DATA_MASK;
+       return readl(priv->mdio_base) & MVPP2_SMI_DATA_MASK;
 }
 
 /*
@@ -4186,7 +4254,7 @@ static int mpp2_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
        smi_reg &= ~MVPP2_SMI_OPCODE_READ;
 
        /* write the smi register */
-       writel(smi_reg, priv->lms_base + MVPP2_SMI);
+       writel(smi_reg, priv->mdio_base);
 
        return 0;
 }
@@ -4374,42 +4442,6 @@ static void mvpp2_stop(struct udevice *dev)
        mvpp2_cleanup_txqs(port);
 }
 
-static int mvpp2_probe(struct udevice *dev)
-{
-       struct mvpp2_port *port = dev_get_priv(dev);
-       struct mvpp2 *priv = dev_get_priv(dev->parent);
-       int err;
-
-       /* Initialize network controller */
-       err = mvpp2_init(dev, priv);
-       if (err < 0) {
-               dev_err(&pdev->dev, "failed to initialize controller\n");
-               return err;
-       }
-
-       return mvpp2_port_probe(dev, port, dev_of_offset(dev), priv);
-}
-
-static const struct eth_ops mvpp2_ops = {
-       .start          = mvpp2_start,
-       .send           = mvpp2_send,
-       .recv           = mvpp2_recv,
-       .stop           = mvpp2_stop,
-};
-
-static struct driver mvpp2_driver = {
-       .name   = "mvpp2",
-       .id     = UCLASS_ETH,
-       .probe  = mvpp2_probe,
-       .ops    = &mvpp2_ops,
-       .priv_auto_alloc_size = sizeof(struct mvpp2_port),
-       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
-};
-
-/*
- * Use a MISC device to bind the n instances (child nodes) of the
- * network base controller in UCLASS_ETH.
- */
 static int mvpp2_base_probe(struct udevice *dev)
 {
        struct mvpp2 *priv = dev_get_priv(dev);
@@ -4460,6 +4492,9 @@ static int mvpp2_base_probe(struct udevice *dev)
                size += RX_BUFFER_SIZE;
        }
 
+       /* Clear the complete area so that all descriptors are cleared */
+       memset(bd_space, 0, size);
+
        /* Save base addresses for later use */
        priv->base = (void *)dev_get_addr_index(dev, 0);
        if (IS_ERR(priv->base))
@@ -4469,10 +4504,14 @@ static int mvpp2_base_probe(struct udevice *dev)
                priv->lms_base = (void *)dev_get_addr_index(dev, 1);
                if (IS_ERR(priv->lms_base))
                        return PTR_ERR(priv->lms_base);
+
+               priv->mdio_base = priv->lms_base + MVPP21_SMI;
        } else {
                priv->iface_base = (void *)dev_get_addr_index(dev, 1);
                if (IS_ERR(priv->iface_base))
                        return PTR_ERR(priv->iface_base);
+
+               priv->mdio_base = priv->iface_base + MVPP22_SMI;
        }
 
        if (priv->hw_version == MVPP21)
@@ -4496,6 +4535,47 @@ static int mvpp2_base_probe(struct udevice *dev)
        return mdio_register(bus);
 }
 
+static int mvpp2_probe(struct udevice *dev)
+{
+       struct mvpp2_port *port = dev_get_priv(dev);
+       struct mvpp2 *priv = dev_get_priv(dev->parent);
+       int err;
+
+       /* Only call the probe function for the parent once */
+       if (!priv->probe_done) {
+               err = mvpp2_base_probe(dev->parent);
+               priv->probe_done = 1;
+       }
+       /* Initialize network controller */
+       err = mvpp2_init(dev, priv);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to initialize controller\n");
+               return err;
+       }
+
+       return mvpp2_port_probe(dev, port, dev_of_offset(dev), priv);
+}
+
+static const struct eth_ops mvpp2_ops = {
+       .start          = mvpp2_start,
+       .send           = mvpp2_send,
+       .recv           = mvpp2_recv,
+       .stop           = mvpp2_stop,
+};
+
+static struct driver mvpp2_driver = {
+       .name   = "mvpp2",
+       .id     = UCLASS_ETH,
+       .probe  = mvpp2_probe,
+       .ops    = &mvpp2_ops,
+       .priv_auto_alloc_size = sizeof(struct mvpp2_port),
+       .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+/*
+ * Use a MISC device to bind the n instances (child nodes) of the
+ * network base controller in UCLASS_ETH.
+ */
 static int mvpp2_base_bind(struct udevice *parent)
 {
        const void *blob = gd->fdt_blob;
@@ -4506,6 +4586,7 @@ static int mvpp2_base_bind(struct udevice *parent)
        char *name;
        int subnode;
        u32 id;
+       int base_id_add;
 
        /* Lookup eth driver */
        drv = lists_uclass_lookup(UCLASS_ETH);
@@ -4514,7 +4595,12 @@ static int mvpp2_base_bind(struct udevice *parent)
                return -ENOENT;
        }
 
+       base_id_add = base_id;
+
        fdt_for_each_subnode(subnode, blob, node) {
+               /* Increment base_id for all subnodes, also the disabled ones */
+               base_id++;
+
                /* Skip disabled ports */
                if (!fdtdec_get_is_enabled(blob, subnode))
                        continue;
@@ -4524,6 +4610,7 @@ static int mvpp2_base_bind(struct udevice *parent)
                        return -ENOMEM;
 
                id = fdtdec_get_int(blob, subnode, "port-id", -1);
+               id += base_id_add;
 
                name = calloc(1, 16);
                sprintf(name, "mvpp2-%d", id);
@@ -4541,6 +4628,10 @@ static const struct udevice_id mvpp2_ids[] = {
                .compatible = "marvell,armada-375-pp2",
                .data = MVPP21,
        },
+       {
+               .compatible = "marvell,armada-7k-pp22",
+               .data = MVPP22,
+       },
        { }
 };
 
@@ -4549,6 +4640,5 @@ U_BOOT_DRIVER(mvpp2_base) = {
        .id     = UCLASS_MISC,
        .of_match = mvpp2_ids,
        .bind   = mvpp2_base_bind,
-       .probe  = mvpp2_base_probe,
        .priv_auto_alloc_size = sizeof(struct mvpp2),
 };