public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC v2 0/3] net: dsa: MT7628 embedded switch initial support
@ 2026-03-14 15:08 Joris Vaisvila
  2026-03-14 15:08 ` [RFC v2 1/3] net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet PHYs Joris Vaisvila
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Joris Vaisvila @ 2026-03-14 15:08 UTC (permalink / raw)
  To: netdev
  Cc: horms, pabeni, kuba, edumazet, davem, olteanv, Andrew Lunn,
	Joris Vaisvila

Hello,

This RFC series adds initial support for the MT7628 Embedded Switch.

The implementation provides basic functionality required to operate the
switch using DSA. The hardware exposes 5 internal Fast Ethernet ports
and two gigabit ports, one of which is internally connected to the CPU
MAC.

Tested on MT7628NN (mistyped as mt7628AN in v1) with 5x Fast Ethernet
ports in a software bridge. All ports were verified for correct
communication while using VLAN-tagged and untagged traffic between two
hosts.

---

v2:
	- Update commit messages with more relevant information
	- Change all references of "special" tag to "MT7628" tag
	- Fix coding style errors
	- Use dsa_xmit_port_mask instead of BIT(dp->index)
	- Replace phy_read/phy_write with an MDIO bus definition
	- Remove PHY init from switch driver
	- Fix undocumented writes to SGC2 and FCT0
	- Fix missing double-tag enable required for VLAN unaware
	  functionality
	- Fix VLAN remove logic
	- Update VLAN add logic to use the first unused slot
	- Add a dedicated phy driver for MT7628 FE PHYs

v1: https://lore.kernel.org/netdev/20260228185242.800836-1-joey@tinyisr.com


Joris Vaisvila (3):
  net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet
    PHYs
  net: dsa: initial MT7628 tagging driver
  net: dsa: initial support for MT7628 embedded switch

 drivers/net/dsa/Kconfig               |   7 +
 drivers/net/dsa/Makefile              |   1 +
 drivers/net/dsa/mt7628.c              | 596 ++++++++++++++++++++++++++
 drivers/net/phy/mediatek/Kconfig      |   6 +
 drivers/net/phy/mediatek/Makefile     |   1 +
 drivers/net/phy/mediatek/mtk-fe-soc.c |  55 +++
 include/net/dsa.h                     |   2 +
 net/dsa/Kconfig                       |   6 +
 net/dsa/Makefile                      |   1 +
 net/dsa/tag_mt7628.c                  |  93 ++++
 10 files changed, 768 insertions(+)
 create mode 100644 drivers/net/dsa/mt7628.c
 create mode 100644 drivers/net/phy/mediatek/mtk-fe-soc.c
 create mode 100644 net/dsa/tag_mt7628.c

-- 
2.53.0


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

* [RFC v2 1/3] net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet PHYs
  2026-03-14 15:08 [RFC v2 0/3] net: dsa: MT7628 embedded switch initial support Joris Vaisvila
@ 2026-03-14 15:08 ` Joris Vaisvila
  2026-03-17 18:03   ` Andrew Lunn
  2026-03-14 15:08 ` [RFC v2 2/3] net: dsa: initial MT7628 tagging driver Joris Vaisvila
  2026-03-14 15:08 ` [RFC v2 3/3] net: dsa: initial support for MT7628 embedded switch Joris Vaisvila
  2 siblings, 1 reply; 10+ messages in thread
From: Joris Vaisvila @ 2026-03-14 15:08 UTC (permalink / raw)
  To: netdev
  Cc: horms, pabeni, kuba, edumazet, davem, olteanv, Andrew Lunn,
	Joris Vaisvila

The Fast Ethernet PHYs present in the MT7628 SoCs require an
undocumented bit to be set before they can establish 100mbps links.

This commit adds the Kconfig option MEDIATEK_FE_SOC_PHY and the
corresponding driver mtk-fe-soc.c.

Signed-off-by: Joris Vaisvila <joey@tinyisr.com>
---
 drivers/net/phy/mediatek/Kconfig      |  6 +++
 drivers/net/phy/mediatek/Makefile     |  1 +
 drivers/net/phy/mediatek/mtk-fe-soc.c | 54 +++++++++++++++++++++++++++
 3 files changed, 61 insertions(+)
 create mode 100644 drivers/net/phy/mediatek/mtk-fe-soc.c

diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig
index bb7dc876271e..62355d46cb1e 100644
--- a/drivers/net/phy/mediatek/Kconfig
+++ b/drivers/net/phy/mediatek/Kconfig
@@ -36,5 +36,11 @@ config MEDIATEK_GE_SOC_PHY
 	  present in the SoCs efuse and will dynamically calibrate VCM
 	  (common-mode voltage) during startup.
 
+config MEDIATEK_FE_SOC_PHY
+	tristate "MediaTek MT7628 SoC Ethernet PHYs"
+	select PHY_PACKAGE
+	help
+	  Support for MediaTek MT7628 built-in Fast Ethernet PHYs.
+
 config MTK_NET_PHYLIB
 	tristate
diff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile
index ac57ecc799fc..54cea813c7ad 100644
--- a/drivers/net/phy/mediatek/Makefile
+++ b/drivers/net/phy/mediatek/Makefile
@@ -2,4 +2,5 @@
 obj-$(CONFIG_MEDIATEK_2P5GE_PHY)	+= mtk-2p5ge.o
 obj-$(CONFIG_MEDIATEK_GE_PHY)		+= mtk-ge.o
 obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)	+= mtk-ge-soc.o
+obj-$(CONFIG_MEDIATEK_FE_SOC_PHY)	+= mtk-fe-soc.o
 obj-$(CONFIG_MTK_NET_PHYLIB)		+= mtk-phy-lib.o
diff --git a/drivers/net/phy/mediatek/mtk-fe-soc.c b/drivers/net/phy/mediatek/mtk-fe-soc.c
new file mode 100644
index 000000000000..4e6ec402296d
--- /dev/null
+++ b/drivers/net/phy/mediatek/mtk-fe-soc.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for MT7628 Embedded Switch internal Fast Ethernet PHYs
+ */
+#include <linux/module.h>
+#include <linux/phy.h>
+
+#define MTK_FPHY_ID_MT7628	0x03a29410
+#define MTK_EXT_PAGE_ACCESS	0x1f
+
+static int mt7628_phy_read_page(struct phy_device *phydev)
+{
+	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+}
+
+static int mt7628_phy_write_page(struct phy_device *phydev, int page)
+{
+	return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+}
+
+static int mt7628_phy_config_init(struct phy_device *phydev)
+{
+	/*
+	 * This undocumented bit is required for the PHYs to be able to
+	 * establish 100mbps links.
+	 */
+	return phy_write_paged(phydev, 0x8000, 30, BIT(13));
+}
+
+static struct phy_driver mtk_soc_fe_phy_driver[] = {
+	{
+		PHY_ID_MATCH_EXACT(MTK_FPHY_ID_MT7628),
+		.name = "MediaTek MT7628 PHY",
+		.config_init = mt7628_phy_config_init,
+		.config_intr = genphy_no_config_intr,
+		.handle_interrupt = genphy_handle_interrupt_no_ack,
+		.suspend = genphy_suspend,
+		.resume = genphy_resume,
+		.read_page = mt7628_phy_read_page,
+		.write_page = mt7628_phy_write_page,
+	},
+};
+
+module_phy_driver(mtk_soc_fe_phy_driver);
+static const struct mdio_device_id __maybe_unused mtk_soc_fe_phy_tbl[] = {
+	{ PHY_ID_MATCH_EXACT(MTK_FPHY_ID_MT7628) },
+	{ }
+};
+
+MODULE_DESCRIPTION("MediaTek SoC Fast Ethernet PHY driver");
+MODULE_AUTHOR("Joris Vaisvila <joey@tinyisr.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(mdio, mtk_soc_fe_phy_tbl);
-- 
2.53.0


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

* [RFC v2 2/3] net: dsa: initial MT7628 tagging driver
  2026-03-14 15:08 [RFC v2 0/3] net: dsa: MT7628 embedded switch initial support Joris Vaisvila
  2026-03-14 15:08 ` [RFC v2 1/3] net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet PHYs Joris Vaisvila
@ 2026-03-14 15:08 ` Joris Vaisvila
  2026-03-14 17:59   ` Daniel Golle
  2026-03-14 15:08 ` [RFC v2 3/3] net: dsa: initial support for MT7628 embedded switch Joris Vaisvila
  2 siblings, 1 reply; 10+ messages in thread
From: Joris Vaisvila @ 2026-03-14 15:08 UTC (permalink / raw)
  To: netdev
  Cc: horms, pabeni, kuba, edumazet, davem, olteanv, Andrew Lunn,
	Joris Vaisvila

Add support for the MT7628 embedded switch's tag.

The MT7628 tag is merged with the VLAN TPID field when a VLAN is
appended by the switch hardware. It is not installed if the VLAN tag is
already there on ingress. Due to this hardware quirk the tag cannot be
trusted for port 0 if we don't know that the VLAN was added by the
hardware. As a workaround for this the switch is configured to always
append the port PVID tag even if the incoming packet is already tagged.
The tagging driver can then trust that the tag is always accurate and
the whole VLAN tag can be removed on ingress as it's only metadata for
the tagger.

On egress the MT7628 tag allows precise TX, but the correct VLAN tag
from tag_8021q is still appended or the switch will not forward the
packet.

Signed-off-by: Joris Vaisvila <joey@tinyisr.com>
---
 include/net/dsa.h    |  2 +
 net/dsa/Kconfig      |  6 +++
 net/dsa/Makefile     |  1 +
 net/dsa/tag_mt7628.c | 93 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 102 insertions(+)
 create mode 100644 net/dsa/tag_mt7628.c

diff --git a/include/net/dsa.h b/include/net/dsa.h
index 6c17446f3dcc..e93f9356b5c3 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -58,6 +58,7 @@ struct tc_action;
 #define DSA_TAG_PROTO_YT921X_VALUE		30
 #define DSA_TAG_PROTO_MXL_GSW1XX_VALUE		31
 #define DSA_TAG_PROTO_MXL862_VALUE		32
+#define DSA_TAG_PROTO_MT7628_VALUE		33
 
 enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
@@ -93,6 +94,7 @@ enum dsa_tag_protocol {
 	DSA_TAG_PROTO_YT921X		= DSA_TAG_PROTO_YT921X_VALUE,
 	DSA_TAG_PROTO_MXL_GSW1XX	= DSA_TAG_PROTO_MXL_GSW1XX_VALUE,
 	DSA_TAG_PROTO_MXL862		= DSA_TAG_PROTO_MXL862_VALUE,
+	DSA_TAG_PROTO_MT7628		= DSA_TAG_PROTO_MT7628_VALUE,
 };
 
 struct dsa_switch;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 5ed8c704636d..4aa73bd1aa9b 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -211,4 +211,10 @@ config NET_DSA_TAG_YT921X
 	  Say Y or M if you want to enable support for tagging frames for
 	  Motorcomm YT921x switches.
 
+config NET_DSA_TAG_MT7628
+	tristate "Tag driver for the MT7628 embedded switch"
+	help
+	  Say Y or M if you want to enable support for tagging frames for the
+	  switch embedded in the MT7628 SoC.
+
 endif
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index bf7247759a64..d25ec0ab7d67 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
 obj-$(CONFIG_NET_DSA_TAG_VSC73XX_8021Q) += tag_vsc73xx_8021q.o
 obj-$(CONFIG_NET_DSA_TAG_XRS700X) += tag_xrs700x.o
 obj-$(CONFIG_NET_DSA_TAG_YT921X) += tag_yt921x.o
+obj-$(CONFIG_NET_DSA_TAG_MT7628) += tag_mt7628.o
 
 # for tracing framework to find trace.h
 CFLAGS_trace.o := -I$(src)
diff --git a/net/dsa/tag_mt7628.c b/net/dsa/tag_mt7628.c
new file mode 100644
index 000000000000..ca286d1c9e44
--- /dev/null
+++ b/net/dsa/tag_mt7628.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2026, Joris Vaisvila <joey@tinyisr.com>
+ * MT7628 switch tag support
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/dsa/8021q.h>
+#include <net/dsa.h>
+
+#include "tag.h"
+
+/*
+ * The MT7628 tag is encoded in the VLAN TPID field.
+ * On TX the lower 6 bits encode the destination port bitmask.
+ * On RX the lower 3 bits encode the source port number.
+ *
+ * The switch hardware will not modify the TPID of an incoming packet if it is
+ * already VLAN tagged. To work around this the switch is configured to always
+ * append a tag_8021q standalone VLAN tag for each port. That means we can
+ * safely strip the outer VLAN tag after parsing it.
+ *
+ * A VLAN tag is constructed on egress to target the standalone VLAN and
+ * destination port.
+ */
+
+#define MT7628_TAG_NAME "mt7628"
+
+#define MT7628_TAG_TX_PORT_BIT_MASK GENMASK(5, 0)
+#define MT7628_TAG_RX_PORT_MASK GENMASK(2, 0)
+#define MT7628_TAG_LEN 4
+
+static struct sk_buff *mt7628_tag_xmit(struct sk_buff *skb,
+				       struct net_device *dev)
+{
+	struct dsa_port *dp;
+	u16 xmit_vlan;
+	u8 *tag;
+
+	dp = dsa_user_to_port(dev);
+	xmit_vlan = dsa_tag_8021q_standalone_vid(dp);
+
+	skb_push(skb, MT7628_TAG_LEN);
+	dsa_alloc_etype_header(skb, MT7628_TAG_LEN);
+
+	tag = dsa_etype_header_pos_tx(skb);
+
+	tag[0] = ETH_P_8021Q >> 8;
+	tag[1] = FIELD_PREP(MT7628_TAG_TX_PORT_BIT_MASK,
+			    dsa_xmit_port_mask(skb, dev));
+
+	tag[2] = xmit_vlan >> 8;
+	tag[3] = xmit_vlan & 0xff;
+	return skb;
+}
+
+static struct sk_buff *mt7628_tag_rcv(struct sk_buff *skb,
+				      struct net_device *dev)
+{
+	int src_port;
+	__be16 *phdr;
+	u16 tpid;
+
+	if (unlikely(!pskb_may_pull(skb, MT7628_TAG_LEN)))
+		return NULL;
+
+	phdr = dsa_etype_header_pos_rx(skb);
+	tpid = ntohs(*phdr);
+	skb_pull_rcsum(skb, MT7628_TAG_LEN);
+	dsa_strip_etype_header(skb, MT7628_TAG_LEN);
+
+	src_port = tpid & MT7628_TAG_RX_PORT_MASK;
+
+	skb->dev = dsa_conduit_find_user(dev, 0, src_port);
+	if (!skb->dev)
+		return NULL;
+	dsa_default_offload_fwd_mark(skb);
+	return skb;
+}
+
+static const struct dsa_device_ops mt7628_tag_ops = {
+	.name = MT7628_TAG_NAME,
+	.proto = DSA_TAG_PROTO_MT7628,
+	.xmit = mt7628_tag_xmit,
+	.rcv = mt7628_tag_rcv,
+	.needed_headroom = MT7628_TAG_LEN,
+};
+
+module_dsa_tag_driver(mt7628_tag_ops);
+
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MT7628, MT7628_TAG_NAME);
+MODULE_DESCRIPTION("DSA tag driver for MT7628 switch");
+MODULE_LICENSE("GPL");
-- 
2.53.0


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

* [RFC v2 3/3] net: dsa: initial support for MT7628 embedded switch
  2026-03-14 15:08 [RFC v2 0/3] net: dsa: MT7628 embedded switch initial support Joris Vaisvila
  2026-03-14 15:08 ` [RFC v2 1/3] net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet PHYs Joris Vaisvila
  2026-03-14 15:08 ` [RFC v2 2/3] net: dsa: initial MT7628 tagging driver Joris Vaisvila
@ 2026-03-14 15:08 ` Joris Vaisvila
  2026-03-14 23:41   ` Daniel Golle
  2 siblings, 1 reply; 10+ messages in thread
From: Joris Vaisvila @ 2026-03-14 15:08 UTC (permalink / raw)
  To: netdev
  Cc: horms, pabeni, kuba, edumazet, davem, olteanv, Andrew Lunn,
	Joris Vaisvila

Add support for the MT7628 embedded switch.

The switch has 5 built-in 100Mbps ports (ports 0-4) and 2x 1Gbps ports.
One of the 1Gbps ports (port 6) is internally attached to the SoCs CPU
MAC and serves as the CPU port. The other 1Gbps port (port 5) requires
an external MAC to function.

The switch hardware has a very limited 16 entry VLAN table. Configuring
VLANs is the only way to control switch forwarding. Currently 7 entries
are used by tag_8021q to isolate the ports. Double tag feature is
enabled to force the switch to append the VLAN tag even if the incoming
packet is already tagged, this simulates VLAN-unaware functionality and
simplifies the tagger implementation.

Signed-off-by: Joris Vaisvila <joey@tinyisr.com>
---
 drivers/net/dsa/Kconfig  |   7 +
 drivers/net/dsa/Makefile |   1 +
 drivers/net/dsa/mt7628.c | 609 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 617 insertions(+)
 create mode 100644 drivers/net/dsa/mt7628.c

diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index 39fb8ead16b5..d07fc8dfe228 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -70,6 +70,13 @@ config NET_DSA_MV88E6060
 	  This enables support for the Marvell 88E6060 ethernet switch
 	  chip.
 
+config NET_DSA_MT7628
+	tristate "MT7628 Embedded ethernet switch support"
+	select NET_DSA_TAG_MT7628
+	select MEDIATEK_FE_SOC_PHY
+	help
+	  This enables support for the switch in the MT7628 SoC.
+
 source "drivers/net/dsa/microchip/Kconfig"
 
 source "drivers/net/dsa/mv88e6xxx/Kconfig"
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index f5a463b87ec2..22da6b680f29 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx-core.o
 obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM) += vitesse-vsc73xx-platform.o
 obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o
 obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
+obj-$(CONFIG_NET_DSA_MT7628) += mt7628.o
 obj-y				+= b53/
 obj-y				+= hirschmann/
 obj-y				+= lantiq/
diff --git a/drivers/net/dsa/mt7628.c b/drivers/net/dsa/mt7628.c
new file mode 100644
index 000000000000..16c3a73606c7
--- /dev/null
+++ b/drivers/net/dsa/mt7628.c
@@ -0,0 +1,609 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek MT7628 Embedded Switch (ESW) DSA driver
+ * Copyright (C) 2026 Joris Vaisvila <joey@tinyisr.com>
+ *
+ * Portions derived from OpenWRT esw_rt3050 driver:
+ * Copyright (C) 2009-2015 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
+ * Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
+ * Copyright (C) 2016 Vittorio Gambaletta <openwrt@vittgam.net>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/dsa/8021q.h>
+#include <linux/if_bridge.h>
+#include <linux/module.h>
+#include <linux/mdio.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/kernel.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <net/dsa.h>
+
+#define MT7628_ESW_REG_IMR 0x04
+#define MT7628_ESW_REG_FCT0 0x08
+#define MT7628_ESW_REG_PFC1 0x14
+#define MT7628_ESW_REG_PVIDC(_n) (0x40 + 4 * (_n))
+#define MT7628_ESW_REG_VLANI(_n) (0x50 + 4 * (_n))
+#define MT7628_ESW_REG_VMSC(_n) (0x70 + 4 * (_n))
+#define MT7628_ESW_REG_VUB(_n) (0x100 + 4 * (_n))
+#define MT7628_ESW_REG_SOCPC 0x8c
+#define MT7628_ESW_REG_POC0 0x90
+#define MT7628_ESW_REG_POC2 0x98
+#define MT7628_ESW_REG_SGC 0x9c
+#define MT7628_ESW_REG_PCR0 0xc0
+#define MT7628_ESW_REG_PCR1 0xc4
+#define MT7628_ESW_REG_FPA2 0xc8
+#define MT7628_ESW_REG_FCT2 0xcc
+#define MT7628_ESW_REG_SGC2 0xe4
+
+#define MT7628_ESW_PFC1_EN_VLAN GENMASK(22, 16)
+
+#define MT7628_ESW_PVIDC_PVID_M 0xfff
+#define MT7628_ESW_PVIDC_PVID_S 12
+#define MT7628_ESW_VLANI_VID_M 0xfff
+#define MT7628_ESW_VLANI_VID_S 12
+#define MT7628_ESW_VMSC_MSC_M 0xff
+#define MT7628_ESW_VMSC_MSC_S 8
+#define MT7628_ESW_VUB_S 7
+#define MT7628_ESW_VUB_M 0x7f
+
+#define MT7628_ESW_SOCPC_CRC_PADDING BIT(25)
+#define MT7628_ESW_SOCPC_DISBC2CPU GENMASK(22, 16)
+#define MT7628_ESW_SOCPC_DISMC2CPU GENMASK(14, 8)
+#define MT7628_ESW_SOCPC_DISUN2CPU GENMASK(6, 0)
+
+#define MT7628_ESW_POC0_PORT_DISABLE GENMASK(29, 23)
+
+#define MT7628_ESW_POC2_PER_VLAN_UNTAG_EN BIT(15)
+
+#define MT7628_ESW_SGC_AGING_INTERVAL GENMASK(3, 0)
+#define MT7628_ESW_BC_STORM_PROT GENMASK(5, 4)
+#define MT7628_ESW_PKT_MAX_LEN GENMASK(7, 6)
+#define MT7628_ESW_DIS_PKT_ABORT BIT(8)
+#define MT7628_ESW_ADDRESS_HASH_ALG GENMASK(10, 9)
+#define MT7628_ESW_DISABLE_TX_BACKOFF BIT(11)
+#define MT7628_ESW_BP_JAM_CNT GENMASK(15, 12)
+#define MT7628_ESW_DISMIIPORT_WASTX GENMASK(17, 16)
+#define MT7628_ESW_BP_MODE GENMASK(19, 18)
+#define MT7628_ESW_BISH_DIS BIT(20)
+#define MT7628_ESW_BISH_TH GENMASK(22, 21)
+#define MT7628_ESW_LED_FLASH_TIME GENMASK(24, 23)
+#define MT7628_ESW_RMC_RULE GENMASK(26, 25)
+#define MT7628_ESW_IP_MULT_RULE GENMASK(28, 27)
+#define MT7628_ESW_LEN_ERR_CHK BIT(29)
+#define MT7628_ESW_BKOFF_ALG BIT(30)
+
+#define MT7628_ESW_PCR0_WT_NWAY_DATA GENMASK(31, 16)
+#define MT7628_ESW_PCR0_RD_PHY_CMD BIT(14)
+#define MT7628_ESW_PCR0_WT_PHY_CMD BIT(13)
+#define MT7628_ESW_PCR0_CPU_PHY_REG GENMASK(12, 8)
+#define MT7628_ESW_PCR0_CPU_PHY_ADDR GENMASK(4, 0)
+
+#define MT7628_ESW_PCR1_RD_DATA GENMASK(31, 16)
+#define MT7628_ESW_PCR1_RD_DONE BIT(1)
+#define MT7628_ESW_PCR1_WT_DONE BIT(0)
+
+#define MT7628_ESW_FPA2_AP_EN BIT(29)
+#define MT7628_ESW_FPA2_EXT_PHY_ADDR_BASE GENMASK(28, 24)
+#define MT7628_ESW_FPA2_FORCE_RGMII_LINK1 BIT(13)
+#define MT7628_ESW_FPA2_FORCE_RGMII_EN1 BIT(11)
+
+#define MT7628_ESW_FCT0_DROP_SET_TH GENMASK(7, 0)
+#define MT7628_ESW_FCT0_DROP_RLS_TH GENMASK(15, 8)
+#define MT7628_ESW_FCT0_FC_SET_TH GENMASK(23, 16)
+#define MT7628_ESW_FCT0_FC_RLS_TH GENMASK(31, 24)
+
+#define MT7628_ESW_FCT2_MUST_DROP_RLS_TH GENMASK(17, 13)
+#define MT7628_ESW_FCT2_MUST_DROP_SET_TH GENMASK(12, 8)
+#define MT7628_ESW_FCT2_MC_PER_PORT_TH GENMASK(5, 0)
+
+#define MT7628_ESW_SGC2_SPECIAL_TAG_EN BIT(23)
+#define MT7628_ESW_SGC2_TX_CPU_TPID_BIT_MAP GENMASK(22, 16)
+#define MT7628_ESW_SGC2_DOUBLE_TAG_EN GENMASK(6, 0)
+
+#define MT7628_ESW_PORTS_NOCPU GENMASK(5, 0)
+#define MT7628_ESW_PORTS_CPU BIT(6)
+#define MT7628_ESW_PORTS_ALL GENMASK(6, 0)
+
+#define MT7628_ESW_NUM_PORTS 7
+#define MT7628_NUM_VLANS 16
+
+static const struct regmap_config mt7628_esw_regmap_cfg = {
+	.name = "mt7628-esw",
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.fast_io = true,
+	.reg_format_endian = REGMAP_ENDIAN_LITTLE,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+struct mt7628_vlan {
+	bool active;
+	u8 members;
+	u8 untag;
+	u16 vid;
+};
+
+struct mt7628_esw {
+	void __iomem *base;
+	struct reset_control *rst_ephy;
+	struct reset_control *rst_esw;
+	struct regmap *regmap;
+	struct dsa_switch *ds;
+	u16 tag_8021q_pvid[MT7628_ESW_NUM_PORTS];
+	struct mt7628_vlan vlans[MT7628_NUM_VLANS];
+	struct device *dev;
+};
+
+static int mt7628_mii_read(struct mii_bus *bus, int port, int regnum)
+{
+	struct mt7628_esw *esw = bus->priv;
+	int ret;
+	u32 val;
+
+	ret =
+	    regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,
+				     !(val & MT7628_ESW_PCR1_RD_DONE), 10,
+				     5000);
+	if (ret)
+		goto out;
+
+	ret = regmap_write(esw->regmap, MT7628_ESW_REG_PCR0,
+			   FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_REG,
+				      regnum) |
+			   FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_ADDR,
+				      port) | MT7628_ESW_PCR0_RD_PHY_CMD);
+	if (ret)
+		goto out;
+
+	ret =
+	    regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,
+				     (val & MT7628_ESW_PCR1_RD_DONE), 10,
+				     5000);
+out:
+	if (ret) {
+		dev_err(&bus->dev, "read failed. MDIO timeout?\n");
+		return -ETIMEDOUT;
+	}
+	return FIELD_GET(MT7628_ESW_PCR1_RD_DATA, val);
+}
+
+static int mt7628_mii_write(struct mii_bus *bus, int port, int regnum,
+			    u16 dat)
+{
+	struct mt7628_esw *esw = bus->priv;
+	u32 val;
+	int ret;
+
+	ret =
+	    regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,
+				     !(val & MT7628_ESW_PCR1_WT_DONE), 10,
+				     5000);
+	if (ret)
+		goto out;
+
+	ret = regmap_write(esw->regmap, MT7628_ESW_REG_PCR0,
+			   FIELD_PREP(MT7628_ESW_PCR0_WT_NWAY_DATA, dat) |
+			   FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_REG,
+				      regnum) |
+			   FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_ADDR,
+				      port) | MT7628_ESW_PCR0_WT_PHY_CMD);
+	if (ret)
+		goto out;
+
+	ret =
+	    regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,
+				     (val & MT7628_ESW_PCR1_WT_DONE), 10,
+				     5000);
+out:
+	if (ret) {
+		dev_err(&bus->dev, "write failed. MDIO timeout?\n");
+		return -ETIMEDOUT;
+	}
+	return ret;
+}
+
+static int mt7628_setup_internal_mdio(struct dsa_switch *ds,
+				      struct device_node *node)
+{
+	struct mt7628_esw *esw = ds->priv;
+	struct mii_bus *bus;
+	int ret;
+
+	bus = devm_mdiobus_alloc(esw->dev);
+	if (!bus)
+		return -ENOMEM;
+
+	bus->name = "MT7628 internal MDIO bus";
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(ds->dev));
+	bus->priv = esw;
+	bus->read = mt7628_mii_read;
+	bus->write = mt7628_mii_write;
+	bus->parent = esw->dev;
+
+	ret = devm_of_mdiobus_register(esw->dev, bus, node);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void mt7628_switch_init(struct dsa_switch *ds)
+{
+	struct mt7628_esw *esw = ds->priv;
+
+	regmap_write(esw->regmap, MT7628_ESW_REG_FCT0,
+		     FIELD_PREP(MT7628_ESW_FCT0_DROP_SET_TH, 0x50) |
+		     FIELD_PREP(MT7628_ESW_FCT0_DROP_RLS_TH, 0x78) |
+		     FIELD_PREP(MT7628_ESW_FCT0_FC_SET_TH, 0xa0) |
+		     FIELD_PREP(MT7628_ESW_FCT0_FC_RLS_TH, 0xc8));
+
+	regmap_write(esw->regmap, MT7628_ESW_REG_FCT2,
+		     FIELD_PREP(MT7628_ESW_FCT2_MC_PER_PORT_TH, 0xc) |
+		     FIELD_PREP(MT7628_ESW_FCT2_MUST_DROP_SET_TH, 0x10) |
+		     FIELD_PREP(MT7628_ESW_FCT2_MUST_DROP_RLS_TH, 0x12));
+
+	/*
+	 * general switch configuration:
+	 * 300s aging interval
+	 * broadcast storm prevention disabled
+	 * max packet length 1536 bytes
+	 * disable collision 16 packet abort and late collision abort
+	 * use xor48 for address hashing
+	 * disable tx backoff
+	 * 10 packet back pressure jam
+	 * disable was_transmit
+	 * jam until BP condition released
+	 * 30ms LED flash
+	 * rmc tb fault to all ports
+	 * unmatched IGMP as broadcast
+	 */
+	regmap_write(esw->regmap, MT7628_ESW_REG_SGC,
+		     FIELD_PREP(MT7628_ESW_SGC_AGING_INTERVAL, 1) |
+		     FIELD_PREP(MT7628_ESW_BC_STORM_PROT, 0) |
+		     FIELD_PREP(MT7628_ESW_PKT_MAX_LEN, 0) |
+		     MT7628_ESW_DIS_PKT_ABORT |
+		     FIELD_PREP(MT7628_ESW_ADDRESS_HASH_ALG, 1) |
+		     MT7628_ESW_DISABLE_TX_BACKOFF |
+		     FIELD_PREP(MT7628_ESW_BP_JAM_CNT, 10) |
+		     FIELD_PREP(MT7628_ESW_DISMIIPORT_WASTX, 0) |
+		     FIELD_PREP(MT7628_ESW_BP_MODE, 0b10) |
+		     FIELD_PREP(MT7628_ESW_LED_FLASH_TIME, 0) |
+		     FIELD_PREP(MT7628_ESW_RMC_RULE, 0) |
+		     FIELD_PREP(MT7628_ESW_IP_MULT_RULE, 0));
+
+	regmap_write(esw->regmap, MT7628_ESW_REG_SOCPC,
+		     MT7628_ESW_SOCPC_CRC_PADDING |
+		     FIELD_PREP(MT7628_ESW_SOCPC_DISUN2CPU,
+				MT7628_ESW_PORTS_CPU) |
+		     FIELD_PREP(MT7628_ESW_SOCPC_DISMC2CPU,
+				MT7628_ESW_PORTS_CPU) |
+		     FIELD_PREP(MT7628_ESW_SOCPC_DISBC2CPU,
+				MT7628_ESW_PORTS_CPU));
+
+	regmap_set_bits(esw->regmap, MT7628_ESW_REG_FPA2,
+			MT7628_ESW_FPA2_FORCE_RGMII_EN1 |
+			MT7628_ESW_FPA2_FORCE_RGMII_LINK1 |
+			MT7628_ESW_FPA2_AP_EN);
+
+	regmap_update_bits(esw->regmap, MT7628_ESW_REG_FPA2,
+			   MT7628_ESW_FPA2_EXT_PHY_ADDR_BASE,
+			   FIELD_PREP(MT7628_ESW_FPA2_EXT_PHY_ADDR_BASE,
+				      31));
+
+	/* disable all interrupts */
+	regmap_write(esw->regmap, MT7628_ESW_REG_IMR, 0);
+
+	/* enable MT7628 DSA tag on CPU port */
+	regmap_write(esw->regmap, MT7628_ESW_REG_SGC2,
+		     MT7628_ESW_SGC2_SPECIAL_TAG_EN |
+		     FIELD_PREP(MT7628_ESW_SGC2_TX_CPU_TPID_BIT_MAP,
+				MT7628_ESW_PORTS_CPU));
+
+	/*
+	 * Double tag feature allows switch to always append the port PVID VLAN tag
+	 * regardless of if the incoming packet already has a VLAN tag.
+	 * This is enabled to simulate VLAN unawareness.
+	 */
+	regmap_set_bits(esw->regmap, MT7628_ESW_REG_SGC2,
+			FIELD_PREP(MT7628_ESW_SGC2_DOUBLE_TAG_EN,
+				   MT7628_ESW_PORTS_NOCPU));
+
+	regmap_set_bits(esw->regmap, MT7628_ESW_REG_POC2,
+			MT7628_ESW_POC2_PER_VLAN_UNTAG_EN);
+
+	regmap_update_bits(esw->regmap, MT7628_ESW_REG_PFC1,
+			   MT7628_ESW_PFC1_EN_VLAN,
+			   FIELD_PREP(MT7628_ESW_PFC1_EN_VLAN,
+				      MT7628_ESW_PORTS_ALL));
+}
+
+static void esw_set_vlan_id(struct mt7628_esw *esw, unsigned int vlan,
+			    unsigned int vid)
+{
+	unsigned int s = MT7628_ESW_VLANI_VID_S * (vlan % 2);
+
+	regmap_update_bits(esw->regmap, MT7628_ESW_REG_VLANI(vlan / 2),
+			   MT7628_ESW_VLANI_VID_M << s,
+			   (vid & MT7628_ESW_VLANI_VID_M) << s);
+}
+
+static void esw_set_pvid(struct mt7628_esw *esw, unsigned int port,
+			 unsigned int pvid)
+{
+	unsigned int s = MT7628_ESW_PVIDC_PVID_S * (port % 2);
+
+	regmap_update_bits(esw->regmap, MT7628_ESW_REG_PVIDC(port / 2),
+			   MT7628_ESW_PVIDC_PVID_M << s,
+			   (pvid & MT7628_ESW_PVIDC_PVID_M) << s);
+}
+
+static void esw_set_vmsc(struct mt7628_esw *esw, unsigned int vlan,
+			 unsigned int msc)
+{
+	unsigned int s = MT7628_ESW_VMSC_MSC_S * (vlan % 4);
+
+	regmap_update_bits(esw->regmap, MT7628_ESW_REG_VMSC(vlan / 4),
+			   MT7628_ESW_VMSC_MSC_M << s,
+			   (msc & MT7628_ESW_VMSC_MSC_M) << s);
+}
+
+static void esw_set_vub(struct mt7628_esw *esw, unsigned int vlan,
+			unsigned int msc)
+{
+	unsigned int s = MT7628_ESW_VUB_S * (vlan % 4);
+
+	regmap_update_bits(esw->regmap, MT7628_ESW_REG_VUB(vlan / 4),
+			   MT7628_ESW_VUB_M << s,
+			   (msc & MT7628_ESW_VUB_M) << s);
+}
+
+static void mt7628_vlan_sync(struct dsa_switch *ds)
+{
+	struct mt7628_esw *esw = ds->priv;
+	int i;
+
+	for (i = 0; i < MT7628_NUM_VLANS; i++) {
+		struct mt7628_vlan *vlan = &esw->vlans[i];
+
+		esw_set_vmsc(esw, i, vlan->members);
+		esw_set_vlan_id(esw, i, vlan->vid);
+		esw_set_vub(esw, i, vlan->untag);
+	}
+
+	for (i = 0; i < ds->num_ports; i++)
+		esw_set_pvid(esw, i, esw->tag_8021q_pvid[i]);
+}
+
+static int mt7628_setup(struct dsa_switch *ds)
+{
+	struct mt7628_esw *esw = ds->priv;
+	struct device_node *child;
+	int ret;
+
+	reset_control_reset(esw->rst_esw);
+	usleep_range(1000, 2000);
+	reset_control_reset(esw->rst_ephy);
+	usleep_range(1000, 2000);
+	/*
+	 * all MMIO reads hang if esw is not out of reset
+	 * ephy needs extra time to get out of reset or it ends up misconfigured
+	 */
+	mt7628_switch_init(ds);
+	rtnl_lock();
+	dsa_tag_8021q_register(ds, htons(ETH_P_8021Q));
+	rtnl_unlock();
+
+	child = of_get_child_by_name(ds->dev->of_node, "mdio");
+	if (child) {
+		ret = mt7628_setup_internal_mdio(ds, child);
+		of_node_put(child);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static int mt7628_port_enable(struct dsa_switch *ds, int port,
+			      struct phy_device *phy)
+{
+	struct mt7628_esw *esw = ds->priv;
+
+	regmap_clear_bits(esw->regmap, MT7628_ESW_REG_POC0,
+			  FIELD_PREP(MT7628_ESW_POC0_PORT_DISABLE,
+				     BIT(port)));
+	return 0;
+}
+
+static void mt7628_port_disable(struct dsa_switch *ds, int port)
+{
+	struct mt7628_esw *esw = ds->priv;
+
+	regmap_set_bits(esw->regmap, MT7628_ESW_REG_POC0,
+			FIELD_PREP(MT7628_ESW_POC0_PORT_DISABLE,
+				   BIT(port)));
+}
+
+static enum dsa_tag_protocol
+mt7628_get_tag_proto(struct dsa_switch *ds, int port,
+		     enum dsa_tag_protocol mp)
+{
+	return DSA_TAG_PROTO_MT7628;
+}
+
+static void mt7628_phylink_get_caps(struct dsa_switch *ds, int port,
+				    struct phylink_config *config)
+{
+	config->mac_capabilities = MAC_100 | MAC_10;
+	__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
+	__set_bit(PHY_INTERFACE_MODE_GMII, config->supported_interfaces);
+}
+
+static int mt7628_dsa_8021q_vlan_add(struct dsa_switch *ds, int port,
+				     u16 vid, u16 flags)
+{
+	struct mt7628_esw *esw = ds->priv;
+	struct mt7628_vlan *vlan = NULL;
+	int i;
+
+	for (i = 0; i < MT7628_NUM_VLANS; i++) {
+		struct mt7628_vlan *check_vlan = &esw->vlans[i];
+
+		if (!check_vlan->active && !vlan) {
+			vlan = check_vlan;
+		} else if (check_vlan->vid == vid) {
+			vlan = check_vlan;
+			break;
+		}
+	}
+
+	if (!vlan)
+		return -ENOSPC;
+
+	vlan->vid = vid;
+	vlan->active = true;
+	vlan->members |= BIT(port);
+
+	if (flags & BRIDGE_VLAN_INFO_PVID)
+		esw->tag_8021q_pvid[port] = vid;
+
+	if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
+		vlan->untag |= BIT(port);
+
+	mt7628_vlan_sync(ds);
+	return 0;
+}
+
+static int mt7628_dsa_8021q_vlan_del(struct dsa_switch *ds, int port,
+				     u16 vid)
+{
+	struct mt7628_esw *esw = ds->priv;
+	struct mt7628_vlan *vlan = NULL;
+	int i;
+
+	for (i = 0; i < MT7628_NUM_VLANS; i++) {
+		struct mt7628_vlan *check_vlan = &esw->vlans[i];
+
+		if (!check_vlan->active || check_vlan->vid != vid)
+			continue;
+		vlan = check_vlan;
+		break;
+	}
+	if (!vlan)
+		return -ENOENT;
+
+	vlan->members &= ~BIT(port);
+	vlan->untag &= ~BIT(port);
+
+	if (!vlan->members)
+		vlan->active = false;
+
+	mt7628_vlan_sync(ds);
+	return 0;
+}
+
+static struct dsa_switch_ops mt7628_switch_ops = {
+	.get_tag_protocol = mt7628_get_tag_proto,
+	.setup = mt7628_setup,
+	.port_enable = mt7628_port_enable,
+	.port_disable = mt7628_port_disable,
+	.phylink_get_caps = mt7628_phylink_get_caps,
+	.tag_8021q_vlan_add = mt7628_dsa_8021q_vlan_add,
+	.tag_8021q_vlan_del = mt7628_dsa_8021q_vlan_del,
+};
+
+static int mt7628_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt7628_esw *esw;
+	struct dsa_switch *ds;
+
+	ds = devm_kzalloc(&pdev->dev, sizeof(*ds), GFP_KERNEL);
+	if (!ds)
+		return -ENOMEM;
+
+	esw = devm_kzalloc(&pdev->dev, sizeof(*esw), GFP_KERNEL);
+	if (!esw)
+		return -ENOMEM;
+
+	esw->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(esw->base))
+		return PTR_ERR(esw->base);
+
+	esw->regmap = devm_regmap_init_mmio(&pdev->dev, esw->base,
+					    &mt7628_esw_regmap_cfg);
+	if (IS_ERR(esw->regmap))
+		return PTR_ERR(esw->regmap);
+
+	esw->rst_ephy =
+	    devm_reset_control_get_exclusive(&pdev->dev, "ephy");
+	if (IS_ERR(esw->rst_ephy))
+		return dev_err_probe(dev, PTR_ERR(esw->rst_ephy),
+				     "failed to get EPHY reset\n");
+
+	esw->rst_esw = devm_reset_control_get_exclusive(&pdev->dev, "esw");
+	if (IS_ERR(esw->rst_esw))
+		return dev_err_probe(dev, PTR_ERR(esw->rst_esw),
+				     "failed to get ESW reset\n");
+
+	ds->dev = dev;
+	ds->num_ports = MT7628_ESW_NUM_PORTS;
+	ds->ops = &mt7628_switch_ops;
+	ds->priv = esw;
+	esw->ds = ds;
+	esw->dev = dev;
+	dev_set_drvdata(dev, esw);
+
+	return dsa_register_switch(ds);
+}
+
+static void mt7628_remove(struct platform_device *pdev)
+{
+	struct mt7628_esw *esw = platform_get_drvdata(pdev);
+
+	if (!esw)
+		return;
+
+	dsa_unregister_switch(esw->ds);
+}
+
+static void mt7628_shutdown(struct platform_device *pdev)
+{
+	struct mt7628_esw *esw = platform_get_drvdata(pdev);
+
+	if (!esw)
+		return;
+
+	dsa_switch_shutdown(esw->ds);
+	dev_set_drvdata(&pdev->dev, NULL);
+}
+
+static const struct of_device_id mt7628_of_match[] = {
+	{ .compatible = "mediatek,mt7628-esw" },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, mt7628_of_match);
+
+static struct platform_driver mt7628_driver = {
+	.driver = {
+		   .name = "mt7628-esw",
+		   .of_match_table = mt7628_of_match,
+		    },
+	.probe = mt7628_probe,
+	.remove = mt7628_remove,
+	.shutdown = mt7628_shutdown,
+};
+
+module_platform_driver(mt7628_driver);
+
+MODULE_AUTHOR("Joris Vaisvila <joey@tinyisr.com>");
+MODULE_DESCRIPTION("Driver for Mediatek MT7628 embedded switch");
+MODULE_LICENSE("GPL");
-- 
2.53.0


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

* Re: [RFC v2 2/3] net: dsa: initial MT7628 tagging driver
  2026-03-14 15:08 ` [RFC v2 2/3] net: dsa: initial MT7628 tagging driver Joris Vaisvila
@ 2026-03-14 17:59   ` Daniel Golle
  2026-03-14 20:46     ` Joris Vaišvila
  0 siblings, 1 reply; 10+ messages in thread
From: Daniel Golle @ 2026-03-14 17:59 UTC (permalink / raw)
  To: Joris Vaisvila
  Cc: netdev, horms, pabeni, kuba, edumazet, davem, olteanv,
	Andrew Lunn

On Sat, Mar 14, 2026 at 05:08:44PM +0200, Joris Vaisvila wrote:
> Add support for the MT7628 embedded switch's tag.
> 
> The MT7628 tag is merged with the VLAN TPID field when a VLAN is
> appended by the switch hardware. It is not installed if the VLAN tag is
> already there on ingress. Due to this hardware quirk the tag cannot be
> trusted for port 0 if we don't know that the VLAN was added by the
> hardware. As a workaround for this the switch is configured to always
> append the port PVID tag even if the incoming packet is already tagged.
> The tagging driver can then trust that the tag is always accurate and
> the whole VLAN tag can be removed on ingress as it's only metadata for
> the tagger.
> 
> On egress the MT7628 tag allows precise TX, but the correct VLAN tag
> from tag_8021q is still appended or the switch will not forward the
> packet.
> 
> Signed-off-by: Joris Vaisvila <joey@tinyisr.com>
> ---
>  include/net/dsa.h    |  2 +
>  net/dsa/Kconfig      |  6 +++
>  net/dsa/Makefile     |  1 +
>  net/dsa/tag_mt7628.c | 93 ++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 102 insertions(+)
>  create mode 100644 net/dsa/tag_mt7628.c
> 
> [...]
> +#define MT7628_TAG_TX_PORT_BIT_MASK GENMASK(5, 0)
> +#define MT7628_TAG_RX_PORT_MASK GENMASK(2, 0)
> +#define MT7628_TAG_LEN 4
> +
> +static struct sk_buff *mt7628_tag_xmit(struct sk_buff *skb,
> +				       struct net_device *dev)
> +{
> +	struct dsa_port *dp;
> +	u16 xmit_vlan;
> +	u8 *tag;
> +
> +	dp = dsa_user_to_port(dev);
> +	xmit_vlan = dsa_tag_8021q_standalone_vid(dp);
> +
> +	skb_push(skb, MT7628_TAG_LEN);
> +	dsa_alloc_etype_header(skb, MT7628_TAG_LEN);
> +
> +	tag = dsa_etype_header_pos_tx(skb);
> +
> +	tag[0] = ETH_P_8021Q >> 8;
> +	tag[1] = FIELD_PREP(MT7628_TAG_TX_PORT_BIT_MASK,
> +			    dsa_xmit_port_mask(skb, dev));
> +
> +	tag[2] = xmit_vlan >> 8;
> +	tag[3] = xmit_vlan & 0xff;

So there are basically two 16-bit fields which need endian swapping
from host-byte order (little endian on MT7628) to network byte-order.
Imho it would be better expressed by using something along the lines
of

	__be16 *tag;
...
	tag = dsa_etype_header_pos_tx(skb);
	tag[0] = htons(ETH_P_8021Q |
		       FIELD_PREP(MT7628_TAG_TX_PORT_BIT_MASK,
				  dsa_xmit_port_mask(skb, dev)));
	tag[1] = htons(xmit_vlan);


> +	return skb;
> +}
> +
> +static struct sk_buff *mt7628_tag_rcv(struct sk_buff *skb,
> +				      struct net_device *dev)
> +{
> +	int src_port;
> +	__be16 *phdr;
> +	u16 tpid;
> +
> +	if (unlikely(!pskb_may_pull(skb, MT7628_TAG_LEN)))
> +		return NULL;
> +
> +	phdr = dsa_etype_header_pos_rx(skb);
> +	tpid = ntohs(*phdr);
> +	skb_pull_rcsum(skb, MT7628_TAG_LEN);
> +	dsa_strip_etype_header(skb, MT7628_TAG_LEN);
> +
> +	src_port = tpid & MT7628_TAG_RX_PORT_MASK;
> +
> +	skb->dev = dsa_conduit_find_user(dev, 0, src_port);
> +	if (!skb->dev)
> +		return NULL;
> +	dsa_default_offload_fwd_mark(skb);
> +	return skb;

This looks like it is semantically identical to the RX path in tag_mtk.c.

Maybe the TX-side can be added to the existing mtk_tag.c driver, so the
RX-side can be shared? tag_brcm.c also defines multiple similar protocols
in the same C source file.

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

* Re: [RFC v2 2/3] net: dsa: initial MT7628 tagging driver
  2026-03-14 17:59   ` Daniel Golle
@ 2026-03-14 20:46     ` Joris Vaišvila
  0 siblings, 0 replies; 10+ messages in thread
From: Joris Vaišvila @ 2026-03-14 20:46 UTC (permalink / raw)
  To: Daniel Golle
  Cc: netdev, horms, pabeni, kuba, edumazet, davem, olteanv,
	Andrew Lunn

Hi Daniel, thanks for the feedback. 

On Sat, Mar 14, 2026 at 05:59:27PM +0000, Daniel Golle wrote:
> On Sat, Mar 14, 2026 at 05:08:44PM +0200, Joris Vaisvila wrote:
> > +	tag[0] = ETH_P_8021Q >> 8;
> > +	tag[1] = FIELD_PREP(MT7628_TAG_TX_PORT_BIT_MASK,
> > +			    dsa_xmit_port_mask(skb, dev));
> > +
> > +	tag[2] = xmit_vlan >> 8;
> > +	tag[3] = xmit_vlan & 0xff;
> 
> So there are basically two 16-bit fields which need endian swapping
> from host-byte order (little endian on MT7628) to network byte-order.
> Imho it would be better expressed by using something along the lines
> of
> 
> 	__be16 *tag;
> ...
> 	tag = dsa_etype_header_pos_tx(skb);
> 	tag[0] = htons(ETH_P_8021Q |
> 		       FIELD_PREP(MT7628_TAG_TX_PORT_BIT_MASK,
> 				  dsa_xmit_port_mask(skb, dev)));
> 	tag[1] = htons(xmit_vlan);

Will use this in later revisions, thanks for the suggestion.

> > +static struct sk_buff *mt7628_tag_rcv(struct sk_buff *skb,
> > +				      struct net_device *dev)
> > +{
> > +	int src_port;
> > +	__be16 *phdr;
> > +	u16 tpid;
> > +
> > +	if (unlikely(!pskb_may_pull(skb, MT7628_TAG_LEN)))
> > +		return NULL;
> > +
> > +	phdr = dsa_etype_header_pos_rx(skb);
> > +	tpid = ntohs(*phdr);
> > +	skb_pull_rcsum(skb, MT7628_TAG_LEN);
> > +	dsa_strip_etype_header(skb, MT7628_TAG_LEN);
> > +
> > +	src_port = tpid & MT7628_TAG_RX_PORT_MASK;
> > +
> > +	skb->dev = dsa_conduit_find_user(dev, 0, src_port);
> > +	if (!skb->dev)
> > +		return NULL;
> > +	dsa_default_offload_fwd_mark(skb);
> > +	return skb;
> 
> This looks like it is semantically identical to the RX path in tag_mtk.c.
> 
> Maybe the TX-side can be added to the existing mtk_tag.c driver, so the
> RX-side can be shared? tag_brcm.c also defines multiple similar protocols
> in the same C source file.

While the core structure is really similar, there are subtle hardware
differences in the MT7628 switch that will make the RX code diverge
from the MTK tag when VLAN offloading is implemented. To account for
that, I'd prefer to keep these drivers separate.

I plan to implement bridge and VLAN offloading after the initial switch
support lands, to keep the initial series smaller and simplify review.

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

* Re: [RFC v2 3/3] net: dsa: initial support for MT7628 embedded switch
  2026-03-14 15:08 ` [RFC v2 3/3] net: dsa: initial support for MT7628 embedded switch Joris Vaisvila
@ 2026-03-14 23:41   ` Daniel Golle
  2026-03-15  7:02     ` Joris Vaišvila
  0 siblings, 1 reply; 10+ messages in thread
From: Daniel Golle @ 2026-03-14 23:41 UTC (permalink / raw)
  To: Joris Vaisvila
  Cc: netdev, horms, pabeni, kuba, edumazet, davem, olteanv,
	Andrew Lunn

On Sat, Mar 14, 2026 at 05:08:45PM +0200, Joris Vaisvila wrote:
> Add support for the MT7628 embedded switch.

Thank you for working on this, MT7628 (especially in "IoT" mode with 3
UARTs and MMC bus exposed instead of the additional switch ports)
still has it's special niche somewhere in between ESP32 and "proper"
Linux-running SoCs ;)

> 
> The switch has 5 built-in 100Mbps ports (ports 0-4) and 2x 1Gbps ports.
> One of the 1Gbps ports (port 6) is internally attached to the SoCs CPU
> MAC and serves as the CPU port. The other 1Gbps port (port 5) requires
> an external MAC to function.

I thought port 5 is a dead-end on MT76x8. Afaik it was only used on
Ralink Rt3052 for RGMII/xMII with this switch IP, and not wired to
any external pins nor to an internal MAC on all other SoCs which came
after.

> 
> The switch hardware has a very limited 16 entry VLAN table. Configuring
> VLANs is the only way to control switch forwarding. Currently 7 entries
> are used by tag_8021q to isolate the ports. Double tag feature is
> enabled to force the switch to append the VLAN tag even if the incoming
> packet is already tagged, this simulates VLAN-unaware functionality and
> simplifies the tagger implementation.
> 
> Signed-off-by: Joris Vaisvila <joey@tinyisr.com>

> +config NET_DSA_MT7628
> +	tristate "MT7628 Embedded ethernet switch support"
> +	select NET_DSA_TAG_MT7628
> +	select MEDIATEK_FE_SOC_PHY
> +	help
> +	  This enables support for the switch in the MT7628 SoC.

And potentially many others (Rt3052, Rt3050, Rt3352, Rt5350).
As support for the Rt5350 is present in mtk_eth_soc at least that
sounds like it would be worth mentioning (or even naming the driver
and tagger interely after rt3050 which is the origin of that IP
block).

> +static int mt7628_mii_read(struct mii_bus *bus, int port, int regnum)
> +{
> +	struct mt7628_esw *esw = bus->priv;
> +	int ret;
> +	u32 val;
> +
> +	ret =
> +	    regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,

Unnecessary linebreak.

> +				     !(val & MT7628_ESW_PCR1_RD_DONE), 10,
> +				     5000);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_write(esw->regmap, MT7628_ESW_REG_PCR0,
> +			   FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_REG,
> +				      regnum) |
> +			   FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_ADDR,
> +				      port) | MT7628_ESW_PCR0_RD_PHY_CMD);
> +	if (ret)
> +		goto out;
> +
> +	ret =
> +	    regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,

Here as well.

> +				     (val & MT7628_ESW_PCR1_RD_DONE), 10,
> +				     5000);
> +out:
> +	if (ret) {
> +		dev_err(&bus->dev, "read failed. MDIO timeout?\n");
> +		return -ETIMEDOUT;
> +	}
> +	return FIELD_GET(MT7628_ESW_PCR1_RD_DATA, val);
> +}
> +
> +static int mt7628_mii_write(struct mii_bus *bus, int port, int regnum,
> +			    u16 dat)
> +{
> +	struct mt7628_esw *esw = bus->priv;
> +	u32 val;
> +	int ret;
> +
> +	ret =
> +	    regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,

Here as well.

> +				     !(val & MT7628_ESW_PCR1_WT_DONE), 10,
> +				     5000);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_write(esw->regmap, MT7628_ESW_REG_PCR0,
> +			   FIELD_PREP(MT7628_ESW_PCR0_WT_NWAY_DATA, dat) |
> +			   FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_REG,
> +				      regnum) |
> +			   FIELD_PREP(MT7628_ESW_PCR0_CPU_PHY_ADDR,
> +				      port) | MT7628_ESW_PCR0_WT_PHY_CMD);
> +	if (ret)
> +		goto out;
> +
> +	ret =
> +	    regmap_read_poll_timeout(esw->regmap, MT7628_ESW_REG_PCR1, val,

And here as well.

> [...]
> +static void esw_set_vlan_id(struct mt7628_esw *esw, unsigned int vlan,
> +			    unsigned int vid)
> +{
> +	unsigned int s = MT7628_ESW_VLANI_VID_S * (vlan % 2);
> +
> +	regmap_update_bits(esw->regmap, MT7628_ESW_REG_VLANI(vlan / 2),
> +			   MT7628_ESW_VLANI_VID_M << s,
> +			   (vid & MT7628_ESW_VLANI_VID_M) << s);

Please add helper macros for those registers and field in them

> +}
> +
> +static void esw_set_pvid(struct mt7628_esw *esw, unsigned int port,
> +			 unsigned int pvid)
> +{
> +	unsigned int s = MT7628_ESW_PVIDC_PVID_S * (port % 2);
> +
> +	regmap_update_bits(esw->regmap, MT7628_ESW_REG_PVIDC(port / 2),
> +			   MT7628_ESW_PVIDC_PVID_M << s,
> +			   (pvid & MT7628_ESW_PVIDC_PVID_M) << s);

and those as well

> +}
> +
> +static void esw_set_vmsc(struct mt7628_esw *esw, unsigned int vlan,
> +			 unsigned int msc)
> +{
> +	unsigned int s = MT7628_ESW_VMSC_MSC_S * (vlan % 4);
> +
> +	regmap_update_bits(esw->regmap, MT7628_ESW_REG_VMSC(vlan / 4),
> +			   MT7628_ESW_VMSC_MSC_M << s,
> +			   (msc & MT7628_ESW_VMSC_MSC_M) << s);

those too

> +}
> +
> +static void esw_set_vub(struct mt7628_esw *esw, unsigned int vlan,
> +			unsigned int msc)
> +{
> +	unsigned int s = MT7628_ESW_VUB_S * (vlan % 4);
> +
> +	regmap_update_bits(esw->regmap, MT7628_ESW_REG_VUB(vlan / 4),
> +			   MT7628_ESW_VUB_M << s,
> +			   (msc & MT7628_ESW_VUB_M) << s);

and those.

> [...]
> +static void mt7628_phylink_get_caps(struct dsa_switch *ds, int port,
> +				    struct phylink_config *config)
> +{
> +	config->mac_capabilities = MAC_100 | MAC_10;
> +	__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
> +	__set_bit(PHY_INTERFACE_MODE_GMII, config->supported_interfaces);

This looks a bit wrong.
Aren't all 5 PHYs internal? PHY_INTERFACE_INTERNAL would be best to
describe them then. And doesn't the CPU port (6) connect with 1000M,
if so it should have MAC_1000 set as well (as neither the Ethernet
driver nor the DSA driver do anything to configure the interface that
is purely cosmetic, but still)

Iff you want to support port 5 on Rt3052 (which will also require
setting the correct interface mode in .mac_config) I'd expect something
like this:

config->mac_capabilities = MAC_100 | MAC_10;

switch (port) {
case 0...4:
	__set_bit(PHY_INTERFACE_INTERNAL, config->supported_interfaces);
	break;
case 5:
	__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
	__set_bit(PHY_INTERFACE_MODE_REVMII, config->supported_interfaces);
	__set_bit(PHY_INTERFACE_MODE_RMII, config->supported_interfaces);
	__set_bit(PHY_INTERFACE_MODE_RGMII, config->supported_interfaces);
	config->mac_capabilities |= MAC_1000;
	break;
case 6:
	__set_bit(PHY_INTERFACE_INTERNAL, config->supported_interfaces);
	config->mac_capabilities |= MAC_1000;
	break;
default:
	return;
}

If you don't want to deal with port 5 you should skip it here as well.


Cheers


Daniel

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

* Re: [RFC v2 3/3] net: dsa: initial support for MT7628 embedded switch
  2026-03-14 23:41   ` Daniel Golle
@ 2026-03-15  7:02     ` Joris Vaišvila
  0 siblings, 0 replies; 10+ messages in thread
From: Joris Vaišvila @ 2026-03-15  7:02 UTC (permalink / raw)
  To: Daniel Golle
  Cc: netdev, horms, pabeni, kuba, edumazet, davem, olteanv,
	Andrew Lunn

On Sat, Mar 14, 2026 at 11:41:28PM +0000, Daniel Golle wrote:
> > The switch has 5 built-in 100Mbps ports (ports 0-4) and 2x 1Gbps ports.
> > One of the 1Gbps ports (port 6) is internally attached to the SoCs CPU
> > MAC and serves as the CPU port. The other 1Gbps port (port 5) requires
> > an external MAC to function.
> 
> I thought port 5 is a dead-end on MT76x8. Afaik it was only used on
> Ralink Rt3052 for RGMII/xMII with this switch IP, and not wired to
> any external pins nor to an internal MAC on all other SoCs which came
> after.

I assumed this was true as that's what the datasheet says, but looking
at the pinout it really doesn't have any pins to attach an external mac.

> > +	  This enables support for the switch in the MT7628 SoC.
> 
> And potentially many others (Rt3052, Rt3050, Rt3352, Rt5350).
> As support for the Rt5350 is present in mtk_eth_soc at least that
> sounds like it would be worth mentioning (or even naming the driver
> and tagger interely after rt3050 which is the origin of that IP
> block).

The RT3050 does not support all the same features the RT5350 does (which
I believe the MT7628 is based on). The DSA tag is now set up in a way
that only the MT7628 and potentially RT5350 can support. The DSA tag
does not appear to be working as described in the datasheet on these
switches and I do not have any of the ralink switches to test this on.
I don't think it's a good idea to assert support for hardware that has
not been tested with this.

I thought it would be fitting for the driver to be called after the
MT7628 as that would be the first supported SoC and add support for the
ralink switches later.

> > [...]
> > +static void mt7628_phylink_get_caps(struct dsa_switch *ds, int port,
> > +				    struct phylink_config *config)
> > +{
> > +	config->mac_capabilities = MAC_100 | MAC_10;
> > +	__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
> > +	__set_bit(PHY_INTERFACE_MODE_GMII, config->supported_interfaces);
> 
> This looks a bit wrong.
> Aren't all 5 PHYs internal? PHY_INTERFACE_INTERNAL would be best to
> describe them then. And doesn't the CPU port (6) connect with 1000M,
> if so it should have MAC_1000 set as well (as neither the Ethernet
> driver nor the DSA driver do anything to configure the interface that
> is purely cosmetic, but still)

Will fix this and coding style issues in v3.

> Iff you want to support port 5 on Rt3052 (which will also require
> setting the correct interface mode in .mac_config) I'd expect something
> like this:
> 
> config->mac_capabilities = MAC_100 | MAC_10;
> 
> switch (port) {
> case 0...4:
> 	__set_bit(PHY_INTERFACE_INTERNAL, config->supported_interfaces);
> 	break;
> case 5:
> 	__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
> 	__set_bit(PHY_INTERFACE_MODE_REVMII, config->supported_interfaces);
> 	__set_bit(PHY_INTERFACE_MODE_RMII, config->supported_interfaces);
> 	__set_bit(PHY_INTERFACE_MODE_RGMII, config->supported_interfaces);
> 	config->mac_capabilities |= MAC_1000;
> 	break;
> case 6:
> 	__set_bit(PHY_INTERFACE_INTERNAL, config->supported_interfaces);
> 	config->mac_capabilities |= MAC_1000;
> 	break;
> default:
> 	return;
> }
> 
> If you don't want to deal with port 5 you should skip it here as well.

Will skip port 5 for now, due to this driver likely not working on
RT3052 as it is anyway for the aforementioned reasons.

Thanks for the review.

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

* Re: [RFC v2 1/3] net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet PHYs
  2026-03-14 15:08 ` [RFC v2 1/3] net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet PHYs Joris Vaisvila
@ 2026-03-17 18:03   ` Andrew Lunn
  2026-03-21 11:35     ` Joris Vaisvila
  0 siblings, 1 reply; 10+ messages in thread
From: Andrew Lunn @ 2026-03-17 18:03 UTC (permalink / raw)
  To: Joris Vaisvila; +Cc: netdev, horms, pabeni, kuba, edumazet, davem, olteanv

> diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig
> index bb7dc876271e..62355d46cb1e 100644
> --- a/drivers/net/phy/mediatek/Kconfig
> +++ b/drivers/net/phy/mediatek/Kconfig
> @@ -36,5 +36,11 @@ config MEDIATEK_GE_SOC_PHY
>  	  present in the SoCs efuse and will dynamically calibrate VCM
>  	  (common-mode voltage) during startup.
>  
> +config MEDIATEK_FE_SOC_PHY
> +	tristate "MediaTek MT7628 SoC Ethernet PHYs"
> +	select PHY_PACKAGE
> +	help
> +	  Support for MediaTek MT7628 built-in Fast Ethernet PHYs.
> +

This file is sorted by tristate string.

It might be best to change:

config MEDIATEK_GE_SOC_PHY
-        tristate "MediaTek SoC Ethernet PHYs"
+        tristate "MediaTek SoC Gigabit Ethernet PHYs"

And then you can add

> +config MEDIATEK_FE_SOC_PHY
> +	tristate "MediaTek SoC Fast Ethernet PHYs"

before?

Also, why do you have `select PHY_PACKAGE`?

>  obj-$(CONFIG_MEDIATEK_2P5GE_PHY)	+= mtk-2p5ge.o
>  obj-$(CONFIG_MEDIATEK_GE_PHY)		+= mtk-ge.o
>  obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)	+= mtk-ge-soc.o
> +obj-$(CONFIG_MEDIATEK_FE_SOC_PHY)	+= mtk-fe-soc.o
>  obj-$(CONFIG_MTK_NET_PHYLIB)		+= mtk-phy-lib.o

Please sort alphabetically. 

> +static struct phy_driver mtk_soc_fe_phy_driver[] = {
> +	{
> +		PHY_ID_MATCH_EXACT(MTK_FPHY_ID_MT7628),
> +		.name = "MediaTek MT7628 PHY",
> +		.config_init = mt7628_phy_config_init,
> +		.config_intr = genphy_no_config_intr,
> +		.handle_interrupt = genphy_handle_interrupt_no_ack,

How do interrupts work in this device? Has this been simply
cut/pasted, or have interrupts been tested using these functions?

	Andrew

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

* Re: [RFC v2 1/3] net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet PHYs
  2026-03-17 18:03   ` Andrew Lunn
@ 2026-03-21 11:35     ` Joris Vaisvila
  0 siblings, 0 replies; 10+ messages in thread
From: Joris Vaisvila @ 2026-03-21 11:35 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: netdev, horms, pabeni, kuba, edumazet, davem, olteanv

Hi Andrew, thanks for the feedback.

On Tue, Mar 17, 2026 at 07:03:03PM +0100, Andrew Lunn wrote:
> > +config MEDIATEK_FE_SOC_PHY
> > +	tristate "MediaTek MT7628 SoC Ethernet PHYs"
> > +	select PHY_PACKAGE
> > +	help
> > +	  Support for MediaTek MT7628 built-in Fast Ethernet PHYs.
> > +
> 
> This file is sorted by tristate string.
> 
> It might be best to change:
> 
> config MEDIATEK_GE_SOC_PHY
> -        tristate "MediaTek SoC Ethernet PHYs"
> +        tristate "MediaTek SoC Gigabit Ethernet PHYs"
> 
> And then you can add
> 
> > +config MEDIATEK_FE_SOC_PHY
> > +	tristate "MediaTek SoC Fast Ethernet PHYs"
> 
> before?
> Also, why do you have `select PHY_PACKAGE`?

Will fix naming and sorting in v3. PHY_PACKAGE is not needed, remaint
from testing.

> >  obj-$(CONFIG_MEDIATEK_2P5GE_PHY)	+= mtk-2p5ge.o
> >  obj-$(CONFIG_MEDIATEK_GE_PHY)		+= mtk-ge.o
> >  obj-$(CONFIG_MEDIATEK_GE_SOC_PHY)	+= mtk-ge-soc.o
> > +obj-$(CONFIG_MEDIATEK_FE_SOC_PHY)	+= mtk-fe-soc.o
> >  obj-$(CONFIG_MTK_NET_PHYLIB)		+= mtk-phy-lib.o
> 
> Please sort alphabetically. 

will fix in v3. 

> > +static struct phy_driver mtk_soc_fe_phy_driver[] = {
> > +	{
> > +		PHY_ID_MATCH_EXACT(MTK_FPHY_ID_MT7628),
> > +		.name = "MediaTek MT7628 PHY",
> > +		.config_init = mt7628_phy_config_init,
> > +		.config_intr = genphy_no_config_intr,
> > +		.handle_interrupt = genphy_handle_interrupt_no_ack,
> 
> How do interrupts work in this device? Has this been simply
> cut/pasted, or have interrupts been tested using these functions?
> 
> 	Andrew

Misunderstood the function and copied from other drivers, will re-test
and fix or remove in v3.

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

end of thread, other threads:[~2026-03-21 11:35 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-14 15:08 [RFC v2 0/3] net: dsa: MT7628 embedded switch initial support Joris Vaisvila
2026-03-14 15:08 ` [RFC v2 1/3] net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet PHYs Joris Vaisvila
2026-03-17 18:03   ` Andrew Lunn
2026-03-21 11:35     ` Joris Vaisvila
2026-03-14 15:08 ` [RFC v2 2/3] net: dsa: initial MT7628 tagging driver Joris Vaisvila
2026-03-14 17:59   ` Daniel Golle
2026-03-14 20:46     ` Joris Vaišvila
2026-03-14 15:08 ` [RFC v2 3/3] net: dsa: initial support for MT7628 embedded switch Joris Vaisvila
2026-03-14 23:41   ` Daniel Golle
2026-03-15  7:02     ` Joris Vaišvila

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