Commit 31113a45 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'net-stmmac-multi-interface-stmmac'

Russell King says:

====================
net: stmmac: multi-interface stmmac

This series adds a callback for platform glue to configure the stmmac
core interface mode depending on the PHY interface mode that is being
used. This is currently only called just before the dwmac core is reset
since these signals are latched on reset.

Included in this series are changes to s32 to move its PHY_INTF_SEL_x
definitions out of the way of the dwmac core's signals which has more
entitlement to use this name. We convert dwmac-imx as an example.

Including other platform glue would make this series excessively large,
but once this core code is merged, the individual platform glue updates
can be posted one after another as they will be independent of each
other.

It is hoped that this callback can be used in future to reconfigure the
dwmac core when the interface mode changes to support PHYs that change
their interface mode, but we're nowhere near being able to do that yet.
====================

Link: https://patch.msgid.link/aQiWzyrXU_2hGJ4j@shell.armlinux.org.uk


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 46173144 eaca1a4d
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -313,6 +313,16 @@ struct stmmac_safety_stats {
#define DMA_HW_FEAT_ACTPHYIF	0x70000000	/* Active/selected PHY iface */
#define DEFAULT_DMA_PBL		8

/* phy_intf_sel_i and ACTPHYIF encodings */
#define PHY_INTF_SEL_GMII_MII	0
#define PHY_INTF_SEL_RGMII	1
#define PHY_INTF_SEL_SGMII	2
#define PHY_INTF_SEL_TBI	3
#define PHY_INTF_SEL_RMII	4
#define PHY_INTF_SEL_RTBI	5
#define PHY_INTF_SEL_SMII	6
#define PHY_INTF_SEL_REVMII	7

/* MSI defines */
#define STMMAC_MSI_VEC_MAX	32

+44 −90
Original line number Diff line number Diff line
@@ -23,18 +23,13 @@
#include "stmmac_platform.h"

#define GPR_ENET_QOS_INTF_MODE_MASK	GENMASK(21, 16)
#define GPR_ENET_QOS_INTF_SEL_MII	(0x0 << 16)
#define GPR_ENET_QOS_INTF_SEL_RMII	(0x4 << 16)
#define GPR_ENET_QOS_INTF_SEL_RGMII	(0x1 << 16)
#define GPR_ENET_QOS_INTF_SEL_MASK	GENMASK(20, 16)
#define GPR_ENET_QOS_CLK_GEN_EN		(0x1 << 19)
#define GPR_ENET_QOS_CLK_TX_CLK_SEL	(0x1 << 20)
#define GPR_ENET_QOS_RGMII_EN		(0x1 << 21)

#define MX93_GPR_ENET_QOS_INTF_MODE_MASK	GENMASK(3, 0)
#define MX93_GPR_ENET_QOS_INTF_MASK		GENMASK(3, 1)
#define MX93_GPR_ENET_QOS_INTF_SEL_MII		(0x0 << 1)
#define MX93_GPR_ENET_QOS_INTF_SEL_RMII		(0x4 << 1)
#define MX93_GPR_ENET_QOS_INTF_SEL_RGMII	(0x1 << 1)
#define MX93_GPR_ENET_QOS_INTF_SEL_MASK		GENMASK(3, 1)
#define MX93_GPR_ENET_QOS_CLK_GEN_EN		(0x1 << 0)
#define MX93_GPR_ENET_QOS_CLK_SEL_MASK		BIT_MASK(0)
#define MX93_GPR_CLK_SEL_OFFSET			(4)
@@ -44,13 +39,15 @@
#define RMII_RESET_SPEED		(0x3 << 14)
#define CTRL_SPEED_MASK			GENMASK(15, 14)

struct imx_priv_data;

struct imx_dwmac_ops {
	u32 addr_width;
	u32 flags;
	bool mac_rgmii_txclk_auto_adj;

	int (*fix_soc_reset)(struct stmmac_priv *priv, void __iomem *ioaddr);
	int (*set_intf_mode)(struct plat_stmmacenet_data *plat_dat);
	int (*set_intf_mode)(struct imx_priv_data *dwmac, u8 phy_intf_sel);
	void (*fix_mac_speed)(void *priv, int speed, unsigned int mode);
};

@@ -67,57 +64,35 @@ struct imx_priv_data {
	struct plat_stmmacenet_data *plat_dat;
};

static int imx8mp_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
static int imx8mp_set_intf_mode(struct imx_priv_data *dwmac, u8 phy_intf_sel)
{
	struct imx_priv_data *dwmac = plat_dat->bsp_priv;
	int val;

	switch (plat_dat->phy_interface) {
	case PHY_INTERFACE_MODE_MII:
		val = GPR_ENET_QOS_INTF_SEL_MII;
		break;
	case PHY_INTERFACE_MODE_RMII:
		val = GPR_ENET_QOS_INTF_SEL_RMII;
		val |= (dwmac->rmii_refclk_ext ? 0 : GPR_ENET_QOS_CLK_TX_CLK_SEL);
		break;
	case PHY_INTERFACE_MODE_RGMII:
	case PHY_INTERFACE_MODE_RGMII_ID:
	case PHY_INTERFACE_MODE_RGMII_RXID:
	case PHY_INTERFACE_MODE_RGMII_TXID:
		val = GPR_ENET_QOS_INTF_SEL_RGMII |
		      GPR_ENET_QOS_RGMII_EN;
		break;
	default:
		pr_debug("imx dwmac doesn't support %s interface\n",
			 phy_modes(plat_dat->phy_interface));
		return -EINVAL;
	}
	unsigned int val;

	val = FIELD_PREP(GPR_ENET_QOS_INTF_SEL_MASK, phy_intf_sel) |
	      GPR_ENET_QOS_CLK_GEN_EN;

	if (phy_intf_sel == PHY_INTF_SEL_RMII && !dwmac->rmii_refclk_ext)
		val |= GPR_ENET_QOS_CLK_TX_CLK_SEL;
	else if (phy_intf_sel == PHY_INTF_SEL_RGMII)
		val |= GPR_ENET_QOS_RGMII_EN;

	val |= GPR_ENET_QOS_CLK_GEN_EN;
	return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
				  GPR_ENET_QOS_INTF_MODE_MASK, val);
};

static int
imx8dxl_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
imx8dxl_set_intf_mode(struct imx_priv_data *dwmac, u8 phy_intf_sel)
{
	int ret = 0;

	/* TBD: depends on imx8dxl scu interfaces to be upstreamed */
	return ret;
	return 0;
}

static int imx93_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
static int imx93_set_intf_mode(struct imx_priv_data *dwmac, u8 phy_intf_sel)
{
	struct imx_priv_data *dwmac = plat_dat->bsp_priv;
	int val, ret;

	switch (plat_dat->phy_interface) {
	case PHY_INTERFACE_MODE_MII:
		val = MX93_GPR_ENET_QOS_INTF_SEL_MII;
		break;
	case PHY_INTERFACE_MODE_RMII:
		if (dwmac->rmii_refclk_ext) {
	unsigned int val;
	int ret;

	if (phy_intf_sel == PHY_INTF_SEL_RMII && dwmac->rmii_refclk_ext) {
		ret = regmap_clear_bits(dwmac->intf_regmap,
					dwmac->intf_reg_off +
					MX93_GPR_CLK_SEL_OFFSET,
@@ -125,21 +100,10 @@ static int imx93_set_intf_mode(struct plat_stmmacenet_data *plat_dat)
		if (ret)
			return ret;
	}
		val = MX93_GPR_ENET_QOS_INTF_SEL_RMII;
		break;
	case PHY_INTERFACE_MODE_RGMII:
	case PHY_INTERFACE_MODE_RGMII_ID:
	case PHY_INTERFACE_MODE_RGMII_RXID:
	case PHY_INTERFACE_MODE_RGMII_TXID:
		val = MX93_GPR_ENET_QOS_INTF_SEL_RGMII;
		break;
	default:
		dev_dbg(dwmac->dev, "imx dwmac doesn't support %s interface\n",
			phy_modes(plat_dat->phy_interface));
		return -EINVAL;
	}

	val |= MX93_GPR_ENET_QOS_CLK_GEN_EN;
	val = FIELD_PREP(MX93_GPR_ENET_QOS_INTF_SEL_MASK, phy_intf_sel) |
	      MX93_GPR_ENET_QOS_CLK_GEN_EN;

	return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
				  MX93_GPR_ENET_QOS_INTF_MODE_MASK, val);
};
@@ -170,34 +134,24 @@ static int imx_dwmac_clks_config(void *priv, bool enabled)
	return ret;
}

static int imx_dwmac_init(struct platform_device *pdev, void *priv)
static int imx_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel)
{
	struct plat_stmmacenet_data *plat_dat;
	struct imx_priv_data *dwmac = priv;
	int ret;

	plat_dat = dwmac->plat_dat;

	if (dwmac->ops->set_intf_mode) {
		ret = dwmac->ops->set_intf_mode(plat_dat);
		if (ret)
			return ret;
	}
	struct imx_priv_data *dwmac = bsp_priv;

	if (!dwmac->ops->set_intf_mode)
		return 0;
}

static void imx_dwmac_exit(struct platform_device *pdev, void *priv)
{
	/* nothing to do now */
	if (phy_intf_sel != PHY_INTF_SEL_GMII_MII &&
	    phy_intf_sel != PHY_INTF_SEL_RGMII &&
	    phy_intf_sel != PHY_INTF_SEL_RMII)
		return -EINVAL;

	return dwmac->ops->set_intf_mode(dwmac, phy_intf_sel);
}

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->phy_interface;
	if (interface == PHY_INTERFACE_MODE_RMII ||
	    interface == PHY_INTERFACE_MODE_MII)
		return 0;
@@ -244,8 +198,8 @@ static void imx93_dwmac_fix_speed(void *priv, int speed, unsigned int mode)
	if (regmap_read(dwmac->intf_regmap, dwmac->intf_reg_off, &iface))
		return;

	iface &= MX93_GPR_ENET_QOS_INTF_MASK;
	if (iface != MX93_GPR_ENET_QOS_INTF_SEL_RGMII)
	if (FIELD_GET(MX93_GPR_ENET_QOS_INTF_SEL_MASK, iface) !=
	    PHY_INTF_SEL_RGMII)
		return;

	old_ctrl = readl(dwmac->base_addr + MAC_CTRL_REG);
@@ -258,6 +212,7 @@ static void imx93_dwmac_fix_speed(void *priv, int speed, unsigned int mode)
	readl(dwmac->base_addr + MAC_CTRL_REG);

	usleep_range(10, 20);
	iface &= MX93_GPR_ENET_QOS_INTF_SEL_MASK;
	iface |= MX93_GPR_ENET_QOS_CLK_GEN_EN;
	regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off,
			   MX93_GPR_ENET_QOS_INTF_MODE_MASK, iface);
@@ -370,8 +325,7 @@ static int imx_dwmac_probe(struct platform_device *pdev)
		plat_dat->tx_queues_cfg[i].tbs_en = 1;

	plat_dat->host_dma_width = dwmac->ops->addr_width;
	plat_dat->init = imx_dwmac_init;
	plat_dat->exit = imx_dwmac_exit;
	plat_dat->set_phy_intf_sel = imx_set_phy_intf_sel;
	plat_dat->clks_config = imx_dwmac_clks_config;
	plat_dat->bsp_priv = dwmac;
	dwmac->plat_dat = plat_dat;
+5 −5
Original line number Diff line number Diff line
@@ -24,10 +24,10 @@
#define GMAC_INTF_RATE_125M	125000000	/* 125MHz */

/* SoC PHY interface control register */
#define PHY_INTF_SEL_MII	0x00
#define PHY_INTF_SEL_SGMII	0x01
#define PHY_INTF_SEL_RGMII	0x02
#define PHY_INTF_SEL_RMII	0x08
#define S32_PHY_INTF_SEL_MII	0x00
#define S32_PHY_INTF_SEL_SGMII	0x01
#define S32_PHY_INTF_SEL_RGMII	0x02
#define S32_PHY_INTF_SEL_RMII	0x08

struct s32_priv_data {
	void __iomem *ioaddr;
@@ -40,7 +40,7 @@ struct s32_priv_data {

static int s32_gmac_write_phy_intf_select(struct s32_priv_data *gmac)
{
	writel(PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
	writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);

	dev_dbg(gmac->dev, "PHY mode set to %s\n", phy_modes(*gmac->intf_mode));

+1 −0
Original line number Diff line number Diff line
@@ -396,6 +396,7 @@ void stmmac_ptp_register(struct stmmac_priv *priv);
void stmmac_ptp_unregister(struct stmmac_priv *priv);
int stmmac_xdp_open(struct net_device *dev);
void stmmac_xdp_release(struct net_device *dev);
int stmmac_get_phy_intf_sel(phy_interface_t interface);
int stmmac_resume(struct device *dev);
int stmmac_suspend(struct device *dev);
void stmmac_dvr_remove(struct device *dev);
+54 −0
Original line number Diff line number Diff line
@@ -3082,6 +3082,56 @@ static void stmmac_check_ether_addr(struct stmmac_priv *priv)
	}
}

int stmmac_get_phy_intf_sel(phy_interface_t interface)
{
	int phy_intf_sel = -EINVAL;

	if (interface == PHY_INTERFACE_MODE_MII ||
	    interface == PHY_INTERFACE_MODE_GMII)
		phy_intf_sel = PHY_INTF_SEL_GMII_MII;
	else if (phy_interface_mode_is_rgmii(interface))
		phy_intf_sel = PHY_INTF_SEL_RGMII;
	else if (interface == PHY_INTERFACE_MODE_SGMII)
		phy_intf_sel = PHY_INTF_SEL_SGMII;
	else if (interface == PHY_INTERFACE_MODE_RMII)
		phy_intf_sel = PHY_INTF_SEL_RMII;
	else if (interface == PHY_INTERFACE_MODE_REVMII)
		phy_intf_sel = PHY_INTF_SEL_REVMII;

	return phy_intf_sel;
}
EXPORT_SYMBOL_GPL(stmmac_get_phy_intf_sel);

static int stmmac_prereset_configure(struct stmmac_priv *priv)
{
	struct plat_stmmacenet_data *plat_dat = priv->plat;
	phy_interface_t interface;
	int phy_intf_sel, ret;

	if (!plat_dat->set_phy_intf_sel)
		return 0;

	interface = plat_dat->phy_interface;
	phy_intf_sel = stmmac_get_phy_intf_sel(interface);
	if (phy_intf_sel < 0) {
		netdev_err(priv->dev,
			   "failed to get phy_intf_sel for %s: %pe\n",
			   phy_modes(interface), ERR_PTR(phy_intf_sel));
		return phy_intf_sel;
	}

	ret = plat_dat->set_phy_intf_sel(plat_dat->bsp_priv, phy_intf_sel);
	if (ret == -EINVAL)
		netdev_err(priv->dev, "platform does not support %s\n",
			   phy_modes(interface));
	else if (ret < 0)
		netdev_err(priv->dev,
			   "platform failed to set interface %s: %pe\n",
			   phy_modes(interface), ERR_PTR(ret));

	return ret;
}

/**
 * stmmac_init_dma_engine - DMA init.
 * @priv: driver private structure
@@ -3108,6 +3158,10 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
	if (priv->extend_desc && (priv->mode == STMMAC_RING_MODE))
		priv->plat->dma_cfg->atds = 1;

	ret = stmmac_prereset_configure(priv);
	if (ret)
		return ret;

	ret = stmmac_reset(priv, priv->ioaddr);
	if (ret) {
		netdev_err(priv->dev, "Failed to reset the dma\n");
Loading