]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
net: gmac_rockchip: Add support for the RV1108 GMAC
authorDavid Wu <david.wu@rock-chips.com>
Sat, 13 Jan 2018 06:01:12 +0000 (14:01 +0800)
committerPhilipp Tomsich <philipp.tomsich@theobroma-systems.com>
Sun, 28 Jan 2018 16:12:37 +0000 (17:12 +0100)
The rv1108 GMAC only support rmii interface, so need to add the
set_rmii() ops. Use the phy current interface to set rmii or
rgmii ops. At the same time, need to set the mac clock rate of
rmii with 50M, the clock rate of rgmii with 125M.

Signed-off-by: David Wu <david.wu@rock-chips.com>
Acked-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Reviewed-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
drivers/net/gmac_rockchip.c

index 586ccbff0a76462efde19bb85c27b05fba6f4acb..cfffe2979d1b31548c9f7af293ee6854449c2183 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/arch/grf_rk3288.h>
 #include <asm/arch/grf_rk3368.h>
 #include <asm/arch/grf_rk3399.h>
+#include <asm/arch/grf_rv1108.h>
 #include <dm/pinctrl.h>
 #include <dt-bindings/clock/rk3288-cru.h>
 #include "designware.h"
@@ -31,12 +32,14 @@ DECLARE_GLOBAL_DATA_PTR;
  */
 struct gmac_rockchip_platdata {
        struct dw_eth_pdata dw_eth_pdata;
+       bool clock_input;
        int tx_delay;
        int rx_delay;
 };
 
 struct rk_gmac_ops {
        int (*fix_mac_speed)(struct dw_eth_dev *priv);
+       void (*set_to_rmii)(struct gmac_rockchip_platdata *pdata);
        void (*set_to_rgmii)(struct gmac_rockchip_platdata *pdata);
 };
 
@@ -44,6 +47,13 @@ struct rk_gmac_ops {
 static int gmac_rockchip_ofdata_to_platdata(struct udevice *dev)
 {
        struct gmac_rockchip_platdata *pdata = dev_get_platdata(dev);
+       const char *string;
+
+       string = dev_read_string(dev, "clock_in_out");
+       if (!strcmp(string, "input"))
+               pdata->clock_input = true;
+       else
+               pdata->clock_input = false;
 
        /* Check the new naming-style first... */
        pdata->tx_delay = dev_read_u32_default(dev, "tx_delay", -ENOENT);
@@ -142,6 +152,41 @@ static int rk3399_gmac_fix_mac_speed(struct dw_eth_dev *priv)
        return 0;
 }
 
+static int rv1108_set_rmii_speed(struct dw_eth_dev *priv)
+{
+       struct rv1108_grf *grf;
+       int clk, speed;
+       enum {
+               RV1108_GMAC_SPEED_MASK          = BIT(2),
+               RV1108_GMAC_SPEED_10M           = 0 << 2,
+               RV1108_GMAC_SPEED_100M          = 1 << 2,
+               RV1108_GMAC_CLK_SEL_MASK        = BIT(7),
+               RV1108_GMAC_CLK_SEL_2_5M        = 0 << 7,
+               RV1108_GMAC_CLK_SEL_25M         = 1 << 7,
+       };
+
+       switch (priv->phydev->speed) {
+       case 10:
+               clk = RV1108_GMAC_CLK_SEL_2_5M;
+               speed = RV1108_GMAC_SPEED_10M;
+               break;
+       case 100:
+               clk = RV1108_GMAC_CLK_SEL_25M;
+               speed = RV1108_GMAC_SPEED_100M;
+               break;
+       default:
+               debug("Unknown phy speed: %d\n", priv->phydev->speed);
+               return -EINVAL;
+       }
+
+       grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+       rk_clrsetreg(&grf->gmac_con0,
+                    RV1108_GMAC_CLK_SEL_MASK | RV1108_GMAC_SPEED_MASK,
+                    clk | speed);
+
+       return 0;
+}
+
 static void rk3288_gmac_set_to_rgmii(struct gmac_rockchip_platdata *pdata)
 {
        struct rk3288_grf *grf;
@@ -221,25 +266,76 @@ static void rk3399_gmac_set_to_rgmii(struct gmac_rockchip_platdata *pdata)
                     pdata->tx_delay << RK3399_CLK_TX_DL_CFG_GMAC_SHIFT);
 }
 
+static void rv1108_gmac_set_to_rmii(struct gmac_rockchip_platdata *pdata)
+{
+       struct rv1108_grf *grf;
+
+       enum {
+               RV1108_GMAC_PHY_INTF_SEL_MASK  = GENMASK(6, 4),
+               RV1108_GMAC_PHY_INTF_SEL_RMII  = 4 << 4,
+       };
+
+       grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+       rk_clrsetreg(&grf->gmac_con0,
+                    RV1108_GMAC_PHY_INTF_SEL_MASK,
+                    RV1108_GMAC_PHY_INTF_SEL_RMII);
+}
+
 static int gmac_rockchip_probe(struct udevice *dev)
 {
        struct gmac_rockchip_platdata *pdata = dev_get_platdata(dev);
        struct rk_gmac_ops *ops =
                (struct rk_gmac_ops *)dev_get_driver_data(dev);
+       struct dw_eth_pdata *dw_pdata = dev_get_platdata(dev);
+       struct eth_pdata *eth_pdata = &dw_pdata->eth_pdata;
        struct clk clk;
+       ulong rate;
        int ret;
 
        ret = clk_get_by_index(dev, 0, &clk);
        if (ret)
                return ret;
 
-       /* Since mac_clk is fed by an external clock we can use 0 here */
-       ret = clk_set_rate(&clk, 0);
-       if (ret)
-               return ret;
+       switch (eth_pdata->phy_interface) {
+       case PHY_INTERFACE_MODE_RGMII:
+               /*
+                * If the gmac clock is from internal pll, need to set and
+                * check the return value for gmac clock at RGMII mode. If
+                * the gmac clock is from external source, the clock rate
+                * is not set, because of it is bypassed.
+                */
+               if (!pdata->clock_input) {
+                       rate = clk_set_rate(&clk, 125000000);
+                       if (rate != 125000000)
+                               return -EINVAL;
+               }
+
+               /* Set to RGMII mode */
+               if (ops->set_to_rgmii)
+                       ops->set_to_rgmii(pdata);
+               else
+                       return -EPERM;
 
-       /* Set to RGMII mode */
-       ops->set_to_rgmii(pdata);
+               break;
+       case PHY_INTERFACE_MODE_RMII:
+               /* The commet is the same as RGMII mode */
+               if (!pdata->clock_input) {
+                       rate = clk_set_rate(&clk, 50000000);
+                       if (rate != 50000000)
+                               return -EINVAL;
+               }
+
+               /* Set to RMII mode */
+               if (ops->set_to_rmii)
+                       ops->set_to_rmii(pdata);
+               else
+                       return -EPERM;
+
+               break;
+       default:
+               debug("NO interface defined!\n");
+               return -ENXIO;
+       }
 
        return designware_eth_probe(dev);
 }
@@ -289,6 +385,11 @@ const struct rk_gmac_ops rk3399_gmac_ops = {
        .set_to_rgmii = rk3399_gmac_set_to_rgmii,
 };
 
+const struct rk_gmac_ops rv1108_gmac_ops = {
+       .fix_mac_speed = rv1108_set_rmii_speed,
+       .set_to_rmii = rv1108_gmac_set_to_rmii,
+};
+
 static const struct udevice_id rockchip_gmac_ids[] = {
        { .compatible = "rockchip,rk3288-gmac",
          .data = (ulong)&rk3288_gmac_ops },
@@ -296,6 +397,8 @@ static const struct udevice_id rockchip_gmac_ids[] = {
          .data = (ulong)&rk3368_gmac_ops },
        { .compatible = "rockchip,rk3399-gmac",
          .data = (ulong)&rk3399_gmac_ops },
+       { .compatible = "rockchip,rv1108-gmac",
+         .data = (ulong)&rv1108_gmac_ops },
        { }
 };