net: sun8i_emac: Add EPHY CLK and RESET support
authorJagan Teki <jagan@amarulasolutions.com>
Wed, 27 Feb 2019 18:57:00 +0000 (00:27 +0530)
committerJagan Teki <jagan@amarulasolutions.com>
Wed, 8 May 2019 19:14:13 +0000 (00:44 +0530)
Add EPHY CLK and RESET support for sun8i_emac driver to
enable EPHY TX clock and EPHY reset pins via CLK and RESET
framework.

Cc: Joe Hershberger <joe.hershberger@ni.com>
Cc: Lothar Felten <lothar.felten@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
drivers/net/sun8i_emac.c

index 98bd7a58232fd0e9416529e67bd835f8949202a0..c0a440886e29c42976174e0443d38046171555e8 100644 (file)
@@ -138,7 +138,9 @@ struct emac_eth_dev {
        struct phy_device *phydev;
        struct mii_dev *bus;
        struct clk tx_clk;
+       struct clk ephy_clk;
        struct reset_ctl tx_rst;
+       struct reset_ctl ephy_rst;
 #ifdef CONFIG_DM_GPIO
        struct gpio_desc reset_gpio;
 #endif
@@ -653,7 +655,6 @@ static int sun8i_eth_write_hwaddr(struct udevice *dev)
 
 static int sun8i_emac_board_setup(struct emac_eth_dev *priv)
 {
-       struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
        int ret;
 
        ret = clk_enable(&priv->tx_clk);
@@ -670,16 +671,20 @@ static int sun8i_emac_board_setup(struct emac_eth_dev *priv)
                }
        }
 
-       if (priv->variant == H3_EMAC) {
-               /* Only H3/H5 have clock controls for internal EPHY */
-               if (priv->use_internal_phy) {
-                       /* Set clock gating for ephy */
-                       setbits_le32(&ccm->bus_gate4,
-                                    BIT(AHB_GATE_OFFSET_EPHY));
-
-                       /* Deassert EPHY */
-                       setbits_le32(&ccm->ahb_reset2_cfg,
-                                    BIT(AHB_RESET_OFFSET_EPHY));
+       /* Only H3/H5 have clock controls for internal EPHY */
+       if (clk_valid(&priv->ephy_clk)) {
+               ret = clk_enable(&priv->ephy_clk);
+               if (ret) {
+                       dev_err(dev, "failed to enable EPHY TX clock\n");
+                       return ret;
+               }
+       }
+
+       if (reset_valid(&priv->ephy_rst)) {
+               ret = reset_deassert(&priv->ephy_rst);
+               if (ret) {
+                       dev_err(dev, "failed to deassert EPHY TX clock\n");
+                       return ret;
                }
        }
 
@@ -839,6 +844,44 @@ static const struct eth_ops sun8i_emac_eth_ops = {
        .stop                   = sun8i_emac_eth_stop,
 };
 
+static int sun8i_get_ephy_nodes(struct emac_eth_dev *priv)
+{
+       int node, ret;
+
+       /* look for mdio-mux node for internal PHY node */
+       node = fdt_path_offset(gd->fdt_blob,
+                       "/soc/ethernet@1c30000/mdio-mux/mdio@1/ethernet-phy@1");
+       if (node < 0) {
+               debug("failed to get mdio-mux with internal PHY\n");
+               return node;
+       }
+
+       ret = fdt_node_check_compatible(gd->fdt_blob, node,
+                                       "allwinner,sun8i-h3-mdio-internal");
+       if (ret < 0) {
+               debug("failed to find mdio-internal node\n");
+               return ret;
+       }
+
+       ret = clk_get_by_index_nodev(offset_to_ofnode(node), 0,
+                                    &priv->ephy_clk);
+       if (ret) {
+               dev_err(dev, "failed to get EPHY TX clock\n");
+               return ret;
+       }
+
+       ret = reset_get_by_index_nodev(offset_to_ofnode(node), 0,
+                                      &priv->ephy_rst);
+       if (ret) {
+               dev_err(dev, "failed to get EPHY TX reset\n");
+               return ret;
+       }
+
+       priv->use_internal_phy = true;
+
+       return 0;
+}
+
 static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
 {
        struct sun8i_eth_pdata *sun8i_pdata = dev_get_platdata(dev);
@@ -920,12 +963,9 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
        }
 
        if (priv->variant == H3_EMAC) {
-               int parent = fdt_parent_offset(gd->fdt_blob, offset);
-
-               if (parent >= 0 &&
-                   !fdt_node_check_compatible(gd->fdt_blob, parent,
-                               "allwinner,sun8i-h3-mdio-internal"))
-                       priv->use_internal_phy = true;
+               ret = sun8i_get_ephy_nodes(priv);
+               if (ret)
+                       return ret;
        }
 
        priv->interface = pdata->phy_interface;