driver: net: cpsw: add support for RGMII id mode support and RMII clock source selection
authorMugunthan V N <mugunthanvnm@ti.com>
Thu, 13 Oct 2016 14:03:38 +0000 (19:33 +0530)
committerJoe Hershberger <joe.hershberger@ni.com>
Thu, 13 Oct 2016 17:25:02 +0000 (12:25 -0500)
cpsw driver supports only selection of phy mode in control module
but control module has more setting like RGMII ID mode selection,
RMII clock source selection. So ported to cpsw-phy-sel driver
from kernel to u-boot.

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
drivers/net/cpsw.c
include/cpsw.h

index d17505e08882c4bd46de3ab3a267639026d2e84c..d1f024e0eb3a8da51febb966511a348761d1e6c8 100644 (file)
@@ -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))
@@ -1150,12 +1162,129 @@ static inline fdt_addr_t cpsw_get_addr_by_node(const void *fdt, int node)
                                                  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)
 {
        struct eth_pdata *pdata = dev_get_platdata(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;
@@ -1271,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;
+                       }
                }
        }
 
@@ -1293,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;
 }
index 257d12a08d721eef149a31b466306cc2465774d6..f135e7bfe0cc6425aa567c61414e2d12d59aae80 100644 (file)
@@ -48,6 +48,7 @@ struct cpsw_platform_data {
        void    (*control)(int enabled);
        u32     host_port_num;
        u32     active_slave;
+       bool    rmii_clock_external;
        u8      version;
 };