]> git.sur5r.net Git - u-boot/blobdiff - drivers/net/cpsw.c
fdt: add memory bank decoding functions for board setup
[u-boot] / drivers / net / cpsw.c
index 774b021e356e430251a26d1a068b45608869a7d1..cbce683eea9ab13369a0a0d8c944daeb7aca92d2 100644 (file)
@@ -21,7 +21,7 @@
 #include <net.h>
 #include <netdev.h>
 #include <cpsw.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
 #include <phy.h>
@@ -225,6 +225,18 @@ struct cpdma_chan {
        void                    *hdp, *cp, *rxfree;
 };
 
+/* AM33xx SoC specific definitions for the CONTROL port */
+#define AM33XX_GMII_SEL_MODE_MII       0
+#define AM33XX_GMII_SEL_MODE_RMII      1
+#define AM33XX_GMII_SEL_MODE_RGMII     2
+
+#define AM33XX_GMII_SEL_RGMII1_IDMODE  BIT(4)
+#define AM33XX_GMII_SEL_RGMII2_IDMODE  BIT(5)
+#define AM33XX_GMII_SEL_RMII1_IO_CLK_EN        BIT(6)
+#define AM33XX_GMII_SEL_RMII2_IO_CLK_EN        BIT(7)
+
+#define GMII_SEL_MODE_MASK             0x3
+
 #define desc_write(desc, fld, val)     __raw_writel((u32)(val), &(desc)->fld)
 #define desc_read(desc, fld)           __raw_readl(&(desc)->fld)
 #define desc_read_ptr(desc, fld)       ((void *)__raw_readl(&(desc)->fld))
@@ -908,7 +920,7 @@ static int _cpsw_send(struct cpsw_priv *priv, void *packet, int length)
        int timeout = CPDMA_TIMEOUT;
 
        flush_dcache_range((unsigned long)packet,
-                          (unsigned long)packet + length);
+                          (unsigned long)packet + ALIGN(length, PKTALIGN));
 
        /* first reap completed packets */
        while (timeout-- &&
@@ -1146,7 +1158,124 @@ static const struct eth_ops cpsw_eth_ops = {
 
 static inline fdt_addr_t cpsw_get_addr_by_node(const void *fdt, int node)
 {
-       return fdtdec_get_addr_size_auto_noparent(fdt, node, "reg", 0, NULL);
+       return fdtdec_get_addr_size_auto_noparent(fdt, node, "reg", 0, NULL,
+                                                 false);
+}
+
+static void cpsw_gmii_sel_am3352(struct cpsw_priv *priv,
+                                phy_interface_t phy_mode)
+{
+       u32 reg;
+       u32 mask;
+       u32 mode = 0;
+       bool rgmii_id = false;
+       int slave = priv->data.active_slave;
+
+       reg = readl(priv->data.gmii_sel);
+
+       switch (phy_mode) {
+       case PHY_INTERFACE_MODE_RMII:
+               mode = AM33XX_GMII_SEL_MODE_RMII;
+               break;
+
+       case PHY_INTERFACE_MODE_RGMII:
+               mode = AM33XX_GMII_SEL_MODE_RGMII;
+               break;
+       case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_RXID:
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               mode = AM33XX_GMII_SEL_MODE_RGMII;
+               rgmii_id = true;
+               break;
+
+       case PHY_INTERFACE_MODE_MII:
+       default:
+               mode = AM33XX_GMII_SEL_MODE_MII;
+               break;
+       };
+
+       mask = GMII_SEL_MODE_MASK << (slave * 2) | BIT(slave + 6);
+       mode <<= slave * 2;
+
+       if (priv->data.rmii_clock_external) {
+               if (slave == 0)
+                       mode |= AM33XX_GMII_SEL_RMII1_IO_CLK_EN;
+               else
+                       mode |= AM33XX_GMII_SEL_RMII2_IO_CLK_EN;
+       }
+
+       if (rgmii_id) {
+               if (slave == 0)
+                       mode |= AM33XX_GMII_SEL_RGMII1_IDMODE;
+               else
+                       mode |= AM33XX_GMII_SEL_RGMII2_IDMODE;
+       }
+
+       reg &= ~mask;
+       reg |= mode;
+
+       writel(reg, priv->data.gmii_sel);
+}
+
+static void cpsw_gmii_sel_dra7xx(struct cpsw_priv *priv,
+                                phy_interface_t phy_mode)
+{
+       u32 reg;
+       u32 mask;
+       u32 mode = 0;
+       int slave = priv->data.active_slave;
+
+       reg = readl(priv->data.gmii_sel);
+
+       switch (phy_mode) {
+       case PHY_INTERFACE_MODE_RMII:
+               mode = AM33XX_GMII_SEL_MODE_RMII;
+               break;
+
+       case PHY_INTERFACE_MODE_RGMII:
+       case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_RXID:
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               mode = AM33XX_GMII_SEL_MODE_RGMII;
+               break;
+
+       case PHY_INTERFACE_MODE_MII:
+       default:
+               mode = AM33XX_GMII_SEL_MODE_MII;
+               break;
+       };
+
+       switch (slave) {
+       case 0:
+               mask = GMII_SEL_MODE_MASK;
+               break;
+       case 1:
+               mask = GMII_SEL_MODE_MASK << 4;
+               mode <<= 4;
+               break;
+       default:
+               dev_err(priv->dev, "invalid slave number...\n");
+               return;
+       }
+
+       if (priv->data.rmii_clock_external)
+               dev_err(priv->dev, "RMII External clock is not supported\n");
+
+       reg &= ~mask;
+       reg |= mode;
+
+       writel(reg, priv->data.gmii_sel);
+}
+
+static void cpsw_phy_sel(struct cpsw_priv *priv, const char *compat,
+                        phy_interface_t phy_mode)
+{
+       if (!strcmp(compat, "ti,am3352-cpsw-phy-sel"))
+               cpsw_gmii_sel_am3352(priv, phy_mode);
+       if (!strcmp(compat, "ti,am43xx-cpsw-phy-sel"))
+               cpsw_gmii_sel_am3352(priv, phy_mode);
+       else if (!strcmp(compat, "ti,dra7xx-cpsw-phy-sel"))
+               cpsw_gmii_sel_dra7xx(priv, phy_mode);
 }
 
 static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
@@ -1155,6 +1284,7 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
        struct cpsw_priv *priv = dev_get_priv(dev);
        struct gpio_desc *mode_gpios;
        const char *phy_mode;
+       const char *phy_sel_compat = NULL;
        const void *fdt = gd->fdt_blob;
        int node = dev->of_offset;
        int subnode;
@@ -1218,7 +1348,7 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
        active_slave = fdtdec_get_int(fdt, node, "active_slave", 0);
        priv->data.active_slave = active_slave;
 
-       fdt_for_each_subnode(fdt, subnode, node) {
+       fdt_for_each_subnode(subnode, fdt, node) {
                int len;
                const char *name;
 
@@ -1270,6 +1400,17 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
                                error("Not able to get gmii_sel reg address\n");
                                return -ENOENT;
                        }
+
+                       if (fdt_get_property(fdt, subnode, "rmii-clock-ext",
+                                            NULL))
+                               priv->data.rmii_clock_external = true;
+
+                       phy_sel_compat = fdt_getprop(fdt, subnode, "compatible",
+                                                    NULL);
+                       if (!phy_sel_compat) {
+                               error("Not able to get gmii_sel compatible\n");
+                               return -ENOENT;
+                       }
                }
        }
 
@@ -1292,20 +1433,9 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
                debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
                return -EINVAL;
        }
-       switch (pdata->phy_interface) {
-       case PHY_INTERFACE_MODE_MII:
-               writel(MII_MODE_ENABLE, priv->data.gmii_sel);
-               break;
-       case PHY_INTERFACE_MODE_RMII:
-               writel(RMII_MODE_ENABLE, priv->data.gmii_sel);
-               break;
-       case PHY_INTERFACE_MODE_RGMII:
-       case PHY_INTERFACE_MODE_RGMII_ID:
-       case PHY_INTERFACE_MODE_RGMII_RXID:
-       case PHY_INTERFACE_MODE_RGMII_TXID:
-               writel(RGMII_MODE_ENABLE, priv->data.gmii_sel);
-               break;
-       }
+
+       /* Select phy interface in control module */
+       cpsw_phy_sel(priv, phy_sel_compat, pdata->phy_interface);
 
        return 0;
 }