Merge branch 'net-stmmac-cleanup-transmit-clock-setting'

Russell King says:

====================
net: stmmac: cleanup transmit clock setting

A lot of stmmac platform code which sets the transmit clock is very
similar - they decode the speed to the clock rate (125, 25 or 2.5 MHz)
and then set a clock to that rate.

The DWMAC core appears to have a clock input for the transmit section
called clk_tx_i which requires this rate.

This series moves the code which sets this clock into the core stmmac
code.

Patch 1 adds a hook that platforms can use to configure the clock rate.
Patch 2 adds a generic implementation.
The remainder of the patches convert the glue code for various platforms
to use this new infrastructure.
====================

Link: https://patch.msgid.link/Z8AtX-wyPal1auVO@shell.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2025-02-28 10:20:50 -08:00
commit 8e7e3d97f9
12 changed files with 108 additions and 90 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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))

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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;