public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH net-next v4 0/3] Add DWMAC glue driver for Motorcomm YT6801
@ 2025-12-16 18:03 Yao Zi
  2025-12-16 18:03 ` [RFC PATCH net-next v4 1/3] net: phy: motorcomm: Support YT8531S PHY in YT6801 Ethernet controller Yao Zi
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Yao Zi @ 2025-12-16 18:03 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Frank, Heiner Kallweit, Russell King,
	Russell King (Oracle), Vladimir Oltean, Choong Yong Liang,
	Chen-Yu Tsai, Jisheng Zhang, Furong Xu
  Cc: linux-kernel, netdev, Mingcong Bai, Kexy Biscuit, Yao Zi

This series adds glue driver for Motorcomm YT6801 PCIe ethernet
controller, which is considered mostly compatible with DWMAC-4 IP by
inspecting the register layout[1]. It integrates a Motorcomm YT8531S PHY
(confirmed by reading PHY ID) and GMII is used to connect the PHY to
MAC[2].

The initialization logic of the MAC is mostly based on previous upstream
effort for the controller[3] and the Deepin-maintained downstream Linux
driver[4] licensed under GPL-2.0 according to its SPDX headers. However,
this series is a completely re-write of the previous patch series,
utilizing the existing DWMAC4 driver and introducing a glue driver only.

This series only aims to add basic networking functions for the
controller, features like WoL, RSS and LED control are omitted for now.
Testing is done on Loongson 3A5000 machine. Through a local GbE switch,
it reaches 872Mbps (TX)/942Mbps (RX) on average,

YT6801 TX

Connecting to host 172.16.70.12, port 5201
[  5] local 172.16.70.230 port 53658 connected to 172.16.70.12 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec   104 MBytes   869 Mbits/sec    0    533 KBytes
[  5]   1.00-2.00   sec   104 MBytes   875 Mbits/sec    0    533 KBytes
[  5]   2.00-3.00   sec   104 MBytes   874 Mbits/sec    0    533 KBytes
[  5]   3.00-4.00   sec   104 MBytes   870 Mbits/sec    0    533 KBytes
[  5]   4.00-5.00   sec   104 MBytes   874 Mbits/sec    0    533 KBytes
[  5]   5.00-6.00   sec   104 MBytes   874 Mbits/sec    0    533 KBytes
[  5]   6.00-7.00   sec   104 MBytes   870 Mbits/sec    0    533 KBytes
[  5]   7.00-8.00   sec   103 MBytes   866 Mbits/sec    0    533 KBytes
[  5]   8.00-9.00   sec   104 MBytes   872 Mbits/sec    0    533 KBytes
[  5]   9.00-10.00  sec   104 MBytes   871 Mbits/sec    0    533 KBytes

YT6801 RX

Connecting to host 172.16.70.230, port 5201
[  5] local 172.16.70.12 port 45596 connected to 172.16.70.230 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec   114 MBytes   955 Mbits/sec    0    427 KBytes
[  5]   1.00-2.00   sec   112 MBytes   942 Mbits/sec    0    427 KBytes
[  5]   2.00-3.00   sec   112 MBytes   937 Mbits/sec    0    427 KBytes
[  5]   3.00-4.00   sec   112 MBytes   940 Mbits/sec    0    427 KBytes
[  5]   4.00-5.00   sec   113 MBytes   945 Mbits/sec    0    427 KBytes
[  5]   5.00-6.00   sec   112 MBytes   940 Mbits/sec    0    427 KBytes
[  5]   6.00-7.00   sec   113 MBytes   947 Mbits/sec    0    427 KBytes
[  5]   7.00-8.00   sec   112 MBytes   935 Mbits/sec    0    427 KBytes
[  5]   8.00-9.00   sec   113 MBytes   945 Mbits/sec    0    427 KBytes
[  5]   9.00-10.00  sec   112 MBytes   938 Mbits/sec    0    427 KBytes

Thanks for your time and review.

[1]: https://lore.kernel.org/all/Z_T6vv013jraCzSD@shell.armlinux.org.uk/
[2]: https://lore.kernel.org/all/a48d76ac-db08-46d5-9528-f046a7b541dc@motor-comm.com/
[3]: https://lore.kernel.org/all/a48d76ac-db08-46d5-9528-f046a7b541dc@motor-comm.com/
[4]: https://github.com/deepin-community/kernel/tree/dc61248a0e21/drivers/net/ethernet/motorcomm/yt6801

Changed from v3
- Manually register a devres action to call pci_free_irq_vectors(),
  instead of relying on the obsolete behavior of
  pci_alloc_irq_vectors().
- Remove redundant call to pci_free_irq_vectors() in remove callback.
- Use my new mail address me@ziyao.cc for Sign-off-by and commit author.
- Link to v3: https://lore.kernel.org/netdev/20251124163211.54994-1-ziyao@disroot.org/

Changed from v2
- Rebase on top of next-20251124
- Switch to stmmac_plat_dat_alloc() then drop now redundant parameters
  from motorcomm_default_plat_data()
- Set STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP
- Add a comment indicating the possible source of CSR clock
- Link to v2: https://lore.kernel.org/netdev/20251111105252.53487-1-ziyao@disroot.org/

Changed from v1
- Drop (original) PATCH 1, add no vendor ID entry to linux/pci_ids.h
- Use PHY_INTERFACE_MODE_GMII instead of PHY_INTERFACE_MODE_INTERNAL
- Drop extra register read in motorcomm_efuse_read_byte()
- Rename EPHY_RESET to EPHY_MDIO_PHY_RESET, add a comment to reflect its
  function better
- Use the newly-introduced generic PCI suspend/resume routines
- Generate a random MAC address instead of failing to probe when no MAC
  address is programmed in eFuse (seen on some OEM EVBs).
- Collect Tested-by tags
- Link to v1: https://lore.kernel.org/netdev/20251014164746.50696-2-ziyao@disroot.org/

Yao Zi (3):
  net: phy: motorcomm: Support YT8531S PHY in YT6801 Ethernet controller
  net: stmmac: Add glue driver for Motorcomm YT6801 ethernet controller
  MAINTAINERS: Assign myself as maintainer of Motorcomm DWMAC glue
    driver

 MAINTAINERS                                   |   6 +
 drivers/net/ethernet/stmicro/stmmac/Kconfig   |   9 +
 drivers/net/ethernet/stmicro/stmmac/Makefile  |   1 +
 .../ethernet/stmicro/stmmac/dwmac-motorcomm.c | 383 ++++++++++++++++++
 drivers/net/phy/motorcomm.c                   |   4 +
 5 files changed, 403 insertions(+)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c

-- 
2.51.2


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

* [RFC PATCH net-next v4 1/3] net: phy: motorcomm: Support YT8531S PHY in YT6801 Ethernet controller
  2025-12-16 18:03 [RFC PATCH net-next v4 0/3] Add DWMAC glue driver for Motorcomm YT6801 Yao Zi
@ 2025-12-16 18:03 ` Yao Zi
  2025-12-21 20:29   ` Andrew Lunn
  2025-12-16 18:03 ` [RFC PATCH net-next v4 2/3] net: stmmac: Add glue driver for Motorcomm YT6801 ethernet controller Yao Zi
  2025-12-16 18:03 ` [RFC PATCH net-next v4 3/3] MAINTAINERS: Assign myself as maintainer of Motorcomm DWMAC glue driver Yao Zi
  2 siblings, 1 reply; 8+ messages in thread
From: Yao Zi @ 2025-12-16 18:03 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Frank, Heiner Kallweit, Russell King,
	Russell King (Oracle), Vladimir Oltean, Choong Yong Liang,
	Chen-Yu Tsai, Jisheng Zhang, Furong Xu
  Cc: linux-kernel, netdev, Mingcong Bai, Kexy Biscuit, Yao Zi

YT6801's internal PHY is confirmed as a GMII-capable variant of YT8531S
by a previous series[1] and reading PHY ID. Add support for
PHY_INTERFACE_MODE_GMII for YT8531S to allow the Ethernet driver to
reuse the PHY code for its internal PHY.

Link: https://lore.kernel.org/all/a48d76ac-db08-46d5-9528-f046a7b541dc@motor-comm.com/ # [1]
Co-developed-by: Frank Sae <Frank.Sae@motor-comm.com>
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
Signed-off-by: Yao Zi <me@ziyao.cc>
---
 drivers/net/phy/motorcomm.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c
index 89b5b19a9bd2..b751fbc6711a 100644
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -910,6 +910,10 @@ static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev)
 		val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg) |
 		       FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg);
 		break;
+	case PHY_INTERFACE_MODE_GMII:
+		if (phydev->drv->phy_id != PHY_ID_YT8531S)
+			return -EOPNOTSUPP;
+		break;
 	default: /* do not support other modes */
 		return -EOPNOTSUPP;
 	}
-- 
2.51.2


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

* [RFC PATCH net-next v4 2/3] net: stmmac: Add glue driver for Motorcomm YT6801 ethernet controller
  2025-12-16 18:03 [RFC PATCH net-next v4 0/3] Add DWMAC glue driver for Motorcomm YT6801 Yao Zi
  2025-12-16 18:03 ` [RFC PATCH net-next v4 1/3] net: phy: motorcomm: Support YT8531S PHY in YT6801 Ethernet controller Yao Zi
@ 2025-12-16 18:03 ` Yao Zi
  2025-12-21 20:42   ` Andrew Lunn
  2025-12-16 18:03 ` [RFC PATCH net-next v4 3/3] MAINTAINERS: Assign myself as maintainer of Motorcomm DWMAC glue driver Yao Zi
  2 siblings, 1 reply; 8+ messages in thread
From: Yao Zi @ 2025-12-16 18:03 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Frank, Heiner Kallweit, Russell King,
	Russell King (Oracle), Vladimir Oltean, Choong Yong Liang,
	Chen-Yu Tsai, Jisheng Zhang, Furong Xu
  Cc: linux-kernel, netdev, Mingcong Bai, Kexy Biscuit, Yao Zi,
	Runhua He, Xi Ruoyao

Motorcomm YT6801 is a PCIe ethernet controller based on DWMAC4 IP. It
integrates an GbE phy, supporting WOL, VLAN tagging and various types
of offloading. It ships an on-chip eFuse for storing various vendor
configuration, including MAC address.

This patch adds basic glue code for the controller, allowing it to be
set up and transmit data at a reasonable speed. Features like WOL could
be implemented in the future.

Signed-off-by: Yao Zi <me@ziyao.cc>
Tested-by: Mingcong Bai <jeffbai@aosc.io>
Tested-by: Runhua He <hua@aosc.io>
Tested-by: Xi Ruoyao <xry111@xry111.site>
---
 drivers/net/ethernet/stmicro/stmmac/Kconfig   |   9 +
 drivers/net/ethernet/stmicro/stmmac/Makefile  |   1 +
 .../ethernet/stmicro/stmmac/dwmac-motorcomm.c | 383 ++++++++++++++++++
 3 files changed, 393 insertions(+)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c

diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 907fe2e927f0..07088d03dbab 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -374,6 +374,15 @@ config DWMAC_LOONGSON
 	  This selects the LOONGSON PCI bus support for the stmmac driver,
 	  Support for ethernet controller on Loongson-2K1000 SoC and LS7A1000 bridge.
 
+config DWMAC_MOTORCOMM
+	tristate "Motorcomm PCI DWMAC support"
+	depends on PCI
+	select MOTORCOMM_PHY
+	select STMMAC_LIBPCI
+	help
+	  This enables glue driver for Motorcomm DWMAC-based PCI Ethernet
+	  controllers. Currently only YT6801 is supported.
+
 config STMMAC_PCI
 	tristate "STMMAC PCI bus support"
 	depends on PCI
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 7bf528731034..c9263987ef8d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -48,4 +48,5 @@ obj-$(CONFIG_STMMAC_LIBPCI)	+= stmmac_libpci.o
 obj-$(CONFIG_STMMAC_PCI)	+= stmmac-pci.o
 obj-$(CONFIG_DWMAC_INTEL)	+= dwmac-intel.o
 obj-$(CONFIG_DWMAC_LOONGSON)	+= dwmac-loongson.o
+obj-$(CONFIG_DWMAC_MOTORCOMM)	+= dwmac-motorcomm.o
 stmmac-pci-objs:= stmmac_pci.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c
new file mode 100644
index 000000000000..11ee470ac8f7
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * DWMAC glue driver for Motorcomm PCI Ethernet controllers
+ *
+ * Copyright (c) 2025 Yao Zi <me@ziyao.cc>
+ */
+
+#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/stmmac.h>
+
+#include "dwmac4.h"
+#include "stmmac.h"
+#include "stmmac_libpci.h"
+
+#define DRIVER_NAME "dwmac-motorcomm"
+
+#define PCI_VENDOR_ID_MOTORCOMM			0x1f0a
+
+/* Register definition */
+#define EPHY_CTRL				0x1004
+/* Clearing this bit asserts resets for internal MDIO bus and PHY */
+#define  EPHY_MDIO_PHY_RESET			BIT(0)
+#define OOB_WOL_CTRL				0x1010
+#define  OOB_WOL_CTRL_DIS			BIT(0)
+#define MGMT_INT_CTRL0				0x1100
+#define MGMT_INT_CTRL0_MASK			GENMASK(31, 16)
+#define  MGMT_INT_CTRL0_MASK_RXCH		GENMASK(3, 0)
+#define  MGMT_INT_CTRL0_MASK_TXCH		BIT(4)
+#define  MGMT_INT_CTRL0_MASK_MISC		BIT(5)
+#define INT_MODERATION				0x1108
+#define INT_MODERATION_RX			GENMASK(11, 0)
+#define INT_MODERATION_TX			GENMASK(27, 16)
+#define EFUSE_OP_CTRL_0				0x1500
+#define  EFUSE_OP_MODE				GENMASK(1, 0)
+#define   EFUSE_OP_ROW_READ			0x1
+#define  EFUSE_OP_START				BIT(2)
+#define  EFUSE_OP_ADDR				GENMASK(15, 8)
+#define EFUSE_OP_CTRL_1				0x1504
+#define  EFUSE_OP_DONE				BIT(1)
+#define  EFUSE_OP_RD_DATA			GENMASK(31, 24)
+#define SYS_RESET				0x152c
+#define  SYS_RESET_RESET			BIT(31)
+#define GMAC_OFFSET				0x2000
+
+/* Constants */
+#define EFUSE_READ_TIMEOUT_US			20000
+#define EFUSE_PATCH_REGION_OFFSET		18
+#define EFUSE_PATCH_MAX_NUM			39
+#define EFUSE_ADDR_MACA0LR			0x1520
+#define EFUSE_ADDR_MACA0HR			0x1524
+
+struct motorcomm_efuse_patch {
+	__le16 addr;
+	__le32 data;
+} __packed;
+
+struct dwmac_motorcomm_priv {
+	void __iomem *base;
+	struct device *dev;
+};
+
+static int motorcomm_efuse_read_byte(struct dwmac_motorcomm_priv *priv,
+				     u8 offset, u8 *byte)
+{
+	u32 reg;
+	int ret;
+
+	writel(FIELD_PREP(EFUSE_OP_MODE, EFUSE_OP_ROW_READ)	|
+	       FIELD_PREP(EFUSE_OP_ADDR, offset)		|
+	       EFUSE_OP_START, priv->base + EFUSE_OP_CTRL_0);
+
+	ret = readl_poll_timeout(priv->base + EFUSE_OP_CTRL_1,
+				 reg, reg & EFUSE_OP_DONE, 2000,
+				 EFUSE_READ_TIMEOUT_US);
+
+	*byte = FIELD_GET(EFUSE_OP_RD_DATA, reg);
+
+	return ret;
+}
+
+static int motorcomm_efuse_read_patch(struct dwmac_motorcomm_priv *priv,
+				      u8 index,
+				      struct motorcomm_efuse_patch *patch)
+{
+	u8 buf[sizeof(*patch)], offset;
+	int i, ret;
+
+	for (i = 0; i < sizeof(*patch); i++) {
+		offset = EFUSE_PATCH_REGION_OFFSET + sizeof(*patch) * index + i;
+
+		ret = motorcomm_efuse_read_byte(priv, offset, &buf[i]);
+		if (ret)
+			return ret;
+	}
+
+	memcpy(patch, buf, sizeof(*patch));
+
+	return 0;
+}
+
+static int motorcomm_efuse_get_patch_value(struct dwmac_motorcomm_priv *priv,
+					   u16 addr, u32 *value)
+{
+	struct motorcomm_efuse_patch patch;
+	int i, ret;
+
+	for (i = 0; i < EFUSE_PATCH_MAX_NUM; i++) {
+		ret = motorcomm_efuse_read_patch(priv, i, &patch);
+		if (ret)
+			return ret;
+
+		if (patch.addr == 0) {
+			return -ENOENT;
+		} else if (le16_to_cpu(patch.addr) == addr) {
+			*value = le32_to_cpu(patch.data);
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
+static int motorcomm_efuse_read_mac(struct dwmac_motorcomm_priv *priv, u8 *mac)
+{
+	u32 maca0lr, maca0hr;
+	int ret;
+
+	ret = motorcomm_efuse_get_patch_value(priv, EFUSE_ADDR_MACA0LR,
+					      &maca0lr);
+	if (ret)
+		return dev_err_probe(priv->dev, ret,
+				     "failed to read maca0lr from eFuse\n");
+
+	ret = motorcomm_efuse_get_patch_value(priv, EFUSE_ADDR_MACA0HR,
+					      &maca0hr);
+	if (ret)
+		return dev_err_probe(priv->dev, ret,
+				     "failed to read maca0hr from eFuse\n");
+
+	mac[0] = FIELD_GET(GENMASK(15, 8), maca0hr);
+	mac[1] = FIELD_GET(GENMASK(7, 0), maca0hr);
+	mac[2] = FIELD_GET(GENMASK(31, 24), maca0lr);
+	mac[3] = FIELD_GET(GENMASK(23, 16), maca0lr);
+	mac[4] = FIELD_GET(GENMASK(15, 8), maca0lr);
+	mac[5] = FIELD_GET(GENMASK(7, 0), maca0lr);
+
+	return 0;
+}
+
+static void motorcomm_deassert_mdio_phy_reset(struct dwmac_motorcomm_priv *priv)
+{
+	u32 reg = readl(priv->base + EPHY_CTRL);
+
+	reg |= EPHY_MDIO_PHY_RESET;
+
+	writel(reg, priv->base + EPHY_CTRL);
+}
+
+static void motorcomm_reset(struct dwmac_motorcomm_priv *priv)
+{
+	u32 reg = readl(priv->base + SYS_RESET);
+
+	reg &= ~SYS_RESET_RESET;
+	writel(reg, priv->base + SYS_RESET);
+
+	reg |= SYS_RESET_RESET;
+	writel(reg, priv->base + SYS_RESET);
+
+	motorcomm_deassert_mdio_phy_reset(priv);
+}
+
+static void motorcomm_init(struct dwmac_motorcomm_priv *priv)
+{
+	writel(0x0, priv->base + MGMT_INT_CTRL0);
+
+	writel(FIELD_PREP(INT_MODERATION_RX, 200) |
+	       FIELD_PREP(INT_MODERATION_TX, 200),
+	       priv->base + INT_MODERATION);
+
+	/*
+	 * OOB WOL must be disabled during normal operation, or DMA interrupts
+	 * cannot be delivered to the host.
+	 */
+	writel(OOB_WOL_CTRL_DIS, priv->base + OOB_WOL_CTRL);
+}
+
+static int motorcomm_resume(struct device *dev, void *bsp_priv)
+{
+	struct dwmac_motorcomm_priv *priv = bsp_priv;
+	int ret;
+
+	ret = stmmac_pci_plat_resume(dev, bsp_priv);
+	if (ret)
+		return ret;
+
+	/*
+	 * When recovering from D3hot, EPHY_MDIO_PHY_RESET is automatically
+	 * asserted, and must be deasserted for normal operation.
+	 */
+	motorcomm_deassert_mdio_phy_reset(priv);
+	motorcomm_init(priv);
+
+	return 0;
+}
+
+static struct plat_stmmacenet_data *
+motorcomm_default_plat_data(struct pci_dev *pdev)
+{
+	struct plat_stmmacenet_data *plat;
+	struct device *dev = &pdev->dev;
+
+	plat = stmmac_plat_dat_alloc(dev);
+	if (!plat)
+		return NULL;
+
+	plat->mdio_bus_data = devm_kzalloc(dev, sizeof(*plat->mdio_bus_data),
+					   GFP_KERNEL);
+	if (!plat->mdio_bus_data)
+		return NULL;
+
+	plat->dma_cfg = devm_kzalloc(dev, sizeof(*plat->dma_cfg), GFP_KERNEL);
+	if (!plat->dma_cfg)
+		return NULL;
+
+	plat->axi = devm_kzalloc(dev, sizeof(*plat->axi), GFP_KERNEL);
+	if (!plat->axi)
+		return NULL;
+
+	plat->dma_cfg->pbl		= DEFAULT_DMA_PBL;
+	plat->dma_cfg->pblx8		= true;
+	plat->dma_cfg->txpbl		= 32;
+	plat->dma_cfg->rxpbl		= 32;
+	plat->dma_cfg->eame		= true;
+	plat->dma_cfg->mixed_burst	= true;
+
+	plat->axi->axi_wr_osr_lmt	= 1;
+	plat->axi->axi_rd_osr_lmt	= 1;
+	plat->axi->axi_mb		= true;
+	plat->axi->axi_blen_regval	= DMA_AXI_BLEN4 | DMA_AXI_BLEN8 |
+					  DMA_AXI_BLEN16 | DMA_AXI_BLEN32;
+
+	plat->bus_id		= pci_dev_id(pdev);
+	plat->phy_interface	= PHY_INTERFACE_MODE_GMII;
+	/*
+	 * YT6801 requires an 25MHz clock input/oscillator to function, which
+	 * is likely the source of CSR clock.
+	 */
+	plat->clk_csr		= STMMAC_CSR_20_35M;
+	plat->tx_coe		= 1;
+	plat->rx_coe		= 1;
+	plat->clk_ref_rate	= 125000000;
+	plat->core_type		= DWMAC_CORE_GMAC4;
+	plat->suspend		= stmmac_pci_plat_suspend;
+	plat->resume		= motorcomm_resume;
+	plat->flags		= STMMAC_FLAG_TSO_EN |
+				  STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP;
+
+	return plat;
+}
+
+static void motorcomm_free_irq(void *data)
+{
+	struct pci_dev *pdev = data;
+
+	pci_free_irq_vectors(pdev);
+}
+
+static int motorcomm_setup_irq(struct pci_dev *pdev,
+			       struct stmmac_resources *res,
+			       struct plat_stmmacenet_data *plat)
+{
+	int ret;
+
+	ret = pci_alloc_irq_vectors(pdev, 6, 6, PCI_IRQ_MSIX);
+	if (ret > 0) {
+		res->rx_irq[0]	= pci_irq_vector(pdev, 0);
+		res->tx_irq[0]	= pci_irq_vector(pdev, 4);
+		res->irq	= pci_irq_vector(pdev, 5);
+
+		plat->flags |= STMMAC_FLAG_MULTI_MSI_EN;
+	} else {
+		dev_info(&pdev->dev, "failed to allocate MSI-X vector: %d\n",
+			 ret);
+		dev_info(&pdev->dev, "try MSI instead\n");
+
+		ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
+		if (ret < 0)
+			return dev_err_probe(&pdev->dev, ret,
+					     "failed to allocate MSI\n");
+
+		res->irq = pci_irq_vector(pdev, 0);
+	}
+
+	return devm_add_action_or_reset(&pdev->dev, motorcomm_free_irq, pdev);
+}
+
+static int motorcomm_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct plat_stmmacenet_data *plat;
+	struct dwmac_motorcomm_priv *priv;
+	struct stmmac_resources res = {};
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = &pdev->dev;
+
+	plat = motorcomm_default_plat_data(pdev);
+	if (!plat)
+		return -ENOMEM;
+
+	plat->bsp_priv = priv;
+
+	ret = pcim_enable_device(pdev);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "failed to enable device\n");
+
+	priv->base = pcim_iomap_region(pdev, 0, DRIVER_NAME);
+	if (IS_ERR(priv->base))
+		return dev_err_probe(&pdev->dev, PTR_ERR(priv->base),
+				     "failed to map IO region\n");
+
+	pci_set_master(pdev);
+
+	motorcomm_reset(priv);
+
+	ret = motorcomm_efuse_read_mac(priv, res.mac);
+	if (ret == -ENOENT) {
+		dev_warn(&pdev->dev, "eFuse contains no valid MAC address\n");
+		dev_warn(&pdev->dev, "fallback to random MAC address\n");
+
+		memset(res.mac, 0, sizeof(res.mac));
+	} else if (ret) {
+		return dev_err_probe(&pdev->dev, ret,
+				     "failed to read MAC address from eFuse\n");
+	}
+
+	ret = motorcomm_setup_irq(pdev, &res, plat);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret, "failed to setup IRQ\n");
+
+	motorcomm_init(priv);
+
+	res.addr = priv->base + GMAC_OFFSET;
+
+	return stmmac_dvr_probe(&pdev->dev, plat, &res);
+}
+
+static void motorcomm_remove(struct pci_dev *pdev)
+{
+	stmmac_dvr_remove(&pdev->dev);
+}
+
+static const struct pci_device_id dwmac_motorcomm_pci_id_table[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_MOTORCOMM, 0x6801) },
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, dwmac_motorcomm_pci_id_table);
+
+static struct pci_driver dwmac_motorcomm_pci_driver = {
+	.name = DRIVER_NAME,
+	.id_table = dwmac_motorcomm_pci_id_table,
+	.probe = motorcomm_probe,
+	.remove = motorcomm_remove,
+	.driver = {
+		.pm = &stmmac_simple_pm_ops,
+	},
+};
+
+module_pci_driver(dwmac_motorcomm_pci_driver);
+
+MODULE_DESCRIPTION("DWMAC glue driver for Motorcomm PCI Ethernet controllers");
+MODULE_AUTHOR("Yao Zi <me@ziyao.cc>");
+MODULE_LICENSE("GPL");
-- 
2.51.2


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

* [RFC PATCH net-next v4 3/3] MAINTAINERS: Assign myself as maintainer of Motorcomm DWMAC glue driver
  2025-12-16 18:03 [RFC PATCH net-next v4 0/3] Add DWMAC glue driver for Motorcomm YT6801 Yao Zi
  2025-12-16 18:03 ` [RFC PATCH net-next v4 1/3] net: phy: motorcomm: Support YT8531S PHY in YT6801 Ethernet controller Yao Zi
  2025-12-16 18:03 ` [RFC PATCH net-next v4 2/3] net: stmmac: Add glue driver for Motorcomm YT6801 ethernet controller Yao Zi
@ 2025-12-16 18:03 ` Yao Zi
  2 siblings, 0 replies; 8+ messages in thread
From: Yao Zi @ 2025-12-16 18:03 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Frank, Heiner Kallweit, Russell King,
	Russell King (Oracle), Vladimir Oltean, Choong Yong Liang,
	Chen-Yu Tsai, Jisheng Zhang, Furong Xu
  Cc: linux-kernel, netdev, Mingcong Bai, Kexy Biscuit, Yao Zi

I volunteer to maintain the DWMAC glue driver for Motorcomm ethernet
controllers.

Signed-off-by: Yao Zi <me@ziyao.cc>
---
 MAINTAINERS | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index e5b1342ee2a6..1483c1071d16 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17666,6 +17666,12 @@ F:	drivers/most/
 F:	drivers/staging/most/
 F:	include/linux/most.h
 
+MOTORCOMM DWMAC GLUE DRIVER
+M:	Yao Zi <me@ziyao.cc>
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	drivers/net/ethernet/stmicro/stmmac/dwmac-motorcomm.c
+
 MOTORCOMM PHY DRIVER
 M:	Frank <Frank.Sae@motor-comm.com>
 L:	netdev@vger.kernel.org
-- 
2.51.2


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

* Re: [RFC PATCH net-next v4 1/3] net: phy: motorcomm: Support YT8531S PHY in YT6801 Ethernet controller
  2025-12-16 18:03 ` [RFC PATCH net-next v4 1/3] net: phy: motorcomm: Support YT8531S PHY in YT6801 Ethernet controller Yao Zi
@ 2025-12-21 20:29   ` Andrew Lunn
  2025-12-23 17:40     ` Yao Zi
  0 siblings, 1 reply; 8+ messages in thread
From: Andrew Lunn @ 2025-12-21 20:29 UTC (permalink / raw)
  To: Yao Zi
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Frank, Heiner Kallweit, Russell King,
	Russell King (Oracle), Vladimir Oltean, Choong Yong Liang,
	Chen-Yu Tsai, Jisheng Zhang, Furong Xu, linux-kernel, netdev,
	Mingcong Bai, Kexy Biscuit

On Tue, Dec 16, 2025 at 06:03:29PM +0000, Yao Zi wrote:
> YT6801's internal PHY is confirmed as a GMII-capable variant of YT8531S
> by a previous series[1] and reading PHY ID. Add support for
> PHY_INTERFACE_MODE_GMII for YT8531S to allow the Ethernet driver to
> reuse the PHY code for its internal PHY.
> 
> Link: https://lore.kernel.org/all/a48d76ac-db08-46d5-9528-f046a7b541dc@motor-comm.com/ # [1]
> Co-developed-by: Frank Sae <Frank.Sae@motor-comm.com>
> Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
> Signed-off-by: Yao Zi <me@ziyao.cc>
> ---
>  drivers/net/phy/motorcomm.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c
> index 89b5b19a9bd2..b751fbc6711a 100644
> --- a/drivers/net/phy/motorcomm.c
> +++ b/drivers/net/phy/motorcomm.c
> @@ -910,6 +910,10 @@ static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev)
>  		val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg) |
>  		       FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg);
>  		break;
> +	case PHY_INTERFACE_MODE_GMII:
> +		if (phydev->drv->phy_id != PHY_ID_YT8531S)
> +			return -EOPNOTSUPP;
> +		break;

You have a break here. So the write to RGMII delay register will be
performed, even thought this is an GMII PHY. Does the register exists?
Would it be better to just return 0;

      Andrew

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

* Re: [RFC PATCH net-next v4 2/3] net: stmmac: Add glue driver for Motorcomm YT6801 ethernet controller
  2025-12-16 18:03 ` [RFC PATCH net-next v4 2/3] net: stmmac: Add glue driver for Motorcomm YT6801 ethernet controller Yao Zi
@ 2025-12-21 20:42   ` Andrew Lunn
  2025-12-23 17:34     ` Yao Zi
  0 siblings, 1 reply; 8+ messages in thread
From: Andrew Lunn @ 2025-12-21 20:42 UTC (permalink / raw)
  To: Yao Zi
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Frank, Heiner Kallweit, Russell King,
	Russell King (Oracle), Vladimir Oltean, Choong Yong Liang,
	Chen-Yu Tsai, Jisheng Zhang, Furong Xu, linux-kernel, netdev,
	Mingcong Bai, Kexy Biscuit, Runhua He, Xi Ruoyao

> +static int motorcomm_efuse_read_patch(struct dwmac_motorcomm_priv *priv,
> +				      u8 index,
> +				      struct motorcomm_efuse_patch *patch)
> +{
> +	u8 buf[sizeof(*patch)], offset;
> +	int i, ret;
> +
> +	for (i = 0; i < sizeof(*patch); i++) {
> +		offset = EFUSE_PATCH_REGION_OFFSET + sizeof(*patch) * index + i;
> +
> +		ret = motorcomm_efuse_read_byte(priv, offset, &buf[i]);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	memcpy(patch, buf, sizeof(*patch));

Why do you write it into a temporary buffer and then copy it to patch?
Why not put it straight into patch?

> +	ret = motorcomm_efuse_read_mac(priv, res.mac);
> +	if (ret == -ENOENT) {
> +		dev_warn(&pdev->dev, "eFuse contains no valid MAC address\n");
> +		dev_warn(&pdev->dev, "fallback to random MAC address\n");
> +
> +		memset(res.mac, 0, sizeof(res.mac));

It is not clear how setting this to zero results in a random MAC
address. Maybe actually call eth_random_addr()?

	 Andrew 

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

* Re: [RFC PATCH net-next v4 2/3] net: stmmac: Add glue driver for Motorcomm YT6801 ethernet controller
  2025-12-21 20:42   ` Andrew Lunn
@ 2025-12-23 17:34     ` Yao Zi
  0 siblings, 0 replies; 8+ messages in thread
From: Yao Zi @ 2025-12-23 17:34 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Frank, Heiner Kallweit, Russell King,
	Russell King (Oracle), Vladimir Oltean, Choong Yong Liang,
	Chen-Yu Tsai, Jisheng Zhang, Furong Xu, linux-kernel, netdev,
	Mingcong Bai, Kexy Biscuit, Runhua He, Xi Ruoyao

On Sun, Dec 21, 2025 at 09:42:20PM +0100, Andrew Lunn wrote:
> > +static int motorcomm_efuse_read_patch(struct dwmac_motorcomm_priv *priv,
> > +				      u8 index,
> > +				      struct motorcomm_efuse_patch *patch)
> > +{
> > +	u8 buf[sizeof(*patch)], offset;
> > +	int i, ret;
> > +
> > +	for (i = 0; i < sizeof(*patch); i++) {
> > +		offset = EFUSE_PATCH_REGION_OFFSET + sizeof(*patch) * index + i;
> > +
> > +		ret = motorcomm_efuse_read_byte(priv, offset, &buf[i]);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	memcpy(patch, buf, sizeof(*patch));
> 
> Why do you write it into a temporary buffer and then copy it to patch?
> Why not put it straight into patch?

Originally I wanted to avoid possible violation of pointer aliasing
rules, so write the RAW data to an extra buffer and do a memcpy() later.

But we have -fno-strict-aliasing in kernel, even without it accessing
any objects with character type should be okay. I'll remove buf and
write to patch directly in v5.

> > +	ret = motorcomm_efuse_read_mac(priv, res.mac);
> > +	if (ret == -ENOENT) {
> > +		dev_warn(&pdev->dev, "eFuse contains no valid MAC address\n");
> > +		dev_warn(&pdev->dev, "fallback to random MAC address\n");
> > +
> > +		memset(res.mac, 0, sizeof(res.mac));
> 
> It is not clear how setting this to zero results in a random MAC
> address. Maybe actually call eth_random_addr()?

stmmac_check_ether_addr() would generate a random MAC address through
eth_random_addr() if res.mac is all zeroes. But I agree calling
eth_random_addr() directly here would be clearer, will do it in v5.

> 	 Andrew 

Thanks for your review, happy holiday!

Regards,
Yao Zi

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

* Re: [RFC PATCH net-next v4 1/3] net: phy: motorcomm: Support YT8531S PHY in YT6801 Ethernet controller
  2025-12-21 20:29   ` Andrew Lunn
@ 2025-12-23 17:40     ` Yao Zi
  0 siblings, 0 replies; 8+ messages in thread
From: Yao Zi @ 2025-12-23 17:40 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Frank, Heiner Kallweit, Russell King,
	Russell King (Oracle), Vladimir Oltean, Choong Yong Liang,
	Chen-Yu Tsai, Jisheng Zhang, Furong Xu, linux-kernel, netdev,
	Mingcong Bai, Kexy Biscuit

On Sun, Dec 21, 2025 at 09:29:01PM +0100, Andrew Lunn wrote:
> On Tue, Dec 16, 2025 at 06:03:29PM +0000, Yao Zi wrote:
> > YT6801's internal PHY is confirmed as a GMII-capable variant of YT8531S
> > by a previous series[1] and reading PHY ID. Add support for
> > PHY_INTERFACE_MODE_GMII for YT8531S to allow the Ethernet driver to
> > reuse the PHY code for its internal PHY.
> > 
> > Link: https://lore.kernel.org/all/a48d76ac-db08-46d5-9528-f046a7b541dc@motor-comm.com/ # [1]
> > Co-developed-by: Frank Sae <Frank.Sae@motor-comm.com>
> > Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
> > Signed-off-by: Yao Zi <me@ziyao.cc>
> > ---
> >  drivers/net/phy/motorcomm.c | 4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c
> > index 89b5b19a9bd2..b751fbc6711a 100644
> > --- a/drivers/net/phy/motorcomm.c
> > +++ b/drivers/net/phy/motorcomm.c
> > @@ -910,6 +910,10 @@ static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev)
> >  		val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg) |
> >  		       FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg);
> >  		break;
> > +	case PHY_INTERFACE_MODE_GMII:
> > +		if (phydev->drv->phy_id != PHY_ID_YT8531S)
> > +			return -EOPNOTSUPP;
> > +		break;
> 
> You have a break here. So the write to RGMII delay register will be
> performed, even thought this is an GMII PHY. Does the register exists?

With testing it seems the register simply makes no effect on the YT8531S
PHY integrated in YT6801.

> Would it be better to just return 0;

However, returning early here could avoid possible confusion. Will
change it in v5.

>       Andrew

Regards,
Yao Zi

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

end of thread, other threads:[~2025-12-23 17:46 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-16 18:03 [RFC PATCH net-next v4 0/3] Add DWMAC glue driver for Motorcomm YT6801 Yao Zi
2025-12-16 18:03 ` [RFC PATCH net-next v4 1/3] net: phy: motorcomm: Support YT8531S PHY in YT6801 Ethernet controller Yao Zi
2025-12-21 20:29   ` Andrew Lunn
2025-12-23 17:40     ` Yao Zi
2025-12-16 18:03 ` [RFC PATCH net-next v4 2/3] net: stmmac: Add glue driver for Motorcomm YT6801 ethernet controller Yao Zi
2025-12-21 20:42   ` Andrew Lunn
2025-12-23 17:34     ` Yao Zi
2025-12-16 18:03 ` [RFC PATCH net-next v4 3/3] MAINTAINERS: Assign myself as maintainer of Motorcomm DWMAC glue driver Yao Zi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox