From nobody Fri Sep 25 06:46:59 2026 Received: from mail.cjdns.fr (mail.cjdns.fr [5.135.140.105]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DABEF340D90; Tue, 15 Sep 2026 17:47:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=5.135.140.105 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494433; cv=none; b=kQH+Mwh3CHwS2+u4/eF2Fb5sQwhaFKPmjhU3UaJFf6SRzk4vyVxNEJCdTH1iiyBCivmFSx01YKPg8Icyg85GXIMnx81eu3NjI/EKkTdddyImusblznBLlVVecKbc+wMharCOC2SR4eKEIfnU2gWWfteoU+DtimOJtko4jO5Ix00= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494433; c=relaxed/simple; bh=rnJ5PP3WTQ9SnOO9xfsFTo5nsF8/8bVCj6N/zeIbd0I=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Pr4472oP4Y0e1AFV7vRMbRfkXxPB0XdmL+bbCIhFVOYBZbIsA1xar7Q1K29b91weJjLrittOLLxzcM46PYyheSsoM83z1Dv5bOK2IUpOKIxdhGZgvfJlGnDoz4y+h+4UEOQbd5AqdXLR10cyG5fx5Dlx+BfluVzgLiRc5unXZIA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr; spf=pass smtp.mailfrom=cjdns.fr; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b=fRijTCb3; arc=none smtp.client-ip=5.135.140.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b="fRijTCb3" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id CC6A748FE85; Tue, 15 Sep 2026 19:46:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cjdns.fr; s=dkim; t=1789494422; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=21vUyi7K+kEoEDI7cJRalDEdEnSV2omSUb/Jt0XHM9c=; b=fRijTCb3AT5QBwGoe/Krb0ze6yISm2hsArZksSwu4Lzar3DR6TQS/8qMB5mn3uRh9U91Iw y1gbVDIk98jZLqFw5TBNM8rlEdorK4edEfPMlzQu6RWy8E9GbdqVArk/GJUHwYFDH75RXU JPyD5wKgxdiG0TGYGKvvH+4i24aBizdG4F2uf3OxnunxTDCBppIu8KFskwrJh/tBJ3e+hG ko5i/vIqw9knwdBVYfWBAK9JlvA5PwyRiWfdbZ5YQfabbVX8ZLvoV99ThTjm4XqlmR6rPH sAfGoTxiADsxgHMny749pQ0MeF4/0H2vQFGzk+7k1EwIjWCbnQAi9rfDqf8pWg== From: Caleb James DeLisle To: netdev@vger.kernel.org Cc: andrew@lunn.ch, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, chester.a.unal@arinc9.com, daniel@makrotopia.org, linux@armlinux.org.uk, arinc.unal@arinc9.com, Landen.Chao@mediatek.com, dqfext@gmail.com, sean.wang@mediatek.com, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, naseefkm@gmail.com, b.larsson@gmx.com, Caleb James DeLisle Subject: [PATCH v2 net-next 1/7] net: dsa: mt7530: get ctrl phy addr using a function Date: Tue, 15 Sep 2026 17:46:37 +0000 Message-Id: <20260915174643.253660-2-cjd@cjdns.fr> In-Reply-To: <20260915174643.253660-1-cjd@cjdns.fr> References: <20260915174643.253660-1-cjd@cjdns.fr> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" The MDIO MT7530 has 5 integrated PHYs, of these, the first PHY has the additional registers that are used for such things as configuring the clock configuration for the switch. The switch is typically on MDIO address 31 and the PHYs are 0, 1, 2, 3, and 4 with 0 being the special one. So taking the address of mdiodev (the switch) add 1 and modulo 31 finds the first PHY. However there are a number of MMIO based implementations of MT7530 and on these, mdiodev is NULL though they often still have a control PHY for the purpose. Move MT753X_CTRL_PHY_ADDR to a function which handles the NULL condition somewhat more gracefully and allows a place for MMIO implementations to add special case handling to provide their control PHY address. Signed-off-by: Caleb James DeLisle --- drivers/net/dsa/mt7530.c | 54 +++++++++++++++++++++------------------- drivers/net/dsa/mt7530.h | 2 -- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 14692497e1a6..54d931002bc1 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -46,6 +46,16 @@ static const struct mt7530_mib_desc mt7530_mib[] =3D { MIB_DESC(1, MT7530_PORT_MIB_RX_ARL_DROP, "RxArlDrop"), }; =20 +static int +mt753x_ctrl_phy_addr(struct mt7530_priv *priv) +{ + if (WARN_ON_ONCE(!priv->mdiodev)) + return 0; + + /* Default is 1st PHY */ + return (priv->mdiodev->addr + 1) & (PHY_MAX_ADDR - 1); +} + static void mt7530_mutex_lock(struct mt7530_priv *priv) { @@ -63,32 +73,30 @@ mt7530_mutex_unlock(struct mt7530_priv *priv) static void core_write(struct mt7530_priv *priv, u32 reg, u32 val) { + int ctl_phy =3D mt753x_ctrl_phy_addr(priv); struct mii_bus *bus =3D priv->bus; int ret; =20 mt7530_mutex_lock(priv); =20 /* Write the desired MMD Devad */ - ret =3D bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr), - MII_MMD_CTRL, MDIO_MMD_VEND2); + ret =3D bus->write(bus, ctl_phy, MII_MMD_CTRL, MDIO_MMD_VEND2); if (ret < 0) goto err; =20 /* Write the desired MMD register address */ - ret =3D bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr), - MII_MMD_DATA, reg); + ret =3D bus->write(bus, ctl_phy, MII_MMD_DATA, reg); if (ret < 0) goto err; =20 /* Select the Function : DATA with no post increment */ - ret =3D bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr), + ret =3D bus->write(bus, ctl_phy, MII_MMD_CTRL, MDIO_MMD_VEND2 | MII_MMD_CTRL_NOINCR); if (ret < 0) goto err; =20 /* Write the data into MMD's selected register */ - ret =3D bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr), - MII_MMD_DATA, val); + ret =3D bus->write(bus, ctl_phy, MII_MMD_DATA, val); err: if (ret < 0) dev_err(&bus->dev, "failed to write mmd register\n"); @@ -99,6 +107,7 @@ core_write(struct mt7530_priv *priv, u32 reg, u32 val) static void core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set) { + int ctl_phy =3D mt753x_ctrl_phy_addr(priv); struct mii_bus *bus =3D priv->bus; u32 val; int ret; @@ -106,26 +115,23 @@ core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask,= u32 set) mt7530_mutex_lock(priv); =20 /* Write the desired MMD Devad */ - ret =3D bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr), - MII_MMD_CTRL, MDIO_MMD_VEND2); + ret =3D bus->write(bus, ctl_phy, MII_MMD_CTRL, MDIO_MMD_VEND2); if (ret < 0) goto err; =20 /* Write the desired MMD register address */ - ret =3D bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr), - MII_MMD_DATA, reg); + ret =3D bus->write(bus, ctl_phy, MII_MMD_DATA, reg); if (ret < 0) goto err; =20 /* Select the Function : DATA with no post increment */ - ret =3D bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr), + ret =3D bus->write(bus, ctl_phy, MII_MMD_CTRL, MDIO_MMD_VEND2 | MII_MMD_CTRL_NOINCR); if (ret < 0) goto err; =20 /* Read the content of the MMD's selected register */ - ret =3D bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr), - MII_MMD_DATA); + ret =3D bus->read(bus, ctl_phy, MII_MMD_DATA); if (ret < 0) goto err; val =3D ret; @@ -133,8 +139,7 @@ core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u= 32 set) val &=3D ~mask; val |=3D set; /* Write the data into MMD's selected register */ - ret =3D bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr), - MII_MMD_DATA, val); + ret =3D bus->write(bus, ctl_phy, MII_MMD_DATA, val); err: if (ret < 0) dev_err(&bus->dev, "failed to write mmd register\n"); @@ -2674,8 +2679,11 @@ mt7531_setup(struct dsa_switch *ds) { struct mt7530_priv *priv =3D ds->priv; u32 val, id; + int ctl_phy; int ret, i; =20 + ctl_phy =3D mt753x_ctrl_phy_addr(priv); + /* Reset whole chip through gpio pin or memory-mapped registers for * different type of hardware */ @@ -2743,25 +2751,21 @@ mt7531_setup(struct dsa_switch *ds) * phy_[read,write]_mmd_indirect is called, we provide our own * mt7531_ind_mmd_phy_[read,write] to complete this function. */ - ret =3D mt7531_ind_c45_phy_read(priv, - MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr), - MDIO_MMD_VEND2, CORE_PLL_GROUP4); + ret =3D mt7531_ind_c45_phy_read(priv, ctl_phy, MDIO_MMD_VEND2, + CORE_PLL_GROUP4); if (ret < 0) return ret; =20 val =3D ret; val |=3D MT7531_RG_SYSPLL_DMY2 | MT7531_PHY_PLL_BYPASS_MODE; val &=3D ~MT7531_PHY_PLL_OFF; - ret =3D mt7531_ind_c45_phy_write(priv, - MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr), - MDIO_MMD_VEND2, CORE_PLL_GROUP4, val); + ret =3D mt7531_ind_c45_phy_write(priv, ctl_phy, MDIO_MMD_VEND2, + CORE_PLL_GROUP4, val); if (ret < 0) return ret; =20 /* Disable EEE advertisement on the switch PHYs. */ - for (i =3D MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr); - i < MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr) + MT7530_NUM_PHYS; - i++) { + for (i =3D ctl_phy; i < ctl_phy + MT7530_NUM_PHYS; i++) { mt7531_ind_c45_phy_write(priv, i, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0); } diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 2bbbe617b52e..3dabbc99fbbc 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -747,8 +747,6 @@ enum mt7531_xtal_fsel { #define MT7531_PHY_PLL_OFF BIT(5) #define MT7531_PHY_PLL_BYPASS_MODE BIT(4) =20 -#define MT753X_CTRL_PHY_ADDR(addr) (((addr) + 1) & (PHY_MAX_ADDR - 1)) - #define CORE_PLL_GROUP5 0x404 #define RG_LCDDS_PCW_NCPO1_MASK GENMASK(15, 0) #define RG_LCDDS_PCW_NCPO1(x) FIELD_PREP(RG_LCDDS_PCW_NCPO1_MASK, x) --=20 2.39.5 From nobody Fri Sep 25 06:46:59 2026 Received: from mail.cjdns.fr (mail.cjdns.fr [5.135.140.105]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D67B23F9A1A; Tue, 15 Sep 2026 17:47:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=5.135.140.105 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494432; cv=none; b=fL5caH/qjFu0znZ2tEBiO62WZoECK0NgtDA8qE6zpfAyz06jw02LaoqxKJ85XSuj405K5G0t6MFVdE8BfAUPKW7PevGYyj/XNh7pXygTuu/VM9F1sjCon2P4dKmnr6/vO6AMHKEcAxwUqkuwzl/EIhgyroA35mMp/StMgHWSVe0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494432; c=relaxed/simple; bh=8UZcZJFE0ZJjSbxEMH1gzEs2SO3POEXxd6LWfafuw6w=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=X36b6yp+1x+pSu4b0sIesFeKidhPOPRpOldTEG/eGADyfPLz7bd+J53/jbpvh57HFbq4jl51BY9Qq+RJ0TkOsQU/JinS5PSmVyJON/XYitmZcrsYAqQJXsUtqnRZm6zaCCXs47pXPflzSe0nwU12OlE2HGC8sDzZM3PB0up1deo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr; spf=pass smtp.mailfrom=cjdns.fr; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b=DcBGrstM; arc=none smtp.client-ip=5.135.140.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b="DcBGrstM" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 9B36948F1D7; Tue, 15 Sep 2026 19:47:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cjdns.fr; s=dkim; t=1789494425; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=9+LSfF6WeN65ydsS+fKszA1mpUfPTI0QyNbajR7Gplk=; b=DcBGrstMfLx9yoDYxrN/8CrGgrPZ5Q4XJs14cpcSavxOgzq21UuhKFhZrDP0ev6EsahPyX 0iPQDXTfrmRoa+W3cvkWSyozvmH9luEptcqX3rxK6L84MvCzddcYauD/fT1k9YrNFDJFDr kDpa7fYzFjVC9Q89yzqxMqFYJROZfW0r+UG7Jr8HnOVwdaV+bD5tYe2+XeXZsEuktp/1Qz O2Q34pdpzVS8UPiCpIkcIGEuYhIs8LC3eNrpk6zgla+tszhz2upnMN5wmUEzg2sn0ZcqRX 8BJ8kX6K5XnsmTyrB53IaYTJxVfHt0ZzN43iULfcOLTQnGSf9wJH6e3V+qldZA== From: Caleb James DeLisle To: netdev@vger.kernel.org Cc: andrew@lunn.ch, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, chester.a.unal@arinc9.com, daniel@makrotopia.org, linux@armlinux.org.uk, arinc.unal@arinc9.com, Landen.Chao@mediatek.com, dqfext@gmail.com, sean.wang@mediatek.com, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, naseefkm@gmail.com, b.larsson@gmx.com, Caleb James DeLisle Subject: [PATCH v2 net-next 2/7] dt-bindings: net: dsa: mediatek,mt7530: add passthrough mode Date: Tue, 15 Sep 2026 17:46:38 +0000 Message-Id: <20260915174643.253660-3-cjd@cjdns.fr> In-Reply-To: <20260915174643.253660-1-cjd@cjdns.fr> References: <20260915174643.253660-1-cjd@cjdns.fr> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" MT7530 switches can be configured to blindly pass packets between their CPU/upstream port and a downstream DSA port, in particular, without altering the MediaTek DSA Tag on the packets. This mode is used in some integrations where an SoC integrated switch exists, but a more capable MCM switch is added to effectively replace it. Signed-off-by: Caleb James DeLisle Acked-by: Rob Herring (Arm) --- .../devicetree/bindings/net/dsa/mediatek,mt7530.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml= b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml index 90b3582b7619..e29fb8693498 100644 --- a/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml +++ b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml @@ -73,6 +73,13 @@ description: | =20 Check out example 7. =20 + The MT7530 and MT7531 switches are capable of being operated in "passthr= ough" + mode. In this mode, traffic is unconditionally passed between the CPU po= rt + and the DSA port which links to a second switch. To use passthrough mode= , the + upstream switch is configured with a DSA link to the downstream switch. = In + passthrough mode the upstream switch is restricted, with no other ports = or + switch configuration allowed. + properties: compatible: oneOf: --=20 2.39.5 From nobody Fri Sep 25 06:46:59 2026 Received: from mail.cjdns.fr (mail.cjdns.fr [5.135.140.105]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0FFE83F4DCA; Tue, 15 Sep 2026 17:47:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=5.135.140.105 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494442; cv=none; b=HY7YGqAKn9FHs8QGZIfwo4cVTavh9z9F65h1y+29Ip8FY+yl3cRdD08bLLZFEpOgzB7Hlc0c8D53yVz2C2BQKD/gWcyCBMbWjCvzO+BkYAPbnTbv3+Ielqj/SGsQahs0/+1j2M/zMNbvl0AyfmyIT252ZksuMpqvV62dARCfE5Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494442; c=relaxed/simple; bh=Fy0WYN5sPf3gkRqvwmUIdNan3vD2NMePpp8PKTBpfDc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=QkRbi5cAo5DIcm1+MKcjADC89YMyMLZf9v5OWbYfSO+G0LrmeO02x1LaXL9wLLEP/SQq8NJ5b3g+mFlXOOjB3P8E5zAaeSAoNELdnHqZ2ndsQdRebPcqXOikCTdjfe3DN+v/GjRqQ8FUi1pyE1DuJsUPEltgVVCMiYxT7JZ1SJ8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr; spf=none smtp.mailfrom=cjdns.fr; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b=Hkpj54R+; arc=none smtp.client-ip=5.135.140.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b="Hkpj54R+" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id E357648F9A8; Tue, 15 Sep 2026 19:47:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cjdns.fr; s=dkim; t=1789494434; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=56ZZFGKTZe46l0WN09lZLfibMWBczbgzk6VvR1nnJkA=; b=Hkpj54R+GRYljhd/KpRlGSkheDiLhNPFaKF+8mkBGXbsHcn7Ip3J7jEuCowDDnvBcqGrle dt8GGIjTdwDCU6VjlVkXIUrH9Vl25dODXfGMs82dDfoW3d11bZWJyAqod6hbrKeklZ19LF NhpK0qIgZbd1iZGdszRqhXT0no2FS66YLTC+kwCQg/mdc4uvJRyPyGFNCix1sBHbapRCcS ID4jetS/pgBQXkhEIxeW4mTIavbCpUZ92OkhrPOs+z6khnS/UmzXafmVV6SDOqAvl3txQ3 GKmjGok3CXe/qWhTzQWgTberle0s9s1dPl47Hg5iE9Rq8kpU6zh9MNT3lJSzEQ== From: Caleb James DeLisle To: netdev@vger.kernel.org Cc: andrew@lunn.ch, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, chester.a.unal@arinc9.com, daniel@makrotopia.org, linux@armlinux.org.uk, arinc.unal@arinc9.com, Landen.Chao@mediatek.com, dqfext@gmail.com, sean.wang@mediatek.com, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, naseefkm@gmail.com, b.larsson@gmx.com, Caleb James DeLisle Subject: [PATCH v2 net-next 3/7] net: dsa: mediatek: add support for passthrough mode Date: Tue, 15 Sep 2026 17:46:39 +0000 Message-Id: <20260915174643.253660-4-cjd@cjdns.fr> In-Reply-To: <20260915174643.253660-1-cjd@cjdns.fr> References: <20260915174643.253660-1-cjd@cjdns.fr> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" In some cases, hardware integrators add a second MT7530 switch to a port of the CPU-connected MT7530 and configure the upstream switch to pass all traffic to and from the downstream switch. Particularly, without altering the MediaTek DSA tag. The typical reason for this is because the downstream switch is more capable, but the upstream switch is an irremovable part of the SoC. To enable passthrough, the main switch has its CPU port, and the port to the second switch, both configured as MT7530_VLAN_EG_DISABLED and MT7530_VLAN_TRANSPARENT and it uses the port matrix to control forwarding. Support passing through to a downstream switch, and also support being the downstream switch - meaning the upstream link is not a CPU port but rather a DSA port. As a point of information: There exist features in the hardware which appear to enable full two-switch hierarchies (i.e. ports on the upstream switch are also available for use). The way that this is supposed to work is though a PASSTHROUGH flag in the DSA tag on BIT(7). The downstream switch sets a flag called "PT_OPTION" on the PVC register of its "CPU" port (the port linking to the upstream switch). This causes the downstream switch to set the PASSTHROUGH flag on all ingress traffic. The CPU then sets the PASSTHROUGH flag on egress traffic meant for the downstream switch. In this configuration, the upstream switch sets MT7530_VLAN_USER, and PORT_SPEC_TAG on the (real) CPU port (as usual), but also sets it on the port leading to the downstream switch. The PORT_SPEC_TAG flag on the downstream link port causes incoming DSA tags to be copied over rather than being replaced by tags identifying the traffic as having come from the link port. Finally, an ACL is installed which causes the upstream switch to forward all egress traffic with the PASSTHROUGH bit to the link port. However for reasons unknown, the PASSTHROUGH bit is cleared by the upstream switch as it receives ingress traffic from the downstream switch. So by the time the traffic reaches the CPU, it no longer bears the PASSTHROUGH bit and its origin cannot be known. Reference code defaults to passthrough mode as is implemented here, but supports a limited hierarchical implementation for hardware that needs it. In this mode it is not permitted to use the same port number on both switches. This implementation does not implement that mode because there is no known hardware using ports on both switches. Signed-off-by: Caleb James DeLisle --- drivers/net/dsa/mt7530.c | 164 +++++++++++++++++++++++++++++++++++---- drivers/net/dsa/mt7530.h | 6 ++ 2 files changed, 153 insertions(+), 17 deletions(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 54d931002bc1..b2344808457c 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -1286,13 +1286,41 @@ mt753x_trap_frames(struct mt7530_priv *priv) TO_CPU_FW_CPU_ONLY); } =20 +static int +mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu); + +/* If this switch is downstream of another switch that is in passthrough m= ode, + * the "CPU" port is actually a DSA port. + */ static void mt753x_cpu_port_enable(struct dsa_switch *ds, int port) { struct mt7530_priv *priv =3D ds->priv; =20 - /* Enable Mediatek header mode on the cpu port */ - regmap_write(priv->regmap, MT7530_PVC_P(port), PORT_SPEC_TAG); + if (priv->is_passthrough) { + /* Disable parsing of the DSA tag, it will be forwarded blindly + * to the downstream switch. + */ + regmap_write(priv->regmap, MT7530_PVC_P(port), + VLAN_ATTR(MT7530_VLAN_TRANSPARENT) | + PVC_EG_TAG(MT7530_VLAN_EG_DISABLED)); + + /* The port is not configured to parse DSA tags, so they are + * liable to be confused for length fields, so length check is + * disabled. + */ + regmap_clear_bits(priv->regmap, MT753X_AGC, AGC_L2LEN_CHK); + + /* In passthrough mode, MTU is only enforced downstream */ + mt7530_port_change_mtu(ds, port, MT7530_MAX_MTU); + + /* Loop detection has no value in passthrough mode */ + regmap_set_bits(priv->regmap, MT753X_MTRAP, + MT7530_LOOP_DET_DISABLE); + } else { + /* Not passthrough, enable DSA tag handling on CPU port. */ + regmap_write(priv->regmap, MT7530_PVC_P(port), PORT_SPEC_TAG); + } =20 /* Enable flooding on the CPU port */ regmap_set_bits(priv->regmap, MT753X_MFC, @@ -1322,6 +1350,7 @@ static int mt7530_port_enable(struct dsa_switch *ds, int port, struct phy_device *phy) { + int upstream_pt =3D dsa_switch_upstream_port(ds); struct dsa_port *dp =3D dsa_to_port(ds, port); struct mt7530_priv *priv =3D ds->priv; =20 @@ -1332,13 +1361,38 @@ mt7530_port_enable(struct dsa_switch *ds, int port, * bridge. */ if (dsa_port_is_user(dp)) { - struct dsa_port *cpu_dp =3D dp->cpu_dp; + priv->ports[port].pm |=3D PCR_MATRIX(BIT(upstream_pt)); + + } else if (dsa_port_is_dsa(dp) && dp->index !=3D upstream_pt) { + priv->ports[port].pm |=3D PCR_MATRIX(BIT(upstream_pt)); + + /* Should not happen */ + WARN_ON_ONCE(!priv->is_passthrough); + + /* We are passing through to a downstream switch so we set both + * CPU and downstream link to pass traffic untouched so that + * the STAG from the downstream switch will pass to the upstream. + */ + regmap_write(priv->regmap, MT7530_PVC_P(port), + VLAN_ATTR(MT7530_VLAN_TRANSPARENT) | + PVC_EG_TAG(MT7530_VLAN_EG_DISABLED)); + + /* We let the downstream switch flood */ + regmap_set_bits(priv->regmap, MT753X_MFC, BC_FFP(BIT(port)) | + UNM_FFP(BIT(port)) | UNU_FFP(BIT(port))); =20 - priv->ports[port].pm |=3D PCR_MATRIX(BIT(cpu_dp->index)); + /* Make the upstream port able to connect to the DSA port. + * This must be explicit because PORT_SPEC_TAG is unset. + */ + regmap_write(priv->regmap, MT7530_PCR_P(upstream_pt), + PCR_MATRIX(BIT(port))); } priv->ports[port].enable =3D true; - regmap_update_bits(priv->regmap, MT7530_PCR_P(port), PCR_MATRIX_MASK, - priv->ports[port].pm); + + /* In passthrough mode, CPU port mask is set above. */ + if (!(priv->is_passthrough && dp->index =3D=3D upstream_pt)) + regmap_update_bits(priv->regmap, MT7530_PCR_P(port), + PCR_MATRIX_MASK, priv->ports[port].pm); =20 mutex_unlock(&priv->reg_mutex); =20 @@ -1390,7 +1444,7 @@ mt7530_port_change_mtu(struct dsa_switch *ds, int por= t, int new_mtu) * largest MTU of the user ports. Because the switch only has a global * RX length register, only allowing CPU port here is enough. */ - if (!dsa_is_cpu_port(ds, port)) + if (!dsa_is_upstream_port(ds, port)) return 0; =20 regmap_read(priv->regmap, MT7530_GMACCR, &val); @@ -2411,11 +2465,6 @@ mt7530_setup(struct dsa_switch *ds) break; } =20 - if (!dn) { - dev_err(ds->dev, "parent OF node of DSA conduit not found"); - return -EINVAL; - } - ds->assisted_learning_on_cpu_port =3D true; ds->untag_vlan_aware_bridge_pvid =3D true; ds->mtu_enforcement_ingress =3D true; @@ -2517,7 +2566,7 @@ mt7530_setup(struct dsa_switch *ds) /* Disable learning by default on all ports */ regmap_set_bits(priv->regmap, MT7530_PSC_P(i), SA_DIS); =20 - if (dsa_is_cpu_port(ds, i)) { + if (dsa_is_upstream_port(ds, i)) { mt753x_cpu_port_enable(ds, i); } else { mt7530_port_disable(ds, i); @@ -2541,7 +2590,7 @@ mt7530_setup(struct dsa_switch *ds) return ret; =20 /* Check for PHY muxing on port 5 */ - if (dsa_is_unused_port(ds, 5)) { + if (dn && dsa_is_unused_port(ds, 5)) { /* Scan the ethernet nodes. Look for GMAC1, lookup the used PHY. * Set priv->p5_mode to the appropriate value if PHY muxing is * detected. @@ -2641,7 +2690,7 @@ mt7531_setup_common(struct dsa_switch *ds) regmap_set_bits(priv->regmap, MT7531_DBG_CNT(i), MT7531_DIS_CLR); =20 - if (dsa_is_cpu_port(ds, i)) { + if (dsa_is_upstream_port(ds, i)) { mt753x_cpu_port_enable(ds, i); } else { mt7530_port_disable(ds, i); @@ -3310,7 +3359,7 @@ mt753x_conduit_state_change(struct dsa_switch *ds, =20 /* Set the CPU port to trap frames to for MT7530. Trapped frames will be * forwarded to the numerically smallest CPU port whose conduit - * interface is up. + * interface is up. NOTE: "CPU port" can also mean an upstream DSA link. */ if (priv->id !=3D ID_MT7530 && priv->id !=3D ID_MT7621 && priv->id !=3D ID_EN7528) @@ -3405,6 +3454,76 @@ static int mt7988_setup(struct dsa_switch *ds) return mt7531_setup_common(ds); } =20 +/* 1 if passthrough, negative if error. */ +static int mt753x_check_passthrough(struct device *dev) +{ + struct device_node *ports, *port; + int passthrough_ports =3D 0; + int enabled_ports =3D 0; + + ports =3D of_get_child_by_name(dev->of_node, "ports"); + if (!ports) + ports =3D of_get_child_by_name(dev->of_node, "ethernet-ports"); + + if (!ports) { + dev_err(dev, "no ports child node found\n"); + return -EINVAL; + } + + for_each_available_child_of_node(ports, port) { + struct device_node *link; + + enabled_ports++; + + link =3D of_parse_phandle(port, "ethernet", 0); + if (!link) + link =3D of_parse_phandle(port, "link", 0); + + if (!link) + continue; + + of_node_put(link); + + passthrough_ports++; + } + + of_node_put(ports); + + /* + * A switch is considered passthrough if exactly two available + * ports have an "ethernet" or "link" phandle. + */ + if (passthrough_ports > 2 || + (passthrough_ports =3D=3D 2 && enabled_ports !=3D 2) + ) { + dev_err(dev, "Only two ports allowed in passthrough mode\n"); + return -EINVAL; + } + + return passthrough_ports =3D=3D 2; +} + +/* No manipulation of forwarding rules allowed in passthrough mode */ +static const struct dsa_switch_ops mt7530_passthrough_switch_ops =3D { + .get_tag_protocol =3D mtk_get_tag_protocol, + .setup =3D mt753x_setup, + .teardown =3D mt753x_teardown, + .preferred_default_local_cpu_port =3D mt753x_preferred_default_local_cpu_= port, + .get_strings =3D mt7530_get_strings, + .get_ethtool_stats =3D mt7530_get_ethtool_stats, + .get_sset_count =3D mt7530_get_sset_count, + .get_eth_mac_stats =3D mt7530_get_eth_mac_stats, + .get_rmon_stats =3D mt7530_get_rmon_stats, + .get_eth_ctrl_stats =3D mt7530_get_eth_ctrl_stats, + .get_stats64 =3D mt7530_get_stats64, + .port_enable =3D mt7530_port_enable, + .port_disable =3D mt7530_port_disable, + .phylink_get_caps =3D mt753x_phylink_get_caps, + .support_eee =3D dsa_supports_eee, + .set_mac_eee =3D mt753x_set_mac_eee, + .conduit_state_change =3D mt753x_conduit_state_change, +}; + static const struct dsa_switch_ops mt7530_switch_ops =3D { .get_tag_protocol =3D mtk_get_tag_protocol, .setup =3D mt753x_setup, @@ -3537,8 +3656,12 @@ EXPORT_SYMBOL_GPL(mt753x_table); int mt7530_probe_common(struct mt7530_priv *priv) { + int passthrough =3D mt753x_check_passthrough(priv->dev); struct device *dev =3D priv->dev; =20 + if (passthrough < 0) + return passthrough; + priv->ds =3D devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL); if (!priv->ds) return -ENOMEM; @@ -3556,7 +3679,14 @@ mt7530_probe_common(struct mt7530_priv *priv) priv->id =3D priv->info->id; priv->dev =3D dev; priv->ds->priv =3D priv; - priv->ds->ops =3D &mt7530_switch_ops; + + if (passthrough) { + priv->ds->ops =3D &mt7530_passthrough_switch_ops; + priv->is_passthrough =3D true; + } else { + priv->ds->ops =3D &mt7530_switch_ops; + } + priv->ds->phylink_mac_ops =3D &mt753x_phylink_mac_ops; mutex_init(&priv->reg_mutex); spin_lock_init(&priv->stats_lock); diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 3dabbc99fbbc..108c831dd012 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -40,6 +40,7 @@ enum mt753x_id { /* Register for ARL global control */ #define MT753X_AGC 0xc #define LOCAL_EN BIT(7) +#define AGC_L2LEN_CHK BIT(4) =20 /* Register for MAC forward control */ #define MT753X_MFC 0x10 @@ -583,6 +584,7 @@ enum mt7531_clk_skew { #define MT753X_MTRAP 0x7804 #define MT7530_P5_PHY0_SEL BIT(20) #define MT7530_CHG_TRAP BIT(16) +#define MT7530_LOOP_DET_DISABLE BIT(14) #define MT7530_P5_MAC_SEL BIT(13) #define MT7530_P6_DIS BIT(8) #define MT7530_P5_RGMII_MODE BIT(7) @@ -897,6 +899,9 @@ struct mt753x_info { * @p5_mode: Holding the current mode of port 5 of the MT7530 switch * @p5_sgmii: Flag for distinguishing if port 5 of the MT7531 switch * has got SGMII + * @is_passthrough: If this switch is to pass traffic between the upstream + * (CPU) port and a second downstream switch, without + * altering the DSA tag. * @irq_domain: IRQ domain of the switch irq_chip * @create_sgmii: Pointer to function creating SGMII PCS instance(s) * @active_cpu_ports: Holding the active CPU ports @@ -921,6 +926,7 @@ struct mt7530_priv { bool p5_sgmii; u8 mirror_rx; u8 mirror_tx; + bool is_passthrough; struct mt7530_port ports[MT7530_NUM_PORTS]; struct mt753x_pcs pcs[MT7530_NUM_PORTS]; /* protect among processes for registers access*/ --=20 2.39.5 From nobody Fri Sep 25 06:46:59 2026 Received: from mail.cjdns.fr (mail.cjdns.fr [5.135.140.105]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 12CF943BDCB; Tue, 15 Sep 2026 17:47:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=5.135.140.105 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494445; cv=none; b=gPCW5pvyg7EETLvmOW8ahrvJHggOxoDReb0ab2y37+NByx5v8FcVcCN/IgtBHw/xbxSM0MYa4QR6eGjORxhzgSds7UWFeRvFSe0nG4ORciRoJhKllqe2KChRhJPn9QD3Tb2YiSd2IpnvTTIiDBZvXgCSdp26KHxr5ONa2dZvuMs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494445; c=relaxed/simple; bh=3xg1Gx4jh/PkxxndNHqZa3eS1s+bCmUMu9ni0hwYEXg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=B4B/FIbmw1zMbh3XYlKPmeS98SoGaMC00hEUami3Ec6thbPmG7lHCJW9cm1pqKiorkOfE6jfIori2uc1IIWjaOxsdRgyioAuyInkmRLAZRmFVexVpywct2q90kMJ4eoXyhttZogZeujOalkxsK62hecTwUehJPLNlWoox4EVCx8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr; spf=none smtp.mailfrom=cjdns.fr; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b=T7BpDmpw; arc=none smtp.client-ip=5.135.140.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b="T7BpDmpw" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 06C5448F929; Tue, 15 Sep 2026 19:47:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cjdns.fr; s=dkim; t=1789494440; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=qvPGDHjj/h5quxN39A7MZhJ00DBT2v1OT7d6avspqus=; b=T7BpDmpwLEP+Bkyld9jY/iUx5Ty4pF5OEIRoEAtgr6xYR1Yxfj7k1bmweQSxHb54TwTr2C VERsSNv7fqQfm4MKmkUC2/A275/GLVbCG5kQ4qWzOKqueRCxX86x2SsrkfzgH04IEJoeZA NTyHGVQz39Msmj70NOgZqxutto/enidYXVn3lAa9aZgZZNyeXv6sRTjttU5voOTWpZvEdt xasLhx65zmx88u1spcrKsEaVcKCx6ZPqBxO9jFwoJtSg9L5mS4Tslxw29JIMmRra4TWi89 rl+CIKpDSRWKEiGiLJGl1b4BEl4Csuz0IKjBNaFHM7p7AY28y2sFPb6M+176rw== From: Caleb James DeLisle To: netdev@vger.kernel.org Cc: andrew@lunn.ch, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, chester.a.unal@arinc9.com, daniel@makrotopia.org, linux@armlinux.org.uk, arinc.unal@arinc9.com, Landen.Chao@mediatek.com, dqfext@gmail.com, sean.wang@mediatek.com, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, naseefkm@gmail.com, b.larsson@gmx.com, Caleb James DeLisle Subject: [PATCH v2 net-next 4/7] net: dsa: mediatek: support PLL setup on MMIO MT7530 Date: Tue, 15 Sep 2026 17:46:40 +0000 Message-Id: <20260915174643.253660-5-cjd@cjdns.fr> In-Reply-To: <20260915174643.253660-1-cjd@cjdns.fr> References: <20260915174643.253660-1-cjd@cjdns.fr> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" On MT7530 and MT7531, PHYs are an integral part of the switch. However, on MT7530, certain configuration such as PLL setup is done via special registers on one of the PHYs. In an MMIO implementation, the MDIO bus is part of the switch itself. This bus is already setup for PHY calibration so begin using it for core switch PLL setup. Signed-off-by: Caleb James DeLisle --- drivers/net/dsa/mt7530.c | 15 +++++++++++++++ drivers/net/dsa/mt7530.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index b2344808457c..b152b73315d5 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -77,6 +77,12 @@ core_write(struct mt7530_priv *priv, u32 reg, u32 val) struct mii_bus *bus =3D priv->bus; int ret; =20 + if (!bus) + bus =3D priv->child_bus; + + if (WARN_ON_ONCE(!bus)) + return; + mt7530_mutex_lock(priv); =20 /* Write the desired MMD Devad */ @@ -112,6 +118,12 @@ core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, = u32 set) u32 val; int ret; =20 + if (!bus) + bus =3D priv->child_bus; + + if (WARN_ON_ONCE(!bus)) + return; + mt7530_mutex_lock(priv); =20 /* Write the desired MMD Devad */ @@ -2429,8 +2441,11 @@ mt7530_setup_mdio(struct mt7530_priv *priv) if (priv->irq_domain && !mnp) mt7530_setup_mdio_irq(priv); =20 + priv->child_bus =3D bus; + ret =3D devm_of_mdiobus_register(dev, bus, mnp); if (ret) { + priv->child_bus =3D NULL; dev_err(dev, "failed to register MDIO bus: %d\n", ret); if (priv->irq_domain && !mnp) mt7530_free_mdio_irq(priv); diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 108c831dd012..5b7394f6383c 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -886,6 +886,9 @@ struct mt753x_info { * @dev: The device pointer * @ds: The pointer to the dsa core structure * @bus: The bus used for the device and built-in PHY + * @child_bus: The bus created by the device, on MDIO implementations + * this is bus indirectly accesses `bus`, on MMIO + * implementations this bus is part of the switch. * @regmap: The regmap instance representing all switch registers * @rstc: The pointer to reset control used by MCM * @core_pwr: The power supplied into the core @@ -914,6 +917,7 @@ struct mt7530_priv { struct device *dev; struct dsa_switch *ds; struct mii_bus *bus; + struct mii_bus *child_bus; struct regmap *regmap; struct reset_control *rstc; struct regulator *core_pwr; --=20 2.39.5 From nobody Fri Sep 25 06:46:59 2026 Received: from mail.cjdns.fr (mail.cjdns.fr [5.135.140.105]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0182E429CCF; Tue, 15 Sep 2026 17:47:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=5.135.140.105 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494452; cv=none; b=a46vCGj3tZO+2me6eNVcJ03niAZipF2LbowMOAI30BmcF1LQHjxwG1SIGjp6zNtuZ+1N8rPvACWeTXSRfwPdZ+o7jSH45xmEkD/yQ4571GOP8+2oJTokX0BS5e6K4O9EdBe7kG9K3Pm3iu//P5bP0AIO0waQqqPX39FXBGqxzek= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494452; c=relaxed/simple; bh=ndKyiTc9a815gB3eWMfUb/cAVaKXG+E4YJVBzapvRk8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=AMrMhkCdX2xKTcR5Akidy5GwyQkW5DnI6e/mH4U27xHp2IVoo5nWz0CD/cxzYtsO9FtRmAxWaDUkWttACAk2RM9SrsvHj6CoRO+k/EiQFnMOFFnv1hhaDucXEVHHiFtMflqIqzLFiV7o2elnvtbtqUMgGZkDgfK3To/VVxx6FpU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr; spf=none smtp.mailfrom=cjdns.fr; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b=PCBxyxZm; arc=none smtp.client-ip=5.135.140.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b="PCBxyxZm" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 546B848DAF7; Tue, 15 Sep 2026 19:47:21 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cjdns.fr; s=dkim; t=1789494446; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=GMESSO5uRX+BzGOQEPo7sGcRIjoMAuqIfwV5Ju1NceI=; b=PCBxyxZmsZ9p0ZoT7lAV1pmvyKUa8WO3gEnQU390/z2piesrzcQ57X7rAjNSk22EbXJ+im jH8woiC9991zRxSmaH47CwgJy7MXBh6HrEhhK1Th6ZBlNzAMe+VzYhqSw5O+7UmRgCZzKP WWlinS1s2itKlo8A69V0Q6bAOVucWqEjjfFlTdbkj2ewyhF/62gX03Vaxhc2cgqW9HegPN IeTnSmi+hV3LHjLdbXY76qwGsazkhOa+ETYJw+PHQ4Fjy8FbNKGxL8YCAALkZDioMqpCFp i6sVSfFudX0/ZzoH5rdI/LaPbLrFrBd28dTmgtkPsKwTHXChkz2R124BEVlRiQ== From: Caleb James DeLisle To: netdev@vger.kernel.org Cc: andrew@lunn.ch, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, chester.a.unal@arinc9.com, daniel@makrotopia.org, linux@armlinux.org.uk, arinc.unal@arinc9.com, Landen.Chao@mediatek.com, dqfext@gmail.com, sean.wang@mediatek.com, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, naseefkm@gmail.com, b.larsson@gmx.com, Caleb James DeLisle Subject: [PATCH v2 net-next 5/7] net: dsa: mediatek: support MDIO switch downstream of MMIO switch Date: Tue, 15 Sep 2026 17:46:41 +0000 Message-Id: <20260915174643.253660-6-cjd@cjdns.fr> In-Reply-To: <20260915174643.253660-1-cjd@cjdns.fr> References: <20260915174643.253660-1-cjd@cjdns.fr> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" The MT7530 / MT7531 can connect via either MDIO or MMIO. In MMIO mode the switch provides its own MDIO bus which connects to its integrated PHYs, but also can be connected to other things, such as another switch. If the MDIO bus contains another switch, then the upstream switch will register but it will not setup the DSA tree because the downstream switch is missing. Without the complete DSA tree, mt753x_setup() will not be called on the switch and therefore mt7530_setup_mdio() is never called so the downstream switch never registers. Update mt7530_setup_mdio() so that it can be called multiple times, export the symbol, and call it again after dsa_register_switch() from mt7988_probe(). Signed-off-by: Caleb James DeLisle --- drivers/net/dsa/mt7530-mmio.c | 9 ++++++++- drivers/net/dsa/mt7530.c | 13 +++++++++---- drivers/net/dsa/mt7530.h | 10 ++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/drivers/net/dsa/mt7530-mmio.c b/drivers/net/dsa/mt7530-mmio.c index cf3bdb23a2d5..f387190a9539 100644 --- a/drivers/net/dsa/mt7530-mmio.c +++ b/drivers/net/dsa/mt7530-mmio.c @@ -61,7 +61,14 @@ mt7988_probe(struct platform_device *pdev) if (IS_ERR(priv->regmap)) return PTR_ERR(priv->regmap); =20 - return dsa_register_switch(priv->ds); + ret =3D dsa_register_switch(priv->ds); + + if (ret) + return ret; + + mt7530_setup_mdio(priv); + + return 0; } =20 static void mt7988_remove(struct platform_device *pdev) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index b152b73315d5..fe93be1ece7d 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -2404,7 +2404,7 @@ mt7530_free_mdio_irq(struct mt7530_priv *priv) } } =20 -static int +int mt7530_setup_mdio(struct mt7530_priv *priv) { struct device_node *mnp, *np =3D priv->dev->of_node; @@ -2414,6 +2414,10 @@ mt7530_setup_mdio(struct mt7530_priv *priv) static int idx; int ret =3D 0; =20 + /* Already done */ + if (priv->child_bus) + return 0; + mnp =3D of_get_child_by_name(np, "mdio"); =20 if (mnp && !of_device_is_available(mnp)) @@ -2438,9 +2442,6 @@ mt7530_setup_mdio(struct mt7530_priv *priv) bus->parent =3D dev; bus->phy_mask =3D ~ds->phys_mii_mask; =20 - if (priv->irq_domain && !mnp) - mt7530_setup_mdio_irq(priv); - priv->child_bus =3D bus; =20 ret =3D devm_of_mdiobus_register(dev, bus, mnp); @@ -2455,6 +2456,7 @@ mt7530_setup_mdio(struct mt7530_priv *priv) of_node_put(mnp); return ret; } +EXPORT_SYMBOL_GPL(mt7530_setup_mdio); =20 static int mt7530_setup(struct dsa_switch *ds) @@ -3285,6 +3287,9 @@ mt753x_setup(struct dsa_switch *ds) if (ret) return ret; =20 + if (priv->irq_domain && ds->user_mii_bus) + mt7530_setup_mdio_irq(priv); + /* Initialise the PCS devices */ for (i =3D 0; i < priv->ds->num_ports; i++) { priv->pcs[i].pcs.ops =3D priv->info->pcs_ops; diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 5b7394f6383c..c86bc4bca29b 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -969,6 +969,16 @@ struct mt7530_hw_stats { int mt7530_probe_common(struct mt7530_priv *priv); void mt7530_remove_common(struct mt7530_priv *priv); =20 +/* + * When an MMIO based switch has an MDIO bus which contains a downstream M= DIO + * switch, the MDIO bus is not normally setup until mt753x_setup() has been + * called. But mt753x_setup() is not called until DSA sees that every swit= ch in + * the tree has been probed. Calling mt7530_setup_mdio() after at the end = of + * the MMIO probe function allows the downstream switch to register, compl= eting + * the tree. + */ +int mt7530_setup_mdio(struct mt7530_priv *priv); + extern const struct mt753x_info mt753x_table[]; =20 #endif /* __MT7530_H */ --=20 2.39.5 From nobody Fri Sep 25 06:46:59 2026 Received: from mail.cjdns.fr (mail.cjdns.fr [5.135.140.105]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A04C643BDCB; Tue, 15 Sep 2026 17:47:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=5.135.140.105 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494459; cv=none; b=GpN6/dI657DWZZXNuyk7yx7jrYVubX3pGX2LdeXDRBW7H9xlV3iIhqNk37qWxW5kUXZT+0F2ieXShkgn5/+WP/CznoR7jF1KyR9hIJpWHQUiKKEAsaQ3IE+BhhagkLRQB5305wv5E2qSLYfLQ9e7zXWGsMrehMnomsZupH/MSiA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494459; c=relaxed/simple; bh=TqpjP5ctdbMBfjdQ3xchi3iQf5+kqiUB8ayK9Hx6gCQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=L5tK4D806tN1qhqUVX4AczQSaivp31v99XOO9qhTR1yA2w7oq0SUqniaqOOV+RGbJwlShUj9E4P9ziP7qVi497Hdv8DTQK1xnZKLYMY+uVtrfB3jSlgrZ9+Y85XAkeDiXD3ArrSLz9lK94LkzaHVRTGCuF34RKeFzB2bxQ+buRU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr; spf=none smtp.mailfrom=cjdns.fr; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b=oOkVdIbj; arc=none smtp.client-ip=5.135.140.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b="oOkVdIbj" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id DA8C948E84C; Tue, 15 Sep 2026 19:47:26 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cjdns.fr; s=dkim; t=1789494451; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=GbZ+kq+bXbuQJ0qyjJXlbpAYIP3f31dn92HzYKo8G1Y=; b=oOkVdIbjfxds+BRAwak3MjBBbThgCRfKwQF97ft0RzNuADZIZrZrBn4FnfgTUdexnc3b01 2Mw6vo7/YXm4F+Go7qoLc3vte35jgCWyzddzUU1JRyz1DrgFOezrSfzunWSB/ZeiH12swq QHN69XwxTQtD0gdAq7F/tcxM4Jkl6YzS45ztWZzDRyv7kdU7Uzg+rlvFsUsVdc2O0x7tre Sq6eQtqSpnlAAfVbOcaPyvSe8sirXcZpxbgm+wrUZI+nhpF1oiu/Q+pIBrkpFdcw/1RJmb u8jsB5lpjcEHBYNGTtecLu3UucJUaWoRhb3JM2IF7ShPgOl2LdYtQFNxq86paw== From: Caleb James DeLisle To: netdev@vger.kernel.org Cc: andrew@lunn.ch, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, chester.a.unal@arinc9.com, daniel@makrotopia.org, linux@armlinux.org.uk, arinc.unal@arinc9.com, Landen.Chao@mediatek.com, dqfext@gmail.com, sean.wang@mediatek.com, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, naseefkm@gmail.com, b.larsson@gmx.com, Caleb James DeLisle Subject: [PATCH v2 net-next 6/7] dt-bindings: net: dsa: mediatek,mt7530: add econet,en751221 Date: Tue, 15 Sep 2026 17:46:42 +0000 Message-Id: <20260915174643.253660-7-cjd@cjdns.fr> In-Reply-To: <20260915174643.253660-1-cjd@cjdns.fr> References: <20260915174643.253660-1-cjd@cjdns.fr> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" The EcoNet EN751221 MIPS SoC integrates an MT7530 switch memory-mapped in the SoC register space. It is similar to the econet,en7528-switch except that ports 0..3 are 10/100 only, port 4 has a gigabit PHY, and port 5 has no PHY, but is in some implementations connected to a downstream MT7530 multi-chip module via a TRGMII link. The downstream MT7530 is similar to the MT7621 multi-chip module and has all gigabit ports. Add the econet,en751221-switch compatible with the same constraints as the other built-in switches and also add the econet,en751221 multi-chip-module switch whose port 6 is configured as a DSA link port. Signed-off-by: Caleb James DeLisle --- .../bindings/net/dsa/mediatek,mt7530.yaml | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml= b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml index e29fb8693498..106c4087528d 100644 --- a/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml +++ b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml @@ -29,6 +29,12 @@ description: | and the switch registers are directly mapped into SoC's memory map rathe= r than using MDIO. The DSA driver currently doesn't support MT7620 variants. =20 + EcoNet EN751221 SoCs have a memory mapped MT7530 with 3x 10/100 PHYs and= 1x + gigabit PHY. Some EN751221 chips such as EN7513G and EN7526G have a mult= i-chip + module implementation of the MT7530 as well as the on-die switch. In the= se + packages, the multi-chip module is connected to port 5 of the on-die swi= tch + via a TRGMII link. + There is only the standalone version of MT7531. =20 Port 5 on MT7530 supports various configurations: @@ -111,6 +117,14 @@ properties: Built-in switch of the EcoNet EN7528 SoC const: econet,en7528-switch =20 + - description: + Built-in switch of EcoNet EN751221 SoC + const: econet,en751221-switch + + - description: + Multi-chip module MT7530 in EN751221 SoC + const: econet,en751221 + reg: maxItems: 1 =20 @@ -160,8 +174,8 @@ properties: mediatek,mcm: type: boolean description: - Used for MT7621AT, MT7621DAT, MT7621ST and MT7623AI SoCs which the M= T7530 - switch is a part of the multi-chip module. + Used for MT7621AT, MT7621DAT, MT7621ST, MT7623AI and EN751221 SoCs w= hich + the MT7530 switch is a part of the multi-chip module. =20 reset-gpios: description: | @@ -223,6 +237,20 @@ $defs: phy-mode: const: internal =20 + mt7530-passthrough-dsa-port: + patternProperties: + "^(ethernet-)?ports$": + patternProperties: + "^(ethernet-)?port@[0-6]$": + if: + required: [ link ] + then: + properties: + reg: + const: 6 + phy-mode: + const: trgmii + mt7530-dsa-port: patternProperties: "^(ethernet-)?ports$": @@ -330,6 +358,7 @@ allOf: - airoha,en7581-switch - airoha,an7583-switch - econet,en7528-switch + - econet,en751221-switch then: $ref: "#/$defs/builtin-dsa-port" properties: @@ -337,6 +366,16 @@ allOf: mediatek,mcm: false reset-names: false =20 + - if: + properties: + compatible: + enum: + - econet,en751221 + then: + $ref: "#/$defs/mt7530-passthrough-dsa-port" + required: + - mediatek,mcm + unevaluatedProperties: false =20 examples: --=20 2.39.5 From nobody Fri Sep 25 06:46:59 2026 Received: from mail.cjdns.fr (mail.cjdns.fr [5.135.140.105]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5A01B4825CA; Tue, 15 Sep 2026 17:47:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=5.135.140.105 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494463; cv=none; b=IPhrWI4vS6HdMeZPwkjl+OZE0+xS2d++uTCWKqvkQz4IkWZUlg6CWmFqC1bw35UP66rZ5Fjo9DUv77psdGiCJQ+jXbBVGoD0N+uosKhy8KneANJPpJXR13JW7nmkejtWI55+rrbm6tVlpSS+PQTAdMxJsBLG+v1EJ5iGBAlWg/Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789494463; c=relaxed/simple; bh=6fNfxrZDzCaIW4H4pp19e78KOPaZAnM5Vj3OVJ+ug/s=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=EjgTH3TO7BbqE90w/VWwB/iwFRAJwZ/W+3nG0E98rHRjet6plIp18XXp9CUP53UC9NWabdbJuAxv3o4iKtz+njHpp6Iog1bdfSsjh3KLz+V3vs7i992bxLcJX4pZxlagKb5r/FqKxMT7iZaCjwZUmZHWAzLmDO6+use/WUyY6rA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr; spf=none smtp.mailfrom=cjdns.fr; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b=dT4ZsT3W; arc=none smtp.client-ip=5.135.140.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b="dT4ZsT3W" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 4813048ED6A; Tue, 15 Sep 2026 19:47:32 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cjdns.fr; s=dkim; t=1789494457; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=3ifsAkv76Mfb64m4aIbPLwbIMKCbWyQgZ3J+K691vWk=; b=dT4ZsT3WUqEa8B4zI1WNUkxK9JRg0A297r01Fph39ktACe/FpA7aD320ocjA8W4334Xp01 fNgKxm7QXROLHmCYolYDVpAXb5RaXIKjkjvqcxb7oLATxO56fy/nfwoK2X3tiL50te/UXU lMoDXw/Z+PMOjvH0BttqX0EtE26PAoDNXSM6HONw7iLQ0KJO6S870YtfVXd1MzOb0/i1be 8ck356FkFFOzGjPD0zpS2/yVW65BsVMS4N6DaD0jM/P+s69FKxogPzSQ3PjER+o9by8BcL KybitRIQLvwgIYXpK/p3URfTzj4OvhedM3oPDr84jt2ZijkCFd3MGf5G8LwbAQ== From: Caleb James DeLisle To: netdev@vger.kernel.org Cc: andrew@lunn.ch, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, matthias.bgg@gmail.com, angelogioacchino.delregno@collabora.com, chester.a.unal@arinc9.com, daniel@makrotopia.org, linux@armlinux.org.uk, arinc.unal@arinc9.com, Landen.Chao@mediatek.com, dqfext@gmail.com, sean.wang@mediatek.com, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-mediatek@lists.infradead.org, naseefkm@gmail.com, b.larsson@gmx.com, Caleb James DeLisle Subject: [PATCH v2 net-next 7/7] net: dsa: mediatek: support EN751221 switch Date: Tue, 15 Sep 2026 17:46:43 +0000 Message-Id: <20260915174643.253660-8-cjd@cjdns.fr> In-Reply-To: <20260915174643.253660-1-cjd@cjdns.fr> References: <20260915174643.253660-1-cjd@cjdns.fr> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" The EcoNet EN751221 has either one, or two, onboard MT7530 switches. Every implementation of this SoC has one switch on die with the CPU, but some chips - notably those with a "G" in the name, have a second MT7530 as an MCM module. The on-die MT7530 has 4 FE ports and 1 GE port. The MCM switch has all gigabit ports. The MCM switch connects to the SoC switch via a TRGMII link from port 5 on the SoC switch to port 6 on the MCM switch. This link undergoes calibration on startup. All known devices with the MCM present do not make any use of the ports on the on-die switch, it is put into "passthrough" mode in which all traffic is shuttled between port 6 and port 5 without alteration of the DSA tags. Add support for both the on-die and the MCM switch, and calibration of the TRGMII link between them. Signed-off-by: Caleb James DeLisle --- drivers/net/dsa/mt7530-mdio.c | 1 + drivers/net/dsa/mt7530-mmio.c | 1 + drivers/net/dsa/mt7530.c | 335 +++++++++++++++++++++++++++++++++- drivers/net/dsa/mt7530.h | 24 +++ 4 files changed, 357 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/mt7530-mdio.c b/drivers/net/dsa/mt7530-mdio.c index 24ef54f3db2a..2fd987ff8510 100644 --- a/drivers/net/dsa/mt7530-mdio.c +++ b/drivers/net/dsa/mt7530-mdio.c @@ -139,6 +139,7 @@ mt7531_create_sgmii(struct mt7530_priv *priv) } =20 static const struct of_device_id mt7530_of_match[] =3D { + { .compatible =3D "econet,en751221", .data =3D &mt753x_table[ID_EN751221_= EXT], }, { .compatible =3D "mediatek,mt7621", .data =3D &mt753x_table[ID_MT7621], = }, { .compatible =3D "mediatek,mt7530", .data =3D &mt753x_table[ID_MT7530], = }, { .compatible =3D "mediatek,mt7531", .data =3D &mt753x_table[ID_MT7531], = }, diff --git a/drivers/net/dsa/mt7530-mmio.c b/drivers/net/dsa/mt7530-mmio.c index f387190a9539..b77e3cb655aa 100644 --- a/drivers/net/dsa/mt7530-mmio.c +++ b/drivers/net/dsa/mt7530-mmio.c @@ -12,6 +12,7 @@ static const struct of_device_id mt7988_of_match[] =3D { { .compatible =3D "airoha,an7583-switch", .data =3D &mt753x_table[ID_AN75= 83], }, { .compatible =3D "airoha,en7581-switch", .data =3D &mt753x_table[ID_EN75= 81], }, + { .compatible =3D "econet,en751221-switch", .data =3D &mt753x_table[ID_EN= 751221], }, { .compatible =3D "econet,en7528-switch", .data =3D &mt753x_table[ID_EN75= 28], }, { .compatible =3D "mediatek,mt7988-switch", .data =3D &mt753x_table[ID_MT= 7988], }, { /* sentinel */ } diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index fe93be1ece7d..4f43454083b9 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -49,6 +49,9 @@ static const struct mt7530_mib_desc mt7530_mib[] =3D { static int mt753x_ctrl_phy_addr(struct mt7530_priv *priv) { + if (priv->id =3D=3D ID_EN751221) + return 12; + if (WARN_ON_ONCE(!priv->mdiodev)) return 0; =20 @@ -344,12 +347,19 @@ mt7530_setup_port6(struct dsa_switch *ds, phy_interfa= ce_t interface) regmap_read(priv->regmap, MT753X_MTRAP, &xtal); xtal &=3D MT7530_XTAL_MASK; =20 + /* EN751221 on-die does not report clock speed in MTRAP */ + if (priv->id =3D=3D ID_EN751221) + xtal =3D MT7530_XTAL_25MHZ; + if (xtal =3D=3D MT7530_XTAL_25MHZ) ssc_delta =3D 0x57; else ssc_delta =3D 0x87; =20 - if (priv->id =3D=3D ID_MT7621) { + if (priv->id =3D=3D ID_EN751221_EXT || priv->id =3D=3D ID_EN751221) { + /* PLL frequency: 362.5Mhz */ + ncpo1 =3D 0x1d00; + } else if (priv->id =3D=3D ID_MT7621) { /* PLL frequency: 125MHz: 1.0GBit */ if (xtal =3D=3D MT7530_XTAL_40MHZ) ncpo1 =3D 0x0640; @@ -466,6 +476,251 @@ mt7531_pll_setup(struct mt7530_priv *priv) usleep_range(25, 35); } =20 +static bool +en751221_trgmii_cal_ok(struct mt7530_priv *rx, u32 reg) +{ + u32 val =3D 0; + + regmap_read(rx->regmap, reg, &val); + regmap_write(rx->regmap, reg, val | EDGE_CHK); + regmap_write(rx->regmap, reg, val & ~EDGE_CHK); + regmap_read(rx->regmap, reg, &val); + + return FIELD_GET(RD_VALUE_MASK, val) =3D=3D TGMII_TD_PAT && + !FIELD_GET(RD_ERR_MASK, val); +} + +static void +en751221_trgmii_calibrate_direction(struct mt7530_priv *tx, + struct mt7530_priv *rx, + u8 *default_taps) +{ + int channel; + + regmap_set_bits(tx->regmap, MT7530_TRGMII_TXCTRL, TRAIN_TXEN); + + /* Put fail pattern on every channel */ + for (channel =3D 0; channel < NUM_TRGMII_CTRL; channel++) + regmap_update_bits(tx->regmap, EN7530_TRGMII_TD_CTRL(channel), + TGMII_TD_PAT_MASK, + FIELD_PREP(TGMII_TD_PAT_MASK, + TGMII_TD_FAIL_PAT)); + + for (channel =3D 0; channel < NUM_TRGMII_CTRL; channel++) { + u32 rx_reg =3D MT7530_TRGMII_RD(channel); + int best_tap =3D -1, best_range =3D -1; + int first =3D -1; + u8 dac; + char log[TD_TAP_MAX + 1]; + + /* Put test pattern on correct channel */ + regmap_update_bits(tx->regmap, EN7530_TRGMII_TD_CTRL(channel), + TGMII_TD_PAT_MASK, + FIELD_PREP(TGMII_TD_PAT_MASK, TGMII_TD_PAT)); + + for (dac =3D 0; dac < TD_TAP_MAX; dac++) { + /* Set TAP */ + regmap_update_bits(rx->regmap, rx_reg, RD_TAP_MASK, + RD_TAP(dac)); + + /* Check if we can get a good read */ + if (en751221_trgmii_cal_ok(rx, rx_reg)) { + log[dac] =3D '+'; + + if (first < 0) + first =3D dac; + + if ((dac - first) > best_range) { + best_tap =3D (first + dac) / 2; + best_range =3D dac - first; + } + } else { + log[dac] =3D '.'; + first =3D -1; + } + } + + log[TD_TAP_MAX] =3D '\0'; + + if (best_tap > -1) { + regmap_update_bits(rx->regmap, rx_reg, RD_TAP_MASK, + RD_TAP(best_tap)); + + log[best_tap] =3D 'X'; + + dev_info(rx->dev, + "TRGMII lane %d: %s tap %d old %d\n", + channel, log, best_tap, default_taps[channel]); + } else { + regmap_update_bits(rx->regmap, rx_reg, RD_TAP_MASK, + RD_TAP(default_taps[channel])); + + dev_warn(rx->dev, + "TRGMII lane %d: %s calibration failed, preserving tap %u\n", + channel, log, default_taps[channel]); + } + + /* Return channel to failure pattern */ + regmap_update_bits(tx->regmap, EN7530_TRGMII_TD_CTRL(channel), + TGMII_TD_PAT_MASK, + FIELD_PREP(TGMII_TD_PAT_MASK, + TGMII_TD_FAIL_PAT)); + } + + regmap_clear_bits(tx->regmap, MT7530_TRGMII_TXCTRL, TRAIN_TXEN); +} + +static void +en751221_set_tx_drive(struct mt7530_priv *priv, u8 drvp, u8 drvn, u8 clk_d= rvp, + u8 clk_drvn) +{ + int channel; + + /* Tx driving for TRGMII path on SoC */ + for (channel =3D 0; channel < NUM_TRGMII_CTRL; channel++) + regmap_write(priv->regmap, MT7530_TRGMII_TD_ODT(channel), + TD_DM_DRVP(drvp) | TD_DM_DRVN(drvn)); + + /* Undocumented 6th channel, probably drive strength for clock line. */ + regmap_write(priv->regmap, MT7530_TRGMII_TD_ODT(5), TD_DM_DRVP(clk_drvp) | + TD_DM_DRVN(clk_drvn)); +} + +static void +en751221_trgmii_pair_setup(struct mt7530_priv *ext, int ext_port, + struct mt7530_priv *ondie, int ondie_port) +{ + u8 default_taps_ondie[NUM_TRGMII_CTRL]; + u8 default_taps_ext[NUM_TRGMII_CTRL]; + u32 mcr_down, mcr_up; + int channel; + int reg_val; + + /* BOTH: Put interfaces in a downed state */ + mcr_down =3D PMCR_IFG_XMIT(PMCR_IFG_XMIT_64) | PMCR_MAC_MODE | + MT7530_FORCE_MODE | PMCR_MAC_RX_EN | PMCR_BACKOFF_EN | + PMCR_BACKPR_EN | PMCR_FORCE_SPEED_1000 | PMCR_FORCE_FDX; + regmap_write(ondie->regmap, MT753X_PMCR_P(ondie_port), mcr_down); + regmap_write(ext->regmap, MT753X_PMCR_P(ext_port), mcr_down); + usleep_range(5000, 6000); + + /* BOTH: Reset TX */ + regmap_set_bits(ext->regmap, MT7530_TRGMII_TXCTRL, TX_RST); + regmap_set_bits(ondie->regmap, MT7530_TRGMII_TXCTRL, TX_RST); + usleep_range(5000, 6000); + regmap_clear_bits(ext->regmap, MT7530_TRGMII_TXCTRL, TX_RST); + regmap_clear_bits(ondie->regmap, MT7530_TRGMII_TXCTRL, TX_RST); + + /* BOTH: Reset RX controllers down */ + regmap_set_bits(ext->regmap, MT7530_TRGMII_RCK_CTRL, RX_RST); + regmap_set_bits(ondie->regmap, MT7530_TRGMII_RCK_CTRL, RX_RST); + + /* BOTH: Set TX drive strength, MCM uses more */ + en751221_set_tx_drive(ondie, 8, 8, 7, 7); + en751221_set_tx_drive(ext, 11, 11, 15, 15); + + /* BOTH: Reset RX controllers up */ + regmap_clear_bits(ext->regmap, MT7530_TRGMII_RCK_CTRL, RX_RST); + regmap_clear_bits(ondie->regmap, MT7530_TRGMII_RCK_CTRL, RX_RST); + + /* BOTH: Ports up */ + mcr_up =3D mcr_down | PMCR_MAC_TX_EN | PMCR_FORCE_LNK; + regmap_write(ondie->regmap, MT753X_PMCR_P(ondie_port), mcr_up); + regmap_write(ext->regmap, MT753X_PMCR_P(ext_port), mcr_up); + + /* MCM: Set Ext->SoC TX delay to 0 */ + for (channel =3D 0; channel < NUM_TRGMII_CTRL; channel++) + regmap_clear_bits(ext->regmap, EN7530_TRGMII_TD_CTRL(channel), + TGMII_TD_TAP_MASK); + + /* SOC: ODT */ + regmap_set_bits(ondie->regmap, MT7530_TRGMII_RCK_RTT, + DQS1_GATE | DQS0_GATE | EN751221_B17); + + /* SOC: Undocumented */ + for (channel =3D 0; channel < NUM_TRGMII_CTRL; channel++) + regmap_write(ondie->regmap, (0x7a14 + channel * 8), + 0x3227700); + + /* MCM: Spread spectrum clock*/ + core_clear(ext, CORE_PLL_GROUP8, RG_LCDDS_SSC_EN); + + /* BOTH: Zero clock delay */ + regmap_clear_bits(ext->regmap, MT7530_TRGMII_RCK_CTRL, + DQSI0_TAP_MASK); + regmap_clear_bits(ondie->regmap, MT7530_TRGMII_RCK_CTRL, + DQSI0_TAP_MASK); + + /* BOTH: Collect and then zero every RX TAP */ + for (channel =3D 0; channel < NUM_TRGMII_CTRL; channel++) { + reg_val =3D 0; + regmap_read(ext->regmap, MT7530_TRGMII_RD(channel), ®_val); + default_taps_ext[channel] =3D FIELD_GET(RD_TAP_MASK, reg_val); + regmap_clear_bits(ext->regmap, MT7530_TRGMII_RD(channel), + RD_TAP_MASK); + + reg_val =3D 0; + regmap_read(ondie->regmap, MT7530_TRGMII_RD(channel), ®_val); + default_taps_ondie[channel] =3D FIELD_GET(RD_TAP_MASK, reg_val); + regmap_clear_bits(ondie->regmap, MT7530_TRGMII_RD(channel), + RD_TAP_MASK); + } + + en751221_trgmii_calibrate_direction(ondie, ext, default_taps_ondie); + en751221_trgmii_calibrate_direction(ext, ondie, default_taps_ext); + + dev_info(ondie->dev, "TRGMII inter-switch link initialized\n"); +} + +static void +mt7530_cal_interswitch_trgmii(struct dsa_port *dp) +{ + struct dsa_switch *ds =3D dp->ds; + struct dsa_switch *peer_ds; + struct dsa_port *peer_dp; + struct mt7530_priv *peer; + struct mt7530_priv *priv; + struct dsa_link *dl; + u32 pmsr =3D 0; + + priv =3D ds->priv; + + if (priv->id !=3D ID_EN751221_EXT) + return; + + if (dp->type !=3D DSA_PORT_TYPE_DSA) + return; + + regmap_read(priv->regmap, MT7530_PMSR_P(dp->index), &pmsr); + + if (!(pmsr & PMSR_LINK)) + return; + + list_for_each_entry(dl, &ds->dst->rtable, list) { + if (dl->dp !=3D dp) + continue; + + peer_dp =3D dl->link_dp; + + if (peer_dp->type !=3D DSA_PORT_TYPE_DSA) + continue; + + peer_ds =3D dl->link_dp->ds; + + if (!of_device_is_compatible(peer_ds->dev->of_node, + "econet,en751221-switch")) + continue; + + peer =3D peer_ds->priv; + + if (peer->id !=3D ID_EN751221) + continue; + + en751221_trgmii_pair_setup(priv, dp->index, peer, + peer_dp->index); + } +} + static void mt7530_mib_reset(struct dsa_switch *ds) { @@ -1408,7 +1663,8 @@ mt7530_port_enable(struct dsa_switch *ds, int port, =20 mutex_unlock(&priv->reg_mutex); =20 - if (priv->id !=3D ID_MT7530 && priv->id !=3D ID_MT7621) + if (priv->id !=3D ID_MT7530 && priv->id !=3D ID_MT7621 && + priv->id !=3D ID_EN751221 && priv->id !=3D ID_EN751221_EXT) return 0; =20 if (port =3D=3D 5) @@ -1435,7 +1691,8 @@ mt7530_port_disable(struct dsa_switch *ds, int port) =20 mutex_unlock(&priv->reg_mutex); =20 - if (priv->id !=3D ID_MT7530 && priv->id !=3D ID_MT7621) + if (priv->id !=3D ID_MT7530 && priv->id !=3D ID_MT7621 && + priv->id !=3D ID_EN751221 && priv->id !=3D ID_EN751221_EXT) return; =20 /* Do not set MT7530_P5_DIS when port 5 is being used for PHY muxing. */ @@ -2560,6 +2817,12 @@ mt7530_setup(struct dsa_switch *ds) MT7530_CHG_TRAP | MT7530_PHY_INDIRECT_ACCESS, MT7530_CHG_TRAP); =20 + /* EN751221 MCM starts on the wrong frequency */ + if (priv->id =3D=3D ID_EN751221_EXT) + regmap_update_bits(priv->regmap, MT753X_MTRAP, + MT7530_CHG_TRAP | MT7530_CK_SEL, + MT7530_CHG_TRAP); + if ((val & MT7530_XTAL_MASK) =3D=3D MT7530_XTAL_40MHZ) mt7530_pll_setup(priv); =20 @@ -2980,6 +3243,44 @@ static void en7528_mac_port_get_caps(struct dsa_swit= ch *ds, int port, } } =20 +static void en751221_mac_port_get_caps(struct dsa_switch *ds, int port, + struct phylink_config *config) +{ + switch (port) { + /* EN751221 ports 0..3 are connected to the integrated FE PHYs. */ + case 0 ... 3: + __set_bit(PHY_INTERFACE_MODE_INTERNAL, + config->supported_interfaces); + + config->mac_capabilities |=3D MAC_10 | MAC_100; + break; + + /* Port 4 is connected to the standalone EN7512/EN7521 GPHY. */ + case 4: + __set_bit(PHY_INTERFACE_MODE_INTERNAL, + config->supported_interfaces); + + config->mac_capabilities |=3D MAC_10 | MAC_100 | MAC_1000FD; + break; + + /* Port 5 is the 1 Gbit/s TRGMII cascade to the external MT7530. */ + case 5: + __set_bit(PHY_INTERFACE_MODE_TRGMII, + config->supported_interfaces); + + config->mac_capabilities |=3D MAC_1000FD; + break; + + /* Port 6 is the 1 Gbit/s CPU link to GDM1. */ + case 6: + __set_bit(PHY_INTERFACE_MODE_INTERNAL, + config->supported_interfaces); + + config->mac_capabilities |=3D MAC_1000FD; + break; + } +} + static void mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface) @@ -3129,6 +3430,9 @@ static void mt753x_phylink_mac_link_up(struct phylink= _config *config, } =20 regmap_set_bits(priv->regmap, MT753X_PMCR_P(dp->index), mcr); + + if (interface =3D=3D PHY_INTERFACE_MODE_TRGMII) + mt7530_cal_interswitch_trgmii(dp); } =20 static void mt753x_phylink_mac_disable_tx_lpi(struct phylink_config *confi= g) @@ -3382,7 +3686,8 @@ mt753x_conduit_state_change(struct dsa_switch *ds, * interface is up. NOTE: "CPU port" can also mean an upstream DSA link. */ if (priv->id !=3D ID_MT7530 && priv->id !=3D ID_MT7621 && - priv->id !=3D ID_EN7528) + priv->id !=3D ID_EN7528 && priv->id !=3D ID_EN751221 && + priv->id !=3D ID_EN751221_EXT) return; =20 mask =3D BIT(cpu_dp->index); @@ -3670,6 +3975,28 @@ const struct mt753x_info mt753x_table[] =3D { .phy_write_c45 =3D mt7531_ind_c45_phy_write, .mac_port_get_caps =3D en7528_mac_port_get_caps, }, + [ID_EN751221] =3D { + .id =3D ID_EN751221, + .pcs_ops =3D &mt7530_pcs_ops, + .sw_setup =3D mt7988_setup, + .phy_read_c22 =3D mt7531_ind_c22_phy_read, + .phy_write_c22 =3D mt7531_ind_c22_phy_write, + .phy_read_c45 =3D mt7531_ind_c45_phy_read, + .phy_write_c45 =3D mt7531_ind_c45_phy_write, + .mac_port_get_caps =3D en751221_mac_port_get_caps, + .mac_port_config =3D mt7530_mac_config, + }, + [ID_EN751221_EXT] =3D { + .id =3D ID_EN751221_EXT, + .pcs_ops =3D &mt7530_pcs_ops, + .sw_setup =3D mt7530_setup, + .phy_read_c22 =3D mt7530_phy_read_c22, + .phy_write_c22 =3D mt7530_phy_write_c22, + .phy_read_c45 =3D mt7530_phy_read_c45, + .phy_write_c45 =3D mt7530_phy_write_c45, + .mac_port_get_caps =3D mt7530_mac_port_get_caps, + .mac_port_config =3D mt7530_mac_config, + }, }; EXPORT_SYMBOL_GPL(mt753x_table); =20 diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index c86bc4bca29b..1a4329749c0f 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -24,6 +24,8 @@ enum mt753x_id { ID_EN7581 =3D 4, ID_AN7583 =3D 5, ID_EN7528 =3D 6, + ID_EN751221 =3D 7, + ID_EN751221_EXT =3D 8, }; =20 #define NUM_TRGMII_CTRL 5 @@ -356,6 +358,9 @@ enum mt7530_vlan_port_acc_frm { #define MT753X_PMCR_P(x) (0x3000 + ((x) * 0x100)) #define PMCR_IFG_XMIT_MASK GENMASK(19, 18) #define PMCR_IFG_XMIT(x) FIELD_PREP(PMCR_IFG_XMIT_MASK, x) +#define PMCR_IFG_XMIT_96 0 +#define PMCR_IFG_XMIT_RAND 1 +#define PMCR_IFG_XMIT_64 2 #define PMCR_EXT_PHY BIT(17) #define PMCR_MAC_MODE BIT(16) #define MT7530_FORCE_MODE BIT(15) @@ -584,6 +589,7 @@ enum mt7531_clk_skew { #define MT753X_MTRAP 0x7804 #define MT7530_P5_PHY0_SEL BIT(20) #define MT7530_CHG_TRAP BIT(16) +#define MT7530_CK_SEL BIT(15) #define MT7530_LOOP_DET_DISABLE BIT(14) #define MT7530_P5_MAC_SEL BIT(13) #define MT7530_P6_DIS BIT(8) @@ -601,6 +607,8 @@ enum mt7531_xtal_fsel { /* Register for TOP signal control */ #define MT7530_TOP_SIG_CTRL 0x7808 #define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16)) +/* Undocumented */ +#define TOP_SIG_CTRL_B0 BIT(0) =20 #define MT7531_TOP_SIG_SR 0x780c #define PAD_DUAL_SGMII_EN BIT(1) @@ -647,18 +655,31 @@ enum mt7531_xtal_fsel { #define MT7530_TRGMII_RCK_RTT 0x7a04 #define DQS1_GATE BIT(31) #define DQS0_GATE BIT(30) +/* Undocumented */ +#define EN751221_B17 BIT(17) =20 #define MT7530_TRGMII_RD(x) (0x7a10 + (x) * 8) #define BSLIP_EN BIT(31) #define EDGE_CHK BIT(30) +#define RD_VALUE_MASK GENMASK(23, 16) +#define RD_ERR_MASK GENMASK(11, 8) #define RD_TAP_MASK GENMASK(6, 0) #define RD_TAP(x) FIELD_PREP(RD_TAP_MASK, x) +/* Training does not try anything beyond this */ +#define TD_TAP_MAX 64 =20 #define MT7530_TRGMII_TXCTRL 0x7a40 #define TRAIN_TXEN BIT(31) #define TXC_INV BIT(30) #define TX_RST BIT(28) =20 +#define EN7530_TRGMII_TD_CTRL(x) (0x7a50 + (x) * 8) +#define TGMII_TD_TAP_MASK GENMASK(11, 8) +#define TGMII_TD_PAT_MASK GENMASK(7, 0) +/* Use a 01010101 bit pattern */ +#define TGMII_TD_PAT 0x55 +#define TGMII_TD_FAIL_PAT 0xaa + #define MT7530_TRGMII_TD_ODT(i) (0x7a54 + 8 * (i)) #define TD_DM_DRVP_MASK GENMASK(3, 0) #define TD_DM_DRVP(x) FIELD_PREP(TD_DM_DRVP_MASK, x) @@ -764,6 +785,9 @@ enum mt7531_xtal_fsel { #define RG_LCCDS_C(x) FIELD_PREP(RG_LCCDS_C_MASK, x) #define RG_LCDDS_PCW_NCPO_CHG BIT(3) =20 +#define CORE_PLL_GROUP8 0x407 +#define RG_LCDDS_SSC_EN BIT(10) + #define CORE_PLL_GROUP10 0x409 #define RG_LCDDS_SSC_DELTA_MASK GENMASK(11, 0) #define RG_LCDDS_SSC_DELTA(x) FIELD_PREP(RG_LCDDS_SSC_DELTA_MASK, x) --=20 2.39.5