From 24ade65ab545c169992c3c95f8cd3ca73a072c8f Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Thu, 9 Jan 2025 18:10:28 +0800 Subject: [PATCH] uboot-mediatek: backport mtk_eth fixes from u-boot next This patch series will provide better support for Mediatek ethernet and add support for Airoha AN8855. Signed-off-by: Shiji Yang --- ...629-fix-parent-clock-of-some-top-clo.patch | 45 + ...ix-sgmii-clock-selection-for-etherne.patch | 28 + ...-correct-register-field-for-SGMII-sp.patch | 64 + ...rect-register-name-of-ethsys-syscfg1.patch | 78 + ...iatek-fix-sgmii-selection-for-mt7622.patch | 90 + ...iatek-fix-gmac2-usability-for-mt7629.patch | 73 + ...t-mediatek-add-support-for-10GBASE-R.patch | 147 + ...mediatek-make-sgmii-usxgmii-optional.patch | 144 + ...-t-enable-GDMA-cpu-bridge-unconditio.patch | 36 + ...atek-fix-usability-with-wget-command.patch | 37 + ...it-ethernet-switch-code-from-mtk_eth.patch | 6311 +++++++++++++++++ ...-add-support-for-MediaTek-MT7987-SoC.patch | 63 + ...-support-for-Airoha-AN8855-ethernet-.patch | 1133 +++ 13 files changed, 8249 insertions(+) create mode 100644 package/boot/uboot-mediatek/patches/060-01-clk-mediatek-mt7629-fix-parent-clock-of-some-top-clo.patch create mode 100644 package/boot/uboot-mediatek/patches/060-02-arm-dts-mt7629-fix-sgmii-clock-selection-for-etherne.patch create mode 100644 package/boot/uboot-mediatek/patches/060-03-net-mediatek-use-correct-register-field-for-SGMII-sp.patch create mode 100644 package/boot/uboot-mediatek/patches/060-04-net-mediatek-correct-register-name-of-ethsys-syscfg1.patch create mode 100644 package/boot/uboot-mediatek/patches/060-05-net-mediatek-fix-sgmii-selection-for-mt7622.patch create mode 100644 package/boot/uboot-mediatek/patches/060-06-net-mediatek-fix-gmac2-usability-for-mt7629.patch create mode 100644 package/boot/uboot-mediatek/patches/060-07-net-mediatek-add-support-for-10GBASE-R.patch create mode 100644 package/boot/uboot-mediatek/patches/060-08-net-mediatek-make-sgmii-usxgmii-optional.patch create mode 100644 package/boot/uboot-mediatek/patches/060-09-net-mediatek-don-t-enable-GDMA-cpu-bridge-unconditio.patch create mode 100644 package/boot/uboot-mediatek/patches/060-10-net-mediatek-fix-usability-with-wget-command.patch create mode 100644 package/boot/uboot-mediatek/patches/061-01-net-mediatek-split-ethernet-switch-code-from-mtk_eth.patch create mode 100644 package/boot/uboot-mediatek/patches/061-02-net-mediatek-add-support-for-MediaTek-MT7987-SoC.patch create mode 100644 package/boot/uboot-mediatek/patches/061-03-net-mediatek-add-support-for-Airoha-AN8855-ethernet-.patch diff --git a/package/boot/uboot-mediatek/patches/060-01-clk-mediatek-mt7629-fix-parent-clock-of-some-top-clo.patch b/package/boot/uboot-mediatek/patches/060-01-clk-mediatek-mt7629-fix-parent-clock-of-some-top-clo.patch new file mode 100644 index 00000000000..387cf90477b --- /dev/null +++ b/package/boot/uboot-mediatek/patches/060-01-clk-mediatek-mt7629-fix-parent-clock-of-some-top-clo.patch @@ -0,0 +1,45 @@ +From 6e45549f4dac42748d66462e04f940ef6737289d Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 17 Dec 2024 16:39:16 +0800 +Subject: [PATCH 01/10] clk: mediatek: mt7629: fix parent clock of some top + clock muxes + +According to the mt7629 programming guide, the CLK_TOP_F10M_REF_SEL +shares the same parent selection with CLK_TOP_IRRX_SEL, while the +present parent selection for CLK_TOP_F10M_REF_SEL is actually used +for CLK_TOP_SGMII_REF_1_SEL. + +Signed-off-by: Weijie Gao +--- + drivers/clk/mediatek/clk-mt7629.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/clk/mediatek/clk-mt7629.c ++++ b/drivers/clk/mediatek/clk-mt7629.c +@@ -186,7 +186,7 @@ static const int pwm_parents[] = { + CLK_TOP_UNIVPLL2_D4 + }; + +-static const int f10m_ref_parents[] = { ++static const int sgmii_ref_1_parents[] = { + CLK_XTAL, + CLK_TOP_SGMIIPLL_D2 + }; +@@ -369,7 +369,7 @@ static const struct mtk_composite top_mu + + /* CLK_CFG_1 */ + MUX_GATE(CLK_TOP_PWM_SEL, pwm_parents, 0x50, 0, 2, 7), +- MUX_GATE(CLK_TOP_F10M_REF_SEL, f10m_ref_parents, 0x50, 8, 1, 15), ++ MUX_GATE(CLK_TOP_F10M_REF_SEL, irrx_parents, 0x50, 8, 1, 15), + MUX_GATE(CLK_TOP_NFI_INFRA_SEL, nfi_infra_parents, 0x50, 16, 4, 23), + MUX_GATE(CLK_TOP_FLASH_SEL, flash_parents, 0x50, 24, 3, 31), + +@@ -412,7 +412,7 @@ static const struct mtk_composite top_mu + + /* CLK_CFG_8 */ + MUX_GATE(CLK_TOP_CRYPTO_SEL, crypto_parents, 0xC0, 0, 3, 7), +- MUX_GATE(CLK_TOP_SGMII_REF_1_SEL, f10m_ref_parents, 0xC0, 8, 1, 15), ++ MUX_GATE(CLK_TOP_SGMII_REF_1_SEL, sgmii_ref_1_parents, 0xC0, 8, 1, 15), + MUX_GATE(CLK_TOP_10M_SEL, gpt10m_parents, 0xC0, 16, 1, 23), + }; + diff --git a/package/boot/uboot-mediatek/patches/060-02-arm-dts-mt7629-fix-sgmii-clock-selection-for-etherne.patch b/package/boot/uboot-mediatek/patches/060-02-arm-dts-mt7629-fix-sgmii-clock-selection-for-etherne.patch new file mode 100644 index 00000000000..c96490e408c --- /dev/null +++ b/package/boot/uboot-mediatek/patches/060-02-arm-dts-mt7629-fix-sgmii-clock-selection-for-etherne.patch @@ -0,0 +1,28 @@ +From ba365c3d23411620d86b5baf621c8f5a4000ab33 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 17 Dec 2024 16:39:20 +0800 +Subject: [PATCH 02/10] arm: dts: mt7629: fix sgmii clock selection for + ethernet + +Setup correct parent of clock CLK_TOP_SGMII_REF_1_SEL to allow +sgmiisys1 work correctly. + +Signed-off-by: Weijie Gao +--- + arch/arm/dts/mt7629.dtsi | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/arch/arm/dts/mt7629.dtsi ++++ b/arch/arm/dts/mt7629.dtsi +@@ -314,8 +314,10 @@ + "sgmii2_cdr_ref", "sgmii2_cdr_fb", + "sgmii_ck", "eth2pll"; + assigned-clocks = <&topckgen CLK_TOP_ETH_SEL>, +- <&topckgen CLK_TOP_F10M_REF_SEL>; ++ <&topckgen CLK_TOP_F10M_REF_SEL>, ++ <&topckgen CLK_TOP_SGMII_REF_1_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL1_D2>, ++ <&topckgen CLK_TOP_SYSPLL4_D16>, + <&topckgen CLK_TOP_SGMIIPLL_D2>; + power-domains = <&scpsys MT7629_POWER_DOMAIN_ETHSYS>; + resets = <ðsys ETHSYS_FE_RST>; diff --git a/package/boot/uboot-mediatek/patches/060-03-net-mediatek-use-correct-register-field-for-SGMII-sp.patch b/package/boot/uboot-mediatek/patches/060-03-net-mediatek-use-correct-register-field-for-SGMII-sp.patch new file mode 100644 index 00000000000..ba3fbf6d7f4 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/060-03-net-mediatek-use-correct-register-field-for-SGMII-sp.patch @@ -0,0 +1,64 @@ +From 0d4d8e6f47ef22ea6b3041b4c0cb27b4ed4bf188 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 17 Dec 2024 16:39:23 +0800 +Subject: [PATCH 03/10] net: mediatek: use correct register field for SGMII + speed selection + +The register field for SGMII speed selection is a 2-bit field with +value 0 for 1Gbps and 1 for 2.5Gbps (2/3 are reserved). +So it's necessary to set both bits instead of just setting/clearing +only the lower bit. + +Signed-off-by: Weijie Gao +--- + drivers/net/mtk_eth.c | 12 ++++++------ + drivers/net/mtk_eth.h | 3 ++- + 2 files changed, 8 insertions(+), 7 deletions(-) + +--- a/drivers/net/mtk_eth.c ++++ b/drivers/net/mtk_eth.c +@@ -835,8 +835,8 @@ static int mt7531_port_sgmii_init(struct + } + + /* Set SGMII GEN2 speed(2.5G) */ +- mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), +- SGMSYS_SPEED_2500, SGMSYS_SPEED_2500); ++ mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), SGMSYS_SPEED_MASK, ++ FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500)); + + /* Disable SGMII AN */ + mt753x_reg_rmw(priv, MT7531_PCS_CONTROL_1(port), +@@ -1281,8 +1281,7 @@ static int mtk_phy_probe(struct udevice + static void mtk_sgmii_an_init(struct mtk_eth_priv *priv) + { + /* Set SGMII GEN1 speed(1G) */ +- clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, +- SGMSYS_SPEED_2500, 0); ++ clrbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, SGMSYS_SPEED_MASK); + + /* Enable SGMII AN */ + setbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1, +@@ -1305,8 +1304,9 @@ static void mtk_sgmii_an_init(struct mtk + static void mtk_sgmii_force_init(struct mtk_eth_priv *priv) + { + /* Set SGMII GEN2 speed(2.5G) */ +- setbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, +- SGMSYS_SPEED_2500); ++ clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, ++ SGMSYS_SPEED_MASK, ++ FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500)); + + /* Disable SGMII AN */ + clrsetbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1, +--- a/drivers/net/mtk_eth.h ++++ b/drivers/net/mtk_eth.h +@@ -108,7 +108,8 @@ enum mkt_eth_capabilities { + + #define SGMSYS_GEN2_SPEED 0x2028 + #define SGMSYS_GEN2_SPEED_V2 0x128 +-#define SGMSYS_SPEED_2500 BIT(2) ++#define SGMSYS_SPEED_MASK GENMASK(3, 2) ++#define SGMSYS_SPEED_2500 1 + + /* USXGMII subsystem config registers */ + /* Register to control USXGMII XFI PLL digital */ diff --git a/package/boot/uboot-mediatek/patches/060-04-net-mediatek-correct-register-name-of-ethsys-syscfg1.patch b/package/boot/uboot-mediatek/patches/060-04-net-mediatek-correct-register-name-of-ethsys-syscfg1.patch new file mode 100644 index 00000000000..8c549e76b1f --- /dev/null +++ b/package/boot/uboot-mediatek/patches/060-04-net-mediatek-correct-register-name-of-ethsys-syscfg1.patch @@ -0,0 +1,78 @@ +From 7562da9454c1a6eff3db3b41c183e03039e855e6 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 17 Dec 2024 16:39:27 +0800 +Subject: [PATCH 04/10] net: mediatek: correct register name of ethsys syscfg1 + +The SYSCFG0 should be SYSCFG1 according to the programming guide. + +Signed-off-by: Weijie Gao +--- + drivers/net/mtk_eth.c | 14 +++++++------- + drivers/net/mtk_eth.h | 12 ++++++------ + 2 files changed, 13 insertions(+), 13 deletions(-) + +--- a/drivers/net/mtk_eth.c ++++ b/drivers/net/mtk_eth.c +@@ -1450,8 +1450,8 @@ static void mtk_mac_init(struct mtk_eth_ + } + + ge_mode = GE_MODE_RGMII; +- mtk_ethsys_rmw(priv, ETHSYS_SYSCFG0_REG, SYSCFG0_SGMII_SEL_M, +- SYSCFG0_SGMII_SEL(priv->gmac_id)); ++ mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, SYSCFG1_SGMII_SEL_M, ++ SYSCFG1_SGMII_SEL(priv->gmac_id)); + if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII) + mtk_sgmii_an_init(priv); + else +@@ -1469,9 +1469,9 @@ static void mtk_mac_init(struct mtk_eth_ + } + + /* set the gmac to the right mode */ +- mtk_ethsys_rmw(priv, ETHSYS_SYSCFG0_REG, +- SYSCFG0_GE_MODE_M << SYSCFG0_GE_MODE_S(priv->gmac_id), +- ge_mode << SYSCFG0_GE_MODE_S(priv->gmac_id)); ++ mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, ++ SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id), ++ ge_mode << SYSCFG1_GE_MODE_S(priv->gmac_id)); + + if (priv->force_mode) { + mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | +@@ -1527,8 +1527,8 @@ static void mtk_xmac_init(struct mtk_eth + } + + /* Set GMAC to the correct mode */ +- mtk_ethsys_rmw(priv, ETHSYS_SYSCFG0_REG, +- SYSCFG0_GE_MODE_M << SYSCFG0_GE_MODE_S(priv->gmac_id), ++ mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, ++ SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id), + 0); + + if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII && +--- a/drivers/net/mtk_eth.h ++++ b/drivers/net/mtk_eth.h +@@ -65,11 +65,11 @@ enum mkt_eth_capabilities { + + /* Ethernet subsystem registers */ + +-#define ETHSYS_SYSCFG0_REG 0x14 +-#define SYSCFG0_GE_MODE_S(n) (12 + ((n) * 2)) +-#define SYSCFG0_GE_MODE_M 0x3 +-#define SYSCFG0_SGMII_SEL_M (0x3 << 8) +-#define SYSCFG0_SGMII_SEL(gmac) ((!(gmac)) ? BIT(9) : BIT(8)) ++#define ETHSYS_SYSCFG1_REG 0x14 ++#define SYSCFG1_GE_MODE_S(n) (12 + ((n) * 2)) ++#define SYSCFG1_GE_MODE_M 0x3 ++#define SYSCFG1_SGMII_SEL_M (0x3 << 8) ++#define SYSCFG1_SGMII_SEL(gmac) ((!(gmac)) ? BIT(9) : BIT(8)) + + #define ETHSYS_CLKCFG0_REG 0x2c + #define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) +@@ -84,7 +84,7 @@ enum mkt_eth_capabilities { + #define QPHY_SEL_MASK 0x3 + #define SGMII_QPHY_SEL 0x2 + +-/* SYSCFG0_GE_MODE: GE Modes */ ++/* SYSCFG1_GE_MODE: GE Modes */ + #define GE_MODE_RGMII 0 + #define GE_MODE_MII 1 + #define GE_MODE_MII_PHY 2 diff --git a/package/boot/uboot-mediatek/patches/060-05-net-mediatek-fix-sgmii-selection-for-mt7622.patch b/package/boot/uboot-mediatek/patches/060-05-net-mediatek-fix-sgmii-selection-for-mt7622.patch new file mode 100644 index 00000000000..a45e8789d29 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/060-05-net-mediatek-fix-sgmii-selection-for-mt7622.patch @@ -0,0 +1,90 @@ +From 82f05bc48821f3709f22f3d1f6e45290547f74be Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 17 Dec 2024 16:39:41 +0800 +Subject: [PATCH 05/10] net: mediatek: fix sgmii selection for mt7622 + +Unlike other platforms, mt7622 has only one SGMII and it can be +attached to either gmac1 or gmac2. So the register field of the +sgmii selection differs from other platforms as newer platforms can +control each sgmii individually. + +This patch adds a new capability for mt7622 to handle this case. + +Signed-off-by: Weijie Gao +--- + drivers/net/mtk_eth.c | 10 ++++++++-- + drivers/net/mtk_eth.h | 8 ++++++-- + 2 files changed, 14 insertions(+), 4 deletions(-) + +--- a/drivers/net/mtk_eth.c ++++ b/drivers/net/mtk_eth.c +@@ -1434,7 +1434,7 @@ static void mtk_usxgmii_an_init(struct m + + static void mtk_mac_init(struct mtk_eth_priv *priv) + { +- int i, ge_mode = 0; ++ int i, sgmii_sel_mask = 0, ge_mode = 0; + u32 mcr; + + switch (priv->phy_interface) { +@@ -1450,8 +1450,13 @@ static void mtk_mac_init(struct mtk_eth_ + } + + ge_mode = GE_MODE_RGMII; +- mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, SYSCFG1_SGMII_SEL_M, ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7622_SGMII)) ++ sgmii_sel_mask = SYSCFG1_SGMII_SEL_M; ++ ++ mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, sgmii_sel_mask, + SYSCFG1_SGMII_SEL(priv->gmac_id)); ++ + if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII) + mtk_sgmii_an_init(priv); + else +@@ -2112,6 +2117,7 @@ static const struct mtk_soc_data mt7623_ + }; + + static const struct mtk_soc_data mt7622_data = { ++ .caps = MT7622_CAPS, + .ana_rgc3 = 0x2028, + .gdma_count = 2, + .pdma_base = PDMA_V1_BASE, +--- a/drivers/net/mtk_eth.h ++++ b/drivers/net/mtk_eth.h +@@ -23,6 +23,7 @@ enum mkt_eth_capabilities { + /* PATH BITS */ + MTK_ETH_PATH_GMAC1_TRGMII_BIT, + MTK_ETH_PATH_GMAC2_SGMII_BIT, ++ MTK_ETH_PATH_MT7622_SGMII_BIT, + }; + + #define MTK_TRGMII BIT(MTK_TRGMII_BIT) +@@ -36,6 +37,7 @@ enum mkt_eth_capabilities { + #define MTK_ETH_PATH_GMAC1_TRGMII BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT) + + #define MTK_ETH_PATH_GMAC2_SGMII BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT) ++#define MTK_ETH_PATH_MT7622_SGMII BIT(MTK_ETH_PATH_MT7622_SGMII_BIT) + + #define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII) + +@@ -45,6 +47,8 @@ enum mkt_eth_capabilities { + + #define MT7621_CAPS (MTK_GMAC1_TRGMII | MTK_TRGMII_MT7621_CLK) + ++#define MT7622_CAPS (MTK_ETH_PATH_MT7622_SGMII) ++ + #define MT7623_CAPS (MTK_GMAC1_TRGMII) + + #define MT7981_CAPS (MTK_GMAC2_U3_QPHY | MTK_NETSYS_V2) +@@ -68,8 +72,8 @@ enum mkt_eth_capabilities { + #define ETHSYS_SYSCFG1_REG 0x14 + #define SYSCFG1_GE_MODE_S(n) (12 + ((n) * 2)) + #define SYSCFG1_GE_MODE_M 0x3 +-#define SYSCFG1_SGMII_SEL_M (0x3 << 8) +-#define SYSCFG1_SGMII_SEL(gmac) ((!(gmac)) ? BIT(9) : BIT(8)) ++#define SYSCFG1_SGMII_SEL_M GENMASK(9, 8) ++#define SYSCFG1_SGMII_SEL(gmac) BIT(9 - (gmac)) + + #define ETHSYS_CLKCFG0_REG 0x2c + #define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) diff --git a/package/boot/uboot-mediatek/patches/060-06-net-mediatek-fix-gmac2-usability-for-mt7629.patch b/package/boot/uboot-mediatek/patches/060-06-net-mediatek-fix-gmac2-usability-for-mt7629.patch new file mode 100644 index 00000000000..5bc6e705d02 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/060-06-net-mediatek-fix-gmac2-usability-for-mt7629.patch @@ -0,0 +1,73 @@ +From d8d7e566545f836dd49611cafbf44eef56434e08 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 17 Dec 2024 16:39:46 +0800 +Subject: [PATCH 06/10] net: mediatek: fix gmac2 usability for mt7629 + +MT7629 need extra setting for gmac2 to work. So additional +capability is added for mt7629 to handle this case. + +Signed-off-by: Weijie Gao +--- + drivers/net/mtk_eth.c | 6 ++++++ + drivers/net/mtk_eth.h | 7 +++++++ + 2 files changed, 13 insertions(+) + +--- a/drivers/net/mtk_eth.c ++++ b/drivers/net/mtk_eth.c +@@ -1437,6 +1437,11 @@ static void mtk_mac_init(struct mtk_eth_ + int i, sgmii_sel_mask = 0, ge_mode = 0; + u32 mcr; + ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7629_GMAC2)) { ++ mtk_infra_rmw(priv, MT7629_INFRA_MISC2_REG, ++ INFRA_MISC2_BONDING_OPTION, priv->gmac_id); ++ } ++ + switch (priv->phy_interface) { + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII: +@@ -2101,6 +2106,7 @@ static const struct mtk_soc_data mt7981_ + }; + + static const struct mtk_soc_data mt7629_data = { ++ .caps = MT7629_CAPS, + .ana_rgc3 = 0x128, + .gdma_count = 2, + .pdma_base = PDMA_V1_BASE, +--- a/drivers/net/mtk_eth.h ++++ b/drivers/net/mtk_eth.h +@@ -24,6 +24,7 @@ enum mkt_eth_capabilities { + MTK_ETH_PATH_GMAC1_TRGMII_BIT, + MTK_ETH_PATH_GMAC2_SGMII_BIT, + MTK_ETH_PATH_MT7622_SGMII_BIT, ++ MTK_ETH_PATH_MT7629_GMAC2_BIT, + }; + + #define MTK_TRGMII BIT(MTK_TRGMII_BIT) +@@ -38,6 +39,7 @@ enum mkt_eth_capabilities { + + #define MTK_ETH_PATH_GMAC2_SGMII BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT) + #define MTK_ETH_PATH_MT7622_SGMII BIT(MTK_ETH_PATH_MT7622_SGMII_BIT) ++#define MTK_ETH_PATH_MT7629_GMAC2 BIT(MTK_ETH_PATH_MT7629_GMAC2_BIT) + + #define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII) + +@@ -51,6 +53,8 @@ enum mkt_eth_capabilities { + + #define MT7623_CAPS (MTK_GMAC1_TRGMII) + ++#define MT7629_CAPS (MTK_ETH_PATH_MT7629_GMAC2 | MTK_INFRA) ++ + #define MT7981_CAPS (MTK_GMAC2_U3_QPHY | MTK_NETSYS_V2) + + #define MT7986_CAPS (MTK_NETSYS_V2) +@@ -88,6 +92,9 @@ enum mkt_eth_capabilities { + #define QPHY_SEL_MASK 0x3 + #define SGMII_QPHY_SEL 0x2 + ++#define MT7629_INFRA_MISC2_REG 0x70c ++#define INFRA_MISC2_BONDING_OPTION GENMASK(15, 0) ++ + /* SYSCFG1_GE_MODE: GE Modes */ + #define GE_MODE_RGMII 0 + #define GE_MODE_MII 1 diff --git a/package/boot/uboot-mediatek/patches/060-07-net-mediatek-add-support-for-10GBASE-R.patch b/package/boot/uboot-mediatek/patches/060-07-net-mediatek-add-support-for-10GBASE-R.patch new file mode 100644 index 00000000000..f7a63a5b8af --- /dev/null +++ b/package/boot/uboot-mediatek/patches/060-07-net-mediatek-add-support-for-10GBASE-R.patch @@ -0,0 +1,147 @@ +From ad0c47109e4c9f6297aa247d8bbf7131438bc435 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 17 Dec 2024 16:39:50 +0800 +Subject: [PATCH 07/10] net: mediatek: add support for 10GBASE-R + +This patch adds support for 10GBASE-R interface mode + +Signed-off-by: Bo-Cun Chen +Signed-off-by: Weijie Gao +--- + drivers/net/mtk_eth.c | 83 +++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 81 insertions(+), 2 deletions(-) + +--- a/drivers/net/mtk_eth.c ++++ b/drivers/net/mtk_eth.c +@@ -1246,6 +1246,7 @@ static int mtk_phy_start(struct mtk_eth_ + + if (!priv->force_mode) { + if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER || + priv->phy_interface == PHY_INTERFACE_MODE_XGMII) + mtk_xphy_link_adjust(priv); + else +@@ -1425,6 +1426,71 @@ static void mtk_usxgmii_setup_phya_an_10 + udelay(400); + } + ++static void mtk_usxgmii_setup_phya_force_10000(struct mtk_eth_priv *priv) ++{ ++ regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6C); ++ regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B); ++ regmap_write(priv->usxgmii_regmap, 0x80C, 0xB0000000); ++ ndelay(1020); ++ regmap_write(priv->usxgmii_regmap, 0x80C, 0x90000000); ++ ndelay(1020); ++ ++ regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C); ++ regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA); ++ regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707); ++ regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F); ++ regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032); ++ regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA); ++ regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B); ++ regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF); ++ regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA); ++ regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F); ++ regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68); ++ regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166); ++ regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF); ++ regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D); ++ regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909); ++ regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000); ++ regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000); ++ regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06); ++ regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C); ++ regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000); ++ regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342); ++ regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20); ++ regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800); ++ ndelay(1020); ++ regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020); ++ regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01); ++ regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884); ++ regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002); ++ regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220); ++ regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01); ++ regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600); ++ regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x47684100); ++ regmap_write(priv->xfi_pextp_regmap, 0x3050, 0x00000000); ++ regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x00000000); ++ regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00); ++ if (priv->gmac_id == 2) ++ regmap_write(priv->xfi_pextp_regmap, 0xA008, 0x0007B400); ++ regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000); ++ regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800); ++ udelay(150); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111); ++ ndelay(1020); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101); ++ udelay(15); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111); ++ ndelay(1020); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101); ++ udelay(100); ++ regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030); ++ regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00); ++ regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000); ++ udelay(400); ++} ++ + static void mtk_usxgmii_an_init(struct mtk_eth_priv *priv) + { + mtk_xfi_pll_enable(priv); +@@ -1432,6 +1498,13 @@ static void mtk_usxgmii_an_init(struct m + mtk_usxgmii_setup_phya_an_10000(priv); + } + ++static void mtk_10gbaser_init(struct mtk_eth_priv *priv) ++{ ++ mtk_xfi_pll_enable(priv); ++ mtk_usxgmii_reset(priv); ++ mtk_usxgmii_setup_phya_force_10000(priv); ++} ++ + static void mtk_mac_init(struct mtk_eth_priv *priv) + { + int i, sgmii_sel_mask = 0, ge_mode = 0; +@@ -1532,6 +1605,9 @@ static void mtk_xmac_init(struct mtk_eth + case PHY_INTERFACE_MODE_USXGMII: + mtk_usxgmii_an_init(priv); + break; ++ case PHY_INTERFACE_MODE_10GBASER: ++ mtk_10gbaser_init(priv); ++ break; + default: + break; + } +@@ -1541,7 +1617,8 @@ static void mtk_xmac_init(struct mtk_eth + SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id), + 0); + +- if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII && ++ if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) && + priv->gmac_id == 1) { + mtk_infra_rmw(priv, TOPMISC_NETSYS_PCS_MUX, + NETSYS_PCS_MUX_MASK, MUX_G2_USXGMII_SEL); +@@ -1843,6 +1920,7 @@ static int mtk_eth_probe(struct udevice + + /* Set MAC mode */ + if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER || + priv->phy_interface == PHY_INTERFACE_MODE_XGMII) + mtk_xmac_init(priv); + else +@@ -1977,7 +2055,8 @@ static int mtk_eth_of_to_plat(struct ude + /* Upstream linux use mediatek,pnswap instead of pn_swap */ + priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") || + ofnode_read_bool(args.node, "mediatek,pnswap"); +- } else if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII) { ++ } else if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) { + /* get corresponding usxgmii phandle */ + ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys", + NULL, 0, 0, &args); diff --git a/package/boot/uboot-mediatek/patches/060-08-net-mediatek-make-sgmii-usxgmii-optional.patch b/package/boot/uboot-mediatek/patches/060-08-net-mediatek-make-sgmii-usxgmii-optional.patch new file mode 100644 index 00000000000..d6a885f889e --- /dev/null +++ b/package/boot/uboot-mediatek/patches/060-08-net-mediatek-make-sgmii-usxgmii-optional.patch @@ -0,0 +1,144 @@ +From 5ac929fd1ab1d0dc77b9167952aea7cafdb8619f Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 17 Dec 2024 16:39:55 +0800 +Subject: [PATCH 08/10] net: mediatek: make sgmii/usxgmii optional + +Not all platforms supports sgmii and/or usxgmii. So we add Kconfig +options for these features and enable them only for supported +platforms. + +Signed-off-by: Weijie Gao +--- + drivers/net/Kconfig | 12 ++++++++++++ + drivers/net/mtk_eth.c | 39 +++++++++++++++++++++++++++++---------- + 2 files changed, 41 insertions(+), 10 deletions(-) + +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -975,6 +975,18 @@ config MEDIATEK_ETH + This Driver support MediaTek Ethernet GMAC + Say Y to enable support for the MediaTek Ethernet GMAC. + ++if MEDIATEK_ETH ++ ++config MTK_ETH_SGMII ++ bool ++ default y if ARCH_MEDIATEK && !TARGET_MT7623 ++ ++config MTK_ETH_XGMII ++ bool ++ default y if TARGET_MT7987 || TARGET_MT7988 ++ ++endif # MEDIATEK_ETH ++ + config HIFEMAC_ETH + bool "HiSilicon Fast Ethernet Controller" + select DM_CLK +--- a/drivers/net/mtk_eth.c ++++ b/drivers/net/mtk_eth.c +@@ -1505,7 +1505,7 @@ static void mtk_10gbaser_init(struct mtk + mtk_usxgmii_setup_phya_force_10000(priv); + } + +-static void mtk_mac_init(struct mtk_eth_priv *priv) ++static int mtk_mac_init(struct mtk_eth_priv *priv) + { + int i, sgmii_sel_mask = 0, ge_mode = 0; + u32 mcr; +@@ -1522,13 +1522,16 @@ static void mtk_mac_init(struct mtk_eth_ + break; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_2500BASEX: ++ if (!IS_ENABLED(CONFIG_MTK_ETH_SGMII)) { ++ printf("Error: SGMII is not supported on this platform\n"); ++ return -ENOTSUPP; ++ } ++ + if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC2_U3_QPHY)) { + mtk_infra_rmw(priv, USB_PHY_SWITCH_REG, QPHY_SEL_MASK, + SGMII_QPHY_SEL); + } + +- ge_mode = GE_MODE_RGMII; +- + if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7622_SGMII)) + sgmii_sel_mask = SYSCFG1_SGMII_SEL_M; + +@@ -1539,6 +1542,8 @@ static void mtk_mac_init(struct mtk_eth_ + mtk_sgmii_an_init(priv); + else + mtk_sgmii_force_init(priv); ++ ++ ge_mode = GE_MODE_RGMII; + break; + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_GMII: +@@ -1595,12 +1600,19 @@ static void mtk_mac_init(struct mtk_eth_ + RX_RST | RXC_DQSISEL); + mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, RX_RST, 0); + } ++ ++ return 0; + } + +-static void mtk_xmac_init(struct mtk_eth_priv *priv) ++static int mtk_xmac_init(struct mtk_eth_priv *priv) + { + u32 force_link = 0; + ++ if (!IS_ENABLED(CONFIG_MTK_ETH_XGMII)) { ++ printf("Error: 10Gb interface is not supported on this platform\n"); ++ return -ENOTSUPP; ++ } ++ + switch (priv->phy_interface) { + case PHY_INTERFACE_MODE_USXGMII: + mtk_usxgmii_an_init(priv); +@@ -1633,6 +1645,8 @@ static void mtk_xmac_init(struct mtk_eth + + /* Force GMAC link down */ + mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), FORCE_MODE); ++ ++ return 0; + } + + static void mtk_eth_fifo_init(struct mtk_eth_priv *priv) +@@ -1922,9 +1936,12 @@ static int mtk_eth_probe(struct udevice + if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || + priv->phy_interface == PHY_INTERFACE_MODE_10GBASER || + priv->phy_interface == PHY_INTERFACE_MODE_XGMII) +- mtk_xmac_init(priv); ++ ret = mtk_xmac_init(priv); + else +- mtk_mac_init(priv); ++ ret = mtk_mac_init(priv); ++ ++ if (ret) ++ return ret; + + /* Probe phy if switch is not specified */ + if (priv->sw == SW_NONE) +@@ -2032,8 +2049,9 @@ static int mtk_eth_of_to_plat(struct ude + } + } + +- if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII || +- priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) { ++ if ((priv->phy_interface == PHY_INTERFACE_MODE_SGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) && ++ IS_ENABLED(CONFIG_MTK_ETH_SGMII)) { + /* get corresponding sgmii phandle */ + ret = dev_read_phandle_with_args(dev, "mediatek,sgmiisys", + NULL, 0, 0, &args); +@@ -2055,8 +2073,9 @@ static int mtk_eth_of_to_plat(struct ude + /* Upstream linux use mediatek,pnswap instead of pn_swap */ + priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") || + ofnode_read_bool(args.node, "mediatek,pnswap"); +- } else if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || +- priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) { ++ } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) && ++ IS_ENABLED(CONFIG_MTK_ETH_XGMII)) { + /* get corresponding usxgmii phandle */ + ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys", + NULL, 0, 0, &args); diff --git a/package/boot/uboot-mediatek/patches/060-09-net-mediatek-don-t-enable-GDMA-cpu-bridge-unconditio.patch b/package/boot/uboot-mediatek/patches/060-09-net-mediatek-don-t-enable-GDMA-cpu-bridge-unconditio.patch new file mode 100644 index 00000000000..c9ea8f44019 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/060-09-net-mediatek-don-t-enable-GDMA-cpu-bridge-unconditio.patch @@ -0,0 +1,36 @@ +From b9dfb5636bc5eb9b783b88b8388dc7d1f41d6498 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 17 Dec 2024 16:39:59 +0800 +Subject: [PATCH 09/10] net: mediatek: don't enable GDMA cpu bridge + unconditionally for NETSYSv3 + +Enable GDMA cpu bridge only when 10Gb interface is enabled for GMAC other +than GMAC0, or when MT7988 internal switch is used. + +Signed-off-by: Weijie Gao +--- + drivers/net/mtk_eth.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +--- a/drivers/net/mtk_eth.c ++++ b/drivers/net/mtk_eth.c +@@ -1762,10 +1762,16 @@ static int mtk_eth_start(struct udevice + if (priv->sw == SW_MT7988 && priv->gmac_id == 0) { + mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, + GDMA_BRIDGE_TO_CPU); +- } + +- mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG, +- GDMA_CPU_BRIDGE_EN); ++ mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG, ++ GDMA_CPU_BRIDGE_EN); ++ } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER || ++ priv->phy_interface == PHY_INTERFACE_MODE_XGMII) && ++ priv->gmac_id != 0) { ++ mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG, ++ GDMA_CPU_BRIDGE_EN); ++ } + } + + udelay(500); diff --git a/package/boot/uboot-mediatek/patches/060-10-net-mediatek-fix-usability-with-wget-command.patch b/package/boot/uboot-mediatek/patches/060-10-net-mediatek-fix-usability-with-wget-command.patch new file mode 100644 index 00000000000..a20d79030fc --- /dev/null +++ b/package/boot/uboot-mediatek/patches/060-10-net-mediatek-fix-usability-with-wget-command.patch @@ -0,0 +1,37 @@ +From c949686e558e00cbb8c38f7c060701006d70cea8 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Tue, 17 Dec 2024 16:40:03 +0800 +Subject: [PATCH 10/10] net: mediatek: fix usability with wget command + +The wget command currently cannot work correctly with mtk_eth driver. +This patch fixed this by increase DMA ring size and invalidate ring data +after use. + +Signed-off-by: Weijie Gao +--- + drivers/net/mtk_eth.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/drivers/net/mtk_eth.c ++++ b/drivers/net/mtk_eth.c +@@ -29,8 +29,8 @@ + + #include "mtk_eth.h" + +-#define NUM_TX_DESC 24 +-#define NUM_RX_DESC 24 ++#define NUM_TX_DESC 32 ++#define NUM_RX_DESC 32 + #define TX_TOTAL_BUF_SIZE (NUM_TX_DESC * PKTSIZE_ALIGN) + #define RX_TOTAL_BUF_SIZE (NUM_RX_DESC * PKTSIZE_ALIGN) + #define TOTAL_PKT_BUF_SIZE (TX_TOTAL_BUF_SIZE + RX_TOTAL_BUF_SIZE) +@@ -1897,6 +1897,9 @@ static int mtk_eth_free_pkt(struct udevi + + rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size; + ++ invalidate_dcache_range((ulong)rxd->rxd1, ++ (ulong)rxd->rxd1 + PKTSIZE_ALIGN); ++ + if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) || + MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) + rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN); diff --git a/package/boot/uboot-mediatek/patches/061-01-net-mediatek-split-ethernet-switch-code-from-mtk_eth.patch b/package/boot/uboot-mediatek/patches/061-01-net-mediatek-split-ethernet-switch-code-from-mtk_eth.patch new file mode 100644 index 00000000000..b212c6c2198 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/061-01-net-mediatek-split-ethernet-switch-code-from-mtk_eth.patch @@ -0,0 +1,6311 @@ +From 626cdca5b68acdc72d2533e2ed2306c06f296725 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Fri, 10 Jan 2025 16:41:13 +0800 +Subject: [PATCH 1/3] net: mediatek: split ethernet switch code from mtk_eth.c + +mtk_eth.c contains not only the ethernet GMAC/DMA driver, but also +some ethernet switch initialization code. As we may add more switch +support in the future, it's better to move them out of mtk_eth.c to +avoid increasing the code complexity. + +Since not all switches are supported for a particular board, Kconfig +options are added to allow user to select which switch should be +built into u-boot. If multiple switches are selected, auto-detecting +can also be enabled. + +Signed-off-by: Weijie Gao +--- + drivers/net/Kconfig | 21 +- + drivers/net/Makefile | 2 +- + drivers/net/mtk_eth/Kconfig | 35 + + drivers/net/mtk_eth/Makefile | 9 + + drivers/net/mtk_eth/mt7530.c | 281 ++++++++ + drivers/net/mtk_eth/mt7531.c | 293 +++++++++ + drivers/net/mtk_eth/mt753x.c | 262 ++++++++ + drivers/net/mtk_eth/mt753x.h | 286 ++++++++ + drivers/net/mtk_eth/mt7988.c | 160 +++++ + drivers/net/{ => mtk_eth}/mtk_eth.c | 971 ++++------------------------ + drivers/net/{ => mtk_eth}/mtk_eth.h | 301 ++------- + 11 files changed, 1520 insertions(+), 1101 deletions(-) + create mode 100644 drivers/net/mtk_eth/Kconfig + create mode 100644 drivers/net/mtk_eth/Makefile + create mode 100644 drivers/net/mtk_eth/mt7530.c + create mode 100644 drivers/net/mtk_eth/mt7531.c + create mode 100644 drivers/net/mtk_eth/mt753x.c + create mode 100644 drivers/net/mtk_eth/mt753x.h + create mode 100644 drivers/net/mtk_eth/mt7988.c + rename drivers/net/{ => mtk_eth}/mtk_eth.c (62%) + rename drivers/net/{ => mtk_eth}/mtk_eth.h (59%) + +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -966,26 +966,7 @@ config TSEC_ENET + This driver implements support for the (Enhanced) Three-Speed + Ethernet Controller found on Freescale SoCs. + +-config MEDIATEK_ETH +- bool "MediaTek Ethernet GMAC Driver" +- select PHYLIB +- select DM_GPIO +- select DM_RESET +- help +- This Driver support MediaTek Ethernet GMAC +- Say Y to enable support for the MediaTek Ethernet GMAC. +- +-if MEDIATEK_ETH +- +-config MTK_ETH_SGMII +- bool +- default y if ARCH_MEDIATEK && !TARGET_MT7623 +- +-config MTK_ETH_XGMII +- bool +- default y if TARGET_MT7987 || TARGET_MT7988 +- +-endif # MEDIATEK_ETH ++source "drivers/net/mtk_eth/Kconfig" + + config HIFEMAC_ETH + bool "HiSilicon Fast Ethernet Controller" +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -67,7 +67,7 @@ obj-$(CONFIG_MDIO_MUX_MESON_GXL) += mdio + obj-$(CONFIG_MDIO_MUX_MMIOREG) += mdio_mux_mmioreg.o + obj-$(CONFIG_MDIO_MUX_SANDBOX) += mdio_mux_sandbox.o + obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o +-obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o ++obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth/ + obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o + obj-$(CONFIG_MT7620_ETH) += mt7620-eth.o + obj-$(CONFIG_MT7628_ETH) += mt7628-eth.o +--- /dev/null ++++ b/drivers/net/mtk_eth/Kconfig +@@ -0,0 +1,35 @@ ++ ++config MEDIATEK_ETH ++ bool "MediaTek Ethernet GMAC Driver" ++ select PHYLIB ++ select DM_GPIO ++ select DM_RESET ++ help ++ This Driver support MediaTek Ethernet GMAC ++ Say Y to enable support for the MediaTek Ethernet GMAC. ++ ++if MEDIATEK_ETH ++ ++config MTK_ETH_SGMII ++ bool ++ default y if ARCH_MEDIATEK && !TARGET_MT7623 ++ ++config MTK_ETH_XGMII ++ bool ++ default y if TARGET_MT7988 ++ ++config MTK_ETH_SWITCH_MT7530 ++ bool "Support for MediaTek MT7530 ethernet switch" ++ default y if TARGET_MT7623 || SOC_MT7621 ++ ++config MTK_ETH_SWITCH_MT7531 ++ bool "Support for MediaTek MT7531 ethernet switch" ++ default y if TARGET_MT7622 || TARGET_MT7629 || TARGET_MT7981 || \ ++ TARGET_MT7986 ++ ++config MTK_ETH_SWITCH_MT7988 ++ bool "Support for MediaTek MT7988 built-in ethernet switch" ++ depends on TARGET_MT7988 ++ default y ++ ++endif # MEDIATEK_ETH +--- /dev/null ++++ b/drivers/net/mtk_eth/Makefile +@@ -0,0 +1,9 @@ ++# SPDX-License-Identifier: GPL-2.0+ ++# ++# Copyright (C) 2025 MediaTek Inc. ++# Author: Weijie Gao ++ ++obj-y += mtk_eth.o ++obj-$(CONFIG_MTK_ETH_SWITCH_MT7530) += mt753x.o mt7530.o ++obj-$(CONFIG_MTK_ETH_SWITCH_MT7531) += mt753x.o mt7531.o ++obj-$(CONFIG_MTK_ETH_SWITCH_MT7988) += mt753x.o mt7988.o +--- /dev/null ++++ b/drivers/net/mtk_eth/mt7530.c +@@ -0,0 +1,281 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2025 MediaTek Inc. ++ * ++ * Author: Weijie Gao ++ * Author: Mark Lee ++ */ ++ ++#include ++#include ++#include ++#include ++#include "mtk_eth.h" ++#include "mt753x.h" ++ ++#define CHIP_REV 0x7ffc ++#define CHIP_NAME_S 16 ++#define CHIP_NAME_M 0xffff0000 ++#define CHIP_REV_S 0 ++#define CHIP_REV_M 0x0f ++ ++static void mt7530_core_reg_write(struct mt753x_switch_priv *priv, u32 reg, ++ u32 val) ++{ ++ u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0); ++ ++ mtk_mmd_ind_write(priv->epriv.eth, phy_addr, 0x1f, reg, val); ++} ++ ++static int mt7530_pad_clk_setup(struct mt753x_switch_priv *priv, int mode) ++{ ++ u32 ncpo1, ssc_delta; ++ ++ switch (mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ ncpo1 = 0x0c80; ++ ssc_delta = 0x87; ++ break; ++ ++ default: ++ printf("error: xMII mode %d is not supported\n", mode); ++ return -EINVAL; ++ } ++ ++ /* Disable MT7530 core clock */ ++ mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, 0); ++ ++ /* Disable MT7530 PLL */ ++ mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1, ++ (2 << RG_GSWPLL_POSDIV_200M_S) | ++ (32 << RG_GSWPLL_FBKDIV_200M_S)); ++ ++ /* For MT7530 core clock = 500Mhz */ ++ mt7530_core_reg_write(priv, CORE_GSWPLL_GRP2, ++ (1 << RG_GSWPLL_POSDIV_500M_S) | ++ (25 << RG_GSWPLL_FBKDIV_500M_S)); ++ ++ /* Enable MT7530 PLL */ ++ mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1, ++ (2 << RG_GSWPLL_POSDIV_200M_S) | ++ (32 << RG_GSWPLL_FBKDIV_200M_S) | ++ RG_GSWPLL_EN_PRE); ++ ++ udelay(20); ++ ++ mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); ++ ++ /* Setup the MT7530 TRGMII Tx Clock */ ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP5, ncpo1); ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP6, 0); ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP10, ssc_delta); ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP11, ssc_delta); ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN | ++ RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN); ++ ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP2, ++ RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN | ++ (1 << RG_SYSPLL_POSDIV_S)); ++ ++ mt7530_core_reg_write(priv, CORE_PLL_GROUP7, ++ RG_LCDDS_PCW_NCPO_CHG | (3 << RG_LCCDS_C_S) | ++ RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); ++ ++ /* Enable MT7530 core clock */ ++ mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, ++ REG_GSWCK_EN | REG_TRGMIICK_EN); ++ ++ return 0; ++} ++ ++static void mt7530_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable) ++{ ++ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; ++ u32 pmcr = FORCE_MODE; ++ ++ if (enable) ++ pmcr = priv->pmcr; ++ ++ mt753x_reg_write(priv, PMCR_REG(6), pmcr); ++} ++ ++static int mt7530_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) ++{ ++ struct mt753x_switch_priv *priv = bus->priv; ++ ++ if (devad < 0) ++ return mtk_mii_read(priv->epriv.eth, addr, reg); ++ ++ return mtk_mmd_ind_read(priv->epriv.eth, addr, devad, reg); ++} ++ ++static int mt7530_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, ++ u16 val) ++{ ++ struct mt753x_switch_priv *priv = bus->priv; ++ ++ if (devad < 0) ++ return mtk_mii_write(priv->epriv.eth, addr, reg, val); ++ ++ return mtk_mmd_ind_write(priv->epriv.eth, addr, devad, reg, val); ++} ++ ++static int mt7530_mdio_register(struct mt753x_switch_priv *priv) ++{ ++ struct mii_dev *mdio_bus = mdio_alloc(); ++ int ret; ++ ++ if (!mdio_bus) ++ return -ENOMEM; ++ ++ mdio_bus->read = mt7530_mdio_read; ++ mdio_bus->write = mt7530_mdio_write; ++ snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name); ++ ++ mdio_bus->priv = priv; ++ ++ ret = mdio_register(mdio_bus); ++ if (ret) { ++ mdio_free(mdio_bus); ++ return ret; ++ } ++ ++ priv->mdio_bus = mdio_bus; ++ ++ return 0; ++} ++ ++static int mt7530_setup(struct mtk_eth_switch_priv *swpriv) ++{ ++ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; ++ u16 phy_addr, phy_val; ++ u32 i, val, txdrv; ++ ++ priv->smi_addr = MT753X_DFL_SMI_ADDR; ++ priv->reg_read = mt753x_mdio_reg_read; ++ priv->reg_write = mt753x_mdio_reg_write; ++ ++ if (!MTK_HAS_CAPS(priv->epriv.soc->caps, MTK_TRGMII_MT7621_CLK)) { ++ /* Select 250MHz clk for RGMII mode */ ++ mtk_ethsys_rmw(priv->epriv.eth, ETHSYS_CLKCFG0_REG, ++ ETHSYS_TRGMII_CLK_SEL362_5, 0); ++ ++ txdrv = 8; ++ } else { ++ txdrv = 4; ++ } ++ ++ /* Modify HWTRAP first to allow direct access to internal PHYs */ ++ mt753x_reg_read(priv, HWTRAP_REG, &val); ++ val |= CHG_TRAP; ++ val &= ~C_MDIO_BPS; ++ mt753x_reg_write(priv, MHWTRAP_REG, val); ++ ++ /* Calculate the phy base address */ ++ val = ((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3; ++ priv->phy_base = (val | 0x7) + 1; ++ ++ /* Turn off PHYs */ ++ for (i = 0; i < MT753X_NUM_PHYS; i++) { ++ phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); ++ phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR); ++ phy_val |= BMCR_PDOWN; ++ mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val); ++ } ++ ++ /* Force MAC link down before reset */ ++ mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE); ++ mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE); ++ ++ /* MT7530 reset */ ++ mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST); ++ udelay(100); ++ ++ val = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | ++ MAC_MODE | FORCE_MODE | ++ MAC_TX_EN | MAC_RX_EN | ++ BKOFF_EN | BACKPR_EN | ++ (SPEED_1000M << FORCE_SPD_S) | ++ FORCE_DPX | FORCE_LINK; ++ ++ /* MT7530 Port6: Forced 1000M/FD, FC disabled */ ++ priv->pmcr = val; ++ ++ /* MT7530 Port5: Forced link down */ ++ mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE); ++ ++ /* Keep MAC link down before starting eth */ ++ mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE); ++ ++ /* MT7530 Port6: Set to RGMII */ ++ mt753x_reg_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_M, P6_INTF_MODE_RGMII); ++ ++ /* Hardware Trap: Enable Port6, Disable Port5 */ ++ mt753x_reg_read(priv, HWTRAP_REG, &val); ++ val |= CHG_TRAP | LOOPDET_DIS | P5_INTF_DIS | ++ (P5_INTF_SEL_GMAC5 << P5_INTF_SEL_S) | ++ (P5_INTF_MODE_RGMII << P5_INTF_MODE_S); ++ val &= ~(C_MDIO_BPS | P6_INTF_DIS); ++ mt753x_reg_write(priv, MHWTRAP_REG, val); ++ ++ /* Setup switch core pll */ ++ mt7530_pad_clk_setup(priv, priv->epriv.phy_interface); ++ ++ /* Lower Tx Driving for TRGMII path */ ++ for (i = 0 ; i < NUM_TRGMII_CTRL ; i++) ++ mt753x_reg_write(priv, MT7530_TRGMII_TD_ODT(i), ++ (txdrv << TD_DM_DRVP_S) | ++ (txdrv << TD_DM_DRVN_S)); ++ ++ for (i = 0 ; i < NUM_TRGMII_CTRL; i++) ++ mt753x_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16); ++ ++ /* Enable port isolation to block inter-port communication */ ++ mt753x_port_isolation(priv); ++ ++ /* Turn on PHYs */ ++ for (i = 0; i < MT753X_NUM_PHYS; i++) { ++ phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); ++ phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR); ++ phy_val &= ~BMCR_PDOWN; ++ mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val); ++ } ++ ++ return mt7530_mdio_register(priv); ++} ++ ++static int mt7530_cleanup(struct mtk_eth_switch_priv *swpriv) ++{ ++ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; ++ ++ mdio_unregister(priv->mdio_bus); ++ ++ return 0; ++} ++ ++static int mt7530_detect(struct mtk_eth_priv *priv) ++{ ++ int ret; ++ u32 rev; ++ ++ ret = __mt753x_mdio_reg_read(priv, MT753X_DFL_SMI_ADDR, CHIP_REV, &rev); ++ if (ret) ++ return ret; ++ ++ if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == 0x7530) ++ return 0; ++ ++ return -ENODEV; ++} ++ ++MTK_ETH_SWITCH(mt7530) = { ++ .name = "mt7530", ++ .desc = "MediaTek MT7530", ++ .priv_size = sizeof(struct mt753x_switch_priv), ++ .reset_wait_time = 1000, ++ ++ .detect = mt7530_detect, ++ .setup = mt7530_setup, ++ .cleanup = mt7530_cleanup, ++ .mac_control = mt7530_mac_control, ++}; +--- /dev/null ++++ b/drivers/net/mtk_eth/mt7531.c +@@ -0,0 +1,293 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2025 MediaTek Inc. ++ * ++ * Author: Weijie Gao ++ * Author: Mark Lee ++ */ ++ ++#include ++#include ++#include ++#include ++#include "mtk_eth.h" ++#include "mt753x.h" ++ ++#define CHIP_REV 0x781C ++#define CHIP_NAME_S 16 ++#define CHIP_NAME_M 0xffff0000 ++#define CHIP_REV_S 0 ++#define CHIP_REV_M 0x0f ++#define CHIP_REV_E1 0x0 ++ ++static int mt7531_core_reg_read(struct mt753x_switch_priv *priv, u32 reg) ++{ ++ u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0); ++ ++ return mt7531_mmd_read(priv, phy_addr, 0x1f, reg); ++} ++ ++static void mt7531_core_reg_write(struct mt753x_switch_priv *priv, u32 reg, ++ u32 val) ++{ ++ u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0); ++ ++ mt7531_mmd_write(priv, phy_addr, 0x1f, reg, val); ++} ++ ++static void mt7531_core_pll_setup(struct mt753x_switch_priv *priv) ++{ ++ /* Step 1 : Disable MT7531 COREPLL */ ++ mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, 0); ++ ++ /* Step 2: switch to XTAL output */ ++ mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_CLKSW, SW_CLKSW); ++ ++ mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, 0); ++ ++ /* Step 3: disable PLLGP and enable program PLLGP */ ++ mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_PLLGP, SW_PLLGP); ++ ++ /* Step 4: program COREPLL output frequency to 500MHz */ ++ mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_POSDIV_M, ++ 2 << RG_COREPLL_POSDIV_S); ++ udelay(25); ++ ++ /* Currently, support XTAL 25Mhz only */ ++ mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_M, ++ 0x140000 << RG_COREPLL_SDM_PCW_S); ++ ++ /* Set feedback divide ratio update signal to high */ ++ mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG, ++ RG_COREPLL_SDM_PCW_CHG); ++ ++ /* Wait for at least 16 XTAL clocks */ ++ udelay(10); ++ ++ /* Step 5: set feedback divide ratio update signal to low */ ++ mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG, 0); ++ ++ /* add enable 325M clock for SGMII */ ++ mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000); ++ ++ /* add enable 250SSC clock for RGMII */ ++ mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000); ++ ++ /*Step 6: Enable MT7531 PLL */ ++ mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, RG_COREPLL_EN); ++ ++ mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, EN_COREPLL); ++ ++ udelay(25); ++} ++ ++static int mt7531_port_sgmii_init(struct mt753x_switch_priv *priv, u32 port) ++{ ++ if (port != 5 && port != 6) { ++ printf("mt7531: port %d is not a SGMII port\n", port); ++ return -EINVAL; ++ } ++ ++ /* Set SGMII GEN2 speed(2.5G) */ ++ mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), SGMSYS_SPEED_MASK, ++ FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500)); ++ ++ /* Disable SGMII AN */ ++ mt753x_reg_rmw(priv, MT7531_PCS_CONTROL_1(port), ++ SGMII_AN_ENABLE, 0); ++ ++ /* SGMII force mode setting */ ++ mt753x_reg_write(priv, MT7531_SGMII_MODE(port), SGMII_FORCE_MODE); ++ ++ /* Release PHYA power down state */ ++ mt753x_reg_rmw(priv, MT7531_QPHY_PWR_STATE_CTRL(port), ++ SGMII_PHYA_PWD, 0); ++ ++ return 0; ++} ++ ++static int mt7531_port_rgmii_init(struct mt753x_switch_priv *priv, u32 port) ++{ ++ u32 val; ++ ++ if (port != 5) { ++ printf("error: RGMII mode is not available for port %d\n", ++ port); ++ return -EINVAL; ++ } ++ ++ mt753x_reg_read(priv, MT7531_CLKGEN_CTRL, &val); ++ val |= GP_CLK_EN; ++ val &= ~GP_MODE_M; ++ val |= GP_MODE_RGMII << GP_MODE_S; ++ val |= TXCLK_NO_REVERSE; ++ val |= RXCLK_NO_DELAY; ++ val &= ~CLK_SKEW_IN_M; ++ val |= CLK_SKEW_IN_NO_CHANGE << CLK_SKEW_IN_S; ++ val &= ~CLK_SKEW_OUT_M; ++ val |= CLK_SKEW_OUT_NO_CHANGE << CLK_SKEW_OUT_S; ++ mt753x_reg_write(priv, MT7531_CLKGEN_CTRL, val); ++ ++ return 0; ++} ++ ++static void mt7531_phy_setting(struct mt753x_switch_priv *priv) ++{ ++ int i; ++ u32 val; ++ ++ for (i = 0; i < MT753X_NUM_PHYS; i++) { ++ /* Enable HW auto downshift */ ++ mt7531_mii_write(priv, i, 0x1f, 0x1); ++ val = mt7531_mii_read(priv, i, PHY_EXT_REG_14); ++ val |= PHY_EN_DOWN_SHFIT; ++ mt7531_mii_write(priv, i, PHY_EXT_REG_14, val); ++ ++ /* PHY link down power saving enable */ ++ val = mt7531_mii_read(priv, i, PHY_EXT_REG_17); ++ val |= PHY_LINKDOWN_POWER_SAVING_EN; ++ mt7531_mii_write(priv, i, PHY_EXT_REG_17, val); ++ ++ val = mt7531_mmd_read(priv, i, 0x1e, PHY_DEV1E_REG_0C6); ++ val &= ~PHY_POWER_SAVING_M; ++ val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S; ++ mt7531_mmd_write(priv, i, 0x1e, PHY_DEV1E_REG_0C6, val); ++ } ++} ++ ++static void mt7531_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable) ++{ ++ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; ++ u32 pmcr = FORCE_MODE_LNK; ++ ++ if (enable) ++ pmcr = priv->pmcr; ++ ++ mt753x_reg_write(priv, PMCR_REG(5), pmcr); ++ mt753x_reg_write(priv, PMCR_REG(6), pmcr); ++} ++ ++static int mt7531_setup(struct mtk_eth_switch_priv *swpriv) ++{ ++ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; ++ u32 i, val, pmcr, port5_sgmii; ++ u16 phy_addr, phy_val; ++ ++ priv->smi_addr = MT753X_DFL_SMI_ADDR; ++ priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK; ++ priv->reg_read = mt753x_mdio_reg_read; ++ priv->reg_write = mt753x_mdio_reg_write; ++ ++ /* Turn off PHYs */ ++ for (i = 0; i < MT753X_NUM_PHYS; i++) { ++ phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); ++ phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); ++ phy_val |= BMCR_PDOWN; ++ mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); ++ } ++ ++ /* Force MAC link down before reset */ ++ mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK); ++ mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK); ++ ++ /* Switch soft reset */ ++ mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST); ++ udelay(100); ++ ++ /* Enable MDC input Schmitt Trigger */ ++ mt753x_reg_rmw(priv, MT7531_SMT0_IOLB, SMT_IOLB_5_SMI_MDC_EN, ++ SMT_IOLB_5_SMI_MDC_EN); ++ ++ mt7531_core_pll_setup(priv); ++ ++ mt753x_reg_read(priv, MT7531_TOP_SIG_SR, &val); ++ port5_sgmii = !!(val & PAD_DUAL_SGMII_EN); ++ ++ /* port5 support either RGMII or SGMII, port6 only support SGMII. */ ++ switch (priv->epriv.phy_interface) { ++ case PHY_INTERFACE_MODE_RGMII: ++ if (!port5_sgmii) ++ mt7531_port_rgmii_init(priv, 5); ++ break; ++ ++ case PHY_INTERFACE_MODE_2500BASEX: ++ mt7531_port_sgmii_init(priv, 6); ++ if (port5_sgmii) ++ mt7531_port_sgmii_init(priv, 5); ++ break; ++ ++ default: ++ break; ++ } ++ ++ pmcr = MT7531_FORCE_MODE | ++ (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | ++ MAC_MODE | MAC_TX_EN | MAC_RX_EN | ++ BKOFF_EN | BACKPR_EN | ++ FORCE_RX_FC | FORCE_TX_FC | ++ (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX | ++ FORCE_LINK; ++ ++ priv->pmcr = pmcr; ++ ++ /* Keep MAC link down before starting eth */ ++ mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK); ++ mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK); ++ ++ /* Enable port isolation to block inter-port communication */ ++ mt753x_port_isolation(priv); ++ ++ /* Turn on PHYs */ ++ for (i = 0; i < MT753X_NUM_PHYS; i++) { ++ phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); ++ phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); ++ phy_val &= ~BMCR_PDOWN; ++ mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); ++ } ++ ++ mt7531_phy_setting(priv); ++ ++ /* Enable Internal PHYs */ ++ val = mt7531_core_reg_read(priv, CORE_PLL_GROUP4); ++ val |= MT7531_BYPASS_MODE; ++ val &= ~MT7531_POWER_ON_OFF; ++ mt7531_core_reg_write(priv, CORE_PLL_GROUP4, val); ++ ++ return mt7531_mdio_register(priv); ++} ++ ++static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv) ++{ ++ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; ++ ++ mdio_unregister(priv->mdio_bus); ++ ++ return 0; ++} ++ ++static int mt7531_detect(struct mtk_eth_priv *priv) ++{ ++ int ret; ++ u32 rev; ++ ++ ret = __mt753x_mdio_reg_read(priv, MT753X_DFL_SMI_ADDR, CHIP_REV, &rev); ++ if (ret) ++ return ret; ++ ++ if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == 0x7531) ++ return 0; ++ ++ return -ENODEV; ++} ++ ++MTK_ETH_SWITCH(mt7531) = { ++ .name = "mt7531", ++ .desc = "MediaTek MT7531", ++ .priv_size = sizeof(struct mt753x_switch_priv), ++ .reset_wait_time = 200, ++ ++ .detect = mt7531_detect, ++ .setup = mt7531_setup, ++ .cleanup = mt7531_cleanup, ++ .mac_control = mt7531_mac_control, ++}; +--- /dev/null ++++ b/drivers/net/mtk_eth/mt753x.c +@@ -0,0 +1,262 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2025 MediaTek Inc. ++ * ++ * Author: Weijie Gao ++ * Author: Mark Lee ++ */ ++ ++#include ++#include ++#include "mtk_eth.h" ++#include "mt753x.h" ++ ++/* ++ * MT753x Internal Register Address Bits ++ * ------------------------------------------------------------------- ++ * | 15 14 13 12 11 10 9 8 7 6 | 5 4 3 2 | 1 0 | ++ * |----------------------------------------|---------------|--------| ++ * | Page Address | Reg Address | Unused | ++ * ------------------------------------------------------------------- ++ */ ++ ++int __mt753x_mdio_reg_read(struct mtk_eth_priv *priv, u32 smi_addr, u32 reg, ++ u32 *data) ++{ ++ int ret, low_word, high_word; ++ ++ /* Write page address */ ++ ret = mtk_mii_write(priv, smi_addr, 0x1f, reg >> 6); ++ if (ret) ++ return ret; ++ ++ /* Read low word */ ++ low_word = mtk_mii_read(priv, smi_addr, (reg >> 2) & 0xf); ++ if (low_word < 0) ++ return low_word; ++ ++ /* Read high word */ ++ high_word = mtk_mii_read(priv, smi_addr, 0x10); ++ if (high_word < 0) ++ return high_word; ++ ++ if (data) ++ *data = ((u32)high_word << 16) | (low_word & 0xffff); ++ ++ return 0; ++} ++ ++int mt753x_mdio_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data) ++{ ++ return __mt753x_mdio_reg_read(priv->epriv.eth, priv->smi_addr, reg, ++ data); ++} ++ ++int mt753x_mdio_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data) ++{ ++ int ret; ++ ++ /* Write page address */ ++ ret = mtk_mii_write(priv->epriv.eth, priv->smi_addr, 0x1f, reg >> 6); ++ if (ret) ++ return ret; ++ ++ /* Write low word */ ++ ret = mtk_mii_write(priv->epriv.eth, priv->smi_addr, (reg >> 2) & 0xf, ++ data & 0xffff); ++ if (ret) ++ return ret; ++ ++ /* Write high word */ ++ return mtk_mii_write(priv->epriv.eth, priv->smi_addr, 0x10, data >> 16); ++} ++ ++int mt753x_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data) ++{ ++ return priv->reg_read(priv, reg, data); ++} ++ ++int mt753x_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data) ++{ ++ return priv->reg_write(priv, reg, data); ++} ++ ++void mt753x_reg_rmw(struct mt753x_switch_priv *priv, u32 reg, u32 clr, u32 set) ++{ ++ u32 val; ++ ++ priv->reg_read(priv, reg, &val); ++ val &= ~clr; ++ val |= set; ++ priv->reg_write(priv, reg, val); ++} ++ ++/* Indirect MDIO clause 22/45 access */ ++static int mt7531_mii_rw(struct mt753x_switch_priv *priv, int phy, int reg, ++ u16 data, u32 cmd, u32 st) ++{ ++ u32 val, timeout_ms; ++ ulong timeout; ++ int ret = 0; ++ ++ val = (st << MDIO_ST_S) | ++ ((cmd << MDIO_CMD_S) & MDIO_CMD_M) | ++ ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) | ++ ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M); ++ ++ if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR) ++ val |= data & MDIO_RW_DATA_M; ++ ++ mt753x_reg_write(priv, MT7531_PHY_IAC, val | PHY_ACS_ST); ++ ++ timeout_ms = 100; ++ timeout = get_timer(0); ++ while (1) { ++ mt753x_reg_read(priv, MT7531_PHY_IAC, &val); ++ ++ if ((val & PHY_ACS_ST) == 0) ++ break; ++ ++ if (get_timer(timeout) > timeout_ms) ++ return -ETIMEDOUT; ++ } ++ ++ if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) { ++ mt753x_reg_read(priv, MT7531_PHY_IAC, &val); ++ ret = val & MDIO_RW_DATA_M; ++ } ++ ++ return ret; ++} ++ ++int mt7531_mii_read(struct mt753x_switch_priv *priv, u8 phy, u8 reg) ++{ ++ u8 phy_addr; ++ ++ if (phy >= MT753X_NUM_PHYS) ++ return -EINVAL; ++ ++ phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy); ++ ++ return mt7531_mii_rw(priv, phy_addr, reg, 0, MDIO_CMD_READ, ++ MDIO_ST_C22); ++} ++ ++int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val) ++{ ++ u8 phy_addr; ++ ++ if (phy >= MT753X_NUM_PHYS) ++ return -EINVAL; ++ ++ phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy); ++ ++ return mt7531_mii_rw(priv, phy_addr, reg, val, MDIO_CMD_WRITE, ++ MDIO_ST_C22); ++} ++ ++int mt7531_mmd_read(struct mt753x_switch_priv *priv, u8 addr, u8 devad, ++ u16 reg) ++{ ++ u8 phy_addr; ++ int ret; ++ ++ if (addr >= MT753X_NUM_PHYS) ++ return -EINVAL; ++ ++ phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr); ++ ++ ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR, ++ MDIO_ST_C45); ++ if (ret) ++ return ret; ++ ++ return mt7531_mii_rw(priv, phy_addr, devad, 0, MDIO_CMD_READ_C45, ++ MDIO_ST_C45); ++} ++ ++int mt7531_mmd_write(struct mt753x_switch_priv *priv, u8 addr, u8 devad, ++ u16 reg, u16 val) ++{ ++ u8 phy_addr; ++ int ret; ++ ++ if (addr >= MT753X_NUM_PHYS) ++ return 0; ++ ++ phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr); ++ ++ ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR, ++ MDIO_ST_C45); ++ if (ret) ++ return ret; ++ ++ return mt7531_mii_rw(priv, phy_addr, devad, val, MDIO_CMD_WRITE, ++ MDIO_ST_C45); ++} ++ ++static int mt7531_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) ++{ ++ struct mt753x_switch_priv *priv = bus->priv; ++ ++ if (devad < 0) ++ return mt7531_mii_read(priv, addr, reg); ++ ++ return mt7531_mmd_read(priv, addr, devad, reg); ++} ++ ++static int mt7531_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, ++ u16 val) ++{ ++ struct mt753x_switch_priv *priv = bus->priv; ++ ++ if (devad < 0) ++ return mt7531_mii_write(priv, addr, reg, val); ++ ++ return mt7531_mmd_write(priv, addr, devad, reg, val); ++} ++ ++int mt7531_mdio_register(struct mt753x_switch_priv *priv) ++{ ++ struct mii_dev *mdio_bus = mdio_alloc(); ++ int ret; ++ ++ if (!mdio_bus) ++ return -ENOMEM; ++ ++ mdio_bus->read = mt7531_mdio_read; ++ mdio_bus->write = mt7531_mdio_write; ++ snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name); ++ ++ mdio_bus->priv = priv; ++ ++ ret = mdio_register(mdio_bus); ++ if (ret) { ++ mdio_free(mdio_bus); ++ return ret; ++ } ++ ++ priv->mdio_bus = mdio_bus; ++ ++ return 0; ++} ++ ++void mt753x_port_isolation(struct mt753x_switch_priv *priv) ++{ ++ u32 i; ++ ++ for (i = 0; i < MT753X_NUM_PORTS; i++) { ++ /* Set port matrix mode */ ++ if (i != 6) ++ mt753x_reg_write(priv, PCR_REG(i), ++ (0x40 << PORT_MATRIX_S)); ++ else ++ mt753x_reg_write(priv, PCR_REG(i), ++ (0x3f << PORT_MATRIX_S)); ++ ++ /* Set port mode to user port */ ++ mt753x_reg_write(priv, PVC_REG(i), ++ (0x8100 << STAG_VPID_S) | ++ (VLAN_ATTR_USER << VLAN_ATTR_S)); ++ } ++} +--- /dev/null ++++ b/drivers/net/mtk_eth/mt753x.h +@@ -0,0 +1,286 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2025 MediaTek Inc. ++ * ++ * Author: Weijie Gao ++ * Author: Mark Lee ++ */ ++ ++#ifndef _MTK_ETH_MT753X_H_ ++#define _MTK_ETH_MT753X_H_ ++ ++#include ++#include ++#include ++#include ++ ++struct mtk_eth_priv; ++ ++#define MT753X_NUM_PHYS 5 ++#define MT753X_NUM_PORTS 7 ++#define MT753X_DFL_SMI_ADDR 31 ++#define MT753X_SMI_ADDR_MASK 0x1f ++ ++#define MT753X_PHY_ADDR(base, addr) \ ++ (((base) + (addr)) & 0x1f) ++ ++/* MT7530 Registers */ ++#define PCR_REG(p) (0x2004 + (p) * 0x100) ++#define PORT_MATRIX_S 16 ++#define PORT_MATRIX_M 0xff0000 ++ ++#define PVC_REG(p) (0x2010 + (p) * 0x100) ++#define STAG_VPID_S 16 ++#define STAG_VPID_M 0xffff0000 ++#define VLAN_ATTR_S 6 ++#define VLAN_ATTR_M 0xc0 ++ ++/* VLAN_ATTR: VLAN attributes */ ++#define VLAN_ATTR_USER 0 ++#define VLAN_ATTR_STACK 1 ++#define VLAN_ATTR_TRANSLATION 2 ++#define VLAN_ATTR_TRANSPARENT 3 ++ ++#define PMCR_REG(p) (0x3000 + (p) * 0x100) ++/* XXX: all fields of MT7530 are defined under GMAC_PORT_MCR ++ * MT7531 specific fields are defined below ++ */ ++#define FORCE_MODE_EEE1G BIT(25) ++#define FORCE_MODE_EEE100 BIT(26) ++#define FORCE_MODE_TX_FC BIT(27) ++#define FORCE_MODE_RX_FC BIT(28) ++#define FORCE_MODE_DPX BIT(29) ++#define FORCE_MODE_SPD BIT(30) ++#define FORCE_MODE_LNK BIT(31) ++#define MT7531_FORCE_MODE FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \ ++ FORCE_MODE_DPX | FORCE_MODE_SPD | \ ++ FORCE_MODE_LNK ++#define MT7988_FORCE_MODE FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \ ++ FORCE_MODE_DPX | FORCE_MODE_SPD | \ ++ FORCE_MODE_LNK ++ ++/* MT7531 SGMII Registers */ ++#define MT7531_SGMII_REG_BASE 0x5000 ++#define MT7531_SGMII_REG_PORT_BASE 0x1000 ++#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \ ++ (p) * MT7531_SGMII_REG_PORT_BASE + (r)) ++#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(((p) - 5), 0x00) ++#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(((p) - 5), 0x20) ++#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(((p) - 5), 0xe8) ++#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(((p) - 5), 0x128) ++#define MT7531_PHYA_ANA_SYSPLL(p) MT7531_SGMII_REG(((p) - 5), 0x158) ++/* XXX: all fields of MT7531 SGMII are defined under SGMSYS */ ++ ++/* MT753x System Control Register */ ++#define SYS_CTRL_REG 0x7000 ++#define SW_PHY_RST BIT(2) ++#define SW_SYS_RST BIT(1) ++#define SW_REG_RST BIT(0) ++ ++/* MT7531 */ ++#define MT7531_PHY_IAC 0x701c ++/* XXX: all fields are defined under GMAC_PIAC_REG */ ++ ++#define MT7531_CLKGEN_CTRL 0x7500 ++#define CLK_SKEW_OUT_S 8 ++#define CLK_SKEW_OUT_M 0x300 ++#define CLK_SKEW_IN_S 6 ++#define CLK_SKEW_IN_M 0xc0 ++#define RXCLK_NO_DELAY BIT(5) ++#define TXCLK_NO_REVERSE BIT(4) ++#define GP_MODE_S 1 ++#define GP_MODE_M 0x06 ++#define GP_CLK_EN BIT(0) ++ ++/* Values of GP_MODE */ ++#define GP_MODE_RGMII 0 ++#define GP_MODE_MII 1 ++#define GP_MODE_REV_MII 2 ++ ++/* Values of CLK_SKEW_IN */ ++#define CLK_SKEW_IN_NO_CHANGE 0 ++#define CLK_SKEW_IN_DELAY_100PPS 1 ++#define CLK_SKEW_IN_DELAY_200PPS 2 ++#define CLK_SKEW_IN_REVERSE 3 ++ ++/* Values of CLK_SKEW_OUT */ ++#define CLK_SKEW_OUT_NO_CHANGE 0 ++#define CLK_SKEW_OUT_DELAY_100PPS 1 ++#define CLK_SKEW_OUT_DELAY_200PPS 2 ++#define CLK_SKEW_OUT_REVERSE 3 ++ ++#define HWTRAP_REG 0x7800 ++/* MT7530 Modified Hardware Trap Status Registers */ ++#define MHWTRAP_REG 0x7804 ++#define CHG_TRAP BIT(16) ++#define LOOPDET_DIS BIT(14) ++#define P5_INTF_SEL_S 13 ++#define P5_INTF_SEL_M 0x2000 ++#define SMI_ADDR_S 11 ++#define SMI_ADDR_M 0x1800 ++#define XTAL_FSEL_S 9 ++#define XTAL_FSEL_M 0x600 ++#define P6_INTF_DIS BIT(8) ++#define P5_INTF_MODE_S 7 ++#define P5_INTF_MODE_M 0x80 ++#define P5_INTF_DIS BIT(6) ++#define C_MDIO_BPS BIT(5) ++#define CHIP_MODE_S 0 ++#define CHIP_MODE_M 0x0f ++ ++/* P5_INTF_SEL: Interface type of Port5 */ ++#define P5_INTF_SEL_GPHY 0 ++#define P5_INTF_SEL_GMAC5 1 ++ ++/* P5_INTF_MODE: Interface mode of Port5 */ ++#define P5_INTF_MODE_GMII_MII 0 ++#define P5_INTF_MODE_RGMII 1 ++ ++#define MT7530_P6ECR 0x7830 ++#define P6_INTF_MODE_M 0x3 ++#define P6_INTF_MODE_S 0 ++ ++/* P6_INTF_MODE: Interface mode of Port6 */ ++#define P6_INTF_MODE_RGMII 0 ++#define P6_INTF_MODE_TRGMII 1 ++ ++#define MT7530_TRGMII_RD(n) (0x7a10 + (n) * 8) ++#define RD_TAP_S 0 ++#define RD_TAP_M 0x7f ++ ++#define MT7530_TRGMII_TD_ODT(n) (0x7a54 + (n) * 8) ++/* XXX: all fields are defined under GMAC_TRGMII_TD_ODT */ ++ ++/* TOP Signals Status Register */ ++#define MT7531_TOP_SIG_SR 0x780c ++#define PAD_MCM_SMI_EN BIT(0) ++#define PAD_DUAL_SGMII_EN BIT(1) ++ ++/* MT7531 PLLGP Registers */ ++#define MT7531_PLLGP_EN 0x7820 ++#define EN_COREPLL BIT(2) ++#define SW_CLKSW BIT(1) ++#define SW_PLLGP BIT(0) ++ ++#define MT7531_PLLGP_CR0 0x78a8 ++#define RG_COREPLL_EN BIT(22) ++#define RG_COREPLL_POSDIV_S 23 ++#define RG_COREPLL_POSDIV_M 0x3800000 ++#define RG_COREPLL_SDM_PCW_S 1 ++#define RG_COREPLL_SDM_PCW_M 0x3ffffe ++#define RG_COREPLL_SDM_PCW_CHG BIT(0) ++ ++/* MT7531 RGMII and SGMII PLL clock */ ++#define MT7531_ANA_PLLGP_CR2 0x78b0 ++#define MT7531_ANA_PLLGP_CR5 0x78bc ++ ++/* MT7531 GPIO GROUP IOLB SMT0 Control */ ++#define MT7531_SMT0_IOLB 0x7f04 ++#define SMT_IOLB_5_SMI_MDC_EN BIT(5) ++ ++/* MT7530 GPHY MDIO MMD Registers */ ++#define CORE_PLL_GROUP2 0x401 ++#define RG_SYSPLL_EN_NORMAL BIT(15) ++#define RG_SYSPLL_VODEN BIT(14) ++#define RG_SYSPLL_POSDIV_S 5 ++#define RG_SYSPLL_POSDIV_M 0x60 ++ ++#define CORE_PLL_GROUP4 0x403 ++#define MT7531_BYPASS_MODE BIT(4) ++#define MT7531_POWER_ON_OFF BIT(5) ++#define RG_SYSPLL_DDSFBK_EN BIT(12) ++#define RG_SYSPLL_BIAS_EN BIT(11) ++#define RG_SYSPLL_BIAS_LPF_EN BIT(10) ++ ++#define CORE_PLL_GROUP5 0x404 ++#define RG_LCDDS_PCW_NCPO1_S 0 ++#define RG_LCDDS_PCW_NCPO1_M 0xffff ++ ++#define CORE_PLL_GROUP6 0x405 ++#define RG_LCDDS_PCW_NCPO0_S 0 ++#define RG_LCDDS_PCW_NCPO0_M 0xffff ++ ++#define CORE_PLL_GROUP7 0x406 ++#define RG_LCDDS_PWDB BIT(15) ++#define RG_LCDDS_ISO_EN BIT(13) ++#define RG_LCCDS_C_S 4 ++#define RG_LCCDS_C_M 0x70 ++#define RG_LCDDS_PCW_NCPO_CHG BIT(3) ++ ++#define CORE_PLL_GROUP10 0x409 ++#define RG_LCDDS_SSC_DELTA_S 0 ++#define RG_LCDDS_SSC_DELTA_M 0xfff ++ ++#define CORE_PLL_GROUP11 0x40a ++#define RG_LCDDS_SSC_DELTA1_S 0 ++#define RG_LCDDS_SSC_DELTA1_M 0xfff ++ ++#define CORE_GSWPLL_GRP1 0x40d ++#define RG_GSWPLL_POSDIV_200M_S 12 ++#define RG_GSWPLL_POSDIV_200M_M 0x3000 ++#define RG_GSWPLL_EN_PRE BIT(11) ++#define RG_GSWPLL_FBKDIV_200M_S 0 ++#define RG_GSWPLL_FBKDIV_200M_M 0xff ++ ++#define CORE_GSWPLL_GRP2 0x40e ++#define RG_GSWPLL_POSDIV_500M_S 8 ++#define RG_GSWPLL_POSDIV_500M_M 0x300 ++#define RG_GSWPLL_FBKDIV_500M_S 0 ++#define RG_GSWPLL_FBKDIV_500M_M 0xff ++ ++#define CORE_TRGMII_GSW_CLK_CG 0x410 ++#define REG_GSWCK_EN BIT(0) ++#define REG_TRGMIICK_EN BIT(1) ++ ++/* Extend PHY Control Register 3 */ ++#define PHY_EXT_REG_14 0x14 ++ ++/* Fields of PHY_EXT_REG_14 */ ++#define PHY_EN_DOWN_SHFIT BIT(4) ++ ++/* Extend PHY Control Register 4 */ ++#define PHY_EXT_REG_17 0x17 ++ ++/* Fields of PHY_EXT_REG_17 */ ++#define PHY_LINKDOWN_POWER_SAVING_EN BIT(4) ++ ++/* PHY RXADC Control Register 7 */ ++#define PHY_DEV1E_REG_0C6 0x0c6 ++ ++/* Fields of PHY_DEV1E_REG_0C6 */ ++#define PHY_POWER_SAVING_S 8 ++#define PHY_POWER_SAVING_M 0x300 ++#define PHY_POWER_SAVING_TX 0x0 ++ ++struct mt753x_switch_priv { ++ struct mtk_eth_switch_priv epriv; ++ struct mii_dev *mdio_bus; ++ u32 smi_addr; ++ u32 phy_base; ++ u32 pmcr; ++ ++ int (*reg_read)(struct mt753x_switch_priv *priv, u32 reg, u32 *data); ++ int (*reg_write)(struct mt753x_switch_priv *priv, u32 reg, u32 data); ++}; ++ ++int __mt753x_mdio_reg_read(struct mtk_eth_priv *priv, u32 smi_addr, u32 reg, ++ u32 *data); ++int mt753x_mdio_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data); ++int mt753x_mdio_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data); ++ ++int mt753x_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data); ++int mt753x_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data); ++void mt753x_reg_rmw(struct mt753x_switch_priv *priv, u32 reg, u32 clr, u32 set); ++ ++int mt7531_mii_read(struct mt753x_switch_priv *priv, u8 phy, u8 reg); ++int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val); ++int mt7531_mmd_read(struct mt753x_switch_priv *priv, u8 addr, u8 devad, ++ u16 reg); ++int mt7531_mmd_write(struct mt753x_switch_priv *priv, u8 addr, u8 devad, ++ u16 reg, u16 val); ++ ++int mt7531_mdio_register(struct mt753x_switch_priv *priv); ++ ++void mt753x_port_isolation(struct mt753x_switch_priv *priv); ++ ++#endif /* _MTK_ETH_MT753X_H_ */ +--- /dev/null ++++ b/drivers/net/mtk_eth/mt7988.c +@@ -0,0 +1,160 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2025 MediaTek Inc. ++ * ++ * Author: Weijie Gao ++ * Author: Mark Lee ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "mtk_eth.h" ++#include "mt753x.h" ++ ++static int mt7988_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data) ++{ ++ *data = readl(priv->epriv.ethsys_base + GSW_BASE + reg); ++ ++ return 0; ++} ++ ++static int mt7988_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data) ++{ ++ writel(data, priv->epriv.ethsys_base + GSW_BASE + reg); ++ ++ return 0; ++} ++ ++static void mt7988_phy_setting(struct mt753x_switch_priv *priv) ++{ ++ u16 val; ++ u32 i; ++ ++ for (i = 0; i < MT753X_NUM_PHYS; i++) { ++ /* Enable HW auto downshift */ ++ mt7531_mii_write(priv, i, 0x1f, 0x1); ++ val = mt7531_mii_read(priv, i, PHY_EXT_REG_14); ++ val |= PHY_EN_DOWN_SHFIT; ++ mt7531_mii_write(priv, i, PHY_EXT_REG_14, val); ++ ++ /* PHY link down power saving enable */ ++ val = mt7531_mii_read(priv, i, PHY_EXT_REG_17); ++ val |= PHY_LINKDOWN_POWER_SAVING_EN; ++ mt7531_mii_write(priv, i, PHY_EXT_REG_17, val); ++ } ++} ++ ++static void mt7988_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable) ++{ ++ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; ++ u32 pmcr = FORCE_MODE_LNK; ++ ++ if (enable) ++ pmcr = priv->pmcr; ++ ++ mt7988_reg_write(priv, PMCR_REG(6), pmcr); ++} ++ ++static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) ++{ ++ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; ++ u16 phy_addr, phy_val; ++ u32 pmcr; ++ int i; ++ ++ priv->smi_addr = MT753X_DFL_SMI_ADDR; ++ priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK; ++ priv->reg_read = mt7988_reg_read; ++ priv->reg_write = mt7988_reg_write; ++ ++ /* Turn off PHYs */ ++ for (i = 0; i < MT753X_NUM_PHYS; i++) { ++ phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); ++ phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); ++ phy_val |= BMCR_PDOWN; ++ mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); ++ } ++ ++ switch (priv->epriv.phy_interface) { ++ case PHY_INTERFACE_MODE_USXGMII: ++ /* Use CPU bridge instead of actual USXGMII path */ ++ ++ /* Disable GDM1 RX CRC stripping */ ++ /* mtk_fe_rmw(priv, 0x500, BIT(16), 0); */ ++ ++ /* Set GDM1 no drop */ ++ mtk_fe_rmw(priv->epriv.eth, PSE_NO_DROP_CFG_REG, 0, ++ PSE_NO_DROP_GDM1); ++ ++ /* Enable GSW CPU bridge as USXGMII */ ++ /* mtk_fe_rmw(priv, 0x504, BIT(31), BIT(31)); */ ++ ++ /* Enable GDM1 to GSW CPU bridge */ ++ mtk_gmac_rmw(priv->epriv.eth, GMAC_MAC_MISC_REG, 0, BIT(0)); ++ ++ /* XGMAC force link up */ ++ mtk_gmac_rmw(priv->epriv.eth, GMAC_XGMAC_STS_REG, 0, ++ P1_XGMAC_FORCE_LINK); ++ ++ /* Setup GSW CPU bridge IPG */ ++ mtk_gmac_rmw(priv->epriv.eth, GMAC_GSW_CFG_REG, ++ GSWTX_IPG_M | GSWRX_IPG_M, ++ (0xB << GSWTX_IPG_S) | (0xB << GSWRX_IPG_S)); ++ break; ++ default: ++ printf("Error: MT7988 GSW does not support %s interface\n", ++ phy_string_for_interface(priv->epriv.phy_interface)); ++ break; ++ } ++ ++ pmcr = MT7988_FORCE_MODE | ++ (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | ++ MAC_MODE | MAC_TX_EN | MAC_RX_EN | ++ BKOFF_EN | BACKPR_EN | ++ FORCE_RX_FC | FORCE_TX_FC | ++ (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX | ++ FORCE_LINK; ++ ++ priv->pmcr = pmcr; ++ ++ /* Keep MAC link down before starting eth */ ++ mt7988_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK); ++ ++ /* Enable port isolation to block inter-port communication */ ++ mt753x_port_isolation(priv); ++ ++ /* Turn on PHYs */ ++ for (i = 0; i < MT753X_NUM_PHYS; i++) { ++ phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); ++ phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); ++ phy_val &= ~BMCR_PDOWN; ++ mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); ++ } ++ ++ mt7988_phy_setting(priv); ++ ++ return mt7531_mdio_register(priv); ++} ++ ++static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv) ++{ ++ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; ++ ++ mdio_unregister(priv->mdio_bus); ++ ++ return 0; ++} ++ ++MTK_ETH_SWITCH(mt7988) = { ++ .name = "mt7988", ++ .desc = "MediaTek MT7988 built-in switch", ++ .priv_size = sizeof(struct mt753x_switch_priv), ++ .reset_wait_time = 50, ++ ++ .setup = mt7988_setup, ++ .cleanup = mt7531_cleanup, ++ .mac_control = mt7988_mac_control, ++}; +--- a/drivers/net/mtk_eth.c ++++ /dev/null +@@ -1,2280 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-/* +- * Copyright (C) 2018 MediaTek Inc. +- * +- * Author: Weijie Gao +- * Author: Mark Lee +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "mtk_eth.h" +- +-#define NUM_TX_DESC 32 +-#define NUM_RX_DESC 32 +-#define TX_TOTAL_BUF_SIZE (NUM_TX_DESC * PKTSIZE_ALIGN) +-#define RX_TOTAL_BUF_SIZE (NUM_RX_DESC * PKTSIZE_ALIGN) +-#define TOTAL_PKT_BUF_SIZE (TX_TOTAL_BUF_SIZE + RX_TOTAL_BUF_SIZE) +- +-#define MT753X_NUM_PHYS 5 +-#define MT753X_NUM_PORTS 7 +-#define MT753X_DFL_SMI_ADDR 31 +-#define MT753X_SMI_ADDR_MASK 0x1f +- +-#define MT753X_PHY_ADDR(base, addr) \ +- (((base) + (addr)) & 0x1f) +- +-#define GDMA_FWD_TO_CPU \ +- (0x20000000 | \ +- GDM_ICS_EN | \ +- GDM_TCS_EN | \ +- GDM_UCS_EN | \ +- STRP_CRC | \ +- (DP_PDMA << MYMAC_DP_S) | \ +- (DP_PDMA << BC_DP_S) | \ +- (DP_PDMA << MC_DP_S) | \ +- (DP_PDMA << UN_DP_S)) +- +-#define GDMA_BRIDGE_TO_CPU \ +- (0xC0000000 | \ +- GDM_ICS_EN | \ +- GDM_TCS_EN | \ +- GDM_UCS_EN | \ +- (DP_PDMA << MYMAC_DP_S) | \ +- (DP_PDMA << BC_DP_S) | \ +- (DP_PDMA << MC_DP_S) | \ +- (DP_PDMA << UN_DP_S)) +- +-#define GDMA_FWD_DISCARD \ +- (0x20000000 | \ +- GDM_ICS_EN | \ +- GDM_TCS_EN | \ +- GDM_UCS_EN | \ +- STRP_CRC | \ +- (DP_DISCARD << MYMAC_DP_S) | \ +- (DP_DISCARD << BC_DP_S) | \ +- (DP_DISCARD << MC_DP_S) | \ +- (DP_DISCARD << UN_DP_S)) +- +-enum mtk_switch { +- SW_NONE, +- SW_MT7530, +- SW_MT7531, +- SW_MT7988, +-}; +- +-/* struct mtk_soc_data - This is the structure holding all differences +- * among various plaforms +- * @caps Flags shown the extra capability for the SoC +- * @ana_rgc3: The offset for register ANA_RGC3 related to +- * sgmiisys syscon +- * @gdma_count: Number of GDMAs +- * @pdma_base: Register base of PDMA block +- * @txd_size: Tx DMA descriptor size. +- * @rxd_size: Rx DMA descriptor size. +- */ +-struct mtk_soc_data { +- u32 caps; +- u32 ana_rgc3; +- u32 gdma_count; +- u32 pdma_base; +- u32 txd_size; +- u32 rxd_size; +-}; +- +-struct mtk_eth_priv { +- char pkt_pool[TOTAL_PKT_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN); +- +- void *tx_ring_noc; +- void *rx_ring_noc; +- +- int rx_dma_owner_idx0; +- int tx_cpu_owner_idx0; +- +- void __iomem *fe_base; +- void __iomem *gmac_base; +- void __iomem *sgmii_base; +- void __iomem *gsw_base; +- +- struct regmap *ethsys_regmap; +- +- struct regmap *infra_regmap; +- +- struct regmap *usxgmii_regmap; +- struct regmap *xfi_pextp_regmap; +- struct regmap *xfi_pll_regmap; +- struct regmap *toprgu_regmap; +- +- struct mii_dev *mdio_bus; +- int (*mii_read)(struct mtk_eth_priv *priv, u8 phy, u8 reg); +- int (*mii_write)(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 val); +- int (*mmd_read)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg); +- int (*mmd_write)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg, +- u16 val); +- +- const struct mtk_soc_data *soc; +- int gmac_id; +- int force_mode; +- int speed; +- int duplex; +- int mdc; +- bool pn_swap; +- +- struct phy_device *phydev; +- int phy_interface; +- int phy_addr; +- +- enum mtk_switch sw; +- int (*switch_init)(struct mtk_eth_priv *priv); +- void (*switch_mac_control)(struct mtk_eth_priv *priv, bool enable); +- u32 mt753x_smi_addr; +- u32 mt753x_phy_base; +- u32 mt753x_pmcr; +- u32 mt753x_reset_wait_time; +- +- struct gpio_desc rst_gpio; +- int mcm; +- +- struct reset_ctl rst_fe; +- struct reset_ctl rst_mcm; +-}; +- +-static void mtk_pdma_write(struct mtk_eth_priv *priv, u32 reg, u32 val) +-{ +- writel(val, priv->fe_base + priv->soc->pdma_base + reg); +-} +- +-static void mtk_pdma_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, +- u32 set) +-{ +- clrsetbits_le32(priv->fe_base + priv->soc->pdma_base + reg, clr, set); +-} +- +-static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg, +- u32 val) +-{ +- u32 gdma_base; +- +- if (no == 2) +- gdma_base = GDMA3_BASE; +- else if (no == 1) +- gdma_base = GDMA2_BASE; +- else +- gdma_base = GDMA1_BASE; +- +- writel(val, priv->fe_base + gdma_base + reg); +-} +- +-static void mtk_fe_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set) +-{ +- clrsetbits_le32(priv->fe_base + reg, clr, set); +-} +- +-static u32 mtk_gmac_read(struct mtk_eth_priv *priv, u32 reg) +-{ +- return readl(priv->gmac_base + reg); +-} +- +-static void mtk_gmac_write(struct mtk_eth_priv *priv, u32 reg, u32 val) +-{ +- writel(val, priv->gmac_base + reg); +-} +- +-static void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set) +-{ +- clrsetbits_le32(priv->gmac_base + reg, clr, set); +-} +- +-static void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, +- u32 set) +-{ +- uint val; +- +- regmap_read(priv->ethsys_regmap, reg, &val); +- val &= ~clr; +- val |= set; +- regmap_write(priv->ethsys_regmap, reg, val); +-} +- +-static void mtk_infra_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, +- u32 set) +-{ +- uint val; +- +- regmap_read(priv->infra_regmap, reg, &val); +- val &= ~clr; +- val |= set; +- regmap_write(priv->infra_regmap, reg, val); +-} +- +-static u32 mtk_gsw_read(struct mtk_eth_priv *priv, u32 reg) +-{ +- return readl(priv->gsw_base + reg); +-} +- +-static void mtk_gsw_write(struct mtk_eth_priv *priv, u32 reg, u32 val) +-{ +- writel(val, priv->gsw_base + reg); +-} +- +-/* Direct MDIO clause 22/45 access via SoC */ +-static int mtk_mii_rw(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data, +- u32 cmd, u32 st) +-{ +- int ret; +- u32 val; +- +- val = (st << MDIO_ST_S) | +- ((cmd << MDIO_CMD_S) & MDIO_CMD_M) | +- (((u32)phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) | +- (((u32)reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M); +- +- if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR) +- val |= data & MDIO_RW_DATA_M; +- +- mtk_gmac_write(priv, GMAC_PIAC_REG, val | PHY_ACS_ST); +- +- ret = wait_for_bit_le32(priv->gmac_base + GMAC_PIAC_REG, +- PHY_ACS_ST, 0, 5000, 0); +- if (ret) { +- pr_warn("MDIO access timeout\n"); +- return ret; +- } +- +- if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) { +- val = mtk_gmac_read(priv, GMAC_PIAC_REG); +- return val & MDIO_RW_DATA_M; +- } +- +- return 0; +-} +- +-/* Direct MDIO clause 22 read via SoC */ +-static int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg) +-{ +- return mtk_mii_rw(priv, phy, reg, 0, MDIO_CMD_READ, MDIO_ST_C22); +-} +- +-/* Direct MDIO clause 22 write via SoC */ +-static int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data) +-{ +- return mtk_mii_rw(priv, phy, reg, data, MDIO_CMD_WRITE, MDIO_ST_C22); +-} +- +-/* Direct MDIO clause 45 read via SoC */ +-static int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg) +-{ +- int ret; +- +- ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45); +- if (ret) +- return ret; +- +- return mtk_mii_rw(priv, addr, devad, 0, MDIO_CMD_READ_C45, +- MDIO_ST_C45); +-} +- +-/* Direct MDIO clause 45 write via SoC */ +-static int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, +- u16 reg, u16 val) +-{ +- int ret; +- +- ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45); +- if (ret) +- return ret; +- +- return mtk_mii_rw(priv, addr, devad, val, MDIO_CMD_WRITE, +- MDIO_ST_C45); +-} +- +-/* Indirect MDIO clause 45 read via MII registers */ +-static int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, +- u16 reg) +-{ +- int ret; +- +- ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG, +- (MMD_ADDR << MMD_CMD_S) | +- ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); +- if (ret) +- return ret; +- +- ret = priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg); +- if (ret) +- return ret; +- +- ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG, +- (MMD_DATA << MMD_CMD_S) | +- ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); +- if (ret) +- return ret; +- +- return priv->mii_read(priv, addr, MII_MMD_ADDR_DATA_REG); +-} +- +-/* Indirect MDIO clause 45 write via MII registers */ +-static int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, +- u16 reg, u16 val) +-{ +- int ret; +- +- ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG, +- (MMD_ADDR << MMD_CMD_S) | +- ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); +- if (ret) +- return ret; +- +- ret = priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg); +- if (ret) +- return ret; +- +- ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG, +- (MMD_DATA << MMD_CMD_S) | +- ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); +- if (ret) +- return ret; +- +- return priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, val); +-} +- +-/* +- * MT7530 Internal Register Address Bits +- * ------------------------------------------------------------------- +- * | 15 14 13 12 11 10 9 8 7 6 | 5 4 3 2 | 1 0 | +- * |----------------------------------------|---------------|--------| +- * | Page Address | Reg Address | Unused | +- * ------------------------------------------------------------------- +- */ +- +-static int mt753x_reg_read(struct mtk_eth_priv *priv, u32 reg, u32 *data) +-{ +- int ret, low_word, high_word; +- +- if (priv->sw == SW_MT7988) { +- *data = mtk_gsw_read(priv, reg); +- return 0; +- } +- +- /* Write page address */ +- ret = mtk_mii_write(priv, priv->mt753x_smi_addr, 0x1f, reg >> 6); +- if (ret) +- return ret; +- +- /* Read low word */ +- low_word = mtk_mii_read(priv, priv->mt753x_smi_addr, (reg >> 2) & 0xf); +- if (low_word < 0) +- return low_word; +- +- /* Read high word */ +- high_word = mtk_mii_read(priv, priv->mt753x_smi_addr, 0x10); +- if (high_word < 0) +- return high_word; +- +- if (data) +- *data = ((u32)high_word << 16) | (low_word & 0xffff); +- +- return 0; +-} +- +-static int mt753x_reg_write(struct mtk_eth_priv *priv, u32 reg, u32 data) +-{ +- int ret; +- +- if (priv->sw == SW_MT7988) { +- mtk_gsw_write(priv, reg, data); +- return 0; +- } +- +- /* Write page address */ +- ret = mtk_mii_write(priv, priv->mt753x_smi_addr, 0x1f, reg >> 6); +- if (ret) +- return ret; +- +- /* Write low word */ +- ret = mtk_mii_write(priv, priv->mt753x_smi_addr, (reg >> 2) & 0xf, +- data & 0xffff); +- if (ret) +- return ret; +- +- /* Write high word */ +- return mtk_mii_write(priv, priv->mt753x_smi_addr, 0x10, data >> 16); +-} +- +-static void mt753x_reg_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, +- u32 set) +-{ +- u32 val; +- +- mt753x_reg_read(priv, reg, &val); +- val &= ~clr; +- val |= set; +- mt753x_reg_write(priv, reg, val); +-} +- +-/* Indirect MDIO clause 22/45 access */ +-static int mt7531_mii_rw(struct mtk_eth_priv *priv, int phy, int reg, u16 data, +- u32 cmd, u32 st) +-{ +- ulong timeout; +- u32 val, timeout_ms; +- int ret = 0; +- +- val = (st << MDIO_ST_S) | +- ((cmd << MDIO_CMD_S) & MDIO_CMD_M) | +- ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) | +- ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M); +- +- if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR) +- val |= data & MDIO_RW_DATA_M; +- +- mt753x_reg_write(priv, MT7531_PHY_IAC, val | PHY_ACS_ST); +- +- timeout_ms = 100; +- timeout = get_timer(0); +- while (1) { +- mt753x_reg_read(priv, MT7531_PHY_IAC, &val); +- +- if ((val & PHY_ACS_ST) == 0) +- break; +- +- if (get_timer(timeout) > timeout_ms) +- return -ETIMEDOUT; +- } +- +- if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) { +- mt753x_reg_read(priv, MT7531_PHY_IAC, &val); +- ret = val & MDIO_RW_DATA_M; +- } +- +- return ret; +-} +- +-static int mt7531_mii_ind_read(struct mtk_eth_priv *priv, u8 phy, u8 reg) +-{ +- u8 phy_addr; +- +- if (phy >= MT753X_NUM_PHYS) +- return -EINVAL; +- +- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, phy); +- +- return mt7531_mii_rw(priv, phy_addr, reg, 0, MDIO_CMD_READ, +- MDIO_ST_C22); +-} +- +-static int mt7531_mii_ind_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, +- u16 val) +-{ +- u8 phy_addr; +- +- if (phy >= MT753X_NUM_PHYS) +- return -EINVAL; +- +- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, phy); +- +- return mt7531_mii_rw(priv, phy_addr, reg, val, MDIO_CMD_WRITE, +- MDIO_ST_C22); +-} +- +-static int mt7531_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, +- u16 reg) +-{ +- u8 phy_addr; +- int ret; +- +- if (addr >= MT753X_NUM_PHYS) +- return -EINVAL; +- +- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, addr); +- +- ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR, +- MDIO_ST_C45); +- if (ret) +- return ret; +- +- return mt7531_mii_rw(priv, phy_addr, devad, 0, MDIO_CMD_READ_C45, +- MDIO_ST_C45); +-} +- +-static int mt7531_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, +- u16 reg, u16 val) +-{ +- u8 phy_addr; +- int ret; +- +- if (addr >= MT753X_NUM_PHYS) +- return 0; +- +- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, addr); +- +- ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR, +- MDIO_ST_C45); +- if (ret) +- return ret; +- +- return mt7531_mii_rw(priv, phy_addr, devad, val, MDIO_CMD_WRITE, +- MDIO_ST_C45); +-} +- +-static int mtk_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) +-{ +- struct mtk_eth_priv *priv = bus->priv; +- +- if (devad < 0) +- return priv->mii_read(priv, addr, reg); +- else +- return priv->mmd_read(priv, addr, devad, reg); +-} +- +-static int mtk_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, +- u16 val) +-{ +- struct mtk_eth_priv *priv = bus->priv; +- +- if (devad < 0) +- return priv->mii_write(priv, addr, reg, val); +- else +- return priv->mmd_write(priv, addr, devad, reg, val); +-} +- +-static int mtk_mdio_register(struct udevice *dev) +-{ +- struct mtk_eth_priv *priv = dev_get_priv(dev); +- struct mii_dev *mdio_bus = mdio_alloc(); +- int ret; +- +- if (!mdio_bus) +- return -ENOMEM; +- +- /* Assign MDIO access APIs according to the switch/phy */ +- switch (priv->sw) { +- case SW_MT7530: +- priv->mii_read = mtk_mii_read; +- priv->mii_write = mtk_mii_write; +- priv->mmd_read = mtk_mmd_ind_read; +- priv->mmd_write = mtk_mmd_ind_write; +- break; +- case SW_MT7531: +- case SW_MT7988: +- priv->mii_read = mt7531_mii_ind_read; +- priv->mii_write = mt7531_mii_ind_write; +- priv->mmd_read = mt7531_mmd_ind_read; +- priv->mmd_write = mt7531_mmd_ind_write; +- break; +- default: +- priv->mii_read = mtk_mii_read; +- priv->mii_write = mtk_mii_write; +- priv->mmd_read = mtk_mmd_read; +- priv->mmd_write = mtk_mmd_write; +- } +- +- mdio_bus->read = mtk_mdio_read; +- mdio_bus->write = mtk_mdio_write; +- snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name); +- +- mdio_bus->priv = (void *)priv; +- +- ret = mdio_register(mdio_bus); +- +- if (ret) +- return ret; +- +- priv->mdio_bus = mdio_bus; +- +- return 0; +-} +- +-static int mt753x_core_reg_read(struct mtk_eth_priv *priv, u32 reg) +-{ +- u8 phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, 0); +- +- return priv->mmd_read(priv, phy_addr, 0x1f, reg); +-} +- +-static void mt753x_core_reg_write(struct mtk_eth_priv *priv, u32 reg, u32 val) +-{ +- u8 phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, 0); +- +- priv->mmd_write(priv, phy_addr, 0x1f, reg, val); +-} +- +-static int mt7530_pad_clk_setup(struct mtk_eth_priv *priv, int mode) +-{ +- u32 ncpo1, ssc_delta; +- +- switch (mode) { +- case PHY_INTERFACE_MODE_RGMII: +- ncpo1 = 0x0c80; +- ssc_delta = 0x87; +- break; +- default: +- printf("error: xMII mode %d not supported\n", mode); +- return -EINVAL; +- } +- +- /* Disable MT7530 core clock */ +- mt753x_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, 0); +- +- /* Disable MT7530 PLL */ +- mt753x_core_reg_write(priv, CORE_GSWPLL_GRP1, +- (2 << RG_GSWPLL_POSDIV_200M_S) | +- (32 << RG_GSWPLL_FBKDIV_200M_S)); +- +- /* For MT7530 core clock = 500Mhz */ +- mt753x_core_reg_write(priv, CORE_GSWPLL_GRP2, +- (1 << RG_GSWPLL_POSDIV_500M_S) | +- (25 << RG_GSWPLL_FBKDIV_500M_S)); +- +- /* Enable MT7530 PLL */ +- mt753x_core_reg_write(priv, CORE_GSWPLL_GRP1, +- (2 << RG_GSWPLL_POSDIV_200M_S) | +- (32 << RG_GSWPLL_FBKDIV_200M_S) | +- RG_GSWPLL_EN_PRE); +- +- udelay(20); +- +- mt753x_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); +- +- /* Setup the MT7530 TRGMII Tx Clock */ +- mt753x_core_reg_write(priv, CORE_PLL_GROUP5, ncpo1); +- mt753x_core_reg_write(priv, CORE_PLL_GROUP6, 0); +- mt753x_core_reg_write(priv, CORE_PLL_GROUP10, ssc_delta); +- mt753x_core_reg_write(priv, CORE_PLL_GROUP11, ssc_delta); +- mt753x_core_reg_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN | +- RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN); +- +- mt753x_core_reg_write(priv, CORE_PLL_GROUP2, +- RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN | +- (1 << RG_SYSPLL_POSDIV_S)); +- +- mt753x_core_reg_write(priv, CORE_PLL_GROUP7, +- RG_LCDDS_PCW_NCPO_CHG | (3 << RG_LCCDS_C_S) | +- RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); +- +- /* Enable MT7530 core clock */ +- mt753x_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, +- REG_GSWCK_EN | REG_TRGMIICK_EN); +- +- return 0; +-} +- +-static void mt7530_mac_control(struct mtk_eth_priv *priv, bool enable) +-{ +- u32 pmcr = FORCE_MODE; +- +- if (enable) +- pmcr = priv->mt753x_pmcr; +- +- mt753x_reg_write(priv, PMCR_REG(6), pmcr); +-} +- +-static int mt7530_setup(struct mtk_eth_priv *priv) +-{ +- u16 phy_addr, phy_val; +- u32 val, txdrv; +- int i; +- +- if (!MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) { +- /* Select 250MHz clk for RGMII mode */ +- mtk_ethsys_rmw(priv, ETHSYS_CLKCFG0_REG, +- ETHSYS_TRGMII_CLK_SEL362_5, 0); +- +- txdrv = 8; +- } else { +- txdrv = 4; +- } +- +- /* Modify HWTRAP first to allow direct access to internal PHYs */ +- mt753x_reg_read(priv, HWTRAP_REG, &val); +- val |= CHG_TRAP; +- val &= ~C_MDIO_BPS; +- mt753x_reg_write(priv, MHWTRAP_REG, val); +- +- /* Calculate the phy base address */ +- val = ((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3; +- priv->mt753x_phy_base = (val | 0x7) + 1; +- +- /* Turn off PHYs */ +- for (i = 0; i < MT753X_NUM_PHYS; i++) { +- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i); +- phy_val = priv->mii_read(priv, phy_addr, MII_BMCR); +- phy_val |= BMCR_PDOWN; +- priv->mii_write(priv, phy_addr, MII_BMCR, phy_val); +- } +- +- /* Force MAC link down before reset */ +- mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE); +- mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE); +- +- /* MT7530 reset */ +- mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST); +- udelay(100); +- +- val = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | +- MAC_MODE | FORCE_MODE | +- MAC_TX_EN | MAC_RX_EN | +- BKOFF_EN | BACKPR_EN | +- (SPEED_1000M << FORCE_SPD_S) | +- FORCE_DPX | FORCE_LINK; +- +- /* MT7530 Port6: Forced 1000M/FD, FC disabled */ +- priv->mt753x_pmcr = val; +- +- /* MT7530 Port5: Forced link down */ +- mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE); +- +- /* Keep MAC link down before starting eth */ +- mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE); +- +- /* MT7530 Port6: Set to RGMII */ +- mt753x_reg_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_M, P6_INTF_MODE_RGMII); +- +- /* Hardware Trap: Enable Port6, Disable Port5 */ +- mt753x_reg_read(priv, HWTRAP_REG, &val); +- val |= CHG_TRAP | LOOPDET_DIS | P5_INTF_DIS | +- (P5_INTF_SEL_GMAC5 << P5_INTF_SEL_S) | +- (P5_INTF_MODE_RGMII << P5_INTF_MODE_S); +- val &= ~(C_MDIO_BPS | P6_INTF_DIS); +- mt753x_reg_write(priv, MHWTRAP_REG, val); +- +- /* Setup switch core pll */ +- mt7530_pad_clk_setup(priv, priv->phy_interface); +- +- /* Lower Tx Driving for TRGMII path */ +- for (i = 0 ; i < NUM_TRGMII_CTRL ; i++) +- mt753x_reg_write(priv, MT7530_TRGMII_TD_ODT(i), +- (txdrv << TD_DM_DRVP_S) | +- (txdrv << TD_DM_DRVN_S)); +- +- for (i = 0 ; i < NUM_TRGMII_CTRL; i++) +- mt753x_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16); +- +- /* Turn on PHYs */ +- for (i = 0; i < MT753X_NUM_PHYS; i++) { +- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i); +- phy_val = priv->mii_read(priv, phy_addr, MII_BMCR); +- phy_val &= ~BMCR_PDOWN; +- priv->mii_write(priv, phy_addr, MII_BMCR, phy_val); +- } +- +- return 0; +-} +- +-static void mt7531_core_pll_setup(struct mtk_eth_priv *priv, int mcm) +-{ +- /* Step 1 : Disable MT7531 COREPLL */ +- mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, 0); +- +- /* Step 2: switch to XTAL output */ +- mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_CLKSW, SW_CLKSW); +- +- mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, 0); +- +- /* Step 3: disable PLLGP and enable program PLLGP */ +- mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_PLLGP, SW_PLLGP); +- +- /* Step 4: program COREPLL output frequency to 500MHz */ +- mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_POSDIV_M, +- 2 << RG_COREPLL_POSDIV_S); +- udelay(25); +- +- /* Currently, support XTAL 25Mhz only */ +- mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_M, +- 0x140000 << RG_COREPLL_SDM_PCW_S); +- +- /* Set feedback divide ratio update signal to high */ +- mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG, +- RG_COREPLL_SDM_PCW_CHG); +- +- /* Wait for at least 16 XTAL clocks */ +- udelay(10); +- +- /* Step 5: set feedback divide ratio update signal to low */ +- mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG, 0); +- +- /* add enable 325M clock for SGMII */ +- mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000); +- +- /* add enable 250SSC clock for RGMII */ +- mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000); +- +- /*Step 6: Enable MT7531 PLL */ +- mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, RG_COREPLL_EN); +- +- mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, EN_COREPLL); +- +- udelay(25); +-} +- +-static int mt7531_port_sgmii_init(struct mtk_eth_priv *priv, +- u32 port) +-{ +- if (port != 5 && port != 6) { +- printf("mt7531: port %d is not a SGMII port\n", port); +- return -EINVAL; +- } +- +- /* Set SGMII GEN2 speed(2.5G) */ +- mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), SGMSYS_SPEED_MASK, +- FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500)); +- +- /* Disable SGMII AN */ +- mt753x_reg_rmw(priv, MT7531_PCS_CONTROL_1(port), +- SGMII_AN_ENABLE, 0); +- +- /* SGMII force mode setting */ +- mt753x_reg_write(priv, MT7531_SGMII_MODE(port), SGMII_FORCE_MODE); +- +- /* Release PHYA power down state */ +- mt753x_reg_rmw(priv, MT7531_QPHY_PWR_STATE_CTRL(port), +- SGMII_PHYA_PWD, 0); +- +- return 0; +-} +- +-static int mt7531_port_rgmii_init(struct mtk_eth_priv *priv, u32 port) +-{ +- u32 val; +- +- if (port != 5) { +- printf("error: RGMII mode is not available for port %d\n", +- port); +- return -EINVAL; +- } +- +- mt753x_reg_read(priv, MT7531_CLKGEN_CTRL, &val); +- val |= GP_CLK_EN; +- val &= ~GP_MODE_M; +- val |= GP_MODE_RGMII << GP_MODE_S; +- val |= TXCLK_NO_REVERSE; +- val |= RXCLK_NO_DELAY; +- val &= ~CLK_SKEW_IN_M; +- val |= CLK_SKEW_IN_NO_CHANGE << CLK_SKEW_IN_S; +- val &= ~CLK_SKEW_OUT_M; +- val |= CLK_SKEW_OUT_NO_CHANGE << CLK_SKEW_OUT_S; +- mt753x_reg_write(priv, MT7531_CLKGEN_CTRL, val); +- +- return 0; +-} +- +-static void mt7531_phy_setting(struct mtk_eth_priv *priv) +-{ +- int i; +- u32 val; +- +- for (i = 0; i < MT753X_NUM_PHYS; i++) { +- /* Enable HW auto downshift */ +- priv->mii_write(priv, i, 0x1f, 0x1); +- val = priv->mii_read(priv, i, PHY_EXT_REG_14); +- val |= PHY_EN_DOWN_SHFIT; +- priv->mii_write(priv, i, PHY_EXT_REG_14, val); +- +- /* PHY link down power saving enable */ +- val = priv->mii_read(priv, i, PHY_EXT_REG_17); +- val |= PHY_LINKDOWN_POWER_SAVING_EN; +- priv->mii_write(priv, i, PHY_EXT_REG_17, val); +- +- val = priv->mmd_read(priv, i, 0x1e, PHY_DEV1E_REG_0C6); +- val &= ~PHY_POWER_SAVING_M; +- val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S; +- priv->mmd_write(priv, i, 0x1e, PHY_DEV1E_REG_0C6, val); +- } +-} +- +-static void mt7531_mac_control(struct mtk_eth_priv *priv, bool enable) +-{ +- u32 pmcr = FORCE_MODE_LNK; +- +- if (enable) +- pmcr = priv->mt753x_pmcr; +- +- mt753x_reg_write(priv, PMCR_REG(5), pmcr); +- mt753x_reg_write(priv, PMCR_REG(6), pmcr); +-} +- +-static int mt7531_setup(struct mtk_eth_priv *priv) +-{ +- u16 phy_addr, phy_val; +- u32 val; +- u32 pmcr; +- u32 port5_sgmii; +- int i; +- +- priv->mt753x_phy_base = (priv->mt753x_smi_addr + 1) & +- MT753X_SMI_ADDR_MASK; +- +- /* Turn off PHYs */ +- for (i = 0; i < MT753X_NUM_PHYS; i++) { +- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i); +- phy_val = priv->mii_read(priv, phy_addr, MII_BMCR); +- phy_val |= BMCR_PDOWN; +- priv->mii_write(priv, phy_addr, MII_BMCR, phy_val); +- } +- +- /* Force MAC link down before reset */ +- mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK); +- mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK); +- +- /* Switch soft reset */ +- mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST); +- udelay(100); +- +- /* Enable MDC input Schmitt Trigger */ +- mt753x_reg_rmw(priv, MT7531_SMT0_IOLB, SMT_IOLB_5_SMI_MDC_EN, +- SMT_IOLB_5_SMI_MDC_EN); +- +- mt7531_core_pll_setup(priv, priv->mcm); +- +- mt753x_reg_read(priv, MT7531_TOP_SIG_SR, &val); +- port5_sgmii = !!(val & PAD_DUAL_SGMII_EN); +- +- /* port5 support either RGMII or SGMII, port6 only support SGMII. */ +- switch (priv->phy_interface) { +- case PHY_INTERFACE_MODE_RGMII: +- if (!port5_sgmii) +- mt7531_port_rgmii_init(priv, 5); +- break; +- case PHY_INTERFACE_MODE_2500BASEX: +- mt7531_port_sgmii_init(priv, 6); +- if (port5_sgmii) +- mt7531_port_sgmii_init(priv, 5); +- break; +- default: +- break; +- } +- +- pmcr = MT7531_FORCE_MODE | +- (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | +- MAC_MODE | MAC_TX_EN | MAC_RX_EN | +- BKOFF_EN | BACKPR_EN | +- FORCE_RX_FC | FORCE_TX_FC | +- (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX | +- FORCE_LINK; +- +- priv->mt753x_pmcr = pmcr; +- +- /* Keep MAC link down before starting eth */ +- mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK); +- mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK); +- +- /* Turn on PHYs */ +- for (i = 0; i < MT753X_NUM_PHYS; i++) { +- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i); +- phy_val = priv->mii_read(priv, phy_addr, MII_BMCR); +- phy_val &= ~BMCR_PDOWN; +- priv->mii_write(priv, phy_addr, MII_BMCR, phy_val); +- } +- +- mt7531_phy_setting(priv); +- +- /* Enable Internal PHYs */ +- val = mt753x_core_reg_read(priv, CORE_PLL_GROUP4); +- val |= MT7531_BYPASS_MODE; +- val &= ~MT7531_POWER_ON_OFF; +- mt753x_core_reg_write(priv, CORE_PLL_GROUP4, val); +- +- return 0; +-} +- +-static void mt7988_phy_setting(struct mtk_eth_priv *priv) +-{ +- u16 val; +- u32 i; +- +- for (i = 0; i < MT753X_NUM_PHYS; i++) { +- /* Enable HW auto downshift */ +- priv->mii_write(priv, i, 0x1f, 0x1); +- val = priv->mii_read(priv, i, PHY_EXT_REG_14); +- val |= PHY_EN_DOWN_SHFIT; +- priv->mii_write(priv, i, PHY_EXT_REG_14, val); +- +- /* PHY link down power saving enable */ +- val = priv->mii_read(priv, i, PHY_EXT_REG_17); +- val |= PHY_LINKDOWN_POWER_SAVING_EN; +- priv->mii_write(priv, i, PHY_EXT_REG_17, val); +- } +-} +- +-static void mt7988_mac_control(struct mtk_eth_priv *priv, bool enable) +-{ +- u32 pmcr = FORCE_MODE_LNK; +- +- if (enable) +- pmcr = priv->mt753x_pmcr; +- +- mt753x_reg_write(priv, PMCR_REG(6), pmcr); +-} +- +-static int mt7988_setup(struct mtk_eth_priv *priv) +-{ +- u16 phy_addr, phy_val; +- u32 pmcr; +- int i; +- +- priv->gsw_base = regmap_get_range(priv->ethsys_regmap, 0) + GSW_BASE; +- +- priv->mt753x_phy_base = (priv->mt753x_smi_addr + 1) & +- MT753X_SMI_ADDR_MASK; +- +- /* Turn off PHYs */ +- for (i = 0; i < MT753X_NUM_PHYS; i++) { +- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i); +- phy_val = priv->mii_read(priv, phy_addr, MII_BMCR); +- phy_val |= BMCR_PDOWN; +- priv->mii_write(priv, phy_addr, MII_BMCR, phy_val); +- } +- +- switch (priv->phy_interface) { +- case PHY_INTERFACE_MODE_USXGMII: +- /* Use CPU bridge instead of actual USXGMII path */ +- +- /* Set GDM1 no drop */ +- mtk_fe_rmw(priv, PSE_NO_DROP_CFG_REG, 0, PSE_NO_DROP_GDM1); +- +- /* Enable GDM1 to GSW CPU bridge */ +- mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, BIT(0)); +- +- /* XGMAC force link up */ +- mtk_gmac_rmw(priv, GMAC_XGMAC_STS_REG, 0, P1_XGMAC_FORCE_LINK); +- +- /* Setup GSW CPU bridge IPG */ +- mtk_gmac_rmw(priv, GMAC_GSW_CFG_REG, GSWTX_IPG_M | GSWRX_IPG_M, +- (0xB << GSWTX_IPG_S) | (0xB << GSWRX_IPG_S)); +- break; +- default: +- printf("Error: MT7988 GSW does not support %s interface\n", +- phy_string_for_interface(priv->phy_interface)); +- break; +- } +- +- pmcr = MT7988_FORCE_MODE | +- (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | +- MAC_MODE | MAC_TX_EN | MAC_RX_EN | +- BKOFF_EN | BACKPR_EN | +- FORCE_RX_FC | FORCE_TX_FC | +- (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX | +- FORCE_LINK; +- +- priv->mt753x_pmcr = pmcr; +- +- /* Keep MAC link down before starting eth */ +- mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK); +- +- /* Turn on PHYs */ +- for (i = 0; i < MT753X_NUM_PHYS; i++) { +- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i); +- phy_val = priv->mii_read(priv, phy_addr, MII_BMCR); +- phy_val &= ~BMCR_PDOWN; +- priv->mii_write(priv, phy_addr, MII_BMCR, phy_val); +- } +- +- mt7988_phy_setting(priv); +- +- return 0; +-} +- +-static int mt753x_switch_init(struct mtk_eth_priv *priv) +-{ +- int ret; +- int i; +- +- /* Global reset switch */ +- if (priv->mcm) { +- reset_assert(&priv->rst_mcm); +- udelay(1000); +- reset_deassert(&priv->rst_mcm); +- mdelay(priv->mt753x_reset_wait_time); +- } else if (dm_gpio_is_valid(&priv->rst_gpio)) { +- dm_gpio_set_value(&priv->rst_gpio, 0); +- udelay(1000); +- dm_gpio_set_value(&priv->rst_gpio, 1); +- mdelay(priv->mt753x_reset_wait_time); +- } +- +- ret = priv->switch_init(priv); +- if (ret) +- return ret; +- +- /* Set port isolation */ +- for (i = 0; i < MT753X_NUM_PORTS; i++) { +- /* Set port matrix mode */ +- if (i != 6) +- mt753x_reg_write(priv, PCR_REG(i), +- (0x40 << PORT_MATRIX_S)); +- else +- mt753x_reg_write(priv, PCR_REG(i), +- (0x3f << PORT_MATRIX_S)); +- +- /* Set port mode to user port */ +- mt753x_reg_write(priv, PVC_REG(i), +- (0x8100 << STAG_VPID_S) | +- (VLAN_ATTR_USER << VLAN_ATTR_S)); +- } +- +- return 0; +-} +- +-static void mtk_xphy_link_adjust(struct mtk_eth_priv *priv) +-{ +- u16 lcl_adv = 0, rmt_adv = 0; +- u8 flowctrl; +- u32 mcr; +- +- mcr = mtk_gmac_read(priv, XGMAC_PORT_MCR(priv->gmac_id)); +- mcr &= ~(XGMAC_FORCE_TX_FC | XGMAC_FORCE_RX_FC); +- +- if (priv->phydev->duplex) { +- if (priv->phydev->pause) +- rmt_adv = LPA_PAUSE_CAP; +- if (priv->phydev->asym_pause) +- rmt_adv |= LPA_PAUSE_ASYM; +- +- if (priv->phydev->advertising & ADVERTISED_Pause) +- lcl_adv |= ADVERTISE_PAUSE_CAP; +- if (priv->phydev->advertising & ADVERTISED_Asym_Pause) +- lcl_adv |= ADVERTISE_PAUSE_ASYM; +- +- flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); +- +- if (flowctrl & FLOW_CTRL_TX) +- mcr |= XGMAC_FORCE_TX_FC; +- if (flowctrl & FLOW_CTRL_RX) +- mcr |= XGMAC_FORCE_RX_FC; +- +- debug("rx pause %s, tx pause %s\n", +- flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled", +- flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled"); +- } +- +- mcr &= ~(XGMAC_TRX_DISABLE); +- mtk_gmac_write(priv, XGMAC_PORT_MCR(priv->gmac_id), mcr); +-} +- +-static void mtk_phy_link_adjust(struct mtk_eth_priv *priv) +-{ +- u16 lcl_adv = 0, rmt_adv = 0; +- u8 flowctrl; +- u32 mcr; +- +- mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | +- (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) | +- MAC_MODE | FORCE_MODE | +- MAC_TX_EN | MAC_RX_EN | +- DEL_RXFIFO_CLR | +- BKOFF_EN | BACKPR_EN; +- +- switch (priv->phydev->speed) { +- case SPEED_10: +- mcr |= (SPEED_10M << FORCE_SPD_S); +- break; +- case SPEED_100: +- mcr |= (SPEED_100M << FORCE_SPD_S); +- break; +- case SPEED_1000: +- case SPEED_2500: +- mcr |= (SPEED_1000M << FORCE_SPD_S); +- break; +- }; +- +- if (priv->phydev->link) +- mcr |= FORCE_LINK; +- +- if (priv->phydev->duplex) { +- mcr |= FORCE_DPX; +- +- if (priv->phydev->pause) +- rmt_adv = LPA_PAUSE_CAP; +- if (priv->phydev->asym_pause) +- rmt_adv |= LPA_PAUSE_ASYM; +- +- if (priv->phydev->advertising & ADVERTISED_Pause) +- lcl_adv |= ADVERTISE_PAUSE_CAP; +- if (priv->phydev->advertising & ADVERTISED_Asym_Pause) +- lcl_adv |= ADVERTISE_PAUSE_ASYM; +- +- flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); +- +- if (flowctrl & FLOW_CTRL_TX) +- mcr |= FORCE_TX_FC; +- if (flowctrl & FLOW_CTRL_RX) +- mcr |= FORCE_RX_FC; +- +- debug("rx pause %s, tx pause %s\n", +- flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled", +- flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled"); +- } +- +- mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr); +-} +- +-static int mtk_phy_start(struct mtk_eth_priv *priv) +-{ +- struct phy_device *phydev = priv->phydev; +- int ret; +- +- ret = phy_startup(phydev); +- +- if (ret) { +- debug("Could not initialize PHY %s\n", phydev->dev->name); +- return ret; +- } +- +- if (!phydev->link) { +- debug("%s: link down.\n", phydev->dev->name); +- return 0; +- } +- +- if (!priv->force_mode) { +- if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || +- priv->phy_interface == PHY_INTERFACE_MODE_10GBASER || +- priv->phy_interface == PHY_INTERFACE_MODE_XGMII) +- mtk_xphy_link_adjust(priv); +- else +- mtk_phy_link_adjust(priv); +- } +- +- debug("Speed: %d, %s duplex%s\n", phydev->speed, +- (phydev->duplex) ? "full" : "half", +- (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); +- +- return 0; +-} +- +-static int mtk_phy_probe(struct udevice *dev) +-{ +- struct mtk_eth_priv *priv = dev_get_priv(dev); +- struct phy_device *phydev; +- +- phydev = phy_connect(priv->mdio_bus, priv->phy_addr, dev, +- priv->phy_interface); +- if (!phydev) +- return -ENODEV; +- +- phydev->supported &= PHY_GBIT_FEATURES; +- phydev->advertising = phydev->supported; +- +- priv->phydev = phydev; +- phy_config(phydev); +- +- return 0; +-} +- +-static void mtk_sgmii_an_init(struct mtk_eth_priv *priv) +-{ +- /* Set SGMII GEN1 speed(1G) */ +- clrbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, SGMSYS_SPEED_MASK); +- +- /* Enable SGMII AN */ +- setbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1, +- SGMII_AN_ENABLE); +- +- /* SGMII AN mode setting */ +- writel(SGMII_AN_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE); +- +- /* SGMII PN SWAP setting */ +- if (priv->pn_swap) { +- setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL, +- SGMII_PN_SWAP_TX_RX); +- } +- +- /* Release PHYA power down state */ +- clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL, +- SGMII_PHYA_PWD, 0); +-} +- +-static void mtk_sgmii_force_init(struct mtk_eth_priv *priv) +-{ +- /* Set SGMII GEN2 speed(2.5G) */ +- clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, +- SGMSYS_SPEED_MASK, +- FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500)); +- +- /* Disable SGMII AN */ +- clrsetbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1, +- SGMII_AN_ENABLE, 0); +- +- /* SGMII force mode setting */ +- writel(SGMII_FORCE_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE); +- +- /* SGMII PN SWAP setting */ +- if (priv->pn_swap) { +- setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL, +- SGMII_PN_SWAP_TX_RX); +- } +- +- /* Release PHYA power down state */ +- clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL, +- SGMII_PHYA_PWD, 0); +-} +- +-static void mtk_xfi_pll_enable(struct mtk_eth_priv *priv) +-{ +- u32 val = 0; +- +- /* Add software workaround for USXGMII PLL TCL issue */ +- regmap_write(priv->xfi_pll_regmap, XFI_PLL_ANA_GLB8, +- RG_XFI_PLL_ANA_SWWA); +- +- regmap_read(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, &val); +- val |= RG_XFI_PLL_EN; +- regmap_write(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, val); +-} +- +-static void mtk_usxgmii_reset(struct mtk_eth_priv *priv) +-{ +- switch (priv->gmac_id) { +- case 1: +- regmap_write(priv->toprgu_regmap, 0xFC, 0x0000A004); +- regmap_write(priv->toprgu_regmap, 0x18, 0x88F0A004); +- regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000); +- regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000); +- regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000); +- break; +- case 2: +- regmap_write(priv->toprgu_regmap, 0xFC, 0x00005002); +- regmap_write(priv->toprgu_regmap, 0x18, 0x88F05002); +- regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000); +- regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000); +- regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000); +- break; +- } +- +- mdelay(10); +-} +- +-static void mtk_usxgmii_setup_phya_an_10000(struct mtk_eth_priv *priv) +-{ +- regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6D); +- regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B); +- regmap_write(priv->usxgmii_regmap, 0x80C, 0x30000000); +- ndelay(1020); +- regmap_write(priv->usxgmii_regmap, 0x80C, 0x10000000); +- ndelay(1020); +- regmap_write(priv->usxgmii_regmap, 0x80C, 0x00000000); +- +- regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C); +- regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA); +- regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707); +- regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F); +- regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032); +- regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA); +- regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B); +- regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF); +- regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA); +- regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F); +- regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68); +- regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166); +- regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF); +- regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D); +- regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909); +- regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000); +- regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000); +- regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06); +- regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C); +- regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000); +- regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342); +- regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20); +- regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00); +- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800); +- ndelay(1020); +- regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020); +- regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01); +- regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884); +- regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002); +- regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220); +- regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01); +- regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600); +- regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x40704000); +- regmap_write(priv->xfi_pextp_regmap, 0x3050, 0xA8000000); +- regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x000000AA); +- regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00); +- regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000); +- regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001); +- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800); +- udelay(150); +- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111); +- ndelay(1020); +- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101); +- udelay(15); +- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111); +- ndelay(1020); +- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101); +- udelay(100); +- regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030); +- regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00); +- regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000); +- udelay(400); +-} +- +-static void mtk_usxgmii_setup_phya_force_10000(struct mtk_eth_priv *priv) +-{ +- regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6C); +- regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B); +- regmap_write(priv->usxgmii_regmap, 0x80C, 0xB0000000); +- ndelay(1020); +- regmap_write(priv->usxgmii_regmap, 0x80C, 0x90000000); +- ndelay(1020); +- +- regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C); +- regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA); +- regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707); +- regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F); +- regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032); +- regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA); +- regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B); +- regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF); +- regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA); +- regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F); +- regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68); +- regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166); +- regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF); +- regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D); +- regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909); +- regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000); +- regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000); +- regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06); +- regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C); +- regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000); +- regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342); +- regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20); +- regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00); +- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800); +- ndelay(1020); +- regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020); +- regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01); +- regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884); +- regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002); +- regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220); +- regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01); +- regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600); +- regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x47684100); +- regmap_write(priv->xfi_pextp_regmap, 0x3050, 0x00000000); +- regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x00000000); +- regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00); +- if (priv->gmac_id == 2) +- regmap_write(priv->xfi_pextp_regmap, 0xA008, 0x0007B400); +- regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000); +- regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001); +- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800); +- udelay(150); +- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111); +- ndelay(1020); +- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101); +- udelay(15); +- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111); +- ndelay(1020); +- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101); +- udelay(100); +- regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030); +- regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00); +- regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000); +- udelay(400); +-} +- +-static void mtk_usxgmii_an_init(struct mtk_eth_priv *priv) +-{ +- mtk_xfi_pll_enable(priv); +- mtk_usxgmii_reset(priv); +- mtk_usxgmii_setup_phya_an_10000(priv); +-} +- +-static void mtk_10gbaser_init(struct mtk_eth_priv *priv) +-{ +- mtk_xfi_pll_enable(priv); +- mtk_usxgmii_reset(priv); +- mtk_usxgmii_setup_phya_force_10000(priv); +-} +- +-static int mtk_mac_init(struct mtk_eth_priv *priv) +-{ +- int i, sgmii_sel_mask = 0, ge_mode = 0; +- u32 mcr; +- +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7629_GMAC2)) { +- mtk_infra_rmw(priv, MT7629_INFRA_MISC2_REG, +- INFRA_MISC2_BONDING_OPTION, priv->gmac_id); +- } +- +- switch (priv->phy_interface) { +- case PHY_INTERFACE_MODE_RGMII_RXID: +- case PHY_INTERFACE_MODE_RGMII: +- ge_mode = GE_MODE_RGMII; +- break; +- case PHY_INTERFACE_MODE_SGMII: +- case PHY_INTERFACE_MODE_2500BASEX: +- if (!IS_ENABLED(CONFIG_MTK_ETH_SGMII)) { +- printf("Error: SGMII is not supported on this platform\n"); +- return -ENOTSUPP; +- } +- +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC2_U3_QPHY)) { +- mtk_infra_rmw(priv, USB_PHY_SWITCH_REG, QPHY_SEL_MASK, +- SGMII_QPHY_SEL); +- } +- +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7622_SGMII)) +- sgmii_sel_mask = SYSCFG1_SGMII_SEL_M; +- +- mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, sgmii_sel_mask, +- SYSCFG1_SGMII_SEL(priv->gmac_id)); +- +- if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII) +- mtk_sgmii_an_init(priv); +- else +- mtk_sgmii_force_init(priv); +- +- ge_mode = GE_MODE_RGMII; +- break; +- case PHY_INTERFACE_MODE_MII: +- case PHY_INTERFACE_MODE_GMII: +- ge_mode = GE_MODE_MII; +- break; +- case PHY_INTERFACE_MODE_RMII: +- ge_mode = GE_MODE_RMII; +- break; +- default: +- break; +- } +- +- /* set the gmac to the right mode */ +- mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, +- SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id), +- ge_mode << SYSCFG1_GE_MODE_S(priv->gmac_id)); +- +- if (priv->force_mode) { +- mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | +- (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) | +- MAC_MODE | FORCE_MODE | +- MAC_TX_EN | MAC_RX_EN | +- BKOFF_EN | BACKPR_EN | +- FORCE_LINK; +- +- switch (priv->speed) { +- case SPEED_10: +- mcr |= SPEED_10M << FORCE_SPD_S; +- break; +- case SPEED_100: +- mcr |= SPEED_100M << FORCE_SPD_S; +- break; +- case SPEED_1000: +- case SPEED_2500: +- mcr |= SPEED_1000M << FORCE_SPD_S; +- break; +- } +- +- if (priv->duplex) +- mcr |= FORCE_DPX; +- +- mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr); +- } +- +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC1_TRGMII) && +- !MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) { +- /* Lower Tx Driving for TRGMII path */ +- for (i = 0 ; i < NUM_TRGMII_CTRL; i++) +- mtk_gmac_write(priv, GMAC_TRGMII_TD_ODT(i), +- (8 << TD_DM_DRVP_S) | +- (8 << TD_DM_DRVN_S)); +- +- mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, 0, +- RX_RST | RXC_DQSISEL); +- mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, RX_RST, 0); +- } +- +- return 0; +-} +- +-static int mtk_xmac_init(struct mtk_eth_priv *priv) +-{ +- u32 force_link = 0; +- +- if (!IS_ENABLED(CONFIG_MTK_ETH_XGMII)) { +- printf("Error: 10Gb interface is not supported on this platform\n"); +- return -ENOTSUPP; +- } +- +- switch (priv->phy_interface) { +- case PHY_INTERFACE_MODE_USXGMII: +- mtk_usxgmii_an_init(priv); +- break; +- case PHY_INTERFACE_MODE_10GBASER: +- mtk_10gbaser_init(priv); +- break; +- default: +- break; +- } +- +- /* Set GMAC to the correct mode */ +- mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, +- SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id), +- 0); +- +- if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || +- priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) && +- priv->gmac_id == 1) { +- mtk_infra_rmw(priv, TOPMISC_NETSYS_PCS_MUX, +- NETSYS_PCS_MUX_MASK, MUX_G2_USXGMII_SEL); +- } +- +- if (priv->phy_interface == PHY_INTERFACE_MODE_XGMII || +- priv->gmac_id == 2) +- force_link = XGMAC_FORCE_LINK(priv->gmac_id); +- +- mtk_gmac_rmw(priv, XGMAC_STS(priv->gmac_id), +- XGMAC_FORCE_LINK(priv->gmac_id), force_link); +- +- /* Force GMAC link down */ +- mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), FORCE_MODE); +- +- return 0; +-} +- +-static void mtk_eth_fifo_init(struct mtk_eth_priv *priv) +-{ +- char *pkt_base = priv->pkt_pool; +- struct mtk_tx_dma_v2 *txd; +- struct mtk_rx_dma_v2 *rxd; +- int i; +- +- mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0xffff0000, 0); +- udelay(500); +- +- memset(priv->tx_ring_noc, 0, NUM_TX_DESC * priv->soc->txd_size); +- memset(priv->rx_ring_noc, 0, NUM_RX_DESC * priv->soc->rxd_size); +- memset(priv->pkt_pool, 0xff, TOTAL_PKT_BUF_SIZE); +- +- flush_dcache_range((ulong)pkt_base, +- (ulong)(pkt_base + TOTAL_PKT_BUF_SIZE)); +- +- priv->rx_dma_owner_idx0 = 0; +- priv->tx_cpu_owner_idx0 = 0; +- +- for (i = 0; i < NUM_TX_DESC; i++) { +- txd = priv->tx_ring_noc + i * priv->soc->txd_size; +- +- txd->txd1 = virt_to_phys(pkt_base); +- txd->txd2 = PDMA_TXD2_DDONE | PDMA_TXD2_LS0; +- +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) +- txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id == 2 ? +- 15 : priv->gmac_id + 1); +- else if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2)) +- txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id + 1); +- else +- txd->txd4 = PDMA_V1_TXD4_FPORT_SET(priv->gmac_id + 1); +- +- pkt_base += PKTSIZE_ALIGN; +- } +- +- for (i = 0; i < NUM_RX_DESC; i++) { +- rxd = priv->rx_ring_noc + i * priv->soc->rxd_size; +- +- rxd->rxd1 = virt_to_phys(pkt_base); +- +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) || +- MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) +- rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN); +- else +- rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN); +- +- pkt_base += PKTSIZE_ALIGN; +- } +- +- mtk_pdma_write(priv, TX_BASE_PTR_REG(0), +- virt_to_phys(priv->tx_ring_noc)); +- mtk_pdma_write(priv, TX_MAX_CNT_REG(0), NUM_TX_DESC); +- mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0); +- +- mtk_pdma_write(priv, RX_BASE_PTR_REG(0), +- virt_to_phys(priv->rx_ring_noc)); +- mtk_pdma_write(priv, RX_MAX_CNT_REG(0), NUM_RX_DESC); +- mtk_pdma_write(priv, RX_CRX_IDX_REG(0), NUM_RX_DESC - 1); +- +- mtk_pdma_write(priv, PDMA_RST_IDX_REG, RST_DTX_IDX0 | RST_DRX_IDX0); +-} +- +-static void mtk_eth_mdc_init(struct mtk_eth_priv *priv) +-{ +- u32 divider; +- +- if (priv->mdc == 0) +- return; +- +- divider = min_t(u32, DIV_ROUND_UP(MDC_MAX_FREQ, priv->mdc), MDC_MAX_DIVIDER); +- +- /* Configure MDC turbo mode */ +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) +- mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, MISC_MDC_TURBO); +- else +- mtk_gmac_rmw(priv, GMAC_PPSC_REG, 0, MISC_MDC_TURBO); +- +- /* Configure MDC divider */ +- mtk_gmac_rmw(priv, GMAC_PPSC_REG, PHY_MDC_CFG, +- FIELD_PREP(PHY_MDC_CFG, divider)); +-} +- +-static int mtk_eth_start(struct udevice *dev) +-{ +- struct mtk_eth_priv *priv = dev_get_priv(dev); +- int i, ret; +- +- /* Reset FE */ +- reset_assert(&priv->rst_fe); +- udelay(1000); +- reset_deassert(&priv->rst_fe); +- mdelay(10); +- +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) || +- MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) +- setbits_le32(priv->fe_base + FE_GLO_MISC_REG, PDMA_VER_V2); +- +- /* Packets forward to PDMA */ +- mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, GDMA_FWD_TO_CPU); +- +- for (i = 0; i < priv->soc->gdma_count; i++) { +- if (i == priv->gmac_id) +- continue; +- +- mtk_gdma_write(priv, i, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD); +- } +- +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) { +- if (priv->sw == SW_MT7988 && priv->gmac_id == 0) { +- mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, +- GDMA_BRIDGE_TO_CPU); +- +- mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG, +- GDMA_CPU_BRIDGE_EN); +- } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || +- priv->phy_interface == PHY_INTERFACE_MODE_10GBASER || +- priv->phy_interface == PHY_INTERFACE_MODE_XGMII) && +- priv->gmac_id != 0) { +- mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG, +- GDMA_CPU_BRIDGE_EN); +- } +- } +- +- udelay(500); +- +- mtk_eth_fifo_init(priv); +- +- if (priv->switch_mac_control) +- priv->switch_mac_control(priv, true); +- +- /* Start PHY */ +- if (priv->sw == SW_NONE) { +- ret = mtk_phy_start(priv); +- if (ret) +- return ret; +- } +- +- mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0, +- TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN); +- udelay(500); +- +- return 0; +-} +- +-static void mtk_eth_stop(struct udevice *dev) +-{ +- struct mtk_eth_priv *priv = dev_get_priv(dev); +- +- if (priv->switch_mac_control) +- priv->switch_mac_control(priv, false); +- +- mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, +- TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN, 0); +- udelay(500); +- +- wait_for_bit_le32(priv->fe_base + priv->soc->pdma_base + PDMA_GLO_CFG_REG, +- RX_DMA_BUSY | TX_DMA_BUSY, 0, 5000, 0); +-} +- +-static int mtk_eth_write_hwaddr(struct udevice *dev) +-{ +- struct eth_pdata *pdata = dev_get_plat(dev); +- struct mtk_eth_priv *priv = dev_get_priv(dev); +- unsigned char *mac = pdata->enetaddr; +- u32 macaddr_lsb, macaddr_msb; +- +- macaddr_msb = ((u32)mac[0] << 8) | (u32)mac[1]; +- macaddr_lsb = ((u32)mac[2] << 24) | ((u32)mac[3] << 16) | +- ((u32)mac[4] << 8) | (u32)mac[5]; +- +- mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_MSB_REG, macaddr_msb); +- mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_LSB_REG, macaddr_lsb); +- +- return 0; +-} +- +-static int mtk_eth_send(struct udevice *dev, void *packet, int length) +-{ +- struct mtk_eth_priv *priv = dev_get_priv(dev); +- u32 idx = priv->tx_cpu_owner_idx0; +- struct mtk_tx_dma_v2 *txd; +- void *pkt_base; +- +- txd = priv->tx_ring_noc + idx * priv->soc->txd_size; +- +- if (!(txd->txd2 & PDMA_TXD2_DDONE)) { +- debug("mtk-eth: TX DMA descriptor ring is full\n"); +- return -EPERM; +- } +- +- pkt_base = (void *)phys_to_virt(txd->txd1); +- memcpy(pkt_base, packet, length); +- flush_dcache_range((ulong)pkt_base, (ulong)pkt_base + +- roundup(length, ARCH_DMA_MINALIGN)); +- +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) || +- MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) +- txd->txd2 = PDMA_TXD2_LS0 | PDMA_V2_TXD2_SDL0_SET(length); +- else +- txd->txd2 = PDMA_TXD2_LS0 | PDMA_V1_TXD2_SDL0_SET(length); +- +- priv->tx_cpu_owner_idx0 = (priv->tx_cpu_owner_idx0 + 1) % NUM_TX_DESC; +- mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0); +- +- return 0; +-} +- +-static int mtk_eth_recv(struct udevice *dev, int flags, uchar **packetp) +-{ +- struct mtk_eth_priv *priv = dev_get_priv(dev); +- u32 idx = priv->rx_dma_owner_idx0; +- struct mtk_rx_dma_v2 *rxd; +- uchar *pkt_base; +- u32 length; +- +- rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size; +- +- if (!(rxd->rxd2 & PDMA_RXD2_DDONE)) { +- debug("mtk-eth: RX DMA descriptor ring is empty\n"); +- return -EAGAIN; +- } +- +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) || +- MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) +- length = PDMA_V2_RXD2_PLEN0_GET(rxd->rxd2); +- else +- length = PDMA_V1_RXD2_PLEN0_GET(rxd->rxd2); +- +- pkt_base = (void *)phys_to_virt(rxd->rxd1); +- invalidate_dcache_range((ulong)pkt_base, (ulong)pkt_base + +- roundup(length, ARCH_DMA_MINALIGN)); +- +- if (packetp) +- *packetp = pkt_base; +- +- return length; +-} +- +-static int mtk_eth_free_pkt(struct udevice *dev, uchar *packet, int length) +-{ +- struct mtk_eth_priv *priv = dev_get_priv(dev); +- u32 idx = priv->rx_dma_owner_idx0; +- struct mtk_rx_dma_v2 *rxd; +- +- rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size; +- +- invalidate_dcache_range((ulong)rxd->rxd1, +- (ulong)rxd->rxd1 + PKTSIZE_ALIGN); +- +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) || +- MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) +- rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN); +- else +- rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN); +- +- mtk_pdma_write(priv, RX_CRX_IDX_REG(0), idx); +- priv->rx_dma_owner_idx0 = (priv->rx_dma_owner_idx0 + 1) % NUM_RX_DESC; +- +- return 0; +-} +- +-static int mtk_eth_probe(struct udevice *dev) +-{ +- struct eth_pdata *pdata = dev_get_plat(dev); +- struct mtk_eth_priv *priv = dev_get_priv(dev); +- ulong iobase = pdata->iobase; +- int ret; +- +- /* Frame Engine Register Base */ +- priv->fe_base = (void *)iobase; +- +- /* GMAC Register Base */ +- priv->gmac_base = (void *)(iobase + GMAC_BASE); +- +- /* MDIO register */ +- ret = mtk_mdio_register(dev); +- if (ret) +- return ret; +- +- /* Prepare for tx/rx rings */ +- priv->tx_ring_noc = (void *) +- noncached_alloc(priv->soc->txd_size * NUM_TX_DESC, +- ARCH_DMA_MINALIGN); +- priv->rx_ring_noc = (void *) +- noncached_alloc(priv->soc->rxd_size * NUM_RX_DESC, +- ARCH_DMA_MINALIGN); +- +- /* Set MDC divider */ +- mtk_eth_mdc_init(priv); +- +- /* Set MAC mode */ +- if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || +- priv->phy_interface == PHY_INTERFACE_MODE_10GBASER || +- priv->phy_interface == PHY_INTERFACE_MODE_XGMII) +- ret = mtk_xmac_init(priv); +- else +- ret = mtk_mac_init(priv); +- +- if (ret) +- return ret; +- +- /* Probe phy if switch is not specified */ +- if (priv->sw == SW_NONE) +- return mtk_phy_probe(dev); +- +- /* Initialize switch */ +- return mt753x_switch_init(priv); +-} +- +-static int mtk_eth_remove(struct udevice *dev) +-{ +- struct mtk_eth_priv *priv = dev_get_priv(dev); +- +- /* MDIO unregister */ +- mdio_unregister(priv->mdio_bus); +- mdio_free(priv->mdio_bus); +- +- /* Stop possibly started DMA */ +- mtk_eth_stop(dev); +- +- return 0; +-} +- +-static int mtk_eth_of_to_plat(struct udevice *dev) +-{ +- struct eth_pdata *pdata = dev_get_plat(dev); +- struct mtk_eth_priv *priv = dev_get_priv(dev); +- struct ofnode_phandle_args args; +- struct regmap *regmap; +- const char *str; +- ofnode subnode; +- int ret; +- +- priv->soc = (const struct mtk_soc_data *)dev_get_driver_data(dev); +- if (!priv->soc) { +- dev_err(dev, "missing soc compatible data\n"); +- return -EINVAL; +- } +- +- pdata->iobase = (phys_addr_t)dev_remap_addr(dev); +- +- /* get corresponding ethsys phandle */ +- ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0, +- &args); +- if (ret) +- return ret; +- +- priv->ethsys_regmap = syscon_node_to_regmap(args.node); +- if (IS_ERR(priv->ethsys_regmap)) +- return PTR_ERR(priv->ethsys_regmap); +- +- if (MTK_HAS_CAPS(priv->soc->caps, MTK_INFRA)) { +- /* get corresponding infracfg phandle */ +- ret = dev_read_phandle_with_args(dev, "mediatek,infracfg", +- NULL, 0, 0, &args); +- +- if (ret) +- return ret; +- +- priv->infra_regmap = syscon_node_to_regmap(args.node); +- if (IS_ERR(priv->infra_regmap)) +- return PTR_ERR(priv->infra_regmap); +- } +- +- /* Reset controllers */ +- ret = reset_get_by_name(dev, "fe", &priv->rst_fe); +- if (ret) { +- printf("error: Unable to get reset ctrl for frame engine\n"); +- return ret; +- } +- +- priv->gmac_id = dev_read_u32_default(dev, "mediatek,gmac-id", 0); +- +- priv->mdc = 0; +- subnode = ofnode_find_subnode(dev_ofnode(dev), "mdio"); +- if (ofnode_valid(subnode)) { +- priv->mdc = ofnode_read_u32_default(subnode, "clock-frequency", 2500000); +- if (priv->mdc > MDC_MAX_FREQ || +- priv->mdc < MDC_MAX_FREQ / MDC_MAX_DIVIDER) { +- printf("error: MDIO clock frequency out of range\n"); +- return -EINVAL; +- } +- } +- +- /* Interface mode is required */ +- pdata->phy_interface = dev_read_phy_mode(dev); +- priv->phy_interface = pdata->phy_interface; +- if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) { +- printf("error: phy-mode is not set\n"); +- return -EINVAL; +- } +- +- /* Force mode or autoneg */ +- subnode = ofnode_find_subnode(dev_ofnode(dev), "fixed-link"); +- if (ofnode_valid(subnode)) { +- priv->force_mode = 1; +- priv->speed = ofnode_read_u32_default(subnode, "speed", 0); +- priv->duplex = ofnode_read_bool(subnode, "full-duplex"); +- +- if (priv->speed != SPEED_10 && priv->speed != SPEED_100 && +- priv->speed != SPEED_1000 && priv->speed != SPEED_2500 && +- priv->speed != SPEED_10000) { +- printf("error: no valid speed set in fixed-link\n"); +- return -EINVAL; +- } +- } +- +- if ((priv->phy_interface == PHY_INTERFACE_MODE_SGMII || +- priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) && +- IS_ENABLED(CONFIG_MTK_ETH_SGMII)) { +- /* get corresponding sgmii phandle */ +- ret = dev_read_phandle_with_args(dev, "mediatek,sgmiisys", +- NULL, 0, 0, &args); +- if (ret) +- return ret; +- +- regmap = syscon_node_to_regmap(args.node); +- +- if (IS_ERR(regmap)) +- return PTR_ERR(regmap); +- +- priv->sgmii_base = regmap_get_range(regmap, 0); +- +- if (!priv->sgmii_base) { +- dev_err(dev, "Unable to find sgmii\n"); +- return -ENODEV; +- } +- +- /* Upstream linux use mediatek,pnswap instead of pn_swap */ +- priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") || +- ofnode_read_bool(args.node, "mediatek,pnswap"); +- } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || +- priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) && +- IS_ENABLED(CONFIG_MTK_ETH_XGMII)) { +- /* get corresponding usxgmii phandle */ +- ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys", +- NULL, 0, 0, &args); +- if (ret) +- return ret; +- +- priv->usxgmii_regmap = syscon_node_to_regmap(args.node); +- if (IS_ERR(priv->usxgmii_regmap)) +- return PTR_ERR(priv->usxgmii_regmap); +- +- /* get corresponding xfi_pextp phandle */ +- ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pextp", +- NULL, 0, 0, &args); +- if (ret) +- return ret; +- +- priv->xfi_pextp_regmap = syscon_node_to_regmap(args.node); +- if (IS_ERR(priv->xfi_pextp_regmap)) +- return PTR_ERR(priv->xfi_pextp_regmap); +- +- /* get corresponding xfi_pll phandle */ +- ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pll", +- NULL, 0, 0, &args); +- if (ret) +- return ret; +- +- priv->xfi_pll_regmap = syscon_node_to_regmap(args.node); +- if (IS_ERR(priv->xfi_pll_regmap)) +- return PTR_ERR(priv->xfi_pll_regmap); +- +- /* get corresponding toprgu phandle */ +- ret = dev_read_phandle_with_args(dev, "mediatek,toprgu", +- NULL, 0, 0, &args); +- if (ret) +- return ret; +- +- priv->toprgu_regmap = syscon_node_to_regmap(args.node); +- if (IS_ERR(priv->toprgu_regmap)) +- return PTR_ERR(priv->toprgu_regmap); +- } +- +- /* check for switch first, otherwise phy will be used */ +- priv->sw = SW_NONE; +- priv->switch_init = NULL; +- priv->switch_mac_control = NULL; +- str = dev_read_string(dev, "mediatek,switch"); +- +- if (str) { +- if (!strcmp(str, "mt7530")) { +- priv->sw = SW_MT7530; +- priv->switch_init = mt7530_setup; +- priv->switch_mac_control = mt7530_mac_control; +- priv->mt753x_smi_addr = MT753X_DFL_SMI_ADDR; +- priv->mt753x_reset_wait_time = 1000; +- } else if (!strcmp(str, "mt7531")) { +- priv->sw = SW_MT7531; +- priv->switch_init = mt7531_setup; +- priv->switch_mac_control = mt7531_mac_control; +- priv->mt753x_smi_addr = MT753X_DFL_SMI_ADDR; +- priv->mt753x_reset_wait_time = 200; +- } else if (!strcmp(str, "mt7988")) { +- priv->sw = SW_MT7988; +- priv->switch_init = mt7988_setup; +- priv->switch_mac_control = mt7988_mac_control; +- priv->mt753x_smi_addr = MT753X_DFL_SMI_ADDR; +- priv->mt753x_reset_wait_time = 50; +- } else { +- printf("error: unsupported switch\n"); +- return -EINVAL; +- } +- +- priv->mcm = dev_read_bool(dev, "mediatek,mcm"); +- if (priv->mcm) { +- ret = reset_get_by_name(dev, "mcm", &priv->rst_mcm); +- if (ret) { +- printf("error: no reset ctrl for mcm\n"); +- return ret; +- } +- } else { +- gpio_request_by_name(dev, "reset-gpios", 0, +- &priv->rst_gpio, GPIOD_IS_OUT); +- } +- } else { +- ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, +- 0, &args); +- if (ret) { +- printf("error: phy-handle is not specified\n"); +- return ret; +- } +- +- priv->phy_addr = ofnode_read_s32_default(args.node, "reg", -1); +- if (priv->phy_addr < 0) { +- printf("error: phy address is not specified\n"); +- return ret; +- } +- } +- +- return 0; +-} +- +-static const struct mtk_soc_data mt7988_data = { +- .caps = MT7988_CAPS, +- .ana_rgc3 = 0x128, +- .gdma_count = 3, +- .pdma_base = PDMA_V3_BASE, +- .txd_size = sizeof(struct mtk_tx_dma_v2), +- .rxd_size = sizeof(struct mtk_rx_dma_v2), +-}; +- +-static const struct mtk_soc_data mt7986_data = { +- .caps = MT7986_CAPS, +- .ana_rgc3 = 0x128, +- .gdma_count = 2, +- .pdma_base = PDMA_V2_BASE, +- .txd_size = sizeof(struct mtk_tx_dma_v2), +- .rxd_size = sizeof(struct mtk_rx_dma_v2), +-}; +- +-static const struct mtk_soc_data mt7981_data = { +- .caps = MT7981_CAPS, +- .ana_rgc3 = 0x128, +- .gdma_count = 2, +- .pdma_base = PDMA_V2_BASE, +- .txd_size = sizeof(struct mtk_tx_dma_v2), +- .rxd_size = sizeof(struct mtk_rx_dma_v2), +-}; +- +-static const struct mtk_soc_data mt7629_data = { +- .caps = MT7629_CAPS, +- .ana_rgc3 = 0x128, +- .gdma_count = 2, +- .pdma_base = PDMA_V1_BASE, +- .txd_size = sizeof(struct mtk_tx_dma), +- .rxd_size = sizeof(struct mtk_rx_dma), +-}; +- +-static const struct mtk_soc_data mt7623_data = { +- .caps = MT7623_CAPS, +- .gdma_count = 2, +- .pdma_base = PDMA_V1_BASE, +- .txd_size = sizeof(struct mtk_tx_dma), +- .rxd_size = sizeof(struct mtk_rx_dma), +-}; +- +-static const struct mtk_soc_data mt7622_data = { +- .caps = MT7622_CAPS, +- .ana_rgc3 = 0x2028, +- .gdma_count = 2, +- .pdma_base = PDMA_V1_BASE, +- .txd_size = sizeof(struct mtk_tx_dma), +- .rxd_size = sizeof(struct mtk_rx_dma), +-}; +- +-static const struct mtk_soc_data mt7621_data = { +- .caps = MT7621_CAPS, +- .gdma_count = 2, +- .pdma_base = PDMA_V1_BASE, +- .txd_size = sizeof(struct mtk_tx_dma), +- .rxd_size = sizeof(struct mtk_rx_dma), +-}; +- +-static const struct udevice_id mtk_eth_ids[] = { +- { .compatible = "mediatek,mt7988-eth", .data = (ulong)&mt7988_data }, +- { .compatible = "mediatek,mt7986-eth", .data = (ulong)&mt7986_data }, +- { .compatible = "mediatek,mt7981-eth", .data = (ulong)&mt7981_data }, +- { .compatible = "mediatek,mt7629-eth", .data = (ulong)&mt7629_data }, +- { .compatible = "mediatek,mt7623-eth", .data = (ulong)&mt7623_data }, +- { .compatible = "mediatek,mt7622-eth", .data = (ulong)&mt7622_data }, +- { .compatible = "mediatek,mt7621-eth", .data = (ulong)&mt7621_data }, +- {} +-}; +- +-static const struct eth_ops mtk_eth_ops = { +- .start = mtk_eth_start, +- .stop = mtk_eth_stop, +- .send = mtk_eth_send, +- .recv = mtk_eth_recv, +- .free_pkt = mtk_eth_free_pkt, +- .write_hwaddr = mtk_eth_write_hwaddr, +-}; +- +-U_BOOT_DRIVER(mtk_eth) = { +- .name = "mtk-eth", +- .id = UCLASS_ETH, +- .of_match = mtk_eth_ids, +- .of_to_plat = mtk_eth_of_to_plat, +- .plat_auto = sizeof(struct eth_pdata), +- .probe = mtk_eth_probe, +- .remove = mtk_eth_remove, +- .ops = &mtk_eth_ops, +- .priv_auto = sizeof(struct mtk_eth_priv), +- .flags = DM_FLAG_ALLOC_PRIV_DMA, +-}; +--- /dev/null ++++ b/drivers/net/mtk_eth/mtk_eth.c +@@ -0,0 +1,1563 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2025 MediaTek Inc. ++ * ++ * Author: Weijie Gao ++ * Author: Mark Lee ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtk_eth.h" ++ ++#define NUM_TX_DESC 32 ++#define NUM_RX_DESC 32 ++#define TX_TOTAL_BUF_SIZE (NUM_TX_DESC * PKTSIZE_ALIGN) ++#define RX_TOTAL_BUF_SIZE (NUM_RX_DESC * PKTSIZE_ALIGN) ++#define TOTAL_PKT_BUF_SIZE (TX_TOTAL_BUF_SIZE + RX_TOTAL_BUF_SIZE) ++ ++#define GDMA_FWD_TO_CPU \ ++ (0x20000000 | \ ++ GDM_ICS_EN | \ ++ GDM_TCS_EN | \ ++ GDM_UCS_EN | \ ++ STRP_CRC | \ ++ (DP_PDMA << MYMAC_DP_S) | \ ++ (DP_PDMA << BC_DP_S) | \ ++ (DP_PDMA << MC_DP_S) | \ ++ (DP_PDMA << UN_DP_S)) ++ ++#define GDMA_BRIDGE_TO_CPU \ ++ (0xC0000000 | \ ++ GDM_ICS_EN | \ ++ GDM_TCS_EN | \ ++ GDM_UCS_EN | \ ++ (DP_PDMA << MYMAC_DP_S) | \ ++ (DP_PDMA << BC_DP_S) | \ ++ (DP_PDMA << MC_DP_S) | \ ++ (DP_PDMA << UN_DP_S)) ++ ++#define GDMA_FWD_DISCARD \ ++ (0x20000000 | \ ++ GDM_ICS_EN | \ ++ GDM_TCS_EN | \ ++ GDM_UCS_EN | \ ++ STRP_CRC | \ ++ (DP_DISCARD << MYMAC_DP_S) | \ ++ (DP_DISCARD << BC_DP_S) | \ ++ (DP_DISCARD << MC_DP_S) | \ ++ (DP_DISCARD << UN_DP_S)) ++ ++struct mtk_eth_priv { ++ char pkt_pool[TOTAL_PKT_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN); ++ ++ void *tx_ring_noc; ++ void *rx_ring_noc; ++ ++ int rx_dma_owner_idx0; ++ int tx_cpu_owner_idx0; ++ ++ void __iomem *fe_base; ++ void __iomem *gmac_base; ++ void __iomem *sgmii_base; ++ ++ struct regmap *ethsys_regmap; ++ ++ struct regmap *infra_regmap; ++ ++ struct regmap *usxgmii_regmap; ++ struct regmap *xfi_pextp_regmap; ++ struct regmap *xfi_pll_regmap; ++ struct regmap *toprgu_regmap; ++ ++ struct mii_dev *mdio_bus; ++ ++ const struct mtk_soc_data *soc; ++ int gmac_id; ++ int force_mode; ++ int speed; ++ int duplex; ++ int mdc; ++ bool pn_swap; ++ ++ struct phy_device *phydev; ++ int phy_interface; ++ int phy_addr; ++ ++ struct mtk_eth_switch_priv *swpriv; ++ const char *swname; ++ ++ struct gpio_desc rst_gpio; ++ int mcm; ++ ++ struct reset_ctl rst_fe; ++ struct reset_ctl rst_mcm; ++}; ++ ++static void mtk_pdma_write(struct mtk_eth_priv *priv, u32 reg, u32 val) ++{ ++ writel(val, priv->fe_base + priv->soc->pdma_base + reg); ++} ++ ++static void mtk_pdma_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, ++ u32 set) ++{ ++ clrsetbits_le32(priv->fe_base + priv->soc->pdma_base + reg, clr, set); ++} ++ ++static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg, ++ u32 val) ++{ ++ u32 gdma_base; ++ ++ if (no == 2) ++ gdma_base = GDMA3_BASE; ++ else if (no == 1) ++ gdma_base = GDMA2_BASE; ++ else ++ gdma_base = GDMA1_BASE; ++ ++ writel(val, priv->fe_base + gdma_base + reg); ++} ++ ++void mtk_fe_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set) ++{ ++ clrsetbits_le32(priv->fe_base + reg, clr, set); ++} ++ ++static u32 mtk_gmac_read(struct mtk_eth_priv *priv, u32 reg) ++{ ++ return readl(priv->gmac_base + reg); ++} ++ ++static void mtk_gmac_write(struct mtk_eth_priv *priv, u32 reg, u32 val) ++{ ++ writel(val, priv->gmac_base + reg); ++} ++ ++void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set) ++{ ++ clrsetbits_le32(priv->gmac_base + reg, clr, set); ++} ++ ++void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set) ++{ ++ uint val; ++ ++ regmap_read(priv->ethsys_regmap, reg, &val); ++ val &= ~clr; ++ val |= set; ++ regmap_write(priv->ethsys_regmap, reg, val); ++} ++ ++static void mtk_infra_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, ++ u32 set) ++{ ++ uint val; ++ ++ regmap_read(priv->infra_regmap, reg, &val); ++ val &= ~clr; ++ val |= set; ++ regmap_write(priv->infra_regmap, reg, val); ++} ++ ++/* Direct MDIO clause 22/45 access via SoC */ ++static int mtk_mii_rw(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data, ++ u32 cmd, u32 st) ++{ ++ int ret; ++ u32 val; ++ ++ val = (st << MDIO_ST_S) | ++ ((cmd << MDIO_CMD_S) & MDIO_CMD_M) | ++ (((u32)phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) | ++ (((u32)reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M); ++ ++ if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR) ++ val |= data & MDIO_RW_DATA_M; ++ ++ mtk_gmac_write(priv, GMAC_PIAC_REG, val | PHY_ACS_ST); ++ ++ ret = wait_for_bit_le32(priv->gmac_base + GMAC_PIAC_REG, ++ PHY_ACS_ST, 0, 5000, 0); ++ if (ret) { ++ pr_warn("MDIO access timeout\n"); ++ return ret; ++ } ++ ++ if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) { ++ val = mtk_gmac_read(priv, GMAC_PIAC_REG); ++ return val & MDIO_RW_DATA_M; ++ } ++ ++ return 0; ++} ++ ++/* Direct MDIO clause 22 read via SoC */ ++int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg) ++{ ++ return mtk_mii_rw(priv, phy, reg, 0, MDIO_CMD_READ, MDIO_ST_C22); ++} ++ ++/* Direct MDIO clause 22 write via SoC */ ++int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data) ++{ ++ return mtk_mii_rw(priv, phy, reg, data, MDIO_CMD_WRITE, MDIO_ST_C22); ++} ++ ++/* Direct MDIO clause 45 read via SoC */ ++int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg) ++{ ++ int ret; ++ ++ ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45); ++ if (ret) ++ return ret; ++ ++ return mtk_mii_rw(priv, addr, devad, 0, MDIO_CMD_READ_C45, ++ MDIO_ST_C45); ++} ++ ++/* Direct MDIO clause 45 write via SoC */ ++int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg, ++ u16 val) ++{ ++ int ret; ++ ++ ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45); ++ if (ret) ++ return ret; ++ ++ return mtk_mii_rw(priv, addr, devad, val, MDIO_CMD_WRITE, ++ MDIO_ST_C45); ++} ++ ++/* Indirect MDIO clause 45 read via MII registers */ ++int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg) ++{ ++ int ret; ++ ++ ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG, ++ (MMD_ADDR << MMD_CMD_S) | ++ ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG, ++ (MMD_DATA << MMD_CMD_S) | ++ ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); ++ if (ret) ++ return ret; ++ ++ return mtk_mii_read(priv, addr, MII_MMD_ADDR_DATA_REG); ++} ++ ++/* Indirect MDIO clause 45 write via MII registers */ ++int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg, ++ u16 val) ++{ ++ int ret; ++ ++ ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG, ++ (MMD_ADDR << MMD_CMD_S) | ++ ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG, ++ (MMD_DATA << MMD_CMD_S) | ++ ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); ++ if (ret) ++ return ret; ++ ++ return mtk_mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, val); ++} ++ ++static int mtk_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) ++{ ++ struct mtk_eth_priv *priv = bus->priv; ++ ++ if (devad < 0) ++ return mtk_mii_read(priv, addr, reg); ++ ++ return mtk_mmd_read(priv, addr, devad, reg); ++} ++ ++static int mtk_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, ++ u16 val) ++{ ++ struct mtk_eth_priv *priv = bus->priv; ++ ++ if (devad < 0) ++ return mtk_mii_write(priv, addr, reg, val); ++ ++ return mtk_mmd_write(priv, addr, devad, reg, val); ++} ++ ++static int mtk_mdio_register(struct udevice *dev) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ struct mii_dev *mdio_bus = mdio_alloc(); ++ int ret; ++ ++ if (!mdio_bus) ++ return -ENOMEM; ++ ++ mdio_bus->read = mtk_mdio_read; ++ mdio_bus->write = mtk_mdio_write; ++ snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name); ++ ++ mdio_bus->priv = (void *)priv; ++ ++ ret = mdio_register(mdio_bus); ++ ++ if (ret) ++ return ret; ++ ++ priv->mdio_bus = mdio_bus; ++ ++ return 0; ++} ++ ++static int mtk_switch_init(struct mtk_eth_priv *priv) ++{ ++ struct mtk_eth_switch *swdrvs = ll_entry_start(struct mtk_eth_switch, ++ mtk_eth_switch); ++ const u32 n_swdrvs = ll_entry_count(struct mtk_eth_switch, ++ mtk_eth_switch); ++ struct mtk_eth_switch *tmp, *swdrv = NULL; ++ u32 reset_wait_time = 500; ++ size_t priv_size; ++ int ret; ++ ++ if (strcmp(priv->swname, "auto")) { ++ for (tmp = swdrvs; tmp < swdrvs + n_swdrvs; tmp++) { ++ if (!strcmp(tmp->name, priv->swname)) { ++ swdrv = tmp; ++ break; ++ } ++ } ++ } ++ ++ if (swdrv) ++ reset_wait_time = swdrv->reset_wait_time; ++ ++ /* Global reset switch */ ++ if (priv->mcm) { ++ reset_assert(&priv->rst_mcm); ++ udelay(1000); ++ reset_deassert(&priv->rst_mcm); ++ mdelay(reset_wait_time); ++ } else if (dm_gpio_is_valid(&priv->rst_gpio)) { ++ dm_gpio_set_value(&priv->rst_gpio, 0); ++ udelay(1000); ++ dm_gpio_set_value(&priv->rst_gpio, 1); ++ mdelay(reset_wait_time); ++ } ++ ++ if (!swdrv) { ++ for (tmp = swdrvs; tmp < swdrvs + n_swdrvs; tmp++) { ++ if (!tmp->detect) ++ continue; ++ ++ ret = tmp->detect(priv); ++ if (!ret) { ++ swdrv = tmp; ++ break; ++ } ++ } ++ ++ if (!swdrv) { ++ printf("Error: unable to detect switch\n"); ++ return -ENODEV; ++ } ++ } else { ++ if (swdrv->detect) { ++ ret = swdrv->detect(priv); ++ if (ret) { ++ printf("Error: switch probing failed\n"); ++ return -ENODEV; ++ } ++ } ++ } ++ ++ printf("%s\n", swdrv->desc); ++ ++ priv_size = swdrv->priv_size; ++ if (priv_size < sizeof(struct mtk_eth_switch_priv)) ++ priv_size = sizeof(struct mtk_eth_switch_priv); ++ ++ priv->swpriv = calloc(1, priv_size); ++ if (!priv->swpriv) { ++ printf("Error: no memory for switch data\n"); ++ return -ENOMEM; ++ } ++ ++ priv->swpriv->eth = priv; ++ priv->swpriv->soc = priv->soc; ++ priv->swpriv->phy_interface = priv->phy_interface; ++ priv->swpriv->sw = swdrv; ++ priv->swpriv->ethsys_base = regmap_get_range(priv->ethsys_regmap, 0); ++ ++ ret = swdrv->setup(priv->swpriv); ++ if (ret) { ++ free(priv->swpriv); ++ priv->swpriv = NULL; ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void mtk_xphy_link_adjust(struct mtk_eth_priv *priv) ++{ ++ u16 lcl_adv = 0, rmt_adv = 0; ++ u8 flowctrl; ++ u32 mcr; ++ ++ mcr = mtk_gmac_read(priv, XGMAC_PORT_MCR(priv->gmac_id)); ++ mcr &= ~(XGMAC_FORCE_TX_FC | XGMAC_FORCE_RX_FC); ++ ++ if (priv->phydev->duplex) { ++ if (priv->phydev->pause) ++ rmt_adv = LPA_PAUSE_CAP; ++ if (priv->phydev->asym_pause) ++ rmt_adv |= LPA_PAUSE_ASYM; ++ ++ if (priv->phydev->advertising & ADVERTISED_Pause) ++ lcl_adv |= ADVERTISE_PAUSE_CAP; ++ if (priv->phydev->advertising & ADVERTISED_Asym_Pause) ++ lcl_adv |= ADVERTISE_PAUSE_ASYM; ++ ++ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); ++ ++ if (flowctrl & FLOW_CTRL_TX) ++ mcr |= XGMAC_FORCE_TX_FC; ++ if (flowctrl & FLOW_CTRL_RX) ++ mcr |= XGMAC_FORCE_RX_FC; ++ ++ debug("rx pause %s, tx pause %s\n", ++ flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled", ++ flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled"); ++ } ++ ++ mcr &= ~(XGMAC_TRX_DISABLE); ++ mtk_gmac_write(priv, XGMAC_PORT_MCR(priv->gmac_id), mcr); ++} ++ ++static void mtk_phy_link_adjust(struct mtk_eth_priv *priv) ++{ ++ u16 lcl_adv = 0, rmt_adv = 0; ++ u8 flowctrl; ++ u32 mcr; ++ ++ mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | ++ (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) | ++ MAC_MODE | FORCE_MODE | ++ MAC_TX_EN | MAC_RX_EN | ++ DEL_RXFIFO_CLR | ++ BKOFF_EN | BACKPR_EN; ++ ++ switch (priv->phydev->speed) { ++ case SPEED_10: ++ mcr |= (SPEED_10M << FORCE_SPD_S); ++ break; ++ case SPEED_100: ++ mcr |= (SPEED_100M << FORCE_SPD_S); ++ break; ++ case SPEED_1000: ++ case SPEED_2500: ++ mcr |= (SPEED_1000M << FORCE_SPD_S); ++ break; ++ }; ++ ++ if (priv->phydev->link) ++ mcr |= FORCE_LINK; ++ ++ if (priv->phydev->duplex) { ++ mcr |= FORCE_DPX; ++ ++ if (priv->phydev->pause) ++ rmt_adv = LPA_PAUSE_CAP; ++ if (priv->phydev->asym_pause) ++ rmt_adv |= LPA_PAUSE_ASYM; ++ ++ if (priv->phydev->advertising & ADVERTISED_Pause) ++ lcl_adv |= ADVERTISE_PAUSE_CAP; ++ if (priv->phydev->advertising & ADVERTISED_Asym_Pause) ++ lcl_adv |= ADVERTISE_PAUSE_ASYM; ++ ++ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); ++ ++ if (flowctrl & FLOW_CTRL_TX) ++ mcr |= FORCE_TX_FC; ++ if (flowctrl & FLOW_CTRL_RX) ++ mcr |= FORCE_RX_FC; ++ ++ debug("rx pause %s, tx pause %s\n", ++ flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled", ++ flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled"); ++ } ++ ++ mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr); ++} ++ ++static int mtk_phy_start(struct mtk_eth_priv *priv) ++{ ++ struct phy_device *phydev = priv->phydev; ++ int ret; ++ ++ ret = phy_startup(phydev); ++ ++ if (ret) { ++ debug("Could not initialize PHY %s\n", phydev->dev->name); ++ return ret; ++ } ++ ++ if (!phydev->link) { ++ debug("%s: link down.\n", phydev->dev->name); ++ return 0; ++ } ++ ++ if (!priv->force_mode) { ++ if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER || ++ priv->phy_interface == PHY_INTERFACE_MODE_XGMII) ++ mtk_xphy_link_adjust(priv); ++ else ++ mtk_phy_link_adjust(priv); ++ } ++ ++ debug("Speed: %d, %s duplex%s\n", phydev->speed, ++ (phydev->duplex) ? "full" : "half", ++ (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); ++ ++ return 0; ++} ++ ++static int mtk_phy_probe(struct udevice *dev) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ struct phy_device *phydev; ++ ++ phydev = phy_connect(priv->mdio_bus, priv->phy_addr, dev, ++ priv->phy_interface); ++ if (!phydev) ++ return -ENODEV; ++ ++ phydev->supported &= PHY_GBIT_FEATURES; ++ phydev->advertising = phydev->supported; ++ ++ priv->phydev = phydev; ++ phy_config(phydev); ++ ++ return 0; ++} ++ ++static void mtk_sgmii_an_init(struct mtk_eth_priv *priv) ++{ ++ /* Set SGMII GEN1 speed(1G) */ ++ clrbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, SGMSYS_SPEED_MASK); ++ ++ /* Enable SGMII AN */ ++ setbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1, ++ SGMII_AN_ENABLE); ++ ++ /* SGMII AN mode setting */ ++ writel(SGMII_AN_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE); ++ ++ /* SGMII PN SWAP setting */ ++ if (priv->pn_swap) { ++ setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL, ++ SGMII_PN_SWAP_TX_RX); ++ } ++ ++ /* Release PHYA power down state */ ++ clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL, ++ SGMII_PHYA_PWD, 0); ++} ++ ++static void mtk_sgmii_force_init(struct mtk_eth_priv *priv) ++{ ++ /* Set SGMII GEN2 speed(2.5G) */ ++ clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, ++ SGMSYS_SPEED_MASK, ++ FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500)); ++ ++ /* Disable SGMII AN */ ++ clrsetbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1, ++ SGMII_AN_ENABLE, 0); ++ ++ /* SGMII force mode setting */ ++ writel(SGMII_FORCE_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE); ++ ++ /* SGMII PN SWAP setting */ ++ if (priv->pn_swap) { ++ setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL, ++ SGMII_PN_SWAP_TX_RX); ++ } ++ ++ /* Release PHYA power down state */ ++ clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL, ++ SGMII_PHYA_PWD, 0); ++} ++ ++static void mtk_xfi_pll_enable(struct mtk_eth_priv *priv) ++{ ++ u32 val = 0; ++ ++ /* Add software workaround for USXGMII PLL TCL issue */ ++ regmap_write(priv->xfi_pll_regmap, XFI_PLL_ANA_GLB8, ++ RG_XFI_PLL_ANA_SWWA); ++ ++ regmap_read(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, &val); ++ val |= RG_XFI_PLL_EN; ++ regmap_write(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, val); ++} ++ ++static void mtk_usxgmii_reset(struct mtk_eth_priv *priv) ++{ ++ switch (priv->gmac_id) { ++ case 1: ++ regmap_write(priv->toprgu_regmap, 0xFC, 0x0000A004); ++ regmap_write(priv->toprgu_regmap, 0x18, 0x88F0A004); ++ regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000); ++ regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000); ++ regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000); ++ break; ++ case 2: ++ regmap_write(priv->toprgu_regmap, 0xFC, 0x00005002); ++ regmap_write(priv->toprgu_regmap, 0x18, 0x88F05002); ++ regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000); ++ regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000); ++ regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000); ++ break; ++ } ++ ++ mdelay(10); ++} ++ ++static void mtk_usxgmii_setup_phya_an_10000(struct mtk_eth_priv *priv) ++{ ++ regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6D); ++ regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B); ++ regmap_write(priv->usxgmii_regmap, 0x80C, 0x30000000); ++ ndelay(1020); ++ regmap_write(priv->usxgmii_regmap, 0x80C, 0x10000000); ++ ndelay(1020); ++ regmap_write(priv->usxgmii_regmap, 0x80C, 0x00000000); ++ ++ regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C); ++ regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA); ++ regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707); ++ regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F); ++ regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032); ++ regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA); ++ regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B); ++ regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF); ++ regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA); ++ regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F); ++ regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68); ++ regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166); ++ regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF); ++ regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D); ++ regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909); ++ regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000); ++ regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000); ++ regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06); ++ regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C); ++ regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000); ++ regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342); ++ regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20); ++ regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800); ++ ndelay(1020); ++ regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020); ++ regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01); ++ regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884); ++ regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002); ++ regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220); ++ regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01); ++ regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600); ++ regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x40704000); ++ regmap_write(priv->xfi_pextp_regmap, 0x3050, 0xA8000000); ++ regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x000000AA); ++ regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00); ++ regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000); ++ regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800); ++ udelay(150); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111); ++ ndelay(1020); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101); ++ udelay(15); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111); ++ ndelay(1020); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101); ++ udelay(100); ++ regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030); ++ regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00); ++ regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000); ++ udelay(400); ++} ++ ++static void mtk_usxgmii_setup_phya_force_10000(struct mtk_eth_priv *priv) ++{ ++ regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6C); ++ regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B); ++ regmap_write(priv->usxgmii_regmap, 0x80C, 0xB0000000); ++ ndelay(1020); ++ regmap_write(priv->usxgmii_regmap, 0x80C, 0x90000000); ++ ndelay(1020); ++ ++ regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C); ++ regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA); ++ regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707); ++ regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F); ++ regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032); ++ regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA); ++ regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B); ++ regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF); ++ regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA); ++ regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F); ++ regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68); ++ regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166); ++ regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF); ++ regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D); ++ regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909); ++ regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000); ++ regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000); ++ regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06); ++ regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C); ++ regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000); ++ regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342); ++ regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20); ++ regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800); ++ ndelay(1020); ++ regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020); ++ regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01); ++ regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884); ++ regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002); ++ regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220); ++ regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01); ++ regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600); ++ regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x47684100); ++ regmap_write(priv->xfi_pextp_regmap, 0x3050, 0x00000000); ++ regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x00000000); ++ regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00); ++ if (priv->gmac_id == 2) ++ regmap_write(priv->xfi_pextp_regmap, 0xA008, 0x0007B400); ++ regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000); ++ regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800); ++ udelay(150); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111); ++ ndelay(1020); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101); ++ udelay(15); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111); ++ ndelay(1020); ++ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101); ++ udelay(100); ++ regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030); ++ regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00); ++ regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000); ++ udelay(400); ++} ++ ++static void mtk_usxgmii_an_init(struct mtk_eth_priv *priv) ++{ ++ mtk_xfi_pll_enable(priv); ++ mtk_usxgmii_reset(priv); ++ mtk_usxgmii_setup_phya_an_10000(priv); ++} ++ ++static void mtk_10gbaser_init(struct mtk_eth_priv *priv) ++{ ++ mtk_xfi_pll_enable(priv); ++ mtk_usxgmii_reset(priv); ++ mtk_usxgmii_setup_phya_force_10000(priv); ++} ++ ++static int mtk_mac_init(struct mtk_eth_priv *priv) ++{ ++ int i, sgmii_sel_mask = 0, ge_mode = 0; ++ u32 mcr; ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7629_GMAC2)) { ++ mtk_infra_rmw(priv, MT7629_INFRA_MISC2_REG, ++ INFRA_MISC2_BONDING_OPTION, priv->gmac_id); ++ } ++ ++ switch (priv->phy_interface) { ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ case PHY_INTERFACE_MODE_RGMII: ++ ge_mode = GE_MODE_RGMII; ++ break; ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_2500BASEX: ++ if (!IS_ENABLED(CONFIG_MTK_ETH_SGMII)) { ++ printf("Error: SGMII is not supported on this platform\n"); ++ return -ENOTSUPP; ++ } ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC2_U3_QPHY)) { ++ mtk_infra_rmw(priv, USB_PHY_SWITCH_REG, QPHY_SEL_MASK, ++ SGMII_QPHY_SEL); ++ } ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7622_SGMII)) ++ sgmii_sel_mask = SYSCFG1_SGMII_SEL_M; ++ ++ mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, sgmii_sel_mask, ++ SYSCFG1_SGMII_SEL(priv->gmac_id)); ++ ++ if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII) ++ mtk_sgmii_an_init(priv); ++ else ++ mtk_sgmii_force_init(priv); ++ ++ ge_mode = GE_MODE_RGMII; ++ break; ++ case PHY_INTERFACE_MODE_MII: ++ case PHY_INTERFACE_MODE_GMII: ++ ge_mode = GE_MODE_MII; ++ break; ++ case PHY_INTERFACE_MODE_RMII: ++ ge_mode = GE_MODE_RMII; ++ break; ++ default: ++ break; ++ } ++ ++ /* set the gmac to the right mode */ ++ mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, ++ SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id), ++ ge_mode << SYSCFG1_GE_MODE_S(priv->gmac_id)); ++ ++ if (priv->force_mode) { ++ mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) | ++ (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) | ++ MAC_MODE | FORCE_MODE | ++ MAC_TX_EN | MAC_RX_EN | ++ BKOFF_EN | BACKPR_EN | ++ FORCE_LINK; ++ ++ switch (priv->speed) { ++ case SPEED_10: ++ mcr |= SPEED_10M << FORCE_SPD_S; ++ break; ++ case SPEED_100: ++ mcr |= SPEED_100M << FORCE_SPD_S; ++ break; ++ case SPEED_1000: ++ case SPEED_2500: ++ mcr |= SPEED_1000M << FORCE_SPD_S; ++ break; ++ } ++ ++ if (priv->duplex) ++ mcr |= FORCE_DPX; ++ ++ mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr); ++ } ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC1_TRGMII) && ++ !MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) { ++ /* Lower Tx Driving for TRGMII path */ ++ for (i = 0 ; i < NUM_TRGMII_CTRL; i++) ++ mtk_gmac_write(priv, GMAC_TRGMII_TD_ODT(i), ++ (8 << TD_DM_DRVP_S) | ++ (8 << TD_DM_DRVN_S)); ++ ++ mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, 0, ++ RX_RST | RXC_DQSISEL); ++ mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, RX_RST, 0); ++ } ++ ++ return 0; ++} ++ ++static int mtk_xmac_init(struct mtk_eth_priv *priv) ++{ ++ u32 force_link = 0; ++ ++ if (!IS_ENABLED(CONFIG_MTK_ETH_XGMII)) { ++ printf("Error: 10Gb interface is not supported on this platform\n"); ++ return -ENOTSUPP; ++ } ++ ++ switch (priv->phy_interface) { ++ case PHY_INTERFACE_MODE_USXGMII: ++ mtk_usxgmii_an_init(priv); ++ break; ++ case PHY_INTERFACE_MODE_10GBASER: ++ mtk_10gbaser_init(priv); ++ break; ++ default: ++ break; ++ } ++ ++ /* Set GMAC to the correct mode */ ++ mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, ++ SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id), ++ 0); ++ ++ if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) && ++ priv->gmac_id == 1) { ++ mtk_infra_rmw(priv, TOPMISC_NETSYS_PCS_MUX, ++ NETSYS_PCS_MUX_MASK, MUX_G2_USXGMII_SEL); ++ } ++ ++ if (priv->phy_interface == PHY_INTERFACE_MODE_XGMII || ++ priv->gmac_id == 2) ++ force_link = XGMAC_FORCE_LINK(priv->gmac_id); ++ ++ mtk_gmac_rmw(priv, XGMAC_STS(priv->gmac_id), ++ XGMAC_FORCE_LINK(priv->gmac_id), force_link); ++ ++ /* Force GMAC link down */ ++ mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), FORCE_MODE); ++ ++ return 0; ++} ++ ++static void mtk_eth_fifo_init(struct mtk_eth_priv *priv) ++{ ++ char *pkt_base = priv->pkt_pool; ++ struct mtk_tx_dma_v2 *txd; ++ struct mtk_rx_dma_v2 *rxd; ++ int i; ++ ++ mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0xffff0000, 0); ++ udelay(500); ++ ++ memset(priv->tx_ring_noc, 0, NUM_TX_DESC * priv->soc->txd_size); ++ memset(priv->rx_ring_noc, 0, NUM_RX_DESC * priv->soc->rxd_size); ++ memset(priv->pkt_pool, 0xff, TOTAL_PKT_BUF_SIZE); ++ ++ flush_dcache_range((ulong)pkt_base, ++ (ulong)(pkt_base + TOTAL_PKT_BUF_SIZE)); ++ ++ priv->rx_dma_owner_idx0 = 0; ++ priv->tx_cpu_owner_idx0 = 0; ++ ++ for (i = 0; i < NUM_TX_DESC; i++) { ++ txd = priv->tx_ring_noc + i * priv->soc->txd_size; ++ ++ txd->txd1 = virt_to_phys(pkt_base); ++ txd->txd2 = PDMA_TXD2_DDONE | PDMA_TXD2_LS0; ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) ++ txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id == 2 ? ++ 15 : priv->gmac_id + 1); ++ else if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2)) ++ txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id + 1); ++ else ++ txd->txd4 = PDMA_V1_TXD4_FPORT_SET(priv->gmac_id + 1); ++ ++ pkt_base += PKTSIZE_ALIGN; ++ } ++ ++ for (i = 0; i < NUM_RX_DESC; i++) { ++ rxd = priv->rx_ring_noc + i * priv->soc->rxd_size; ++ ++ rxd->rxd1 = virt_to_phys(pkt_base); ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) || ++ MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) ++ rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN); ++ else ++ rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN); ++ ++ pkt_base += PKTSIZE_ALIGN; ++ } ++ ++ mtk_pdma_write(priv, TX_BASE_PTR_REG(0), ++ virt_to_phys(priv->tx_ring_noc)); ++ mtk_pdma_write(priv, TX_MAX_CNT_REG(0), NUM_TX_DESC); ++ mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0); ++ ++ mtk_pdma_write(priv, RX_BASE_PTR_REG(0), ++ virt_to_phys(priv->rx_ring_noc)); ++ mtk_pdma_write(priv, RX_MAX_CNT_REG(0), NUM_RX_DESC); ++ mtk_pdma_write(priv, RX_CRX_IDX_REG(0), NUM_RX_DESC - 1); ++ ++ mtk_pdma_write(priv, PDMA_RST_IDX_REG, RST_DTX_IDX0 | RST_DRX_IDX0); ++} ++ ++static void mtk_eth_mdc_init(struct mtk_eth_priv *priv) ++{ ++ u32 divider; ++ ++ if (priv->mdc == 0) ++ return; ++ ++ divider = min_t(u32, DIV_ROUND_UP(MDC_MAX_FREQ, priv->mdc), MDC_MAX_DIVIDER); ++ ++ /* Configure MDC turbo mode */ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) ++ mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, MISC_MDC_TURBO); ++ else ++ mtk_gmac_rmw(priv, GMAC_PPSC_REG, 0, MISC_MDC_TURBO); ++ ++ /* Configure MDC divider */ ++ mtk_gmac_rmw(priv, GMAC_PPSC_REG, PHY_MDC_CFG, ++ FIELD_PREP(PHY_MDC_CFG, divider)); ++} ++ ++static int mtk_eth_start(struct udevice *dev) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ int i, ret; ++ ++ /* Reset FE */ ++ reset_assert(&priv->rst_fe); ++ udelay(1000); ++ reset_deassert(&priv->rst_fe); ++ mdelay(10); ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) || ++ MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) ++ setbits_le32(priv->fe_base + FE_GLO_MISC_REG, PDMA_VER_V2); ++ ++ /* Packets forward to PDMA */ ++ mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, GDMA_FWD_TO_CPU); ++ ++ for (i = 0; i < priv->soc->gdma_count; i++) { ++ if (i == priv->gmac_id) ++ continue; ++ ++ mtk_gdma_write(priv, i, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD); ++ } ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) { ++ if (priv->swpriv && !strcmp(priv->swpriv->sw->name, "mt7988") && ++ priv->gmac_id == 0) { ++ mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, ++ GDMA_BRIDGE_TO_CPU); ++ ++ mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG, ++ GDMA_CPU_BRIDGE_EN); ++ } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER || ++ priv->phy_interface == PHY_INTERFACE_MODE_XGMII) && ++ priv->gmac_id != 0) { ++ mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG, ++ GDMA_CPU_BRIDGE_EN); ++ } ++ } ++ ++ udelay(500); ++ ++ mtk_eth_fifo_init(priv); ++ ++ if (priv->swpriv) { ++ /* Enable communication with switch */ ++ if (priv->swpriv->sw->mac_control) ++ priv->swpriv->sw->mac_control(priv->swpriv, true); ++ } else { ++ /* Start PHY */ ++ ret = mtk_phy_start(priv); ++ if (ret) ++ return ret; ++ } ++ ++ mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0, ++ TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN); ++ udelay(500); ++ ++ return 0; ++} ++ ++static void mtk_eth_stop(struct udevice *dev) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ ++ if (priv->swpriv) { ++ if (priv->swpriv->sw->mac_control) ++ priv->swpriv->sw->mac_control(priv->swpriv, false); ++ } ++ ++ mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, ++ TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN, 0); ++ udelay(500); ++ ++ wait_for_bit_le32(priv->fe_base + priv->soc->pdma_base + PDMA_GLO_CFG_REG, ++ RX_DMA_BUSY | TX_DMA_BUSY, 0, 5000, 0); ++} ++ ++static int mtk_eth_write_hwaddr(struct udevice *dev) ++{ ++ struct eth_pdata *pdata = dev_get_plat(dev); ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ unsigned char *mac = pdata->enetaddr; ++ u32 macaddr_lsb, macaddr_msb; ++ ++ macaddr_msb = ((u32)mac[0] << 8) | (u32)mac[1]; ++ macaddr_lsb = ((u32)mac[2] << 24) | ((u32)mac[3] << 16) | ++ ((u32)mac[4] << 8) | (u32)mac[5]; ++ ++ mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_MSB_REG, macaddr_msb); ++ mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_LSB_REG, macaddr_lsb); ++ ++ return 0; ++} ++ ++static int mtk_eth_send(struct udevice *dev, void *packet, int length) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ u32 idx = priv->tx_cpu_owner_idx0; ++ struct mtk_tx_dma_v2 *txd; ++ void *pkt_base; ++ ++ txd = priv->tx_ring_noc + idx * priv->soc->txd_size; ++ ++ if (!(txd->txd2 & PDMA_TXD2_DDONE)) { ++ debug("mtk-eth: TX DMA descriptor ring is full\n"); ++ return -EPERM; ++ } ++ ++ pkt_base = (void *)phys_to_virt(txd->txd1); ++ memcpy(pkt_base, packet, length); ++ flush_dcache_range((ulong)pkt_base, (ulong)pkt_base + ++ roundup(length, ARCH_DMA_MINALIGN)); ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) || ++ MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) ++ txd->txd2 = PDMA_TXD2_LS0 | PDMA_V2_TXD2_SDL0_SET(length); ++ else ++ txd->txd2 = PDMA_TXD2_LS0 | PDMA_V1_TXD2_SDL0_SET(length); ++ ++ priv->tx_cpu_owner_idx0 = (priv->tx_cpu_owner_idx0 + 1) % NUM_TX_DESC; ++ mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0); ++ ++ return 0; ++} ++ ++static int mtk_eth_recv(struct udevice *dev, int flags, uchar **packetp) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ u32 idx = priv->rx_dma_owner_idx0; ++ struct mtk_rx_dma_v2 *rxd; ++ uchar *pkt_base; ++ u32 length; ++ ++ rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size; ++ ++ if (!(rxd->rxd2 & PDMA_RXD2_DDONE)) { ++ debug("mtk-eth: RX DMA descriptor ring is empty\n"); ++ return -EAGAIN; ++ } ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) || ++ MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) ++ length = PDMA_V2_RXD2_PLEN0_GET(rxd->rxd2); ++ else ++ length = PDMA_V1_RXD2_PLEN0_GET(rxd->rxd2); ++ ++ pkt_base = (void *)phys_to_virt(rxd->rxd1); ++ invalidate_dcache_range((ulong)pkt_base, (ulong)pkt_base + ++ roundup(length, ARCH_DMA_MINALIGN)); ++ ++ if (packetp) ++ *packetp = pkt_base; ++ ++ return length; ++} ++ ++static int mtk_eth_free_pkt(struct udevice *dev, uchar *packet, int length) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ u32 idx = priv->rx_dma_owner_idx0; ++ struct mtk_rx_dma_v2 *rxd; ++ ++ rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size; ++ ++ invalidate_dcache_range((ulong)rxd->rxd1, ++ (ulong)rxd->rxd1 + PKTSIZE_ALIGN); ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) || ++ MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) ++ rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN); ++ else ++ rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN); ++ ++ mtk_pdma_write(priv, RX_CRX_IDX_REG(0), idx); ++ priv->rx_dma_owner_idx0 = (priv->rx_dma_owner_idx0 + 1) % NUM_RX_DESC; ++ ++ return 0; ++} ++ ++static int mtk_eth_probe(struct udevice *dev) ++{ ++ struct eth_pdata *pdata = dev_get_plat(dev); ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ ulong iobase = pdata->iobase; ++ int ret; ++ ++ /* Frame Engine Register Base */ ++ priv->fe_base = (void *)iobase; ++ ++ /* GMAC Register Base */ ++ priv->gmac_base = (void *)(iobase + GMAC_BASE); ++ ++ /* MDIO register */ ++ ret = mtk_mdio_register(dev); ++ if (ret) ++ return ret; ++ ++ /* Prepare for tx/rx rings */ ++ priv->tx_ring_noc = (void *) ++ noncached_alloc(priv->soc->txd_size * NUM_TX_DESC, ++ ARCH_DMA_MINALIGN); ++ priv->rx_ring_noc = (void *) ++ noncached_alloc(priv->soc->rxd_size * NUM_RX_DESC, ++ ARCH_DMA_MINALIGN); ++ ++ /* Set MDC divider */ ++ mtk_eth_mdc_init(priv); ++ ++ /* Set MAC mode */ ++ if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER || ++ priv->phy_interface == PHY_INTERFACE_MODE_XGMII) ++ ret = mtk_xmac_init(priv); ++ else ++ ret = mtk_mac_init(priv); ++ ++ if (ret) ++ return ret; ++ ++ /* Probe phy if switch is not specified */ ++ if (!priv->swname) ++ return mtk_phy_probe(dev); ++ ++ /* Initialize switch */ ++ return mtk_switch_init(priv); ++} ++ ++static int mtk_eth_remove(struct udevice *dev) ++{ ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ ++ /* MDIO unregister */ ++ mdio_unregister(priv->mdio_bus); ++ mdio_free(priv->mdio_bus); ++ ++ /* Stop possibly started DMA */ ++ mtk_eth_stop(dev); ++ ++ if (priv->swpriv) { ++ if (priv->swpriv->sw->cleanup) ++ priv->swpriv->sw->cleanup(priv->swpriv); ++ free(priv->swpriv); ++ } ++ ++ return 0; ++} ++ ++static int mtk_eth_of_to_plat(struct udevice *dev) ++{ ++ struct eth_pdata *pdata = dev_get_plat(dev); ++ struct mtk_eth_priv *priv = dev_get_priv(dev); ++ struct ofnode_phandle_args args; ++ struct regmap *regmap; ++ ofnode subnode; ++ int ret; ++ ++ priv->soc = (const struct mtk_soc_data *)dev_get_driver_data(dev); ++ if (!priv->soc) { ++ dev_err(dev, "missing soc compatible data\n"); ++ return -EINVAL; ++ } ++ ++ pdata->iobase = (phys_addr_t)dev_remap_addr(dev); ++ ++ /* get corresponding ethsys phandle */ ++ ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0, ++ &args); ++ if (ret) ++ return ret; ++ ++ priv->ethsys_regmap = syscon_node_to_regmap(args.node); ++ if (IS_ERR(priv->ethsys_regmap)) ++ return PTR_ERR(priv->ethsys_regmap); ++ ++ if (MTK_HAS_CAPS(priv->soc->caps, MTK_INFRA)) { ++ /* get corresponding infracfg phandle */ ++ ret = dev_read_phandle_with_args(dev, "mediatek,infracfg", ++ NULL, 0, 0, &args); ++ ++ if (ret) ++ return ret; ++ ++ priv->infra_regmap = syscon_node_to_regmap(args.node); ++ if (IS_ERR(priv->infra_regmap)) ++ return PTR_ERR(priv->infra_regmap); ++ } ++ ++ /* Reset controllers */ ++ ret = reset_get_by_name(dev, "fe", &priv->rst_fe); ++ if (ret) { ++ printf("error: Unable to get reset ctrl for frame engine\n"); ++ return ret; ++ } ++ ++ priv->gmac_id = dev_read_u32_default(dev, "mediatek,gmac-id", 0); ++ ++ priv->mdc = 0; ++ subnode = ofnode_find_subnode(dev_ofnode(dev), "mdio"); ++ if (ofnode_valid(subnode)) { ++ priv->mdc = ofnode_read_u32_default(subnode, "clock-frequency", 2500000); ++ if (priv->mdc > MDC_MAX_FREQ || ++ priv->mdc < MDC_MAX_FREQ / MDC_MAX_DIVIDER) { ++ printf("error: MDIO clock frequency out of range\n"); ++ return -EINVAL; ++ } ++ } ++ ++ /* Interface mode is required */ ++ pdata->phy_interface = dev_read_phy_mode(dev); ++ priv->phy_interface = pdata->phy_interface; ++ if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) { ++ printf("error: phy-mode is not set\n"); ++ return -EINVAL; ++ } ++ ++ /* Force mode or autoneg */ ++ subnode = ofnode_find_subnode(dev_ofnode(dev), "fixed-link"); ++ if (ofnode_valid(subnode)) { ++ priv->force_mode = 1; ++ priv->speed = ofnode_read_u32_default(subnode, "speed", 0); ++ priv->duplex = ofnode_read_bool(subnode, "full-duplex"); ++ ++ if (priv->speed != SPEED_10 && priv->speed != SPEED_100 && ++ priv->speed != SPEED_1000 && priv->speed != SPEED_2500 && ++ priv->speed != SPEED_10000) { ++ printf("error: no valid speed set in fixed-link\n"); ++ return -EINVAL; ++ } ++ } ++ ++ if ((priv->phy_interface == PHY_INTERFACE_MODE_SGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) && ++ IS_ENABLED(CONFIG_MTK_ETH_SGMII)) { ++ /* get corresponding sgmii phandle */ ++ ret = dev_read_phandle_with_args(dev, "mediatek,sgmiisys", ++ NULL, 0, 0, &args); ++ if (ret) ++ return ret; ++ ++ regmap = syscon_node_to_regmap(args.node); ++ ++ if (IS_ERR(regmap)) ++ return PTR_ERR(regmap); ++ ++ priv->sgmii_base = regmap_get_range(regmap, 0); ++ ++ if (!priv->sgmii_base) { ++ dev_err(dev, "Unable to find sgmii\n"); ++ return -ENODEV; ++ } ++ ++ /* Upstream linux use mediatek,pnswap instead of pn_swap */ ++ priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") || ++ ofnode_read_bool(args.node, "mediatek,pnswap"); ++ } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII || ++ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) && ++ IS_ENABLED(CONFIG_MTK_ETH_XGMII)) { ++ /* get corresponding usxgmii phandle */ ++ ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys", ++ NULL, 0, 0, &args); ++ if (ret) ++ return ret; ++ ++ priv->usxgmii_regmap = syscon_node_to_regmap(args.node); ++ if (IS_ERR(priv->usxgmii_regmap)) ++ return PTR_ERR(priv->usxgmii_regmap); ++ ++ /* get corresponding xfi_pextp phandle */ ++ ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pextp", ++ NULL, 0, 0, &args); ++ if (ret) ++ return ret; ++ ++ priv->xfi_pextp_regmap = syscon_node_to_regmap(args.node); ++ if (IS_ERR(priv->xfi_pextp_regmap)) ++ return PTR_ERR(priv->xfi_pextp_regmap); ++ ++ /* get corresponding xfi_pll phandle */ ++ ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pll", ++ NULL, 0, 0, &args); ++ if (ret) ++ return ret; ++ ++ priv->xfi_pll_regmap = syscon_node_to_regmap(args.node); ++ if (IS_ERR(priv->xfi_pll_regmap)) ++ return PTR_ERR(priv->xfi_pll_regmap); ++ ++ /* get corresponding toprgu phandle */ ++ ret = dev_read_phandle_with_args(dev, "mediatek,toprgu", ++ NULL, 0, 0, &args); ++ if (ret) ++ return ret; ++ ++ priv->toprgu_regmap = syscon_node_to_regmap(args.node); ++ if (IS_ERR(priv->toprgu_regmap)) ++ return PTR_ERR(priv->toprgu_regmap); ++ } ++ ++ priv->swname = dev_read_string(dev, "mediatek,switch"); ++ if (priv->swname) { ++ priv->mcm = dev_read_bool(dev, "mediatek,mcm"); ++ if (priv->mcm) { ++ ret = reset_get_by_name(dev, "mcm", &priv->rst_mcm); ++ if (ret) { ++ printf("error: no reset ctrl for mcm\n"); ++ return ret; ++ } ++ } else { ++ gpio_request_by_name(dev, "reset-gpios", 0, ++ &priv->rst_gpio, GPIOD_IS_OUT); ++ } ++ } else { ++ ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, ++ 0, &args); ++ if (ret) { ++ printf("error: phy-handle is not specified\n"); ++ return ret; ++ } ++ ++ priv->phy_addr = ofnode_read_s32_default(args.node, "reg", -1); ++ if (priv->phy_addr < 0) { ++ printf("error: phy address is not specified\n"); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct mtk_soc_data mt7988_data = { ++ .caps = MT7988_CAPS, ++ .ana_rgc3 = 0x128, ++ .gdma_count = 3, ++ .pdma_base = PDMA_V3_BASE, ++ .txd_size = sizeof(struct mtk_tx_dma_v2), ++ .rxd_size = sizeof(struct mtk_rx_dma_v2), ++}; ++ ++static const struct mtk_soc_data mt7986_data = { ++ .caps = MT7986_CAPS, ++ .ana_rgc3 = 0x128, ++ .gdma_count = 2, ++ .pdma_base = PDMA_V2_BASE, ++ .txd_size = sizeof(struct mtk_tx_dma_v2), ++ .rxd_size = sizeof(struct mtk_rx_dma_v2), ++}; ++ ++static const struct mtk_soc_data mt7981_data = { ++ .caps = MT7981_CAPS, ++ .ana_rgc3 = 0x128, ++ .gdma_count = 2, ++ .pdma_base = PDMA_V2_BASE, ++ .txd_size = sizeof(struct mtk_tx_dma_v2), ++ .rxd_size = sizeof(struct mtk_rx_dma_v2), ++}; ++ ++static const struct mtk_soc_data mt7629_data = { ++ .caps = MT7629_CAPS, ++ .ana_rgc3 = 0x128, ++ .gdma_count = 2, ++ .pdma_base = PDMA_V1_BASE, ++ .txd_size = sizeof(struct mtk_tx_dma), ++ .rxd_size = sizeof(struct mtk_rx_dma), ++}; ++ ++static const struct mtk_soc_data mt7623_data = { ++ .caps = MT7623_CAPS, ++ .gdma_count = 2, ++ .pdma_base = PDMA_V1_BASE, ++ .txd_size = sizeof(struct mtk_tx_dma), ++ .rxd_size = sizeof(struct mtk_rx_dma), ++}; ++ ++static const struct mtk_soc_data mt7622_data = { ++ .caps = MT7622_CAPS, ++ .ana_rgc3 = 0x2028, ++ .gdma_count = 2, ++ .pdma_base = PDMA_V1_BASE, ++ .txd_size = sizeof(struct mtk_tx_dma), ++ .rxd_size = sizeof(struct mtk_rx_dma), ++}; ++ ++static const struct mtk_soc_data mt7621_data = { ++ .caps = MT7621_CAPS, ++ .gdma_count = 2, ++ .pdma_base = PDMA_V1_BASE, ++ .txd_size = sizeof(struct mtk_tx_dma), ++ .rxd_size = sizeof(struct mtk_rx_dma), ++}; ++ ++static const struct udevice_id mtk_eth_ids[] = { ++ { .compatible = "mediatek,mt7988-eth", .data = (ulong)&mt7988_data }, ++ { .compatible = "mediatek,mt7986-eth", .data = (ulong)&mt7986_data }, ++ { .compatible = "mediatek,mt7981-eth", .data = (ulong)&mt7981_data }, ++ { .compatible = "mediatek,mt7629-eth", .data = (ulong)&mt7629_data }, ++ { .compatible = "mediatek,mt7623-eth", .data = (ulong)&mt7623_data }, ++ { .compatible = "mediatek,mt7622-eth", .data = (ulong)&mt7622_data }, ++ { .compatible = "mediatek,mt7621-eth", .data = (ulong)&mt7621_data }, ++ {} ++}; ++ ++static const struct eth_ops mtk_eth_ops = { ++ .start = mtk_eth_start, ++ .stop = mtk_eth_stop, ++ .send = mtk_eth_send, ++ .recv = mtk_eth_recv, ++ .free_pkt = mtk_eth_free_pkt, ++ .write_hwaddr = mtk_eth_write_hwaddr, ++}; ++ ++U_BOOT_DRIVER(mtk_eth) = { ++ .name = "mtk-eth", ++ .id = UCLASS_ETH, ++ .of_match = mtk_eth_ids, ++ .of_to_plat = mtk_eth_of_to_plat, ++ .plat_auto = sizeof(struct eth_pdata), ++ .probe = mtk_eth_probe, ++ .remove = mtk_eth_remove, ++ .ops = &mtk_eth_ops, ++ .priv_auto = sizeof(struct mtk_eth_priv), ++ .flags = DM_FLAG_ALLOC_PRIV_DMA, ++}; +--- a/drivers/net/mtk_eth.h ++++ /dev/null +@@ -1,600 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-/* +- * Copyright (C) 2018 MediaTek Inc. +- * +- * Author: Weijie Gao +- * Author: Mark Lee +- */ +- +-#ifndef _MTK_ETH_H_ +-#define _MTK_ETH_H_ +- +-#include +-#include +- +-enum mkt_eth_capabilities { +- MTK_TRGMII_BIT, +- MTK_TRGMII_MT7621_CLK_BIT, +- MTK_U3_COPHY_V2_BIT, +- MTK_INFRA_BIT, +- MTK_NETSYS_V2_BIT, +- MTK_NETSYS_V3_BIT, +- +- /* PATH BITS */ +- MTK_ETH_PATH_GMAC1_TRGMII_BIT, +- MTK_ETH_PATH_GMAC2_SGMII_BIT, +- MTK_ETH_PATH_MT7622_SGMII_BIT, +- MTK_ETH_PATH_MT7629_GMAC2_BIT, +-}; +- +-#define MTK_TRGMII BIT(MTK_TRGMII_BIT) +-#define MTK_TRGMII_MT7621_CLK BIT(MTK_TRGMII_MT7621_CLK_BIT) +-#define MTK_U3_COPHY_V2 BIT(MTK_U3_COPHY_V2_BIT) +-#define MTK_INFRA BIT(MTK_INFRA_BIT) +-#define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT) +-#define MTK_NETSYS_V3 BIT(MTK_NETSYS_V3_BIT) +- +-/* Supported path present on SoCs */ +-#define MTK_ETH_PATH_GMAC1_TRGMII BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT) +- +-#define MTK_ETH_PATH_GMAC2_SGMII BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT) +-#define MTK_ETH_PATH_MT7622_SGMII BIT(MTK_ETH_PATH_MT7622_SGMII_BIT) +-#define MTK_ETH_PATH_MT7629_GMAC2 BIT(MTK_ETH_PATH_MT7629_GMAC2_BIT) +- +-#define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII) +- +-#define MTK_GMAC2_U3_QPHY (MTK_ETH_PATH_GMAC2_SGMII | MTK_U3_COPHY_V2 | MTK_INFRA) +- +-#define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x)) +- +-#define MT7621_CAPS (MTK_GMAC1_TRGMII | MTK_TRGMII_MT7621_CLK) +- +-#define MT7622_CAPS (MTK_ETH_PATH_MT7622_SGMII) +- +-#define MT7623_CAPS (MTK_GMAC1_TRGMII) +- +-#define MT7629_CAPS (MTK_ETH_PATH_MT7629_GMAC2 | MTK_INFRA) +- +-#define MT7981_CAPS (MTK_GMAC2_U3_QPHY | MTK_NETSYS_V2) +- +-#define MT7986_CAPS (MTK_NETSYS_V2) +- +-#define MT7988_CAPS (MTK_NETSYS_V3 | MTK_INFRA) +- +-/* Frame Engine Register Bases */ +-#define PDMA_V1_BASE 0x0800 +-#define PDMA_V2_BASE 0x6000 +-#define PDMA_V3_BASE 0x6800 +-#define GDMA1_BASE 0x0500 +-#define GDMA2_BASE 0x1500 +-#define GDMA3_BASE 0x0540 +-#define GMAC_BASE 0x10000 +-#define GSW_BASE 0x20000 +- +-/* Ethernet subsystem registers */ +- +-#define ETHSYS_SYSCFG1_REG 0x14 +-#define SYSCFG1_GE_MODE_S(n) (12 + ((n) * 2)) +-#define SYSCFG1_GE_MODE_M 0x3 +-#define SYSCFG1_SGMII_SEL_M GENMASK(9, 8) +-#define SYSCFG1_SGMII_SEL(gmac) BIT(9 - (gmac)) +- +-#define ETHSYS_CLKCFG0_REG 0x2c +-#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) +- +-/* Top misc registers */ +-#define TOPMISC_NETSYS_PCS_MUX 0x84 +-#define NETSYS_PCS_MUX_MASK GENMASK(1, 0) +-#define MUX_G2_USXGMII_SEL BIT(1) +-#define MUX_HSGMII1_G1_SEL BIT(0) +- +-#define USB_PHY_SWITCH_REG 0x218 +-#define QPHY_SEL_MASK 0x3 +-#define SGMII_QPHY_SEL 0x2 +- +-#define MT7629_INFRA_MISC2_REG 0x70c +-#define INFRA_MISC2_BONDING_OPTION GENMASK(15, 0) +- +-/* SYSCFG1_GE_MODE: GE Modes */ +-#define GE_MODE_RGMII 0 +-#define GE_MODE_MII 1 +-#define GE_MODE_MII_PHY 2 +-#define GE_MODE_RMII 3 +- +-/* SGMII subsystem config registers */ +-#define SGMSYS_PCS_CONTROL_1 0x0 +-#define SGMII_LINK_STATUS BIT(18) +-#define SGMII_AN_ENABLE BIT(12) +-#define SGMII_AN_RESTART BIT(9) +- +-#define SGMSYS_SGMII_MODE 0x20 +-#define SGMII_AN_MODE 0x31120103 +-#define SGMII_FORCE_MODE 0x31120019 +- +-#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 +-#define SGMII_PHYA_PWD BIT(4) +- +-#define SGMSYS_QPHY_WRAP_CTRL 0xec +-#define SGMII_PN_SWAP_TX_RX 0x03 +- +-#define SGMSYS_GEN2_SPEED 0x2028 +-#define SGMSYS_GEN2_SPEED_V2 0x128 +-#define SGMSYS_SPEED_MASK GENMASK(3, 2) +-#define SGMSYS_SPEED_2500 1 +- +-/* USXGMII subsystem config registers */ +-/* Register to control USXGMII XFI PLL digital */ +-#define XFI_PLL_DIG_GLB8 0x08 +-#define RG_XFI_PLL_EN BIT(31) +- +-/* Register to control USXGMII XFI PLL analog */ +-#define XFI_PLL_ANA_GLB8 0x108 +-#define RG_XFI_PLL_ANA_SWWA 0x02283248 +- +-/* Frame Engine Registers */ +-#define PSE_NO_DROP_CFG_REG 0x108 +-#define PSE_NO_DROP_GDM1 BIT(1) +- +-#define FE_GLO_MISC_REG 0x124 +-#define PDMA_VER_V2 BIT(4) +- +-/* PDMA */ +-#define TX_BASE_PTR_REG(n) (0x000 + (n) * 0x10) +-#define TX_MAX_CNT_REG(n) (0x004 + (n) * 0x10) +-#define TX_CTX_IDX_REG(n) (0x008 + (n) * 0x10) +-#define TX_DTX_IDX_REG(n) (0x00c + (n) * 0x10) +- +-#define RX_BASE_PTR_REG(n) (0x100 + (n) * 0x10) +-#define RX_MAX_CNT_REG(n) (0x104 + (n) * 0x10) +-#define RX_CRX_IDX_REG(n) (0x108 + (n) * 0x10) +-#define RX_DRX_IDX_REG(n) (0x10c + (n) * 0x10) +- +-#define PDMA_GLO_CFG_REG 0x204 +-#define TX_WB_DDONE BIT(6) +-#define RX_DMA_BUSY BIT(3) +-#define RX_DMA_EN BIT(2) +-#define TX_DMA_BUSY BIT(1) +-#define TX_DMA_EN BIT(0) +- +-#define PDMA_RST_IDX_REG 0x208 +-#define RST_DRX_IDX0 BIT(16) +-#define RST_DTX_IDX0 BIT(0) +- +-/* GDMA */ +-#define GDMA_IG_CTRL_REG 0x000 +-#define GDM_ICS_EN BIT(22) +-#define GDM_TCS_EN BIT(21) +-#define GDM_UCS_EN BIT(20) +-#define STRP_CRC BIT(16) +-#define MYMAC_DP_S 12 +-#define MYMAC_DP_M 0xf000 +-#define BC_DP_S 8 +-#define BC_DP_M 0xf00 +-#define MC_DP_S 4 +-#define MC_DP_M 0xf0 +-#define UN_DP_S 0 +-#define UN_DP_M 0x0f +- +-#define GDMA_EG_CTRL_REG 0x004 +-#define GDMA_CPU_BRIDGE_EN BIT(31) +- +-#define GDMA_MAC_LSB_REG 0x008 +- +-#define GDMA_MAC_MSB_REG 0x00c +- +-/* MYMAC_DP/BC_DP/MC_DP/UN_DP: Destination ports */ +-#define DP_PDMA 0 +-#define DP_GDMA1 1 +-#define DP_GDMA2 2 +-#define DP_PPE 4 +-#define DP_QDMA 5 +-#define DP_DISCARD 7 +- +-/* GMAC Registers */ +- +-#define GMAC_PPSC_REG 0x0000 +-#define PHY_MDC_CFG GENMASK(29, 24) +-#define MDC_TURBO BIT(20) +-#define MDC_MAX_FREQ 25000000 +-#define MDC_MAX_DIVIDER 63 +- +-#define GMAC_PIAC_REG 0x0004 +-#define PHY_ACS_ST BIT(31) +-#define MDIO_REG_ADDR_S 25 +-#define MDIO_REG_ADDR_M 0x3e000000 +-#define MDIO_PHY_ADDR_S 20 +-#define MDIO_PHY_ADDR_M 0x1f00000 +-#define MDIO_CMD_S 18 +-#define MDIO_CMD_M 0xc0000 +-#define MDIO_ST_S 16 +-#define MDIO_ST_M 0x30000 +-#define MDIO_RW_DATA_S 0 +-#define MDIO_RW_DATA_M 0xffff +- +-#define GMAC_XGMAC_STS_REG 0x000c +-#define P1_XGMAC_FORCE_LINK BIT(15) +- +-#define GMAC_MAC_MISC_REG 0x0010 +-#define MISC_MDC_TURBO BIT(4) +- +-#define GMAC_GSW_CFG_REG 0x0080 +-#define GSWTX_IPG_M 0xF0000 +-#define GSWTX_IPG_S 16 +-#define GSWRX_IPG_M 0xF +-#define GSWRX_IPG_S 0 +- +-/* MDIO_CMD: MDIO commands */ +-#define MDIO_CMD_ADDR 0 +-#define MDIO_CMD_WRITE 1 +-#define MDIO_CMD_READ 2 +-#define MDIO_CMD_READ_C45 3 +- +-/* MDIO_ST: MDIO start field */ +-#define MDIO_ST_C45 0 +-#define MDIO_ST_C22 1 +- +-#define GMAC_PORT_MCR(p) (0x0100 + (p) * 0x100) +-#define MAC_RX_PKT_LEN_S 24 +-#define MAC_RX_PKT_LEN_M 0x3000000 +-#define IPG_CFG_S 18 +-#define IPG_CFG_M 0xc0000 +-#define MAC_MODE BIT(16) +-#define FORCE_MODE BIT(15) +-#define MAC_TX_EN BIT(14) +-#define MAC_RX_EN BIT(13) +-#define DEL_RXFIFO_CLR BIT(12) +-#define BKOFF_EN BIT(9) +-#define BACKPR_EN BIT(8) +-#define FORCE_RX_FC BIT(5) +-#define FORCE_TX_FC BIT(4) +-#define FORCE_SPD_S 2 +-#define FORCE_SPD_M 0x0c +-#define FORCE_DPX BIT(1) +-#define FORCE_LINK BIT(0) +- +-/* Values of IPG_CFG */ +-#define IPG_96BIT 0 +-#define IPG_96BIT_WITH_SHORT_IPG 1 +-#define IPG_64BIT 2 +- +-/* MAC_RX_PKT_LEN: Max RX packet length */ +-#define MAC_RX_PKT_LEN_1518 0 +-#define MAC_RX_PKT_LEN_1536 1 +-#define MAC_RX_PKT_LEN_1552 2 +-#define MAC_RX_PKT_LEN_JUMBO 3 +- +-/* FORCE_SPD: Forced link speed */ +-#define SPEED_10M 0 +-#define SPEED_100M 1 +-#define SPEED_1000M 2 +- +-#define GMAC_TRGMII_RCK_CTRL 0x300 +-#define RX_RST BIT(31) +-#define RXC_DQSISEL BIT(30) +- +-#define GMAC_TRGMII_TD_ODT(n) (0x354 + (n) * 8) +-#define TD_DM_DRVN_S 4 +-#define TD_DM_DRVN_M 0xf0 +-#define TD_DM_DRVP_S 0 +-#define TD_DM_DRVP_M 0x0f +- +-/* XGMAC Status Registers */ +-#define XGMAC_STS(x) (((x) == 2) ? 0x001C : 0x000C) +-#define XGMAC_FORCE_LINK(x) (((x) == 1) ? BIT(31) : BIT(15)) +- +-/* XGMAC Registers */ +-#define XGMAC_PORT_MCR(x) (0x2000 + (((x) - 1) * 0x1000)) +-#define XGMAC_TRX_DISABLE 0xf +-#define XGMAC_FORCE_TX_FC BIT(5) +-#define XGMAC_FORCE_RX_FC BIT(4) +- +-/* MT7530 Registers */ +- +-#define PCR_REG(p) (0x2004 + (p) * 0x100) +-#define PORT_MATRIX_S 16 +-#define PORT_MATRIX_M 0xff0000 +- +-#define PVC_REG(p) (0x2010 + (p) * 0x100) +-#define STAG_VPID_S 16 +-#define STAG_VPID_M 0xffff0000 +-#define VLAN_ATTR_S 6 +-#define VLAN_ATTR_M 0xc0 +- +-/* VLAN_ATTR: VLAN attributes */ +-#define VLAN_ATTR_USER 0 +-#define VLAN_ATTR_STACK 1 +-#define VLAN_ATTR_TRANSLATION 2 +-#define VLAN_ATTR_TRANSPARENT 3 +- +-#define PMCR_REG(p) (0x3000 + (p) * 0x100) +-/* XXX: all fields of MT7530 are defined under GMAC_PORT_MCR +- * MT7531 specific fields are defined below +- */ +-#define FORCE_MODE_EEE1G BIT(25) +-#define FORCE_MODE_EEE100 BIT(26) +-#define FORCE_MODE_TX_FC BIT(27) +-#define FORCE_MODE_RX_FC BIT(28) +-#define FORCE_MODE_DPX BIT(29) +-#define FORCE_MODE_SPD BIT(30) +-#define FORCE_MODE_LNK BIT(31) +-#define MT7531_FORCE_MODE FORCE_MODE_EEE1G | FORCE_MODE_EEE100 |\ +- FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \ +- FORCE_MODE_DPX | FORCE_MODE_SPD | \ +- FORCE_MODE_LNK +-#define MT7988_FORCE_MODE FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \ +- FORCE_MODE_DPX | FORCE_MODE_SPD | \ +- FORCE_MODE_LNK +- +-/* MT7531 SGMII Registers */ +-#define MT7531_SGMII_REG_BASE 0x5000 +-#define MT7531_SGMII_REG_PORT_BASE 0x1000 +-#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \ +- (p) * MT7531_SGMII_REG_PORT_BASE + (r)) +-#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(((p) - 5), 0x00) +-#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(((p) - 5), 0x20) +-#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(((p) - 5), 0xe8) +-#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(((p) - 5), 0x128) +-/* XXX: all fields of MT7531 SGMII are defined under SGMSYS */ +- +-/* MT753x System Control Register */ +-#define SYS_CTRL_REG 0x7000 +-#define SW_PHY_RST BIT(2) +-#define SW_SYS_RST BIT(1) +-#define SW_REG_RST BIT(0) +- +-/* MT7531 */ +-#define MT7531_PHY_IAC 0x701c +-/* XXX: all fields are defined under GMAC_PIAC_REG */ +- +-#define MT7531_CLKGEN_CTRL 0x7500 +-#define CLK_SKEW_OUT_S 8 +-#define CLK_SKEW_OUT_M 0x300 +-#define CLK_SKEW_IN_S 6 +-#define CLK_SKEW_IN_M 0xc0 +-#define RXCLK_NO_DELAY BIT(5) +-#define TXCLK_NO_REVERSE BIT(4) +-#define GP_MODE_S 1 +-#define GP_MODE_M 0x06 +-#define GP_CLK_EN BIT(0) +- +-/* Values of GP_MODE */ +-#define GP_MODE_RGMII 0 +-#define GP_MODE_MII 1 +-#define GP_MODE_REV_MII 2 +- +-/* Values of CLK_SKEW_IN */ +-#define CLK_SKEW_IN_NO_CHANGE 0 +-#define CLK_SKEW_IN_DELAY_100PPS 1 +-#define CLK_SKEW_IN_DELAY_200PPS 2 +-#define CLK_SKEW_IN_REVERSE 3 +- +-/* Values of CLK_SKEW_OUT */ +-#define CLK_SKEW_OUT_NO_CHANGE 0 +-#define CLK_SKEW_OUT_DELAY_100PPS 1 +-#define CLK_SKEW_OUT_DELAY_200PPS 2 +-#define CLK_SKEW_OUT_REVERSE 3 +- +-#define HWTRAP_REG 0x7800 +-/* MT7530 Modified Hardware Trap Status Registers */ +-#define MHWTRAP_REG 0x7804 +-#define CHG_TRAP BIT(16) +-#define LOOPDET_DIS BIT(14) +-#define P5_INTF_SEL_S 13 +-#define P5_INTF_SEL_M 0x2000 +-#define SMI_ADDR_S 11 +-#define SMI_ADDR_M 0x1800 +-#define XTAL_FSEL_S 9 +-#define XTAL_FSEL_M 0x600 +-#define P6_INTF_DIS BIT(8) +-#define P5_INTF_MODE_S 7 +-#define P5_INTF_MODE_M 0x80 +-#define P5_INTF_DIS BIT(6) +-#define C_MDIO_BPS BIT(5) +-#define CHIP_MODE_S 0 +-#define CHIP_MODE_M 0x0f +- +-/* P5_INTF_SEL: Interface type of Port5 */ +-#define P5_INTF_SEL_GPHY 0 +-#define P5_INTF_SEL_GMAC5 1 +- +-/* P5_INTF_MODE: Interface mode of Port5 */ +-#define P5_INTF_MODE_GMII_MII 0 +-#define P5_INTF_MODE_RGMII 1 +- +-#define MT7530_P6ECR 0x7830 +-#define P6_INTF_MODE_M 0x3 +-#define P6_INTF_MODE_S 0 +- +-/* P6_INTF_MODE: Interface mode of Port6 */ +-#define P6_INTF_MODE_RGMII 0 +-#define P6_INTF_MODE_TRGMII 1 +- +-#define NUM_TRGMII_CTRL 5 +- +-#define MT7530_TRGMII_RD(n) (0x7a10 + (n) * 8) +-#define RD_TAP_S 0 +-#define RD_TAP_M 0x7f +- +-#define MT7530_TRGMII_TD_ODT(n) (0x7a54 + (n) * 8) +-/* XXX: all fields are defined under GMAC_TRGMII_TD_ODT */ +- +-/* TOP Signals Status Register */ +-#define MT7531_TOP_SIG_SR 0x780c +-#define PAD_MCM_SMI_EN BIT(0) +-#define PAD_DUAL_SGMII_EN BIT(1) +- +-/* MT7531 PLLGP Registers */ +-#define MT7531_PLLGP_EN 0x7820 +-#define EN_COREPLL BIT(2) +-#define SW_CLKSW BIT(1) +-#define SW_PLLGP BIT(0) +- +-#define MT7531_PLLGP_CR0 0x78a8 +-#define RG_COREPLL_EN BIT(22) +-#define RG_COREPLL_POSDIV_S 23 +-#define RG_COREPLL_POSDIV_M 0x3800000 +-#define RG_COREPLL_SDM_PCW_S 1 +-#define RG_COREPLL_SDM_PCW_M 0x3ffffe +-#define RG_COREPLL_SDM_PCW_CHG BIT(0) +- +-/* MT7531 RGMII and SGMII PLL clock */ +-#define MT7531_ANA_PLLGP_CR2 0x78b0 +-#define MT7531_ANA_PLLGP_CR5 0x78bc +- +-/* MT7531 GPIO GROUP IOLB SMT0 Control */ +-#define MT7531_SMT0_IOLB 0x7f04 +-#define SMT_IOLB_5_SMI_MDC_EN BIT(5) +- +-/* MT7530 GPHY MDIO Indirect Access Registers */ +-#define MII_MMD_ACC_CTL_REG 0x0d +-#define MMD_CMD_S 14 +-#define MMD_CMD_M 0xc000 +-#define MMD_DEVAD_S 0 +-#define MMD_DEVAD_M 0x1f +- +-/* MMD_CMD: MMD commands */ +-#define MMD_ADDR 0 +-#define MMD_DATA 1 +-#define MMD_DATA_RW_POST_INC 2 +-#define MMD_DATA_W_POST_INC 3 +- +-#define MII_MMD_ADDR_DATA_REG 0x0e +- +-/* MT7530 GPHY MDIO MMD Registers */ +-#define CORE_PLL_GROUP2 0x401 +-#define RG_SYSPLL_EN_NORMAL BIT(15) +-#define RG_SYSPLL_VODEN BIT(14) +-#define RG_SYSPLL_POSDIV_S 5 +-#define RG_SYSPLL_POSDIV_M 0x60 +- +-#define CORE_PLL_GROUP4 0x403 +-#define MT7531_BYPASS_MODE BIT(4) +-#define MT7531_POWER_ON_OFF BIT(5) +-#define RG_SYSPLL_DDSFBK_EN BIT(12) +-#define RG_SYSPLL_BIAS_EN BIT(11) +-#define RG_SYSPLL_BIAS_LPF_EN BIT(10) +- +-#define CORE_PLL_GROUP5 0x404 +-#define RG_LCDDS_PCW_NCPO1_S 0 +-#define RG_LCDDS_PCW_NCPO1_M 0xffff +- +-#define CORE_PLL_GROUP6 0x405 +-#define RG_LCDDS_PCW_NCPO0_S 0 +-#define RG_LCDDS_PCW_NCPO0_M 0xffff +- +-#define CORE_PLL_GROUP7 0x406 +-#define RG_LCDDS_PWDB BIT(15) +-#define RG_LCDDS_ISO_EN BIT(13) +-#define RG_LCCDS_C_S 4 +-#define RG_LCCDS_C_M 0x70 +-#define RG_LCDDS_PCW_NCPO_CHG BIT(3) +- +-#define CORE_PLL_GROUP10 0x409 +-#define RG_LCDDS_SSC_DELTA_S 0 +-#define RG_LCDDS_SSC_DELTA_M 0xfff +- +-#define CORE_PLL_GROUP11 0x40a +-#define RG_LCDDS_SSC_DELTA1_S 0 +-#define RG_LCDDS_SSC_DELTA1_M 0xfff +- +-#define CORE_GSWPLL_GRP1 0x40d +-#define RG_GSWPLL_POSDIV_200M_S 12 +-#define RG_GSWPLL_POSDIV_200M_M 0x3000 +-#define RG_GSWPLL_EN_PRE BIT(11) +-#define RG_GSWPLL_FBKDIV_200M_S 0 +-#define RG_GSWPLL_FBKDIV_200M_M 0xff +- +-#define CORE_GSWPLL_GRP2 0x40e +-#define RG_GSWPLL_POSDIV_500M_S 8 +-#define RG_GSWPLL_POSDIV_500M_M 0x300 +-#define RG_GSWPLL_FBKDIV_500M_S 0 +-#define RG_GSWPLL_FBKDIV_500M_M 0xff +- +-#define CORE_TRGMII_GSW_CLK_CG 0x410 +-#define REG_GSWCK_EN BIT(0) +-#define REG_TRGMIICK_EN BIT(1) +- +-/* Extend PHY Control Register 3 */ +-#define PHY_EXT_REG_14 0x14 +- +-/* Fields of PHY_EXT_REG_14 */ +-#define PHY_EN_DOWN_SHFIT BIT(4) +- +-/* Extend PHY Control Register 4 */ +-#define PHY_EXT_REG_17 0x17 +- +-/* Fields of PHY_EXT_REG_17 */ +-#define PHY_LINKDOWN_POWER_SAVING_EN BIT(4) +- +-/* PHY RXADC Control Register 7 */ +-#define PHY_DEV1E_REG_0C6 0x0c6 +- +-/* Fields of PHY_DEV1E_REG_0C6 */ +-#define PHY_POWER_SAVING_S 8 +-#define PHY_POWER_SAVING_M 0x300 +-#define PHY_POWER_SAVING_TX 0x0 +- +-/* PDMA descriptors */ +-struct mtk_rx_dma { +- unsigned int rxd1; +- unsigned int rxd2; +- unsigned int rxd3; +- unsigned int rxd4; +-} __packed __aligned(4); +- +-struct mtk_rx_dma_v2 { +- unsigned int rxd1; +- unsigned int rxd2; +- unsigned int rxd3; +- unsigned int rxd4; +- unsigned int rxd5; +- unsigned int rxd6; +- unsigned int rxd7; +- unsigned int rxd8; +-} __packed __aligned(4); +- +-struct mtk_tx_dma { +- unsigned int txd1; +- unsigned int txd2; +- unsigned int txd3; +- unsigned int txd4; +-} __packed __aligned(4); +- +-struct mtk_tx_dma_v2 { +- unsigned int txd1; +- unsigned int txd2; +- unsigned int txd3; +- unsigned int txd4; +- unsigned int txd5; +- unsigned int txd6; +- unsigned int txd7; +- unsigned int txd8; +-} __packed __aligned(4); +- +-/* PDMA TXD fields */ +-#define PDMA_TXD2_DDONE BIT(31) +-#define PDMA_TXD2_LS0 BIT(30) +-#define PDMA_V1_TXD2_SDL0_M GENMASK(29, 16) +-#define PDMA_V1_TXD2_SDL0_SET(_v) FIELD_PREP(PDMA_V1_TXD2_SDL0_M, (_v)) +-#define PDMA_V2_TXD2_SDL0_M GENMASK(23, 8) +-#define PDMA_V2_TXD2_SDL0_SET(_v) FIELD_PREP(PDMA_V2_TXD2_SDL0_M, (_v)) +- +-#define PDMA_V1_TXD4_FPORT_M GENMASK(27, 25) +-#define PDMA_V1_TXD4_FPORT_SET(_v) FIELD_PREP(PDMA_V1_TXD4_FPORT_M, (_v)) +-#define PDMA_V2_TXD4_FPORT_M GENMASK(27, 24) +-#define PDMA_V2_TXD4_FPORT_SET(_v) FIELD_PREP(PDMA_V2_TXD4_FPORT_M, (_v)) +- +-#define PDMA_V2_TXD5_FPORT_M GENMASK(19, 16) +-#define PDMA_V2_TXD5_FPORT_SET(_v) FIELD_PREP(PDMA_V2_TXD5_FPORT_M, (_v)) +- +-/* PDMA RXD fields */ +-#define PDMA_RXD2_DDONE BIT(31) +-#define PDMA_RXD2_LS0 BIT(30) +-#define PDMA_V1_RXD2_PLEN0_M GENMASK(29, 16) +-#define PDMA_V1_RXD2_PLEN0_GET(_v) FIELD_GET(PDMA_V1_RXD2_PLEN0_M, (_v)) +-#define PDMA_V1_RXD2_PLEN0_SET(_v) FIELD_PREP(PDMA_V1_RXD2_PLEN0_M, (_v)) +-#define PDMA_V2_RXD2_PLEN0_M GENMASK(23, 8) +-#define PDMA_V2_RXD2_PLEN0_GET(_v) FIELD_GET(PDMA_V2_RXD2_PLEN0_M, (_v)) +-#define PDMA_V2_RXD2_PLEN0_SET(_v) FIELD_PREP(PDMA_V2_RXD2_PLEN0_M, (_v)) +- +-#endif /* _MTK_ETH_H_ */ +--- /dev/null ++++ b/drivers/net/mtk_eth/mtk_eth.h +@@ -0,0 +1,429 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2025 MediaTek Inc. ++ * ++ * Author: Weijie Gao ++ * Author: Mark Lee ++ */ ++ ++#ifndef _MTK_ETH_H_ ++#define _MTK_ETH_H_ ++ ++#include ++#include ++#include ++ ++struct mtk_eth_priv; ++struct mtk_eth_switch_priv; ++ ++/* struct mtk_soc_data - This is the structure holding all differences ++ * among various plaforms ++ * @caps Flags shown the extra capability for the SoC ++ * @ana_rgc3: The offset for register ANA_RGC3 related to ++ * sgmiisys syscon ++ * @gdma_count: Number of GDMAs ++ * @pdma_base: Register base of PDMA block ++ * @txd_size: Tx DMA descriptor size. ++ * @rxd_size: Rx DMA descriptor size. ++ */ ++struct mtk_soc_data { ++ u32 caps; ++ u32 ana_rgc3; ++ u32 gdma_count; ++ u32 pdma_base; ++ u32 txd_size; ++ u32 rxd_size; ++}; ++ ++struct mtk_eth_switch { ++ const char *name; ++ const char *desc; ++ size_t priv_size; ++ u32 reset_wait_time; ++ ++ int (*detect)(struct mtk_eth_priv *priv); ++ int (*setup)(struct mtk_eth_switch_priv *priv); ++ int (*cleanup)(struct mtk_eth_switch_priv *priv); ++ void (*mac_control)(struct mtk_eth_switch_priv *priv, bool enable); ++}; ++ ++#define MTK_ETH_SWITCH(__name) \ ++ ll_entry_declare(struct mtk_eth_switch, __name, mtk_eth_switch) ++ ++struct mtk_eth_switch_priv { ++ struct mtk_eth_priv *eth; ++ const struct mtk_eth_switch *sw; ++ const struct mtk_soc_data *soc; ++ void *ethsys_base; ++ int phy_interface; ++}; ++ ++enum mkt_eth_capabilities { ++ MTK_TRGMII_BIT, ++ MTK_TRGMII_MT7621_CLK_BIT, ++ MTK_U3_COPHY_V2_BIT, ++ MTK_INFRA_BIT, ++ MTK_NETSYS_V2_BIT, ++ MTK_NETSYS_V3_BIT, ++ ++ /* PATH BITS */ ++ MTK_ETH_PATH_GMAC1_TRGMII_BIT, ++ MTK_ETH_PATH_GMAC2_SGMII_BIT, ++ MTK_ETH_PATH_MT7622_SGMII_BIT, ++ MTK_ETH_PATH_MT7629_GMAC2_BIT, ++}; ++ ++#define MTK_TRGMII BIT(MTK_TRGMII_BIT) ++#define MTK_TRGMII_MT7621_CLK BIT(MTK_TRGMII_MT7621_CLK_BIT) ++#define MTK_U3_COPHY_V2 BIT(MTK_U3_COPHY_V2_BIT) ++#define MTK_INFRA BIT(MTK_INFRA_BIT) ++#define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT) ++#define MTK_NETSYS_V3 BIT(MTK_NETSYS_V3_BIT) ++ ++/* Supported path present on SoCs */ ++#define MTK_ETH_PATH_GMAC1_TRGMII BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT) ++#define MTK_ETH_PATH_GMAC2_SGMII BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT) ++#define MTK_ETH_PATH_MT7622_SGMII BIT(MTK_ETH_PATH_MT7622_SGMII_BIT) ++#define MTK_ETH_PATH_MT7629_GMAC2 BIT(MTK_ETH_PATH_MT7629_GMAC2_BIT) ++ ++#define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII) ++ ++#define MTK_GMAC2_U3_QPHY (MTK_ETH_PATH_GMAC2_SGMII | MTK_U3_COPHY_V2 | MTK_INFRA) ++ ++#define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x)) ++ ++#define MT7621_CAPS (MTK_GMAC1_TRGMII | MTK_TRGMII_MT7621_CLK) ++ ++#define MT7622_CAPS (MTK_ETH_PATH_MT7622_SGMII) ++ ++#define MT7623_CAPS (MTK_GMAC1_TRGMII) ++ ++#define MT7629_CAPS (MTK_ETH_PATH_MT7629_GMAC2 | MTK_INFRA) ++ ++#define MT7981_CAPS (MTK_GMAC2_U3_QPHY | MTK_NETSYS_V2) ++ ++#define MT7986_CAPS (MTK_NETSYS_V2) ++ ++#define MT7987_CAPS (MTK_NETSYS_V3 | MTK_GMAC2_U3_QPHY | MTK_INFRA) ++ ++#define MT7988_CAPS (MTK_NETSYS_V3 | MTK_INFRA) ++ ++/* Frame Engine Register Bases */ ++#define PDMA_V1_BASE 0x0800 ++#define PDMA_V2_BASE 0x6000 ++#define PDMA_V3_BASE 0x6800 ++#define GDMA1_BASE 0x0500 ++#define GDMA2_BASE 0x1500 ++#define GDMA3_BASE 0x0540 ++#define GMAC_BASE 0x10000 ++#define GSW_BASE 0x20000 ++ ++/* Ethernet subsystem registers */ ++#define ETHSYS_SYSCFG1_REG 0x14 ++#define SYSCFG1_GE_MODE_S(n) (12 + ((n) * 2)) ++#define SYSCFG1_GE_MODE_M 0x3 ++#define SYSCFG1_SGMII_SEL_M GENMASK(9, 8) ++#define SYSCFG1_SGMII_SEL(gmac) BIT(9 - (gmac)) ++ ++#define ETHSYS_CLKCFG0_REG 0x2c ++#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) ++ ++/* Top misc registers */ ++#define TOPMISC_NETSYS_PCS_MUX 0x84 ++#define NETSYS_PCS_MUX_MASK GENMASK(1, 0) ++#define MUX_G2_USXGMII_SEL BIT(1) ++#define MUX_HSGMII1_G1_SEL BIT(0) ++ ++#define USB_PHY_SWITCH_REG 0x218 ++#define QPHY_SEL_MASK 0x3 ++#define SGMII_QPHY_SEL 0x2 ++ ++#define MT7629_INFRA_MISC2_REG 0x70c ++#define INFRA_MISC2_BONDING_OPTION GENMASK(15, 0) ++ ++/* SYSCFG1_GE_MODE: GE Modes */ ++#define GE_MODE_RGMII 0 ++#define GE_MODE_MII 1 ++#define GE_MODE_MII_PHY 2 ++#define GE_MODE_RMII 3 ++ ++/* SGMII subsystem config registers */ ++#define SGMSYS_PCS_CONTROL_1 0x0 ++#define SGMII_LINK_STATUS BIT(18) ++#define SGMII_AN_ENABLE BIT(12) ++#define SGMII_AN_RESTART BIT(9) ++ ++#define SGMSYS_SGMII_MODE 0x20 ++#define SGMII_AN_MODE 0x31120103 ++#define SGMII_FORCE_MODE 0x31120019 ++ ++#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 ++#define SGMII_PHYA_PWD BIT(4) ++ ++#define SGMSYS_QPHY_WRAP_CTRL 0xec ++#define SGMII_PN_SWAP_TX_RX 0x03 ++ ++#define SGMSYS_GEN2_SPEED 0x2028 ++#define SGMSYS_GEN2_SPEED_V2 0x128 ++#define SGMSYS_SPEED_MASK GENMASK(3, 2) ++#define SGMSYS_SPEED_2500 1 ++ ++/* USXGMII subsystem config registers */ ++/* Register to control USXGMII XFI PLL digital */ ++#define XFI_PLL_DIG_GLB8 0x08 ++#define RG_XFI_PLL_EN BIT(31) ++ ++/* Register to control USXGMII XFI PLL analog */ ++#define XFI_PLL_ANA_GLB8 0x108 ++#define RG_XFI_PLL_ANA_SWWA 0x02283248 ++ ++/* Frame Engine Registers */ ++#define PSE_NO_DROP_CFG_REG 0x108 ++#define PSE_NO_DROP_GDM1 BIT(1) ++ ++#define FE_GLO_MISC_REG 0x124 ++#define PDMA_VER_V2 BIT(4) ++ ++/* PDMA */ ++#define TX_BASE_PTR_REG(n) (0x000 + (n) * 0x10) ++#define TX_MAX_CNT_REG(n) (0x004 + (n) * 0x10) ++#define TX_CTX_IDX_REG(n) (0x008 + (n) * 0x10) ++#define TX_DTX_IDX_REG(n) (0x00c + (n) * 0x10) ++ ++#define RX_BASE_PTR_REG(n) (0x100 + (n) * 0x10) ++#define RX_MAX_CNT_REG(n) (0x104 + (n) * 0x10) ++#define RX_CRX_IDX_REG(n) (0x108 + (n) * 0x10) ++#define RX_DRX_IDX_REG(n) (0x10c + (n) * 0x10) ++ ++#define PDMA_GLO_CFG_REG 0x204 ++#define TX_WB_DDONE BIT(6) ++#define RX_DMA_BUSY BIT(3) ++#define RX_DMA_EN BIT(2) ++#define TX_DMA_BUSY BIT(1) ++#define TX_DMA_EN BIT(0) ++ ++#define PDMA_RST_IDX_REG 0x208 ++#define RST_DRX_IDX0 BIT(16) ++#define RST_DTX_IDX0 BIT(0) ++ ++/* GDMA */ ++#define GDMA_IG_CTRL_REG 0x000 ++#define GDM_ICS_EN BIT(22) ++#define GDM_TCS_EN BIT(21) ++#define GDM_UCS_EN BIT(20) ++#define STRP_CRC BIT(16) ++#define MYMAC_DP_S 12 ++#define MYMAC_DP_M 0xf000 ++#define BC_DP_S 8 ++#define BC_DP_M 0xf00 ++#define MC_DP_S 4 ++#define MC_DP_M 0xf0 ++#define UN_DP_S 0 ++#define UN_DP_M 0x0f ++ ++#define GDMA_EG_CTRL_REG 0x004 ++#define GDMA_CPU_BRIDGE_EN BIT(31) ++ ++#define GDMA_MAC_LSB_REG 0x008 ++ ++#define GDMA_MAC_MSB_REG 0x00c ++ ++/* MYMAC_DP/BC_DP/MC_DP/UN_DP: Destination ports */ ++#define DP_PDMA 0 ++#define DP_GDMA1 1 ++#define DP_GDMA2 2 ++#define DP_PPE 4 ++#define DP_QDMA 5 ++#define DP_DISCARD 7 ++ ++/* GMAC Registers */ ++#define GMAC_PPSC_REG 0x0000 ++#define PHY_MDC_CFG GENMASK(29, 24) ++#define MDC_TURBO BIT(20) ++#define MDC_MAX_FREQ 25000000 ++#define MDC_MAX_DIVIDER 63 ++ ++#define GMAC_PIAC_REG 0x0004 ++#define PHY_ACS_ST BIT(31) ++#define MDIO_REG_ADDR_S 25 ++#define MDIO_REG_ADDR_M 0x3e000000 ++#define MDIO_PHY_ADDR_S 20 ++#define MDIO_PHY_ADDR_M 0x1f00000 ++#define MDIO_CMD_S 18 ++#define MDIO_CMD_M 0xc0000 ++#define MDIO_ST_S 16 ++#define MDIO_ST_M 0x30000 ++#define MDIO_RW_DATA_S 0 ++#define MDIO_RW_DATA_M 0xffff ++ ++#define GMAC_XGMAC_STS_REG 0x000c ++#define P1_XGMAC_FORCE_LINK BIT(15) ++ ++#define GMAC_MAC_MISC_REG 0x0010 ++#define MISC_MDC_TURBO BIT(4) ++ ++#define GMAC_GSW_CFG_REG 0x0080 ++#define GSWTX_IPG_M 0xF0000 ++#define GSWTX_IPG_S 16 ++#define GSWRX_IPG_M 0xF ++#define GSWRX_IPG_S 0 ++ ++/* MDIO_CMD: MDIO commands */ ++#define MDIO_CMD_ADDR 0 ++#define MDIO_CMD_WRITE 1 ++#define MDIO_CMD_READ 2 ++#define MDIO_CMD_READ_C45 3 ++ ++/* MDIO_ST: MDIO start field */ ++#define MDIO_ST_C45 0 ++#define MDIO_ST_C22 1 ++ ++#define GMAC_PORT_MCR(p) (0x0100 + (p) * 0x100) ++#define MAC_RX_PKT_LEN_S 24 ++#define MAC_RX_PKT_LEN_M 0x3000000 ++#define IPG_CFG_S 18 ++#define IPG_CFG_M 0xc0000 ++#define MAC_MODE BIT(16) ++#define FORCE_MODE BIT(15) ++#define MAC_TX_EN BIT(14) ++#define MAC_RX_EN BIT(13) ++#define DEL_RXFIFO_CLR BIT(12) ++#define BKOFF_EN BIT(9) ++#define BACKPR_EN BIT(8) ++#define FORCE_RX_FC BIT(5) ++#define FORCE_TX_FC BIT(4) ++#define FORCE_SPD_S 2 ++#define FORCE_SPD_M 0x0c ++#define FORCE_DPX BIT(1) ++#define FORCE_LINK BIT(0) ++ ++/* Values of IPG_CFG */ ++#define IPG_96BIT 0 ++#define IPG_96BIT_WITH_SHORT_IPG 1 ++#define IPG_64BIT 2 ++ ++/* MAC_RX_PKT_LEN: Max RX packet length */ ++#define MAC_RX_PKT_LEN_1518 0 ++#define MAC_RX_PKT_LEN_1536 1 ++#define MAC_RX_PKT_LEN_1552 2 ++#define MAC_RX_PKT_LEN_JUMBO 3 ++ ++/* FORCE_SPD: Forced link speed */ ++#define SPEED_10M 0 ++#define SPEED_100M 1 ++#define SPEED_1000M 2 ++ ++#define GMAC_TRGMII_RCK_CTRL 0x300 ++#define RX_RST BIT(31) ++#define RXC_DQSISEL BIT(30) ++ ++#define NUM_TRGMII_CTRL 5 ++ ++#define GMAC_TRGMII_TD_ODT(n) (0x354 + (n) * 8) ++#define TD_DM_DRVN_S 4 ++#define TD_DM_DRVN_M 0xf0 ++#define TD_DM_DRVP_S 0 ++#define TD_DM_DRVP_M 0x0f ++ ++/* XGMAC Status Registers */ ++#define XGMAC_STS(x) (((x) == 2) ? 0x001C : 0x000C) ++#define XGMAC_FORCE_LINK(x) (((x) == 1) ? BIT(31) : BIT(15)) ++ ++/* XGMAC Registers */ ++#define XGMAC_PORT_MCR(x) (0x2000 + (((x) - 1) * 0x1000)) ++#define XGMAC_TRX_DISABLE 0xf ++#define XGMAC_FORCE_TX_FC BIT(5) ++#define XGMAC_FORCE_RX_FC BIT(4) ++ ++/* MDIO Indirect Access Registers */ ++#define MII_MMD_ACC_CTL_REG 0x0d ++#define MMD_CMD_S 14 ++#define MMD_CMD_M 0xc000 ++#define MMD_DEVAD_S 0 ++#define MMD_DEVAD_M 0x1f ++ ++/* MMD_CMD: MMD commands */ ++#define MMD_ADDR 0 ++#define MMD_DATA 1 ++#define MMD_DATA_RW_POST_INC 2 ++#define MMD_DATA_W_POST_INC 3 ++ ++#define MII_MMD_ADDR_DATA_REG 0x0e ++ ++/* PDMA descriptors */ ++struct mtk_rx_dma { ++ unsigned int rxd1; ++ unsigned int rxd2; ++ unsigned int rxd3; ++ unsigned int rxd4; ++} __packed __aligned(4); ++ ++struct mtk_rx_dma_v2 { ++ unsigned int rxd1; ++ unsigned int rxd2; ++ unsigned int rxd3; ++ unsigned int rxd4; ++ unsigned int rxd5; ++ unsigned int rxd6; ++ unsigned int rxd7; ++ unsigned int rxd8; ++} __packed __aligned(4); ++ ++struct mtk_tx_dma { ++ unsigned int txd1; ++ unsigned int txd2; ++ unsigned int txd3; ++ unsigned int txd4; ++} __packed __aligned(4); ++ ++struct mtk_tx_dma_v2 { ++ unsigned int txd1; ++ unsigned int txd2; ++ unsigned int txd3; ++ unsigned int txd4; ++ unsigned int txd5; ++ unsigned int txd6; ++ unsigned int txd7; ++ unsigned int txd8; ++} __packed __aligned(4); ++ ++/* PDMA TXD fields */ ++#define PDMA_TXD2_DDONE BIT(31) ++#define PDMA_TXD2_LS0 BIT(30) ++#define PDMA_V1_TXD2_SDL0_M GENMASK(29, 16) ++#define PDMA_V1_TXD2_SDL0_SET(_v) FIELD_PREP(PDMA_V1_TXD2_SDL0_M, (_v)) ++#define PDMA_V2_TXD2_SDL0_M GENMASK(23, 8) ++#define PDMA_V2_TXD2_SDL0_SET(_v) FIELD_PREP(PDMA_V2_TXD2_SDL0_M, (_v)) ++ ++#define PDMA_V1_TXD4_FPORT_M GENMASK(27, 25) ++#define PDMA_V1_TXD4_FPORT_SET(_v) FIELD_PREP(PDMA_V1_TXD4_FPORT_M, (_v)) ++#define PDMA_V2_TXD4_FPORT_M GENMASK(27, 24) ++#define PDMA_V2_TXD4_FPORT_SET(_v) FIELD_PREP(PDMA_V2_TXD4_FPORT_M, (_v)) ++ ++#define PDMA_V2_TXD5_FPORT_M GENMASK(19, 16) ++#define PDMA_V2_TXD5_FPORT_SET(_v) FIELD_PREP(PDMA_V2_TXD5_FPORT_M, (_v)) ++ ++/* PDMA RXD fields */ ++#define PDMA_RXD2_DDONE BIT(31) ++#define PDMA_RXD2_LS0 BIT(30) ++#define PDMA_V1_RXD2_PLEN0_M GENMASK(29, 16) ++#define PDMA_V1_RXD2_PLEN0_GET(_v) FIELD_GET(PDMA_V1_RXD2_PLEN0_M, (_v)) ++#define PDMA_V1_RXD2_PLEN0_SET(_v) FIELD_PREP(PDMA_V1_RXD2_PLEN0_M, (_v)) ++#define PDMA_V2_RXD2_PLEN0_M GENMASK(23, 8) ++#define PDMA_V2_RXD2_PLEN0_GET(_v) FIELD_GET(PDMA_V2_RXD2_PLEN0_M, (_v)) ++#define PDMA_V2_RXD2_PLEN0_SET(_v) FIELD_PREP(PDMA_V2_RXD2_PLEN0_M, (_v)) ++ ++void mtk_fe_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set); ++void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set); ++void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set); ++ ++int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg); ++int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data); ++int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg); ++int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg, ++ u16 val); ++int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg); ++int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg, ++ u16 val); ++ ++#endif /* _MTK_ETH_H_ */ diff --git a/package/boot/uboot-mediatek/patches/061-02-net-mediatek-add-support-for-MediaTek-MT7987-SoC.patch b/package/boot/uboot-mediatek/patches/061-02-net-mediatek-add-support-for-MediaTek-MT7987-SoC.patch new file mode 100644 index 00000000000..183c7129ab2 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/061-02-net-mediatek-add-support-for-MediaTek-MT7987-SoC.patch @@ -0,0 +1,63 @@ +From fe106f2093733b8bd61946372945dfea552b4755 Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Fri, 10 Jan 2025 16:41:20 +0800 +Subject: [PATCH 2/3] net: mediatek: add support for MediaTek MT7987 SoC + +This patch adds support for MediaTek MT7987. + +MT7987 features MediaTek NETSYS v3, similar to MT7988, features three GMACs +which support 2.5Gb HSGMII. One 2.5Gb PHY is also embedded an can be +connected to a dedicated GMAC. + +Signed-off-by: Weijie Gao +--- + drivers/net/mtk_eth/Kconfig | 4 ++-- + drivers/net/mtk_eth/mtk_eth.c | 10 ++++++++++ + 2 files changed, 12 insertions(+), 2 deletions(-) + +--- a/drivers/net/mtk_eth/Kconfig ++++ b/drivers/net/mtk_eth/Kconfig +@@ -16,7 +16,7 @@ config MTK_ETH_SGMII + + config MTK_ETH_XGMII + bool +- default y if TARGET_MT7988 ++ default y if TARGET_MT7987 || TARGET_MT7988 + + config MTK_ETH_SWITCH_MT7530 + bool "Support for MediaTek MT7530 ethernet switch" +@@ -25,7 +25,7 @@ config MTK_ETH_SWITCH_MT7530 + config MTK_ETH_SWITCH_MT7531 + bool "Support for MediaTek MT7531 ethernet switch" + default y if TARGET_MT7622 || TARGET_MT7629 || TARGET_MT7981 || \ +- TARGET_MT7986 ++ TARGET_MT7986 || TARGET_MT7987 + + config MTK_ETH_SWITCH_MT7988 + bool "Support for MediaTek MT7988 built-in ethernet switch" +--- a/drivers/net/mtk_eth/mtk_eth.c ++++ b/drivers/net/mtk_eth/mtk_eth.c +@@ -1477,6 +1477,15 @@ static const struct mtk_soc_data mt7988_ + .rxd_size = sizeof(struct mtk_rx_dma_v2), + }; + ++static const struct mtk_soc_data mt7987_data = { ++ .caps = MT7987_CAPS, ++ .ana_rgc3 = 0x128, ++ .gdma_count = 3, ++ .pdma_base = PDMA_V3_BASE, ++ .txd_size = sizeof(struct mtk_tx_dma_v2), ++ .rxd_size = sizeof(struct mtk_rx_dma_v2), ++}; ++ + static const struct mtk_soc_data mt7986_data = { + .caps = MT7986_CAPS, + .ana_rgc3 = 0x128, +@@ -1531,6 +1540,7 @@ static const struct mtk_soc_data mt7621_ + + static const struct udevice_id mtk_eth_ids[] = { + { .compatible = "mediatek,mt7988-eth", .data = (ulong)&mt7988_data }, ++ { .compatible = "mediatek,mt7987-eth", .data = (ulong)&mt7987_data }, + { .compatible = "mediatek,mt7986-eth", .data = (ulong)&mt7986_data }, + { .compatible = "mediatek,mt7981-eth", .data = (ulong)&mt7981_data }, + { .compatible = "mediatek,mt7629-eth", .data = (ulong)&mt7629_data }, diff --git a/package/boot/uboot-mediatek/patches/061-03-net-mediatek-add-support-for-Airoha-AN8855-ethernet-.patch b/package/boot/uboot-mediatek/patches/061-03-net-mediatek-add-support-for-Airoha-AN8855-ethernet-.patch new file mode 100644 index 00000000000..8e4f4391b10 --- /dev/null +++ b/package/boot/uboot-mediatek/patches/061-03-net-mediatek-add-support-for-Airoha-AN8855-ethernet-.patch @@ -0,0 +1,1133 @@ +From cedafee9ff39d13aaf8b80361b673445a85f117e Mon Sep 17 00:00:00 2001 +From: Weijie Gao +Date: Fri, 10 Jan 2025 16:41:24 +0800 +Subject: [PATCH 3/3] net: mediatek: add support for Airoha AN8855 ethernet + switch + +Airoha AN8855 is a 5-port gigabit switch with a 2.5G HSGMII CPU port + +Signed-off-by: Weijie Gao +--- + drivers/net/mtk_eth/Kconfig | 4 + + drivers/net/mtk_eth/Makefile | 1 + + drivers/net/mtk_eth/an8855.c | 1096 ++++++++++++++++++++++++++++++++++ + 3 files changed, 1101 insertions(+) + create mode 100644 drivers/net/mtk_eth/an8855.c + +--- a/drivers/net/mtk_eth/Kconfig ++++ b/drivers/net/mtk_eth/Kconfig +@@ -32,4 +32,8 @@ config MTK_ETH_SWITCH_MT7988 + depends on TARGET_MT7988 + default y + ++config MTK_ETH_SWITCH_AN8855 ++ bool "Support for Airoha AN8855 ethernet switch" ++ default y if TARGET_MT7981 || TARGET_MT7987 ++ + endif # MEDIATEK_ETH +--- a/drivers/net/mtk_eth/Makefile ++++ b/drivers/net/mtk_eth/Makefile +@@ -7,3 +7,4 @@ obj-y += mtk_eth.o + obj-$(CONFIG_MTK_ETH_SWITCH_MT7530) += mt753x.o mt7530.o + obj-$(CONFIG_MTK_ETH_SWITCH_MT7531) += mt753x.o mt7531.o + obj-$(CONFIG_MTK_ETH_SWITCH_MT7988) += mt753x.o mt7988.o ++obj-$(CONFIG_MTK_ETH_SWITCH_AN8855) += an8855.o +--- /dev/null ++++ b/drivers/net/mtk_eth/an8855.c +@@ -0,0 +1,1096 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2025 MediaTek Inc. ++ * ++ * Author: Neal Yen ++ * Author: Weijie Gao ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mtk_eth.h" ++ ++/* AN8855 Register Definitions */ ++#define AN8855_SYS_CTRL_REG 0x100050c0 ++#define AN8855_SW_SYS_RST BIT(31) ++ ++#define AN8855_PMCR_REG(p) (0x10210000 + (p) * 0x200) ++#define AN8855_FORCE_MODE_LNK BIT(31) ++#define AN8855_FORCE_MODE 0xb31593f0 ++ ++#define AN8855_PORT_CTRL_BASE (0x10208000) ++#define AN8855_PORT_CTRL_REG(p, r) (AN8855_PORT_CTRL_BASE + (p) * 0x200 + (r)) ++ ++#define AN8855_PORTMATRIX_REG(p) AN8855_PORT_CTRL_REG(p, 0x44) ++ ++#define AN8855_PVC(p) AN8855_PORT_CTRL_REG(p, 0x10) ++#define AN8855_STAG_VPID_S 16 ++#define AN8855_STAG_VPID_M 0xffff0000 ++#define AN8855_VLAN_ATTR_S 6 ++#define AN8855_VLAN_ATTR_M 0xc0 ++ ++#define VLAN_ATTR_USER 0 ++ ++#define AN8855_INT_MASK 0x100050F0 ++#define AN8855_INT_SYS_BIT BIT(15) ++ ++#define AN8855_RG_CLK_CPU_ICG 0x10005034 ++#define AN8855_MCU_ENABLE BIT(3) ++ ++#define AN8855_RG_TIMER_CTL 0x1000a100 ++#define AN8855_WDOG_ENABLE BIT(25) ++ ++#define AN8855_CKGCR 0x10213e1c ++ ++#define AN8855_SCU_BASE 0x10000000 ++#define AN8855_RG_RGMII_TXCK_C (AN8855_SCU_BASE + 0x1d0) ++#define AN8855_RG_GPIO_LED_MODE (AN8855_SCU_BASE + 0x0054) ++#define AN8855_RG_GPIO_LED_SEL(i) (AN8855_SCU_BASE + (0x0058 + ((i) * 4))) ++#define AN8855_RG_INTB_MODE (AN8855_SCU_BASE + 0x0080) ++#define AN8855_RG_GDMP_RAM (AN8855_SCU_BASE + 0x10000) ++#define AN8855_RG_GPIO_L_INV (AN8855_SCU_BASE + 0x0010) ++#define AN8855_RG_GPIO_CTRL (AN8855_SCU_BASE + 0xa300) ++#define AN8855_RG_GPIO_DATA (AN8855_SCU_BASE + 0xa304) ++#define AN8855_RG_GPIO_OE (AN8855_SCU_BASE + 0xa314) ++ ++#define AN8855_HSGMII_AN_CSR_BASE 0x10220000 ++#define AN8855_SGMII_REG_AN0 (AN8855_HSGMII_AN_CSR_BASE + 0x000) ++#define AN8855_SGMII_REG_AN_13 (AN8855_HSGMII_AN_CSR_BASE + 0x034) ++#define AN8855_SGMII_REG_AN_FORCE_CL37 (AN8855_HSGMII_AN_CSR_BASE + 0x060) ++ ++#define AN8855_HSGMII_CSR_PCS_BASE 0x10220000 ++#define AN8855_RG_HSGMII_PCS_CTROL_1 (AN8855_HSGMII_CSR_PCS_BASE + 0xa00) ++#define AN8855_RG_AN_SGMII_MODE_FORCE (AN8855_HSGMII_CSR_PCS_BASE + 0xa24) ++ ++#define AN8855_MULTI_SGMII_CSR_BASE 0x10224000 ++#define AN8855_SGMII_STS_CTRL_0 (AN8855_MULTI_SGMII_CSR_BASE + 0x018) ++#define AN8855_MSG_RX_CTRL_0 (AN8855_MULTI_SGMII_CSR_BASE + 0x100) ++#define AN8855_MSG_RX_LIK_STS_0 (AN8855_MULTI_SGMII_CSR_BASE + 0x514) ++#define AN8855_MSG_RX_LIK_STS_2 (AN8855_MULTI_SGMII_CSR_BASE + 0x51c) ++#define AN8855_PHY_RX_FORCE_CTRL_0 (AN8855_MULTI_SGMII_CSR_BASE + 0x520) ++ ++#define AN8855_XFI_CSR_PCS_BASE 0x10225000 ++#define AN8855_RG_USXGMII_AN_CONTROL_0 (AN8855_XFI_CSR_PCS_BASE + 0xbf8) ++ ++#define AN8855_MULTI_PHY_RA_CSR_BASE 0x10226000 ++#define AN8855_RG_RATE_ADAPT_CTRL_0 (AN8855_MULTI_PHY_RA_CSR_BASE + 0x000) ++#define AN8855_RATE_ADP_P0_CTRL_0 (AN8855_MULTI_PHY_RA_CSR_BASE + 0x100) ++#define AN8855_MII_RA_AN_ENABLE (AN8855_MULTI_PHY_RA_CSR_BASE + 0x300) ++ ++#define AN8855_QP_DIG_CSR_BASE 0x1022a000 ++#define AN8855_QP_CK_RST_CTRL_4 (AN8855_QP_DIG_CSR_BASE + 0x310) ++#define AN8855_QP_DIG_MODE_CTRL_0 (AN8855_QP_DIG_CSR_BASE + 0x324) ++#define AN8855_QP_DIG_MODE_CTRL_1 (AN8855_QP_DIG_CSR_BASE + 0x330) ++ ++#define AN8855_QP_PMA_TOP_BASE 0x1022e000 ++#define AN8855_PON_RXFEDIG_CTRL_0 (AN8855_QP_PMA_TOP_BASE + 0x100) ++#define AN8855_PON_RXFEDIG_CTRL_9 (AN8855_QP_PMA_TOP_BASE + 0x124) ++ ++#define AN8855_SS_LCPLL_PWCTL_SETTING_2 (AN8855_QP_PMA_TOP_BASE + 0x208) ++#define AN8855_SS_LCPLL_TDC_FLT_2 (AN8855_QP_PMA_TOP_BASE + 0x230) ++#define AN8855_SS_LCPLL_TDC_FLT_5 (AN8855_QP_PMA_TOP_BASE + 0x23c) ++#define AN8855_SS_LCPLL_TDC_PCW_1 (AN8855_QP_PMA_TOP_BASE + 0x248) ++#define AN8855_INTF_CTRL_8 (AN8855_QP_PMA_TOP_BASE + 0x320) ++#define AN8855_INTF_CTRL_9 (AN8855_QP_PMA_TOP_BASE + 0x324) ++#define AN8855_PLL_CTRL_0 (AN8855_QP_PMA_TOP_BASE + 0x400) ++#define AN8855_PLL_CTRL_2 (AN8855_QP_PMA_TOP_BASE + 0x408) ++#define AN8855_PLL_CTRL_3 (AN8855_QP_PMA_TOP_BASE + 0x40c) ++#define AN8855_PLL_CTRL_4 (AN8855_QP_PMA_TOP_BASE + 0x410) ++#define AN8855_PLL_CK_CTRL_0 (AN8855_QP_PMA_TOP_BASE + 0x414) ++#define AN8855_RX_DLY_0 (AN8855_QP_PMA_TOP_BASE + 0x614) ++#define AN8855_RX_CTRL_2 (AN8855_QP_PMA_TOP_BASE + 0x630) ++#define AN8855_RX_CTRL_5 (AN8855_QP_PMA_TOP_BASE + 0x63c) ++#define AN8855_RX_CTRL_6 (AN8855_QP_PMA_TOP_BASE + 0x640) ++#define AN8855_RX_CTRL_7 (AN8855_QP_PMA_TOP_BASE + 0x644) ++#define AN8855_RX_CTRL_8 (AN8855_QP_PMA_TOP_BASE + 0x648) ++#define AN8855_RX_CTRL_26 (AN8855_QP_PMA_TOP_BASE + 0x690) ++#define AN8855_RX_CTRL_42 (AN8855_QP_PMA_TOP_BASE + 0x6d0) ++ ++#define AN8855_QP_ANA_CSR_BASE 0x1022f000 ++#define AN8855_RG_QP_RX_DAC_EN (AN8855_QP_ANA_CSR_BASE + 0x00) ++#define AN8855_RG_QP_RXAFE_RESERVE (AN8855_QP_ANA_CSR_BASE + 0x04) ++#define AN8855_RG_QP_CDR_LPF_MJV_LIM (AN8855_QP_ANA_CSR_BASE + 0x0c) ++#define AN8855_RG_QP_CDR_LPF_SETVALUE (AN8855_QP_ANA_CSR_BASE + 0x14) ++#define AN8855_RG_QP_CDR_PR_CKREF_DIV1 (AN8855_QP_ANA_CSR_BASE + 0x18) ++#define AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE (AN8855_QP_ANA_CSR_BASE + 0x1c) ++#define AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF (AN8855_QP_ANA_CSR_BASE + 0x20) ++#define AN8855_RG_QP_TX_MODE_16B_EN (AN8855_QP_ANA_CSR_BASE + 0x28) ++#define AN8855_RG_QP_PLL_IPLL_DIG_PWR_SEL (AN8855_QP_ANA_CSR_BASE + 0x3c) ++#define AN8855_RG_QP_PLL_SDM_ORD (AN8855_QP_ANA_CSR_BASE + 0x40) ++ ++#define AN8855_ETHER_SYS_BASE 0x1028c800 ++#define RG_GPHY_AFE_PWD (AN8855_ETHER_SYS_BASE + 0x40) ++ ++#define AN8855_PKG_SEL 0x10000094 ++#define PAG_SEL_AN8855H 0x2 ++ ++/* PHY LED Register bitmap of define */ ++#define PHY_LED_CTRL_SELECT 0x3e8 ++#define PHY_SINGLE_LED_ON_CTRL(i) (0x3e0 + ((i) * 2)) ++#define PHY_SINGLE_LED_BLK_CTRL(i) (0x3e1 + ((i) * 2)) ++#define PHY_SINGLE_LED_ON_DUR(i) (0x3e9 + ((i) * 2)) ++#define PHY_SINGLE_LED_BLK_DUR(i) (0x3ea + ((i) * 2)) ++ ++#define PHY_PMA_CTRL (0x340) ++ ++#define PHY_DEV1F 0x1f ++ ++#define PHY_LED_ON_CTRL(i) (0x24 + ((i) * 2)) ++#define LED_ON_EN (1 << 15) ++#define LED_ON_POL (1 << 14) ++#define LED_ON_EVT_MASK (0x7f) ++ ++/* LED ON Event */ ++#define LED_ON_EVT_FORCE (1 << 6) ++#define LED_ON_EVT_LINK_HD (1 << 5) ++#define LED_ON_EVT_LINK_FD (1 << 4) ++#define LED_ON_EVT_LINK_DOWN (1 << 3) ++#define LED_ON_EVT_LINK_10M (1 << 2) ++#define LED_ON_EVT_LINK_100M (1 << 1) ++#define LED_ON_EVT_LINK_1000M (1 << 0) ++ ++#define PHY_LED_BLK_CTRL(i) (0x25 + ((i) * 2)) ++#define LED_BLK_EVT_MASK (0x3ff) ++/* LED Blinking Event */ ++#define LED_BLK_EVT_FORCE (1 << 9) ++#define LED_BLK_EVT_10M_RX_ACT (1 << 5) ++#define LED_BLK_EVT_10M_TX_ACT (1 << 4) ++#define LED_BLK_EVT_100M_RX_ACT (1 << 3) ++#define LED_BLK_EVT_100M_TX_ACT (1 << 2) ++#define LED_BLK_EVT_1000M_RX_ACT (1 << 1) ++#define LED_BLK_EVT_1000M_TX_ACT (1 << 0) ++ ++#define PHY_LED_BCR (0x21) ++#define LED_BCR_EXT_CTRL (1 << 15) ++#define LED_BCR_CLK_EN (1 << 3) ++#define LED_BCR_TIME_TEST (1 << 2) ++#define LED_BCR_MODE_MASK (3) ++#define LED_BCR_MODE_DISABLE (0) ++ ++#define PHY_LED_ON_DUR (0x22) ++#define LED_ON_DUR_MASK (0xffff) ++ ++#define PHY_LED_BLK_DUR (0x23) ++#define LED_BLK_DUR_MASK (0xffff) ++ ++#define PHY_LED_BLINK_DUR_CTRL (0x720) ++ ++/* Definition of LED */ ++#define LED_ON_EVENT (LED_ON_EVT_LINK_1000M | \ ++ LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M |\ ++ LED_ON_EVT_LINK_HD | LED_ON_EVT_LINK_FD) ++ ++#define LED_BLK_EVENT (LED_BLK_EVT_1000M_TX_ACT | \ ++ LED_BLK_EVT_1000M_RX_ACT | \ ++ LED_BLK_EVT_100M_TX_ACT | \ ++ LED_BLK_EVT_100M_RX_ACT | \ ++ LED_BLK_EVT_10M_TX_ACT | \ ++ LED_BLK_EVT_10M_RX_ACT) ++ ++#define LED_FREQ AIR_LED_BLK_DUR_64M ++ ++#define AN8855_NUM_PHYS 5 ++#define AN8855_NUM_PORTS 6 ++#define AN8855_PHY_ADDR(base, addr) (((base) + (addr)) & 0x1f) ++ ++/* PHY LED Register bitmap of define */ ++#define PHY_LED_CTRL_SELECT 0x3e8 ++#define PHY_SINGLE_LED_ON_CTRL(i) (0x3e0 + ((i) * 2)) ++#define PHY_SINGLE_LED_BLK_CTRL(i) (0x3e1 + ((i) * 2)) ++#define PHY_SINGLE_LED_ON_DUR(i) (0x3e9 + ((i) * 2)) ++#define PHY_SINGLE_LED_BLK_DUR(i) (0x3ea + ((i) * 2)) ++ ++/* AN8855 LED */ ++enum an8855_led_blk_dur { ++ AIR_LED_BLK_DUR_32M, ++ AIR_LED_BLK_DUR_64M, ++ AIR_LED_BLK_DUR_128M, ++ AIR_LED_BLK_DUR_256M, ++ AIR_LED_BLK_DUR_512M, ++ AIR_LED_BLK_DUR_1024M, ++ AIR_LED_BLK_DUR_LAST ++}; ++ ++enum an8855_led_polarity { ++ LED_LOW, ++ LED_HIGH, ++}; ++ ++enum an8855_led_mode { ++ AN8855_LED_MODE_DISABLE, ++ AN8855_LED_MODE_USER_DEFINE, ++ AN8855_LED_MODE_LAST ++}; ++ ++enum phy_led_idx { ++ P0_LED0, ++ P0_LED1, ++ P0_LED2, ++ P0_LED3, ++ P1_LED0, ++ P1_LED1, ++ P1_LED2, ++ P1_LED3, ++ P2_LED0, ++ P2_LED1, ++ P2_LED2, ++ P2_LED3, ++ P3_LED0, ++ P3_LED1, ++ P3_LED2, ++ P3_LED3, ++ P4_LED0, ++ P4_LED1, ++ P4_LED2, ++ P4_LED3, ++ PHY_LED_MAX ++}; ++ ++struct an8855_led_cfg { ++ u16 en; ++ u8 phy_led_idx; ++ u16 pol; ++ u16 on_cfg; ++ u16 blk_cfg; ++ u8 led_freq; ++}; ++ ++struct an8855_switch_priv { ++ struct mtk_eth_switch_priv epriv; ++ struct mii_dev *mdio_bus; ++ u32 phy_base; ++}; ++ ++/* AN8855 Reference Board */ ++static const struct an8855_led_cfg led_cfg[] = { ++/************************************************************************* ++ * Enable, LED idx, LED Polarity, LED ON event, LED Blink event LED Freq ++ ************************************************************************* ++ */ ++ /* GPIO0 */ ++ {1, P4_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO1 */ ++ {1, P4_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO2 */ ++ {1, P0_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO3 */ ++ {1, P0_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO4 */ ++ {1, P1_LED0, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO5 */ ++ {1, P1_LED1, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO6 */ ++ {0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO7 */ ++ {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO8 */ ++ {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO9 */ ++ {1, P2_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO10 */ ++ {1, P2_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO11 */ ++ {1, P3_LED0, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO12 */ ++ {1, P3_LED1, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO13 */ ++ {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO14 */ ++ {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO15 */ ++ {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO16 */ ++ {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO17 */ ++ {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO18 */ ++ {0, PHY_LED_MAX, LED_HIGH, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO19 */ ++ {0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++ /* GPIO20 */ ++ {0, PHY_LED_MAX, LED_LOW, LED_ON_EVENT, LED_BLK_EVENT, LED_FREQ}, ++}; ++ ++static int __an8855_reg_read(struct mtk_eth_priv *priv, u8 phy_base, u32 reg, u32 *data) ++{ ++ int ret, low_word, high_word; ++ ++ ret = mtk_mii_write(priv, phy_base, 0x1f, 0x4); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv, phy_base, 0x10, 0); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv, phy_base, 0x15, ((reg >> 16) & 0xFFFF)); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv, phy_base, 0x16, (reg & 0xFFFF)); ++ if (ret) ++ return ret; ++ ++ low_word = mtk_mii_read(priv, phy_base, 0x18); ++ if (low_word < 0) ++ return low_word; ++ ++ high_word = mtk_mii_read(priv, phy_base, 0x17); ++ if (high_word < 0) ++ return high_word; ++ ++ ret = mtk_mii_write(priv, phy_base, 0x1f, 0); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv, phy_base, 0x10, 0); ++ if (ret) ++ return ret; ++ ++ if (data) ++ *data = ((u32)high_word << 16) | (low_word & 0xffff); ++ ++ return 0; ++} ++ ++static int an8855_reg_read(struct an8855_switch_priv *priv, u32 reg, u32 *data) ++{ ++ return __an8855_reg_read(priv->epriv.eth, priv->phy_base, reg, data); ++} ++ ++static int an8855_reg_write(struct an8855_switch_priv *priv, u32 reg, u32 data) ++{ ++ int ret; ++ ++ ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x1f, 0x4); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x10, 0); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x11, ++ ((reg >> 16) & 0xFFFF)); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x12, ++ (reg & 0xFFFF)); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x13, ++ ((data >> 16) & 0xFFFF)); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x14, ++ (data & 0xFFFF)); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x1f, 0); ++ if (ret) ++ return ret; ++ ++ ret = mtk_mii_write(priv->epriv.eth, priv->phy_base, 0x10, 0); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int an8855_phy_cl45_read(struct an8855_switch_priv *priv, int port, ++ int devad, int regnum, u16 *data) ++{ ++ u16 phy_addr = AN8855_PHY_ADDR(priv->phy_base, port); ++ ++ *data = mtk_mmd_ind_read(priv->epriv.eth, phy_addr, devad, regnum); ++ ++ return 0; ++} ++ ++static int an8855_phy_cl45_write(struct an8855_switch_priv *priv, int port, ++ int devad, int regnum, u16 data) ++{ ++ u16 phy_addr = AN8855_PHY_ADDR(priv->phy_base, port); ++ ++ mtk_mmd_ind_write(priv->epriv.eth, phy_addr, devad, regnum, data); ++ ++ return 0; ++} ++ ++static int an8855_port_sgmii_init(struct an8855_switch_priv *priv, u32 port) ++{ ++ u32 val = 0; ++ ++ if (port != 5) { ++ printf("an8855: port %d is not a SGMII port\n", port); ++ return -EINVAL; ++ } ++ ++ /* PLL */ ++ an8855_reg_read(priv, AN8855_QP_DIG_MODE_CTRL_1, &val); ++ val &= ~(0x3 << 2); ++ val |= (0x1 << 2); ++ an8855_reg_write(priv, AN8855_QP_DIG_MODE_CTRL_1, val); ++ ++ /* PLL - LPF */ ++ an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val); ++ val &= ~(0x3 << 0); ++ val |= (0x1 << 0); ++ val &= ~(0x7 << 2); ++ val |= (0x5 << 2); ++ val &= ~GENMASK(7, 6); ++ val &= ~(0x7 << 8); ++ val |= (0x3 << 8); ++ val |= BIT(29); ++ val &= ~GENMASK(13, 12); ++ an8855_reg_write(priv, AN8855_PLL_CTRL_2, val); ++ ++ /* PLL - ICO */ ++ an8855_reg_read(priv, AN8855_PLL_CTRL_4, &val); ++ val |= BIT(2); ++ an8855_reg_write(priv, AN8855_PLL_CTRL_4, val); ++ ++ an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val); ++ val &= ~BIT(14); ++ an8855_reg_write(priv, AN8855_PLL_CTRL_2, val); ++ ++ /* PLL - CHP */ ++ an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val); ++ val &= ~(0xf << 16); ++ val |= (0x6 << 16); ++ an8855_reg_write(priv, AN8855_PLL_CTRL_2, val); ++ ++ /* PLL - PFD */ ++ an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val); ++ val &= ~(0x3 << 20); ++ val |= (0x1 << 20); ++ val &= ~(0x3 << 24); ++ val |= (0x1 << 24); ++ val &= ~BIT(26); ++ an8855_reg_write(priv, AN8855_PLL_CTRL_2, val); ++ ++ /* PLL - POSTDIV */ ++ an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val); ++ val |= BIT(22); ++ val &= ~BIT(27); ++ val &= ~BIT(28); ++ an8855_reg_write(priv, AN8855_PLL_CTRL_2, val); ++ ++ /* PLL - SDM */ ++ an8855_reg_read(priv, AN8855_PLL_CTRL_4, &val); ++ val &= ~GENMASK(4, 3); ++ an8855_reg_write(priv, AN8855_PLL_CTRL_4, val); ++ ++ an8855_reg_read(priv, AN8855_PLL_CTRL_2, &val); ++ val &= ~BIT(30); ++ an8855_reg_write(priv, AN8855_PLL_CTRL_2, val); ++ ++ an8855_reg_read(priv, AN8855_SS_LCPLL_PWCTL_SETTING_2, &val); ++ val &= ~(0x3 << 16); ++ val |= (0x1 << 16); ++ an8855_reg_write(priv, AN8855_SS_LCPLL_PWCTL_SETTING_2, val); ++ ++ an8855_reg_write(priv, AN8855_SS_LCPLL_TDC_FLT_2, 0x7a000000); ++ an8855_reg_write(priv, AN8855_SS_LCPLL_TDC_PCW_1, 0x7a000000); ++ ++ an8855_reg_read(priv, AN8855_SS_LCPLL_TDC_FLT_5, &val); ++ val &= ~BIT(24); ++ an8855_reg_write(priv, AN8855_SS_LCPLL_TDC_FLT_5, val); ++ ++ an8855_reg_read(priv, AN8855_PLL_CK_CTRL_0, &val); ++ val &= ~BIT(8); ++ an8855_reg_write(priv, AN8855_PLL_CK_CTRL_0, val); ++ ++ /* PLL - SS */ ++ an8855_reg_read(priv, AN8855_PLL_CTRL_3, &val); ++ val &= ~GENMASK(15, 0); ++ an8855_reg_write(priv, AN8855_PLL_CTRL_3, val); ++ ++ an8855_reg_read(priv, AN8855_PLL_CTRL_4, &val); ++ val &= ~GENMASK(1, 0); ++ an8855_reg_write(priv, AN8855_PLL_CTRL_4, val); ++ ++ an8855_reg_read(priv, AN8855_PLL_CTRL_3, &val); ++ val &= ~GENMASK(31, 16); ++ an8855_reg_write(priv, AN8855_PLL_CTRL_3, val); ++ ++ /* PLL - TDC */ ++ an8855_reg_read(priv, AN8855_PLL_CK_CTRL_0, &val); ++ val &= ~BIT(9); ++ an8855_reg_write(priv, AN8855_PLL_CK_CTRL_0, val); ++ ++ an8855_reg_read(priv, AN8855_RG_QP_PLL_SDM_ORD, &val); ++ val |= BIT(3); ++ val |= BIT(4); ++ an8855_reg_write(priv, AN8855_RG_QP_PLL_SDM_ORD, val); ++ ++ an8855_reg_read(priv, AN8855_RG_QP_RX_DAC_EN, &val); ++ val &= ~(0x3 << 16); ++ val |= (0x2 << 16); ++ an8855_reg_write(priv, AN8855_RG_QP_RX_DAC_EN, val); ++ ++ /* TCL Disable (only for Co-SIM) */ ++ an8855_reg_read(priv, AN8855_PON_RXFEDIG_CTRL_0, &val); ++ val &= ~BIT(12); ++ an8855_reg_write(priv, AN8855_PON_RXFEDIG_CTRL_0, val); ++ ++ /* TX Init */ ++ an8855_reg_read(priv, AN8855_RG_QP_TX_MODE_16B_EN, &val); ++ val &= ~BIT(0); ++ val &= ~(0xffff << 16); ++ val |= (0x4 << 16); ++ an8855_reg_write(priv, AN8855_RG_QP_TX_MODE_16B_EN, val); ++ ++ /* RX Control */ ++ an8855_reg_read(priv, AN8855_RG_QP_RXAFE_RESERVE, &val); ++ val |= BIT(11); ++ an8855_reg_write(priv, AN8855_RG_QP_RXAFE_RESERVE, val); ++ ++ an8855_reg_read(priv, AN8855_RG_QP_CDR_LPF_MJV_LIM, &val); ++ val &= ~(0x3 << 4); ++ val |= (0x1 << 4); ++ an8855_reg_write(priv, AN8855_RG_QP_CDR_LPF_MJV_LIM, val); ++ ++ an8855_reg_read(priv, AN8855_RG_QP_CDR_LPF_SETVALUE, &val); ++ val &= ~(0xf << 25); ++ val |= (0x1 << 25); ++ val &= ~(0x7 << 29); ++ val |= (0x3 << 29); ++ an8855_reg_write(priv, AN8855_RG_QP_CDR_LPF_SETVALUE, val); ++ ++ an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, &val); ++ val &= ~(0x1f << 8); ++ val |= (0xf << 8); ++ an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, val); ++ ++ an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, &val); ++ val &= ~(0x3f << 0); ++ val |= (0x19 << 0); ++ val &= ~BIT(6); ++ an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, val); ++ ++ an8855_reg_read(priv, AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF, &val); ++ val &= ~(0x7f << 6); ++ val |= (0x21 << 6); ++ val &= ~(0x3 << 16); ++ val |= (0x2 << 16); ++ val &= ~BIT(13); ++ an8855_reg_write(priv, AN8855_RG_QP_CDR_FORCE_IBANDLPF_R_OFF, val); ++ ++ an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, &val); ++ val &= ~BIT(30); ++ an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_KBAND_DIV_PCIE, val); ++ ++ an8855_reg_read(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, &val); ++ val &= ~(0x7 << 24); ++ val |= (0x4 << 24); ++ an8855_reg_write(priv, AN8855_RG_QP_CDR_PR_CKREF_DIV1, val); ++ ++ an8855_reg_read(priv, AN8855_PLL_CTRL_0, &val); ++ val |= BIT(0); ++ an8855_reg_write(priv, AN8855_PLL_CTRL_0, val); ++ ++ an8855_reg_read(priv, AN8855_RX_CTRL_26, &val); ++ val &= ~BIT(23); ++ val |= BIT(26); ++ an8855_reg_write(priv, AN8855_RX_CTRL_26, val); ++ ++ an8855_reg_read(priv, AN8855_RX_DLY_0, &val); ++ val &= ~(0xff << 0); ++ val |= (0x6f << 0); ++ val |= GENMASK(13, 8); ++ an8855_reg_write(priv, AN8855_RX_DLY_0, val); ++ ++ an8855_reg_read(priv, AN8855_RX_CTRL_42, &val); ++ val &= ~(0x1fff << 0); ++ val |= (0x150 << 0); ++ an8855_reg_write(priv, AN8855_RX_CTRL_42, val); ++ ++ an8855_reg_read(priv, AN8855_RX_CTRL_2, &val); ++ val &= ~(0x1fff << 16); ++ val |= (0x150 << 16); ++ an8855_reg_write(priv, AN8855_RX_CTRL_2, val); ++ ++ an8855_reg_read(priv, AN8855_PON_RXFEDIG_CTRL_9, &val); ++ val &= ~(0x7 << 0); ++ val |= (0x1 << 0); ++ an8855_reg_write(priv, AN8855_PON_RXFEDIG_CTRL_9, val); ++ ++ an8855_reg_read(priv, AN8855_RX_CTRL_8, &val); ++ val &= ~(0xfff << 16); ++ val |= (0x200 << 16); ++ val &= ~(0x7fff << 14); ++ val |= (0xfff << 14); ++ an8855_reg_write(priv, AN8855_RX_CTRL_8, val); ++ ++ /* Frequency memter */ ++ an8855_reg_read(priv, AN8855_RX_CTRL_5, &val); ++ val &= ~(0xfffff << 10); ++ val |= (0x10 << 10); ++ an8855_reg_write(priv, AN8855_RX_CTRL_5, val); ++ ++ an8855_reg_read(priv, AN8855_RX_CTRL_6, &val); ++ val &= ~(0xfffff << 0); ++ val |= (0x64 << 0); ++ an8855_reg_write(priv, AN8855_RX_CTRL_6, val); ++ ++ an8855_reg_read(priv, AN8855_RX_CTRL_7, &val); ++ val &= ~(0xfffff << 0); ++ val |= (0x2710 << 0); ++ an8855_reg_write(priv, AN8855_RX_CTRL_7, val); ++ ++ /* PCS Init */ ++ an8855_reg_read(priv, AN8855_RG_HSGMII_PCS_CTROL_1, &val); ++ val &= ~BIT(30); ++ an8855_reg_write(priv, AN8855_RG_HSGMII_PCS_CTROL_1, val); ++ ++ /* Rate Adaption */ ++ an8855_reg_read(priv, AN8855_RATE_ADP_P0_CTRL_0, &val); ++ val &= ~BIT(31); ++ an8855_reg_write(priv, AN8855_RATE_ADP_P0_CTRL_0, val); ++ ++ an8855_reg_read(priv, AN8855_RG_RATE_ADAPT_CTRL_0, &val); ++ val |= BIT(0); ++ val |= BIT(4); ++ val |= GENMASK(27, 26); ++ an8855_reg_write(priv, AN8855_RG_RATE_ADAPT_CTRL_0, val); ++ ++ /* Disable AN */ ++ an8855_reg_read(priv, AN8855_SGMII_REG_AN0, &val); ++ val &= ~BIT(12); ++ an8855_reg_write(priv, AN8855_SGMII_REG_AN0, val); ++ ++ /* Force Speed */ ++ an8855_reg_read(priv, AN8855_SGMII_STS_CTRL_0, &val); ++ val |= BIT(2); ++ val |= GENMASK(5, 4); ++ an8855_reg_write(priv, AN8855_SGMII_STS_CTRL_0, val); ++ ++ /* bypass flow control to MAC */ ++ an8855_reg_write(priv, AN8855_MSG_RX_LIK_STS_0, 0x01010107); ++ an8855_reg_write(priv, AN8855_MSG_RX_LIK_STS_2, 0x00000EEF); ++ ++ return 0; ++} ++ ++static void an8855_led_set_usr_def(struct an8855_switch_priv *priv, u8 entity, ++ enum an8855_led_polarity pol, u16 on_evt, ++ u16 blk_evt, u8 led_freq) ++{ ++ u32 cl45_data; ++ ++ if (pol == LED_HIGH) ++ on_evt |= LED_ON_POL; ++ else ++ on_evt &= ~LED_ON_POL; ++ ++ /* LED on event */ ++ an8855_phy_cl45_write(priv, (entity / 4), 0x1e, ++ PHY_SINGLE_LED_ON_CTRL(entity % 4), ++ on_evt | LED_ON_EN); ++ ++ /* LED blink event */ ++ an8855_phy_cl45_write(priv, (entity / 4), 0x1e, ++ PHY_SINGLE_LED_BLK_CTRL(entity % 4), ++ blk_evt); ++ ++ /* LED freq */ ++ switch (led_freq) { ++ case AIR_LED_BLK_DUR_32M: ++ cl45_data = 0x30e; ++ break; ++ ++ case AIR_LED_BLK_DUR_64M: ++ cl45_data = 0x61a; ++ break; ++ ++ case AIR_LED_BLK_DUR_128M: ++ cl45_data = 0xc35; ++ break; ++ ++ case AIR_LED_BLK_DUR_256M: ++ cl45_data = 0x186a; ++ break; ++ ++ case AIR_LED_BLK_DUR_512M: ++ cl45_data = 0x30d4; ++ break; ++ ++ case AIR_LED_BLK_DUR_1024M: ++ cl45_data = 0x61a8; ++ break; ++ ++ default: ++ cl45_data = 0; ++ break; ++ } ++ ++ an8855_phy_cl45_write(priv, (entity / 4), 0x1e, ++ PHY_SINGLE_LED_BLK_DUR(entity % 4), ++ cl45_data); ++ ++ an8855_phy_cl45_write(priv, (entity / 4), 0x1e, ++ PHY_SINGLE_LED_ON_DUR(entity % 4), ++ (cl45_data >> 1)); ++ ++ /* Disable DATA & BAD_SSD for port LED blink behavior */ ++ cl45_data = mtk_mmd_ind_read(priv->epriv.eth, (entity / 4), 0x1e, PHY_PMA_CTRL); ++ cl45_data &= ~BIT(0); ++ cl45_data &= ~BIT(15); ++ an8855_phy_cl45_write(priv, (entity / 4), 0x1e, PHY_PMA_CTRL, cl45_data); ++} ++ ++static int an8855_led_set_mode(struct an8855_switch_priv *priv, u8 mode) ++{ ++ u16 cl45_data; ++ ++ an8855_phy_cl45_read(priv, 0, 0x1f, PHY_LED_BCR, &cl45_data); ++ ++ switch (mode) { ++ case AN8855_LED_MODE_DISABLE: ++ cl45_data &= ~LED_BCR_EXT_CTRL; ++ cl45_data &= ~LED_BCR_MODE_MASK; ++ cl45_data |= LED_BCR_MODE_DISABLE; ++ break; ++ ++ case AN8855_LED_MODE_USER_DEFINE: ++ cl45_data |= LED_BCR_EXT_CTRL; ++ cl45_data |= LED_BCR_CLK_EN; ++ break; ++ ++ default: ++ printf("an8855: LED mode%d is not supported!\n", mode); ++ return -EINVAL; ++ } ++ ++ an8855_phy_cl45_write(priv, 0, 0x1f, PHY_LED_BCR, cl45_data); ++ ++ return 0; ++} ++ ++static int an8855_led_set_state(struct an8855_switch_priv *priv, u8 entity, ++ u8 state) ++{ ++ u16 cl45_data = 0; ++ ++ /* Change to per port contorl */ ++ an8855_phy_cl45_read(priv, (entity / 4), 0x1e, PHY_LED_CTRL_SELECT, ++ &cl45_data); ++ ++ if (state == 1) ++ cl45_data |= (1 << (entity % 4)); ++ else ++ cl45_data &= ~(1 << (entity % 4)); ++ ++ an8855_phy_cl45_write(priv, (entity / 4), 0x1e, PHY_LED_CTRL_SELECT, ++ cl45_data); ++ ++ /* LED enable setting */ ++ an8855_phy_cl45_read(priv, (entity / 4), 0x1e, ++ PHY_SINGLE_LED_ON_CTRL(entity % 4), &cl45_data); ++ ++ if (state == 1) ++ cl45_data |= LED_ON_EN; ++ else ++ cl45_data &= ~LED_ON_EN; ++ ++ an8855_phy_cl45_write(priv, (entity / 4), 0x1e, ++ PHY_SINGLE_LED_ON_CTRL(entity % 4), cl45_data); ++ ++ return 0; ++} ++ ++static int an8855_led_init(struct an8855_switch_priv *priv) ++{ ++ u32 val, id, tmp_id = 0; ++ int ret; ++ ++ ret = an8855_led_set_mode(priv, AN8855_LED_MODE_USER_DEFINE); ++ if (ret) { ++ printf("an8855: led_set_mode failed with %d!\n", ret); ++ return ret; ++ } ++ ++ for (id = 0; id < ARRAY_SIZE(led_cfg); id++) { ++ ret = an8855_led_set_state(priv, led_cfg[id].phy_led_idx, ++ led_cfg[id].en); ++ if (ret != 0) { ++ printf("an8855: led_set_state failed with %d!\n", ret); ++ return ret; ++ } ++ ++ if (led_cfg[id].en == 1) { ++ an8855_led_set_usr_def(priv, ++ led_cfg[id].phy_led_idx, ++ led_cfg[id].pol, ++ led_cfg[id].on_cfg, ++ led_cfg[id].blk_cfg, ++ led_cfg[id].led_freq); ++ } ++ } ++ ++ /* Setting for System LED & Loop LED */ ++ an8855_reg_write(priv, AN8855_RG_GPIO_OE, 0x0); ++ an8855_reg_write(priv, AN8855_RG_GPIO_CTRL, 0x0); ++ an8855_reg_write(priv, AN8855_RG_GPIO_L_INV, 0); ++ ++ an8855_reg_write(priv, AN8855_RG_GPIO_CTRL, 0x1001); ++ an8855_reg_read(priv, AN8855_RG_GPIO_DATA, &val); ++ val |= GENMASK(3, 1); ++ val &= ~(BIT(0)); ++ val &= ~(BIT(6)); ++ an8855_reg_write(priv, AN8855_RG_GPIO_DATA, val); ++ ++ an8855_reg_read(priv, AN8855_RG_GPIO_OE, &val); ++ val |= 0x41; ++ an8855_reg_write(priv, AN8855_RG_GPIO_OE, val); ++ ++ /* Mapping between GPIO & LED */ ++ val = 0; ++ for (id = 0; id < ARRAY_SIZE(led_cfg); id++) { ++ /* Skip GPIO6, due to GPIO6 does not support PORT LED */ ++ if (id == 6) ++ continue; ++ ++ if (led_cfg[id].en == 1) { ++ if (id < 7) ++ val |= led_cfg[id].phy_led_idx << ((id % 4) * 8); ++ else ++ val |= led_cfg[id].phy_led_idx << (((id - 1) % 4) * 8); ++ } ++ ++ if (id < 7) ++ tmp_id = id; ++ else ++ tmp_id = id - 1; ++ ++ if ((tmp_id % 4) == 0x3) { ++ an8855_reg_write(priv, ++ AN8855_RG_GPIO_LED_SEL(tmp_id / 4), ++ val); ++ val = 0; ++ } ++ } ++ ++ /* Turn on LAN LED mode */ ++ val = 0; ++ for (id = 0; id < ARRAY_SIZE(led_cfg); id++) { ++ if (led_cfg[id].en == 1) ++ val |= 0x1 << id; ++ } ++ an8855_reg_write(priv, AN8855_RG_GPIO_LED_MODE, val); ++ ++ /* Force clear blink pulse for per port LED */ ++ an8855_phy_cl45_write(priv, 0, 0x1f, PHY_LED_BLINK_DUR_CTRL, 0x1f); ++ udelay(1000); ++ an8855_phy_cl45_write(priv, 0, 0x1f, PHY_LED_BLINK_DUR_CTRL, 0); ++ ++ return 0; ++} ++ ++static void an8855_port_isolation(struct an8855_switch_priv *priv) ++{ ++ u32 i; ++ ++ for (i = 0; i < AN8855_NUM_PORTS; i++) { ++ /* Set port matrix mode */ ++ if (i != 5) ++ an8855_reg_write(priv, AN8855_PORTMATRIX_REG(i), 0x20); ++ else ++ an8855_reg_write(priv, AN8855_PORTMATRIX_REG(i), 0x1f); ++ ++ /* Set port mode to user port */ ++ an8855_reg_write(priv, AN8855_PVC(i), ++ (0x8100 << AN8855_STAG_VPID_S) | ++ (VLAN_ATTR_USER << AN8855_VLAN_ATTR_S)); ++ } ++} ++ ++static void an8855_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable) ++{ ++ struct an8855_switch_priv *priv = (struct an8855_switch_priv *)swpriv; ++ u32 pmcr = AN8855_FORCE_MODE_LNK; ++ ++ if (enable) ++ pmcr = AN8855_FORCE_MODE; ++ ++ an8855_reg_write(priv, AN8855_PMCR_REG(5), pmcr); ++} ++ ++static int an8855_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) ++{ ++ struct an8855_switch_priv *priv = bus->priv; ++ ++ if (devad < 0) ++ return mtk_mii_read(priv->epriv.eth, addr, reg); ++ ++ return mtk_mmd_ind_read(priv->epriv.eth, addr, devad, reg); ++} ++ ++static int an8855_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, ++ u16 val) ++{ ++ struct an8855_switch_priv *priv = bus->priv; ++ ++ if (devad < 0) ++ return mtk_mii_write(priv->epriv.eth, addr, reg, val); ++ ++ return mtk_mmd_ind_write(priv->epriv.eth, addr, devad, reg, val); ++} ++ ++static int an8855_mdio_register(struct an8855_switch_priv *priv) ++{ ++ struct mii_dev *mdio_bus = mdio_alloc(); ++ int ret; ++ ++ if (!mdio_bus) ++ return -ENOMEM; ++ ++ mdio_bus->read = an8855_mdio_read; ++ mdio_bus->write = an8855_mdio_write; ++ snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name); ++ ++ mdio_bus->priv = priv; ++ ++ ret = mdio_register(mdio_bus); ++ if (ret) { ++ mdio_free(mdio_bus); ++ return ret; ++ } ++ ++ priv->mdio_bus = mdio_bus; ++ ++ return 0; ++} ++ ++static int an8855_setup(struct mtk_eth_switch_priv *swpriv) ++{ ++ struct an8855_switch_priv *priv = (struct an8855_switch_priv *)swpriv; ++ u16 phy_addr, phy_val; ++ u32 i, id, val = 0; ++ int ret; ++ ++ priv->phy_base = 1; ++ ++ /* Turn off PHYs */ ++ for (i = 0; i < AN8855_NUM_PHYS; i++) { ++ phy_addr = AN8855_PHY_ADDR(priv->phy_base, i); ++ phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR); ++ phy_val |= BMCR_PDOWN; ++ mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val); ++ } ++ ++ /* Force MAC link down before reset */ ++ an8855_reg_write(priv, AN8855_PMCR_REG(5), AN8855_FORCE_MODE_LNK); ++ ++ /* Switch soft reset */ ++ an8855_reg_write(priv, AN8855_SYS_CTRL_REG, AN8855_SW_SYS_RST); ++ udelay(100000); ++ ++ an8855_reg_read(priv, AN8855_PKG_SEL, &val); ++ if ((val & 0x7) == PAG_SEL_AN8855H) { ++ /* Release power down */ ++ an8855_reg_write(priv, RG_GPHY_AFE_PWD, 0x0); ++ ++ /* Invert for LED activity change */ ++ an8855_reg_read(priv, AN8855_RG_GPIO_L_INV, &val); ++ for (id = 0; id < ARRAY_SIZE(led_cfg); id++) { ++ if ((led_cfg[id].pol == LED_HIGH) && ++ (led_cfg[id].en == 1)) ++ val |= 0x1 << id; ++ } ++ an8855_reg_write(priv, AN8855_RG_GPIO_L_INV, (val | 0x1)); ++ ++ /* MCU NOP CMD */ ++ an8855_reg_write(priv, AN8855_RG_GDMP_RAM, 0x846); ++ an8855_reg_write(priv, AN8855_RG_GDMP_RAM + 4, 0x4a); ++ ++ /* Enable MCU */ ++ an8855_reg_read(priv, AN8855_RG_CLK_CPU_ICG, &val); ++ an8855_reg_write(priv, AN8855_RG_CLK_CPU_ICG, ++ val | AN8855_MCU_ENABLE); ++ udelay(1000); ++ ++ /* Disable MCU watchdog */ ++ an8855_reg_read(priv, AN8855_RG_TIMER_CTL, &val); ++ an8855_reg_write(priv, AN8855_RG_TIMER_CTL, ++ (val & (~AN8855_WDOG_ENABLE))); ++ ++ /* LED settings for T830 reference board */ ++ ret = an8855_led_init(priv); ++ if (ret < 0) { ++ printf("an8855: an8855_led_init failed with %d\n", ret); ++ return ret; ++ } ++ } ++ ++ switch (priv->epriv.phy_interface) { ++ case PHY_INTERFACE_MODE_2500BASEX: ++ an8855_port_sgmii_init(priv, 5); ++ break; ++ ++ default: ++ break; ++ } ++ ++ an8855_reg_read(priv, AN8855_CKGCR, &val); ++ val &= ~(0x3); ++ an8855_reg_write(priv, AN8855_CKGCR, val); ++ ++ /* Enable port isolation to block inter-port communication */ ++ an8855_port_isolation(priv); ++ ++ /* Turn on PHYs */ ++ for (i = 0; i < AN8855_NUM_PHYS; i++) { ++ phy_addr = AN8855_PHY_ADDR(priv->phy_base, i); ++ phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR); ++ phy_val &= ~BMCR_PDOWN; ++ mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val); ++ } ++ ++ return an8855_mdio_register(priv); ++} ++ ++static int an8855_cleanup(struct mtk_eth_switch_priv *swpriv) ++{ ++ struct an8855_switch_priv *priv = (struct an8855_switch_priv *)swpriv; ++ ++ mdio_unregister(priv->mdio_bus); ++ ++ return 0; ++} ++ ++static int an8855_detect(struct mtk_eth_priv *priv) ++{ ++ int ret; ++ u32 val; ++ ++ ret = __an8855_reg_read(priv, 1, 0x10005000, &val); ++ if (ret) ++ return ret; ++ ++ if (val == 0x8855) ++ return 0; ++ ++ return -ENODEV; ++} ++ ++MTK_ETH_SWITCH(an8855) = { ++ .name = "an8855", ++ .desc = "Airoha AN8855", ++ .priv_size = sizeof(struct an8855_switch_priv), ++ .reset_wait_time = 100, ++ ++ .detect = an8855_detect, ++ .setup = an8855_setup, ++ .cleanup = an8855_cleanup, ++ .mac_control = an8855_mac_control, ++};