The rmii_internal clock is needed only when PHY interface is RMII, and reference clock is from MAC. Re-arrange the clock setting as following: 1. the optional "rmii_internal" is controlled by devm_clk_get(), 2. other clocks still be configured by devm_clk_bulk_get(). Signed-off-by: Biao Huang <biao.huang@xxxxxxxxxxxx> --- .../ethernet/stmicro/stmmac/dwmac-mediatek.c | 71 +++++++++++++------ 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c index 8747aa4403e8..b2507a2ba326 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c @@ -49,12 +49,12 @@ struct mac_delay_struct { struct mediatek_dwmac_plat_data { const struct mediatek_dwmac_variant *variant; struct mac_delay_struct mac_delay; + struct clk *rmii_internal_clk; struct clk_bulk_data *clks; - struct device_node *np; struct regmap *peri_regmap; + struct device_node *np; struct device *dev; phy_interface_t phy_mode; - int num_clks_to_config; bool rmii_clk_from_mac; bool rmii_rxc; }; @@ -74,7 +74,7 @@ struct mediatek_dwmac_variant { /* list of clocks required for mac */ static const char * const mt2712_dwmac_clk_l[] = { - "axi", "apb", "mac_main", "ptp_ref", "rmii_internal" + "axi", "apb", "mac_main", "ptp_ref" }; static int mt2712_set_interface(struct mediatek_dwmac_plat_data *plat) @@ -83,23 +83,12 @@ static int mt2712_set_interface(struct mediatek_dwmac_plat_data *plat) int rmii_rxc = plat->rmii_rxc ? RMII_CLK_SRC_RXC : 0; u32 intf_val = 0; - /* The clock labeled as "rmii_internal" in mt2712_dwmac_clk_l is needed - * only in RMII(when MAC provides the reference clock), and useless for - * RGMII/MII/RMII(when PHY provides the reference clock). - * num_clks_to_config indicates the real number of clocks should be - * configured, equals to (plat->variant->num_clks - 1) in default for all the case, - * then +1 for rmii_clk_from_mac case. - */ - plat->num_clks_to_config = plat->variant->num_clks - 1; - /* select phy interface in top control domain */ switch (plat->phy_mode) { case PHY_INTERFACE_MODE_MII: intf_val |= PHY_INTF_MII; break; case PHY_INTERFACE_MODE_RMII: - if (plat->rmii_clk_from_mac) - plat->num_clks_to_config++; intf_val |= (PHY_INTF_RMII | rmii_rxc | rmii_clk_from_mac); break; case PHY_INTERFACE_MODE_RGMII: @@ -314,18 +303,34 @@ static int mediatek_dwmac_config_dt(struct mediatek_dwmac_plat_data *plat) static int mediatek_dwmac_clk_init(struct mediatek_dwmac_plat_data *plat) { const struct mediatek_dwmac_variant *variant = plat->variant; - int i, num = variant->num_clks; + int i, ret; - plat->clks = devm_kcalloc(plat->dev, num, sizeof(*plat->clks), GFP_KERNEL); + plat->clks = devm_kcalloc(plat->dev, variant->num_clks, sizeof(*plat->clks), GFP_KERNEL); if (!plat->clks) return -ENOMEM; - for (i = 0; i < num; i++) + for (i = 0; i < variant->num_clks; i++) plat->clks[i].id = variant->clk_list[i]; - plat->num_clks_to_config = variant->num_clks; + ret = devm_clk_bulk_get(plat->dev, variant->num_clks, plat->clks); + if (ret) + return ret; - return devm_clk_bulk_get(plat->dev, num, plat->clks); + /* The clock labeled as "rmii_internal" is needed only in RMII(when + * MAC provides the reference clock), and useless for RGMII/MII or + * RMII(when PHY provides the reference clock). + * So, "rmii_internal" clock is got and configured only when + * reference clock of RMII is from MAC. + */ + if (plat->rmii_clk_from_mac) { + plat->rmii_internal_clk = devm_clk_get(plat->dev, "rmii_internal"); + if (IS_ERR(plat->rmii_internal_clk)) + ret = PTR_ERR(plat->rmii_internal_clk); + } else { + plat->rmii_internal_clk = NULL; + } + + return ret; } static int mediatek_dwmac_init(struct platform_device *pdev, void *priv) @@ -350,35 +355,55 @@ static int mediatek_dwmac_init(struct platform_device *pdev, void *priv) } } - ret = clk_bulk_prepare_enable(plat->num_clks_to_config, plat->clks); + ret = clk_bulk_prepare_enable(variant->num_clks, plat->clks); if (ret) { dev_err(plat->dev, "failed to enable clks, err = %d\n", ret); return ret; } + ret = clk_prepare_enable(plat->rmii_internal_clk); + if (ret) { + dev_err(plat->dev, "failed to enable rmii internal clk, err = %d\n", ret); + goto err_clk; + } + return 0; + +err_clk: + clk_bulk_disable_unprepare(variant->num_clks, plat->clks); + return ret; } static void mediatek_dwmac_exit(struct platform_device *pdev, void *priv) { struct mediatek_dwmac_plat_data *plat = priv; + const struct mediatek_dwmac_variant *variant = plat->variant; - clk_bulk_disable_unprepare(plat->num_clks_to_config, plat->clks); + clk_disable_unprepare(plat->rmii_internal_clk); + clk_bulk_disable_unprepare(variant->num_clks, plat->clks); } static int mediatek_dwmac_clks_config(void *priv, bool enabled) { struct mediatek_dwmac_plat_data *plat = priv; + const struct mediatek_dwmac_variant *variant = plat->variant; int ret = 0; if (enabled) { - ret = clk_bulk_prepare_enable(plat->num_clks_to_config, plat->clks); + ret = clk_bulk_prepare_enable(variant->num_clks, plat->clks); if (ret) { dev_err(plat->dev, "failed to enable clks, err = %d\n", ret); return ret; } + + ret = clk_prepare_enable(plat->rmii_internal_clk); + if (ret) { + dev_err(plat->dev, "failed to enable rmii internal clk, err = %d\n", ret); + return ret; + } } else { - clk_bulk_disable_unprepare(plat->num_clks_to_config, plat->clks); + clk_disable_unprepare(plat->rmii_internal_clk); + clk_bulk_disable_unprepare(variant->num_clks, plat->clks); } return ret; -- 2.25.1