diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c index 6cadf24a575c..3f0f4ea6cf2e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c @@ -30,7 +30,6 @@ struct tegra_eqos { struct reset_control *rst; struct clk *clk_slave; - struct clk *clk_tx; struct gpio_desc *reset; }; @@ -150,7 +149,6 @@ static void tegra_eqos_fix_speed(void *priv, int speed, unsigned int mode) { struct tegra_eqos *eqos = priv; bool needs_calibration = false; - long rate = 125000000; u32 value; int err; @@ -161,7 +159,6 @@ static void tegra_eqos_fix_speed(void *priv, int speed, unsigned int mode) fallthrough; case SPEED_10: - rate = rgmii_clock(speed); break; default: @@ -208,10 +205,6 @@ static void tegra_eqos_fix_speed(void *priv, int speed, unsigned int mode) value &= ~AUTO_CAL_CONFIG_ENABLE; writel(value, eqos->regs + AUTO_CAL_CONFIG); } - - err = clk_set_rate(eqos->clk_tx, rate); - if (err < 0) - dev_err(eqos->dev, "failed to set TX rate: %d\n", err); } static int tegra_eqos_init(struct platform_device *pdev, void *priv) @@ -247,7 +240,7 @@ static int tegra_eqos_probe(struct platform_device *pdev, if (!is_of_node(dev->fwnode)) goto bypass_clk_reset_gpio; - eqos->clk_tx = dwc_eth_find_clk(plat_dat, "tx"); + plat_dat->clk_tx_i = dwc_eth_find_clk(plat_dat, "tx"); eqos->reset = devm_gpiod_get(&pdev->dev, "phy-reset", GPIOD_OUT_HIGH); if (IS_ERR(eqos->reset)) { @@ -281,6 +274,7 @@ static int tegra_eqos_probe(struct platform_device *pdev, bypass_clk_reset_gpio: plat_dat->fix_mac_speed = tegra_eqos_fix_speed; + plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate; plat_dat->init = tegra_eqos_init; plat_dat->bsp_priv = eqos; plat_dat->flags |= STMMAC_FLAG_SPH_DISABLE; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c index 610204b51e3f..5d279fa54b3e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c @@ -192,6 +192,19 @@ static void imx_dwmac_exit(struct platform_device *pdev, void *priv) /* nothing to do now */ } +static int imx_dwmac_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, + phy_interface_t interface, int speed) +{ + struct imx_priv_data *dwmac = bsp_priv; + + interface = dwmac->plat_dat->mac_interface; + if (interface == PHY_INTERFACE_MODE_RMII || + interface == PHY_INTERFACE_MODE_MII) + return 0; + + return stmmac_set_clk_tx_rate(bsp_priv, clk_tx_i, interface, speed); +} + static void imx_dwmac_fix_speed(void *priv, int speed, unsigned int mode) { struct plat_stmmacenet_data *plat_dat; @@ -358,7 +371,6 @@ static int imx_dwmac_probe(struct platform_device *pdev) plat_dat->init = imx_dwmac_init; plat_dat->exit = imx_dwmac_exit; plat_dat->clks_config = imx_dwmac_clks_config; - plat_dat->fix_mac_speed = imx_dwmac_fix_speed; plat_dat->bsp_priv = dwmac; dwmac->plat_dat = plat_dat; dwmac->base_addr = stmmac_res.addr; @@ -371,8 +383,13 @@ static int imx_dwmac_probe(struct platform_device *pdev) if (ret) goto err_dwmac_init; - if (dwmac->ops->fix_mac_speed) + if (dwmac->ops->fix_mac_speed) { plat_dat->fix_mac_speed = dwmac->ops->fix_mac_speed; + } else if (!dwmac->ops->mac_rgmii_txclk_auto_adj) { + plat_dat->clk_tx_i = dwmac->clk_tx; + plat_dat->set_clk_tx_rate = imx_dwmac_set_clk_tx_rate; + } + dwmac->plat_dat->fix_soc_reset = dwmac->ops->fix_soc_reset; ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c index 0591756a2100..599def7b3a64 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c @@ -22,31 +22,12 @@ struct intel_dwmac { }; struct intel_dwmac_data { - void (*fix_mac_speed)(void *priv, int speed, unsigned int mode); unsigned long ptp_ref_clk_rate; unsigned long tx_clk_rate; bool tx_clk_en; }; -static void kmb_eth_fix_mac_speed(void *priv, int speed, unsigned int mode) -{ - struct intel_dwmac *dwmac = priv; - long rate; - int ret; - - rate = rgmii_clock(speed); - if (rate < 0) { - dev_err(dwmac->dev, "Invalid speed\n"); - return; - } - - ret = clk_set_rate(dwmac->tx_clk, rate); - if (ret) - dev_err(dwmac->dev, "Failed to configure tx clock rate\n"); -} - static const struct intel_dwmac_data kmb_data = { - .fix_mac_speed = kmb_eth_fix_mac_speed, .ptp_ref_clk_rate = 200000000, .tx_clk_rate = 125000000, .tx_clk_en = true, @@ -89,8 +70,6 @@ static int intel_eth_plat_probe(struct platform_device *pdev) * platform_match(). */ dwmac->data = device_get_match_data(&pdev->dev); - if (dwmac->data->fix_mac_speed) - plat_dat->fix_mac_speed = dwmac->data->fix_mac_speed; /* Enable TX clock */ if (dwmac->data->tx_clk_en) { @@ -132,6 +111,9 @@ static int intel_eth_plat_probe(struct platform_device *pdev) } } + plat_dat->clk_tx_i = dwmac->tx_clk; + plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate; + plat_dat->bsp_priv = dwmac; plat_dat->eee_usecs_rate = plat_dat->clk_ptp_rate; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c index 7f4b9c1cc32b..0a9c137cc4e6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -260,11 +260,12 @@ static int ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac) return PTR_ERR_OR_ZERO(gmac->qsgmii_csr); } -static void ipq806x_gmac_fix_mac_speed(void *priv, int speed, unsigned int mode) +static int ipq806x_gmac_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, + phy_interface_t interface, int speed) { - struct ipq806x_gmac *gmac = priv; + struct ipq806x_gmac *gmac = bsp_priv; - ipq806x_gmac_set_speed(gmac, speed); + return ipq806x_gmac_set_speed(gmac, speed); } static int @@ -478,7 +479,7 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) plat_dat->has_gmac = true; plat_dat->bsp_priv = gmac; - plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed; + plat_dat->set_clk_tx_rate = ipq806x_gmac_set_clk_tx_rate; plat_dat->multicast_filter_bins = 0; plat_dat->tx_fifo_size = 8192; plat_dat->rx_fifo_size = 8192; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c index b115b7873cef..07c504d07604 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c @@ -22,9 +22,10 @@ struct meson_dwmac { void __iomem *reg; }; -static void meson6_dwmac_fix_mac_speed(void *priv, int speed, unsigned int mode) +static int meson6_dwmac_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, + phy_interface_t interface, int speed) { - struct meson_dwmac *dwmac = priv; + struct meson_dwmac *dwmac = bsp_priv; unsigned int val; val = readl(dwmac->reg); @@ -39,6 +40,8 @@ static void meson6_dwmac_fix_mac_speed(void *priv, int speed, unsigned int mode) } writel(val, dwmac->reg); + + return 0; } static int meson6_dwmac_probe(struct platform_device *pdev) @@ -65,7 +68,7 @@ static int meson6_dwmac_probe(struct platform_device *pdev) return PTR_ERR(dwmac->reg); plat_dat->bsp_priv = dwmac; - plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed; + plat_dat->set_clk_tx_rate = meson6_dwmac_set_clk_tx_rate; return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 83d104a274c5..003fa5cf42c3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -1920,9 +1920,10 @@ static void rk_gmac_powerdown(struct rk_priv_data *gmac) gmac_clk_enable(gmac, false); } -static void rk_fix_speed(void *priv, int speed, unsigned int mode) +static int rk_set_clk_tx_rate(void *bsp_priv_, struct clk *clk_tx_i, + phy_interface_t interface, int speed) { - struct rk_priv_data *bsp_priv = priv; + struct rk_priv_data *bsp_priv = bsp_priv_; struct device *dev = &bsp_priv->pdev->dev; switch (bsp_priv->phy_iface) { @@ -1940,6 +1941,8 @@ static void rk_fix_speed(void *priv, int speed, unsigned int mode) default: dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface); } + + return 0; } static int rk_gmac_probe(struct platform_device *pdev) @@ -1968,7 +1971,8 @@ static int rk_gmac_probe(struct platform_device *pdev) */ if (!plat_dat->has_gmac4) plat_dat->has_gmac = true; - plat_dat->fix_mac_speed = rk_fix_speed; + + plat_dat->set_clk_tx_rate = rk_set_clk_tx_rate; plat_dat->bsp_priv = rk_gmac_setup(pdev, plat_dat, data); if (IS_ERR(plat_dat->bsp_priv)) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c index 6a498833b8ed..221539d760bc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c @@ -100,24 +100,6 @@ static void s32_gmac_exit(struct platform_device *pdev, void *priv) clk_disable_unprepare(gmac->rx_clk); } -static void s32_fix_mac_speed(void *priv, int speed, unsigned int mode) -{ - struct s32_priv_data *gmac = priv; - long tx_clk_rate; - int ret; - - tx_clk_rate = rgmii_clock(speed); - if (tx_clk_rate < 0) { - dev_err(gmac->dev, "Unsupported/Invalid speed: %d\n", speed); - return; - } - - dev_dbg(gmac->dev, "Set tx clock to %ld Hz\n", tx_clk_rate); - ret = clk_set_rate(gmac->tx_clk, tx_clk_rate); - if (ret) - dev_err(gmac->dev, "Can't set tx clock\n"); -} - static int s32_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat; @@ -172,7 +154,9 @@ static int s32_dwmac_probe(struct platform_device *pdev) plat->init = s32_gmac_init; plat->exit = s32_gmac_exit; - plat->fix_mac_speed = s32_fix_mac_speed; + + plat->clk_tx_i = gmac->tx_clk; + plat->set_clk_tx_rate = stmmac_set_clk_tx_rate; plat->bsp_priv = gmac; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c index 282c846dad0b..5e31cb3bb4b8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c @@ -27,27 +27,9 @@ struct starfive_dwmac_data { struct starfive_dwmac { struct device *dev; - struct clk *clk_tx; const struct starfive_dwmac_data *data; }; -static void starfive_dwmac_fix_mac_speed(void *priv, int speed, unsigned int mode) -{ - struct starfive_dwmac *dwmac = priv; - long rate; - int err; - - rate = rgmii_clock(speed); - if (rate < 0) { - dev_err(dwmac->dev, "invalid speed %d\n", speed); - return; - } - - err = clk_set_rate(dwmac->clk_tx, rate); - if (err) - dev_err(dwmac->dev, "failed to set tx rate %lu\n", rate); -} - static int starfive_dwmac_set_mode(struct plat_stmmacenet_data *plat_dat) { struct starfive_dwmac *dwmac = plat_dat->bsp_priv; @@ -122,9 +104,9 @@ static int starfive_dwmac_probe(struct platform_device *pdev) dwmac->data = device_get_match_data(&pdev->dev); - dwmac->clk_tx = devm_clk_get_enabled(&pdev->dev, "tx"); - if (IS_ERR(dwmac->clk_tx)) - return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->clk_tx), + plat_dat->clk_tx_i = devm_clk_get_enabled(&pdev->dev, "tx"); + if (IS_ERR(plat_dat->clk_tx_i)) + return dev_err_probe(&pdev->dev, PTR_ERR(plat_dat->clk_tx_i), "error getting tx clock\n"); clk_gtx = devm_clk_get_enabled(&pdev->dev, "gtx"); @@ -139,7 +121,7 @@ static int starfive_dwmac_probe(struct platform_device *pdev) * internally, because rgmii_rxin will be adaptively adjusted. */ if (!device_property_read_bool(&pdev->dev, "starfive,tx-use-rgmii-clk")) - plat_dat->fix_mac_speed = starfive_dwmac_fix_mac_speed; + plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate; dwmac->dev = &pdev->dev; plat_dat->bsp_priv = dwmac; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c index f9f2bd65959f..c72ee759aae5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c @@ -101,10 +101,11 @@ static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat) return 0; } -static void thead_dwmac_fix_speed(void *priv, int speed, unsigned int mode) +static int thead_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, + phy_interface_t interface, int speed) { + struct thead_dwmac *dwmac = bsp_priv; struct plat_stmmacenet_data *plat; - struct thead_dwmac *dwmac = priv; unsigned long rate; long tx_rate; u32 div, reg; @@ -114,7 +115,7 @@ static void thead_dwmac_fix_speed(void *priv, int speed, unsigned int mode) switch (plat->mac_interface) { /* For MII, rxc/txc is provided by phy */ case PHY_INTERFACE_MODE_MII: - return; + return 0; case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: @@ -127,23 +128,24 @@ static void thead_dwmac_fix_speed(void *priv, int speed, unsigned int mode) tx_rate = rgmii_clock(speed); if (tx_rate < 0) { dev_err(dwmac->dev, "invalid speed %d\n", speed); - return; + return tx_rate; } div = rate / tx_rate; if (rate != tx_rate * div) { dev_err(dwmac->dev, "invalid gmac rate %lu\n", rate); - return; + return -EINVAL; } reg = FIELD_PREP(GMAC_PLLCLK_DIV_EN, 1) | FIELD_PREP(GMAC_PLLCLK_DIV_NUM, div); writel(reg, dwmac->apb_base + GMAC_PLLCLK_DIV); - break; + return 0; + default: dev_err(dwmac->dev, "unsupported phy interface %d\n", plat->mac_interface); - return; + return -EINVAL; } } @@ -235,7 +237,7 @@ static int thead_dwmac_probe(struct platform_device *pdev) dwmac->plat = plat; dwmac->apb_base = apb; plat->bsp_priv = dwmac; - plat->fix_mac_speed = thead_dwmac_fix_speed; + plat->set_clk_tx_rate = thead_set_clk_tx_rate; plat->init = thead_dwmac_init; return devm_stmmac_pltfr_probe(pdev, plat, &stmmac_res); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index b32187284607..3a00a988cb36 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -407,6 +407,8 @@ int stmmac_dvr_probe(struct device *device, int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt); int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size); int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled); +int stmmac_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, + phy_interface_t interface, int speed); static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 424fa2fe31c6..aec230353ac4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -177,6 +177,38 @@ int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled) } EXPORT_SYMBOL_GPL(stmmac_bus_clks_config); +/** + * stmmac_set_clk_tx_rate() - set the clock rate for the MAC transmit clock + * @bsp_priv: BSP private data structure (unused) + * @clk_tx_i: the transmit clock + * @interface: the selected interface mode + * @speed: the speed that the MAC will be operating at + * + * Set the transmit clock rate for the MAC, normally 2.5MHz for 10Mbps, + * 25MHz for 100Mbps and 125MHz for 1Gbps. This is suitable for at least + * MII, GMII, RGMII and RMII interface modes. Platforms can hook this into + * the plat_data->set_clk_tx_rate method directly, call it via their own + * implementation, or implement their own method should they have more + * complex requirements. It is intended to only be used in this method. + * + * plat_data->clk_tx_i must be filled in. + */ +int stmmac_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, + phy_interface_t interface, int speed) +{ + long rate = rgmii_clock(speed); + + /* Silently ignore unsupported speeds as rgmii_clock() only + * supports 10, 100 and 1000Mbps. We do not want to spit + * errors for 2500 and higher speeds here. + */ + if (rate < 0) + return 0; + + return clk_set_rate(clk_tx_i, rate); +} +EXPORT_SYMBOL_GPL(stmmac_set_clk_tx_rate); + /** * stmmac_verify_args - verify the driver parameters. * Description: it checks the driver parameters and set a default in case of @@ -928,6 +960,7 @@ static void stmmac_mac_link_up(struct phylink_config *config, struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); unsigned int flow_ctrl; u32 old_ctrl, ctrl; + int ret; if ((priv->plat->flags & STMMAC_FLAG_SERDES_UP_AFTER_PHY_LINKUP) && priv->plat->serdes_powerup) @@ -1020,6 +1053,16 @@ static void stmmac_mac_link_up(struct phylink_config *config, if (ctrl != old_ctrl) writel(ctrl, priv->ioaddr + MAC_CTRL_REG); + if (priv->plat->set_clk_tx_rate) { + ret = priv->plat->set_clk_tx_rate(priv->plat->bsp_priv, + priv->plat->clk_tx_i, + interface, speed); + if (ret < 0) + netdev_err(priv->dev, + "failed to configure transmit clock for %dMbps: %pe\n", + speed, ERR_PTR(ret)); + } + stmmac_mac_set(priv, priv->ioaddr, true); if (priv->dma_cap.eee) stmmac_set_eee_pls(priv, priv->hw, true); diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index 6d2aa77ea963..cd0d1383df87 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -78,6 +78,7 @@ | DMA_AXI_BLEN_32 | DMA_AXI_BLEN_64 \ | DMA_AXI_BLEN_128 | DMA_AXI_BLEN_256) +struct clk; struct stmmac_priv; /* Platfrom data for platform device structure's platform_data field */ @@ -231,6 +232,8 @@ struct plat_stmmacenet_data { u8 tx_sched_algorithm; struct stmmac_rxq_cfg rx_queues_cfg[MTL_MAX_RX_QUEUES]; struct stmmac_txq_cfg tx_queues_cfg[MTL_MAX_TX_QUEUES]; + int (*set_clk_tx_rate)(void *priv, struct clk *clk_tx_i, + phy_interface_t interface, int speed); void (*fix_mac_speed)(void *priv, int speed, unsigned int mode); int (*fix_soc_reset)(void *priv, void __iomem *ioaddr); int (*serdes_powerup)(struct net_device *ndev, void *priv); @@ -252,6 +255,7 @@ struct plat_stmmacenet_data { struct clk *stmmac_clk; struct clk *pclk; struct clk *clk_ptp_ref; + struct clk *clk_tx_i; /* clk_tx_i to MAC core */ unsigned long clk_ptp_rate; unsigned long clk_ref_rate; struct clk_bulk_data *clks;