netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 5/7] net: stmmac: dwmac-s32cc: add basic NXP S32G/S32R glue driver
@ 2024-08-18 21:50 Jan Petrous (OSS)
  2024-08-20 21:15 ` Jacob Keller
  0 siblings, 1 reply; 3+ messages in thread
From: Jan Petrous (OSS) @ 2024-08-18 21:50 UTC (permalink / raw)
  To: Jan Petrous (OSS), David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Jose Abreu, Maxime Coquelin, Vinod Koul,
	Andrew Lunn, Heiner Kallweit, Russell King, Richard Cochran,
	Giuseppe Cavallaro
  Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-stm32@st-md-mailman.stormreply.com,
	linux-arm-kernel@lists.infradead.org,
	linux-arm-msm@vger.kernel.org, dl-S32

NXP S32G2xx/S32G3xx and S32R45 are automotive grade SoCs
that integrate one or two Synopsys DWMAC 5.10/5.20 IPs.

The basic driver supports only RGMII interface.

Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
---
 drivers/net/ethernet/stmicro/stmmac/Kconfig   |  12 +
 drivers/net/ethernet/stmicro/stmmac/Makefile  |   1 +
 .../net/ethernet/stmicro/stmmac/dwmac-s32cc.c | 235 ++++++++++++++++++
 3 files changed, 248 insertions(+)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-s32cc.c

diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 05cc07b8f48c..b2ba72a0b8dc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -154,6 +154,18 @@ config DWMAC_RZN1
 	  the stmmac device driver. This support can make use of a custom MII
 	  converter PCS device.
 
+config DWMAC_S32CC
+	tristate "NXP S32G/S32R GMAC support"
+	default ARCH_S32
+	depends on OF && (ARCH_S32 || COMPILE_TEST)
+	help
+	  Support for ethernet controller on NXP S32CC SOCs.
+
+	  This selects NXP SoC glue layer support for the stmmac
+	  device driver. This driver is used for the S32CC series
+	  SOCs GMAC ethernet controller, ie. S32G2xx, S32G3xx and
+	  S32R45.
+
 config DWMAC_SOCFPGA
 	tristate "SOCFPGA dwmac support"
 	default ARCH_INTEL_SOCFPGA
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c2f0e91f6bf8..089ef3c1c45b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_DWMAC_MESON)	+= dwmac-meson.o dwmac-meson8b.o
 obj-$(CONFIG_DWMAC_QCOM_ETHQOS)	+= dwmac-qcom-ethqos.o
 obj-$(CONFIG_DWMAC_ROCKCHIP)	+= dwmac-rk.o
 obj-$(CONFIG_DWMAC_RZN1)	+= dwmac-rzn1.o
+obj-$(CONFIG_DWMAC_S32CC)	+= dwmac-s32cc.o
 obj-$(CONFIG_DWMAC_SOCFPGA)	+= dwmac-altr-socfpga.o
 obj-$(CONFIG_DWMAC_STARFIVE)	+= dwmac-starfive.o
 obj-$(CONFIG_DWMAC_STI)		+= dwmac-sti.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32cc.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32cc.c
new file mode 100644
index 000000000000..8daa01d01f29
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32cc.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NXP S32G/R GMAC glue layer
+ *
+ * Copyright 2019-2024 NXP
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/ethtool.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_mdio.h>
+#include <linux/of_address.h>
+#include <linux/phy.h>
+#include <linux/phylink.h>
+#include <linux/platform_device.h>
+#include <linux/stmmac.h>
+
+#include "stmmac_platform.h"
+
+#define GMAC_TX_RATE_125M	125000000	/* 125MHz */
+#define GMAC_TX_RATE_25M	25000000	/* 25MHz */
+#define GMAC_TX_RATE_2M5	2500000		/* 2.5MHz */
+
+/* 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
+
+struct s32cc_priv_data {
+	void __iomem *ioaddr;
+	void __iomem *ctrl_sts;
+	struct device *dev;
+	phy_interface_t intf_mode;
+	struct clk *tx_clk;
+	struct clk *rx_clk;
+	bool rx_clk_enabled;
+};
+
+static int s32cc_gmac_write_phy_intf_select(struct s32cc_priv_data *gmac)
+{
+	u32 intf_sel;
+
+	switch (gmac->intf_mode) {
+	case PHY_INTERFACE_MODE_SGMII:
+		intf_sel = PHY_INTF_SEL_SGMII;
+		break;
+	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_RGMII_ID:
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+		intf_sel = PHY_INTF_SEL_RGMII;
+		break;
+	case PHY_INTERFACE_MODE_RMII:
+		intf_sel = PHY_INTF_SEL_RMII;
+		break;
+	case PHY_INTERFACE_MODE_MII:
+		intf_sel = PHY_INTF_SEL_MII;
+		break;
+	default:
+		dev_err(gmac->dev, "Unsupported PHY interface: %s\n",
+			phy_modes(gmac->intf_mode));
+		return -EINVAL;
+	}
+
+	writel(intf_sel, gmac->ctrl_sts);
+
+	dev_dbg(gmac->dev, "PHY mode set to %s\n", phy_modes(gmac->intf_mode));
+
+	return 0;
+}
+
+static int s32cc_gmac_init(struct platform_device *pdev, void *priv)
+{
+	struct s32cc_priv_data *gmac = priv;
+	int ret;
+
+	ret = clk_set_rate(gmac->tx_clk, GMAC_TX_RATE_125M);
+	if (!ret)
+		ret = clk_prepare_enable(gmac->tx_clk);
+
+	if (ret) {
+		dev_err(&pdev->dev, "Can't set tx clock\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(gmac->rx_clk);
+	if (ret)
+		dev_dbg(&pdev->dev, "Can't set rx, clock source is disabled.\n");
+	else
+		gmac->rx_clk_enabled = true;
+
+	ret = s32cc_gmac_write_phy_intf_select(gmac);
+	if (ret) {
+		clk_disable_unprepare(gmac->tx_clk);
+		if (gmac->rx_clk_enabled) {
+			clk_disable_unprepare(gmac->rx_clk);
+			gmac->rx_clk_enabled = false;
+		}
+
+		dev_err(&pdev->dev, "Can't set PHY interface mode\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void s32cc_gmac_exit(struct platform_device *pdev, void *priv)
+{
+	struct s32cc_priv_data *gmac = priv;
+
+	clk_disable_unprepare(gmac->tx_clk);
+
+	if (gmac->rx_clk_enabled) {
+		clk_disable_unprepare(gmac->rx_clk);
+		gmac->rx_clk_enabled = false;
+	}
+}
+
+static void s32cc_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode)
+{
+	struct s32cc_priv_data *gmac = priv;
+	long tx_clk_rate;
+	int ret;
+
+	if (!gmac->rx_clk_enabled) {
+		ret = clk_prepare_enable(gmac->rx_clk);
+		if (ret) {
+			dev_err(gmac->dev, "Can't set rx clock\n");
+			return;
+		}
+		dev_dbg(gmac->dev, "rx clock enabled\n");
+		gmac->rx_clk_enabled = true;
+	}
+
+	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 s32cc_dwmac_probe(struct platform_device *pdev)
+{
+	struct plat_stmmacenet_data *plat;
+	struct device *dev = &pdev->dev;
+	struct s32cc_priv_data *gmac;
+	struct stmmac_resources res;
+	int ret;
+
+	gmac = devm_kzalloc(&pdev->dev, sizeof(*gmac), GFP_KERNEL);
+	if (!gmac)
+		return -ENOMEM;
+
+	gmac->dev = &pdev->dev;
+
+	ret = stmmac_get_platform_resources(pdev, &res);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to get platform resources\n");
+
+	plat = devm_stmmac_probe_config_dt(pdev, res.mac);
+	if (IS_ERR(plat))
+		return dev_err_probe(dev, PTR_ERR(plat),
+				     "dt configuration failed\n");
+
+	/* PHY interface mode control reg */
+	gmac->ctrl_sts = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
+	if (IS_ERR(gmac->ctrl_sts))
+		return dev_err_probe(dev, PTR_ERR(gmac->ctrl_sts),
+				     "S32CC config region is missing\n");
+
+	/* tx clock */
+	gmac->tx_clk = devm_clk_get(&pdev->dev, "tx");
+	if (IS_ERR(gmac->tx_clk))
+		return dev_err_probe(dev, PTR_ERR(gmac->tx_clk),
+				     "tx clock not found\n");
+
+	/* rx clock */
+	gmac->rx_clk = devm_clk_get(&pdev->dev, "rx");
+	if (IS_ERR(gmac->rx_clk))
+		return dev_err_probe(dev, PTR_ERR(gmac->rx_clk),
+				     "rx clock not found\n");
+
+	gmac->intf_mode = plat->phy_interface;
+	gmac->ioaddr = res.addr;
+
+	/* S32CC core feature set */
+	plat->has_gmac4 = true;
+	plat->pmt = 1;
+	plat->flags |= STMMAC_FLAG_SPH_DISABLE;
+	plat->rx_fifo_size = 20480;
+	plat->tx_fifo_size = 20480;
+
+	plat->init = s32cc_gmac_init;
+	plat->exit = s32cc_gmac_exit;
+	plat->fix_mac_speed = s32cc_fix_mac_speed;
+
+	plat->bsp_priv = gmac;
+
+	return stmmac_pltfr_probe(pdev, plat, &res);
+}
+
+static const struct of_device_id s32cc_dwmac_match[] = {
+	{ .compatible = "nxp,s32g2-dwmac" },
+	{ .compatible = "nxp,s32g3-dwmac" },
+	{ .compatible = "nxp,s32r45-dwmac" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, s32cc_dwmac_match);
+
+static struct platform_driver s32cc_dwmac_driver = {
+	.probe		= s32cc_dwmac_probe,
+	.remove_new	= stmmac_pltfr_remove,
+	.driver		= {
+			    .name		= "s32cc-dwmac",
+			    .pm		= &stmmac_pltfr_pm_ops,
+			    .of_match_table = s32cc_dwmac_match,
+	},
+};
+module_platform_driver(s32cc_dwmac_driver);
+
+MODULE_AUTHOR("Jan Petrous (OSS) <jan.petrous@oss.nxp.com>");
+MODULE_DESCRIPTION("NXP S32G/R common chassis GMAC driver");
+MODULE_LICENSE("GPL");
+
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2 5/7] net: stmmac: dwmac-s32cc: add basic NXP S32G/S32R glue driver
  2024-08-18 21:50 [PATCH v2 5/7] net: stmmac: dwmac-s32cc: add basic NXP S32G/S32R glue driver Jan Petrous (OSS)
@ 2024-08-20 21:15 ` Jacob Keller
  2024-10-06 19:46   ` Jan Petrous
  0 siblings, 1 reply; 3+ messages in thread
From: Jacob Keller @ 2024-08-20 21:15 UTC (permalink / raw)
  To: Jan Petrous (OSS), David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Jose Abreu, Maxime Coquelin, Vinod Koul,
	Andrew Lunn, Heiner Kallweit, Russell King, Richard Cochran,
	Giuseppe Cavallaro
  Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-stm32@st-md-mailman.stormreply.com,
	linux-arm-kernel@lists.infradead.org,
	linux-arm-msm@vger.kernel.org, dl-S32



On 8/18/2024 2:50 PM, Jan Petrous (OSS) wrote:
> NXP S32G2xx/S32G3xx and S32R45 are automotive grade SoCs
> that integrate one or two Synopsys DWMAC 5.10/5.20 IPs.
> 
> The basic driver supports only RGMII interface.
> 

You mention that it only supports RGMII.. so...

> +static int s32cc_gmac_write_phy_intf_select(struct s32cc_priv_data *gmac)
> +{
> +	u32 intf_sel;
> +
> +	switch (gmac->intf_mode) {
> +	case PHY_INTERFACE_MODE_SGMII:
> +		intf_sel = PHY_INTF_SEL_SGMII;
> +		break;
> +	case PHY_INTERFACE_MODE_RGMII:
> +	case PHY_INTERFACE_MODE_RGMII_ID:
> +	case PHY_INTERFACE_MODE_RGMII_TXID:
> +	case PHY_INTERFACE_MODE_RGMII_RXID:
> +		intf_sel = PHY_INTF_SEL_RGMII;
> +		break;
> +	case PHY_INTERFACE_MODE_RMII:
> +		intf_sel = PHY_INTF_SEL_RMII;
> +		break;
> +	case PHY_INTERFACE_MODE_MII:
> +		intf_sel = PHY_INTF_SEL_MII;
> +		break;
> +	default:
> +		dev_err(gmac->dev, "Unsupported PHY interface: %s\n",
> +			phy_modes(gmac->intf_mode));
> +		return -EINVAL;
> +	}
> +
> +	writel(intf_sel, gmac->ctrl_sts);
> +
> +	dev_dbg(gmac->dev, "PHY mode set to %s\n", phy_modes(gmac->intf_mode));
> +

Why does this code seem to support others?

Is that support just not yet fully baked?

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2 5/7] net: stmmac: dwmac-s32cc: add basic NXP S32G/S32R glue driver
  2024-08-20 21:15 ` Jacob Keller
@ 2024-10-06 19:46   ` Jan Petrous
  0 siblings, 0 replies; 3+ messages in thread
From: Jan Petrous @ 2024-10-06 19:46 UTC (permalink / raw)
  To: Jacob Keller
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Alexandre Torgue,
	Jose Abreu, Maxime Coquelin, Vinod Koul, Andrew Lunn,
	Heiner Kallweit, Russell King, Richard Cochran,
	Giuseppe Cavallaro, netdev@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-stm32@st-md-mailman.stormreply.com,
	linux-arm-kernel@lists.infradead.org,
	linux-arm-msm@vger.kernel.org, dl-S32

On Tue, Aug 20, 2024 at 02:15:46PM -0700, Jacob Keller wrote:
> 
> 
> On 8/18/2024 2:50 PM, Jan Petrous (OSS) wrote:
> > NXP S32G2xx/S32G3xx and S32R45 are automotive grade SoCs
> > that integrate one or two Synopsys DWMAC 5.10/5.20 IPs.
> > 
> > The basic driver supports only RGMII interface.
> > 
> 
> You mention that it only supports RGMII.. so...
> 
> > +static int s32cc_gmac_write_phy_intf_select(struct s32cc_priv_data *gmac)
> > +{
> > +	u32 intf_sel;
> > +
> > +	switch (gmac->intf_mode) {
> > +	case PHY_INTERFACE_MODE_SGMII:
> > +		intf_sel = PHY_INTF_SEL_SGMII;
> > +		break;
> > +	case PHY_INTERFACE_MODE_RGMII:
> > +	case PHY_INTERFACE_MODE_RGMII_ID:
> > +	case PHY_INTERFACE_MODE_RGMII_TXID:
> > +	case PHY_INTERFACE_MODE_RGMII_RXID:
> > +		intf_sel = PHY_INTF_SEL_RGMII;
> > +		break;
> > +	case PHY_INTERFACE_MODE_RMII:
> > +		intf_sel = PHY_INTF_SEL_RMII;
> > +		break;
> > +	case PHY_INTERFACE_MODE_MII:
> > +		intf_sel = PHY_INTF_SEL_MII;
> > +		break;
> > +	default:
> > +		dev_err(gmac->dev, "Unsupported PHY interface: %s\n",
> > +			phy_modes(gmac->intf_mode));
> > +		return -EINVAL;
> > +	}
> > +
> > +	writel(intf_sel, gmac->ctrl_sts);
> > +
> > +	dev_dbg(gmac->dev, "PHY mode set to %s\n", phy_modes(gmac->intf_mode));
> > +
> 
> Why does this code seem to support others?
> 
> Is that support just not yet fully baked?

Exactly. I have more functionality already implemented, but I started
from very basic driver to simplify review process.

I will remove all occurence of other interfaces but RGMII in v3.

BR.
/Jan

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2024-10-06 19:47 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-18 21:50 [PATCH v2 5/7] net: stmmac: dwmac-s32cc: add basic NXP S32G/S32R glue driver Jan Petrous (OSS)
2024-08-20 21:15 ` Jacob Keller
2024-10-06 19:46   ` Jan Petrous

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).