Debian for MT7621 折腾记 (2) – 实现 MT7530 DSA

转载请注明原帖链接和作者!


OpenWrt 自带的 swconfig 功能对于 Debian 来说,就不是那么好用了。除此之外,Linux 对交换机的支持就只剩 DSA 了。幸好 MT7530 有 DSA 驱动。

但是 MT7530 的 DSA 驱动是给 MT7623 用的,里面硬编码了很多 MT7623 的设置,还用到了很多 MT7621 中不存在的东西,例如 Power domain。
这些都需要全部去掉,并为 MT7621 添加所需的代码。

此外,用于 MT7621 的以太网驱动 mtk_soc_eth 也一团糟,里面杂揉了各个芯片的代码,不纯粹,不适合拿给 DSA 用。因此也需要进行修改。

1. 修改 mtk_soc_eth

我选择对 ARM 版的 mtk_soc_eth 下手。

1.1 加入 MT7621 支持

--- a/drivers/net/ethernet/mediatek/Kconfig
+++ b/drivers/net/ethernet/mediatek/Kconfig
@@ -1,6 +1,6 @@
 config NET_VENDOR_MEDIATEK
 	bool "MediaTek ethernet driver"
-	depends on ARCH_MEDIATEK
+	depends on ARCH_MEDIATEK || SOC_MT7621
 	---help---
 	  If you have a Mediatek SoC with ethernet, say Y.
 

--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -76,7 +76,6 @@ static int mtk_mdio_busy_wait(struct mtk
 			return 0;
 		if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT))
 			break;
-		usleep_range(10, 20);
 	}
 
 	dev_err(eth->dev, "mdio: MDIO timeout\n");
@@ -1748,6 +1747,34 @@ static void mtk_tx_timeout(struct net_de
 	schedule_work(&eth->pending_work);
 }
 
+static irqreturn_t mtk_handle_irq_tx_rx(int irq, void *_eth)
+{
+	struct mtk_eth *eth = _eth;
+	u32 tx_status, rx_status;
+
+	tx_status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+
+	if (tx_status & MTK_TX_DONE_INT) {
+		if (likely(napi_schedule_prep(&eth->tx_napi))) {
+			mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
+			__napi_schedule(&eth->tx_napi);
+		}
+		mtk_w32(eth, tx_status, MTK_QMTK_INT_STATUS);
+	}
+
+	rx_status = mtk_r32(eth, MTK_PDMA_INT_STATUS);
+
+	if (rx_status & MTK_RX_DONE_INT) {
+		if (likely(napi_schedule_prep(&eth->rx_napi))) {
+			mtk_rx_irq_disable(eth, MTK_RX_DONE_INT);
+			__napi_schedule(&eth->rx_napi);
+		}
+		mtk_w32(eth, rx_status, MTK_PDMA_INT_STATUS);
+	}
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t mtk_handle_irq_rx(int irq, void *_eth)
 {
 	struct mtk_eth *eth = _eth;
@@ -1950,14 +1977,16 @@ static int mtk_hw_init(struct mtk_eth *e
 	}
 	regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
 
-	/* Set GE2 driving and slew rate */
-	regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00);
+	if (eth->pctl) {
+		/* Set GE2 driving and slew rate */
+		regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00);
 
-	/* set GE2 TDSEL */
-	regmap_write(eth->pctl, GPIO_OD33_CTRL8, 0x5);
+		/* set GE2 TDSEL */
+		regmap_write(eth->pctl, GPIO_OD33_CTRL8, 0x5);
 
-	/* set GE2 TUNE */
-	regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0);
+		/* set GE2 TUNE */
+		regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0);
+	}
 
 	/* Set linkdown as the default for each GMAC. Its own MCR would be set
 	 * up with the more appropriate value when mtk_phy_link_adjust call is
@@ -2536,14 +2565,16 @@ static int mtk_probe(struct platform_dev
 		}
 	}
 
-	eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
-						    "mediatek,pctl");
-	if (IS_ERR(eth->pctl)) {
-		dev_err(&pdev->dev, "no pctl regmap found\n");
-		return PTR_ERR(eth->pctl);
+	if (eth->soc->require_pctl) {
+		eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+							    "mediatek,pctl");
+		if (IS_ERR(eth->pctl)) {
+			dev_info(&pdev->dev, "no pctl regmap found\n");
+			return PTR_ERR(eth->pctl);
+		}
 	}
 
-	for (i = 0; i < 3; i++) {
+	for (i = 0; i < eth->soc->irq_num; i++) {
 		eth->irq[i] = platform_get_irq(pdev, i);
 		if (eth->irq[i] < 0) {
 			dev_err(&pdev->dev, "no IRQ%d resource found\n", i);
@@ -2591,15 +2622,22 @@ static int mtk_probe(struct platform_dev
 			goto err_deinit_hw;
 	}
 
-	err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0,
-			       dev_name(eth->dev), eth);
-	if (err)
-		goto err_free_dev;
+	if (eth->soc->irq_num > 1) {
+		err = devm_request_irq(eth->dev, eth->irq[1], mtk_handle_irq_tx, 0,
+				       dev_name(eth->dev), eth);
+		if (err)
+			goto err_free_dev;
 
-	err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0,
-			       dev_name(eth->dev), eth);
-	if (err)
-		goto err_free_dev;
+		err = devm_request_irq(eth->dev, eth->irq[2], mtk_handle_irq_rx, 0,
+				       dev_name(eth->dev), eth);
+		if (err)
+			goto err_free_dev;
+	} else {
+		err = devm_request_irq(eth->dev, eth->irq[0], mtk_handle_irq_tx_rx, 0,
+				       dev_name(eth->dev), eth);
+		if (err)
+			goto err_free_dev;
+	}
 
 	err = mtk_mdio_init(eth);
 	if (err)
@@ -2666,23 +2704,37 @@ static int mtk_remove(struct platform_de
 
 static const struct mtk_soc_data mt2701_data = {
 	.caps = MTK_GMAC1_TRGMII,
-	.required_clks = MT7623_CLKS_BITMAP
+	.required_clks = MT7623_CLKS_BITMAP,
+	.require_pctl = true,
+	.irq_num = 3,
 };
 
 static const struct mtk_soc_data mt7622_data = {
 	.caps = MTK_DUAL_GMAC_SHARED_SGMII | MTK_GMAC1_ESW,
-	.required_clks = MT7622_CLKS_BITMAP
+	.required_clks = MT7622_CLKS_BITMAP,
+	.require_pctl = false,
+	.irq_num = 3,
 };
 
 static const struct mtk_soc_data mt7623_data = {
 	.caps = MTK_GMAC1_TRGMII,
-	.required_clks = MT7623_CLKS_BITMAP
+	.required_clks = MT7623_CLKS_BITMAP,
+	.require_pctl = true,
+	.irq_num = 3,
+};
+
+static const struct mtk_soc_data mt7621_data = {
+	.caps = MTK_GMAC1_TRGMII,
+	.required_clks = MT7621_CLKS_BITMAP,
+	.require_pctl = false,
+	.irq_num = 1,
 };
 
 const struct of_device_id of_mtk_match[] = {
 	{ .compatible = "mediatek,mt2701-eth", .data = &mt2701_data},
 	{ .compatible = "mediatek,mt7622-eth", .data = &mt7622_data},
 	{ .compatible = "mediatek,mt7623-eth", .data = &mt7623_data},
+	{ .compatible = "mediatek,mt7621-eth", .data = &mt7621_data},
 	{},
 };
 MODULE_DEVICE_TABLE(of, of_mtk_match);
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -486,6 +486,8 @@ enum mtk_clks_map {
 				 BIT(MTK_CLK_SGMII_CDR_FB) | \
 				 BIT(MTK_CLK_SGMII_CK) | \
 				 BIT(MTK_CLK_ETH2PLL))
+#define MT7621_CLKS_BITMAP	0
+
 enum mtk_dev_state {
 	MTK_HW_INIT,
 	MTK_RESETTING
@@ -575,6 +577,8 @@ struct mtk_rx_ring {
 struct mtk_soc_data {
 	u32		caps;
 	u32		required_clks;
+	bool		require_pctl;
+	u32             irq_num;
 };
 
 /* currently no SoC has more than 2 macs */
 };
 
 /* currently no SoC has more than 2 macs */

1.2 从 mediatek 这个 target 中提取 mtk_soc_eth 相关的改动

0027-net-next-mediatek-fix-DQL-support.patch
0035-net-mediatek-disable-RX-VLan-offloading.patch
0042-net-next-mediatek-honour-special-tag-bit-inside-RX-D.patch
0043-net-next-mediatek-enable-special-tag-indication-for-.patch
0051-net-mediatek-increase-tx_timeout.patch
0063-atomic-sleep.patch

2. 修改 DSA 驱动

2.1 从 mediatek 这个 target 中提取 DSA 相关的改动

0032-net-dsa-mediatek-add-support-for-GMAC2-wired-to-ext-.patch
0033-dsa-multi-cpu.patch
0044-net-next-dsa-mediatek-tell-GDMA-when-we-are-turning-.patch
0045-net-dsa-mediatek-turn-into-platform-driver.patch

2.2 针对 MT7621 进行修改

2.2.1 去除 MT7623 TRGMII 相关的设置

--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -76,58 +76,6 @@ static const struct mt7530_mib_desc mt75
 };
 
 static int
-mt7623_trgmii_write(struct mt7530_priv *priv,  u32 reg, u32 val)
-{
-	int ret;
-
-	ret =  regmap_write(priv->ethernet, TRGMII_BASE(reg), val);
-	if (ret < 0)
-		dev_err(priv->dev,
-			"failed to priv write register\n");
-	return ret;
-}
-
-static u32
-mt7623_trgmii_read(struct mt7530_priv *priv, u32 reg)
-{
-	int ret;
-	u32 val;
-
-	ret = regmap_read(priv->ethernet, TRGMII_BASE(reg), &val);
-	if (ret < 0) {
-		dev_err(priv->dev,
-			"failed to priv read register\n");
-		return ret;
-	}
-
-	return val;
-}
-
-static void
-mt7623_trgmii_rmw(struct mt7530_priv *priv, u32 reg,
-		  u32 mask, u32 set)
-{
-	u32 val;
-
-	val = mt7623_trgmii_read(priv, reg);
-	val &= ~mask;
-	val |= set;
-	mt7623_trgmii_write(priv, reg, val);
-}
-
-static void
-mt7623_trgmii_set(struct mt7530_priv *priv, u32 reg, u32 val)
-{
-	mt7623_trgmii_rmw(priv, reg, 0, val);
-}
-
-static void
-mt7623_trgmii_clear(struct mt7530_priv *priv, u32 reg, u32 val)
-{
-	mt7623_trgmii_rmw(priv, reg, val, 0);
-}
-
-static int
 core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad)
 {
 	struct mii_bus *bus = priv->bus;
@@ -515,24 +463,6 @@ mt7530_pad_clk_setup(struct dsa_switch *
 		for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
 			mt7530_rmw(priv, MT7530_TRGMII_RD(i),
 				   RD_TAP_MASK, RD_TAP(16));
-	else
-		mt7623_trgmii_set(priv, GSW_INTF_MODE, INTF_MODE_TRGMII);
-
-	return 0;
-}
-
-static int
-mt7623_pad_clk_setup(struct dsa_switch *ds)
-{
-	struct mt7530_priv *priv = ds->priv;
-	int i;
-
-	for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
-		mt7623_trgmii_write(priv, GSW_TRGMII_TD_ODT(i),
-				    TD_DM_DRVP(8) | TD_DM_DRVN(8));
-
-	mt7623_trgmii_set(priv, GSW_TRGMII_RCK_CTRL, RX_RST | RXC_DQSISEL);
-	mt7623_trgmii_clear(priv, GSW_TRGMII_RCK_CTRL, RX_RST);
 
 	return 0;
 }
@@ -619,12 +549,6 @@ static void mt7530_adjust_link(struct ds
 
 		/* Setup TX circuit incluing relevant PAD and driving */
 		mt7530_pad_clk_setup(ds, phydev->interface);
-
-		/* Setup RX circuit, relevant PAD and driving on the host
-		 * which must be placed after the setup on the device side is
-		 * all finished.
-		 */
-		mt7623_pad_clk_setup(ds);
 	} else {
 		u16 lcl_adv = 0, rmt_adv = 0;
 		u8 flowctrl;

2.2.2 添加 MT7621 TRGMII 相关的设置

目前 Upstream 并没有完善的 TRGMII 支持,因此暂时先用 RGMII。毕竟 MT7621 的 TRGMII 只有 1.2Gbps,只比 RGMII 的 1Gbps 快了一点,影响不大。

这个先留着,等以后再补充。

3. 修改 DTS 文件

3.1 修改 mt7621.dtsi

--- a/target/linux/ramips/dts/mt7621.dtsi
+++ b/target/linux/ramips/dts/mt7621.dtsi
@@ -406,22 +406,38 @@
 			0x1e003800 0x800>;
 	};
 
+	ethsys: ethsys@1e000000 {
+		compatible = "mediatek,mt7621-ethsys", "syscon";
+		reg = <0x1e000000 0x8000>;
+	};
+
 	ethernet: ethernet@1e100000 {
-		compatible = "mediatek,mt7621-eth";
+		compatible = "mediatek,mt7621-eth", "syscon";
 		reg = <0x1e100000 0x10000>;
 
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		mediatek,ethsys = <&ethsys>;
+
 		resets = <&rstctrl 6 &rstctrl 23>;
 		reset-names = "fe", "eth";
 
 		interrupt-parent = <&gic>;
 		interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>;
 
-		mediatek,switch = <&gsw>;
+		gmac0: mac@0 {
+			compatible = "mediatek,eth-mac";
+			reg = <0>;
+			phy-mode = "rgmii";
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+				pause;
+			};
+		};
 
-		mdio-bus {
+		mdio: mdio-bus {
 			#address-cells = <1>;
 			#size-cells = <0>;
 
@@ -430,16 +446,6 @@
 				phy-mode = "rgmii";
 			};
 		};
-
-		hnat: hnat@0 {
-			compatible = "mediatek,mt7623-hnat";
-			reg = <0 0x10000>;
-			mtketh-ppd = "eth0";
-			mtketh-lan = "eth0";
-			mtketh-wan = "eth0";
-			resets = <&rstctrl 0>;
-			reset-names = "mtketh";
-		};
 	};
 
 	gsw: gsw@1e110000 {

3.2 修改对应板子的 dts

这里用的是 CreativeBox 这个板子。

--- a/target/linux/ramips/dts/CreativeBox-v1.dts
+++ b/target/linux/ramips/dts/CreativeBox-v1.dts
@@ -86,6 +86,10 @@
 			gpios = <&gpio0 27 GPIO_ACTIVE_HIGH>;
 		};
 	};
+
+	mt7530: switch@0 {
+		compatible = "mediatek,mt7530";
+	};
 };
 
 &sdhci {
@@ -115,6 +119,67 @@
 	mtd-mac-address = <&factory 0xe000>;
 };
 
+&mt7530 {
+	compatible = "mediatek,mt7530";
+
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	mediatek,mcm;
+	resets = <&rstctrl 2>;
+	reset-names = "mcm";
+
+	dsa,mii-bus = <&mdio>;
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+
+		port@0 {
+			reg = <0>;
+			label = "lan0";
+			cpu = <&cpu_port0>;
+		};
+
+		port@1 {
+			reg = <1>;
+			label = "lan1";
+			cpu = <&cpu_port0>;
+		};
+
+		port@2 {
+			reg = <2>;
+			label = "lan2";
+			cpu = <&cpu_port0>;
+		};
+
+		port@3 {
+			reg = <3>;
+			label = "lan3";
+			cpu = <&cpu_port0>;
+		};
+
+		port@4 {
+			reg = <4>;
+			label = "wan";
+			cpu = <&cpu_port0>;
+		};
+
+		cpu_port0: port@6 {
+			reg = <6>;
+			label = "cpu";
+			ethernet = <&gmac0>;
+			phy-mode = "rgmii";
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+	};
+};
+
 &pinctrl {
 	state_default: pinctrl0 {
 		gpio {

4. 修改 OpenWrt 中的网络配置

这里仅仅是为了在 OpenWrt 中测试 DSA 是否正常工作

修改 target/linux/ramips/base-files/etc/board.d/02_network,将对应板子的脚本语句修改为:

ucidef_set_interfaces_lan_wan "lan0 lan1 lan2 lan3" "wan"

5. 开启 kernel 网络子系统的 DSA 功能

Networking support   —>   Networking options   —>   Distributed Switch Architecture
Device Drivers   —>   Network device support   —>   Distributed Switch Architecture drivers   —>   Mediatek MT7530 Ethernet switch support

6. 编译测试

Debian for MT7621 折腾记 (2) – 实现 MT7530 DSA” 中有 2 条评论

  1. 手头有1台 水星的MER2600G, 用的MT7621芯片
    RAM 128M
    ROM 16M
    有5G和2.4G, 带PA和LNA

    原厂系统有一个BUG
    运行一段时间后,就会卡住,不回复ISP OLT发出的PPP echo 导致被服务器判断为掉线。
    改为光猫直接拨号,路由的WAN是 静态IP,也一样无法上网。
    官方自己写了一个判断是否掉线的小程序,也会导致无法上网。
    要冷却一段时间后才能再次PPPoe上网,联系了官方技术,换了3次新机,都没有解决。

    想自己编译一下 最新版本的 openwrt
    已用breed 测试出 几个 GPIO 的情况

    reset按钮 GPIO 8
    turbo按钮 GPIO 12
    sys LED GPIO 3
    turbo LED GPIO 4
    USB LED GPIO 15

    想请教一下 在DTS里应该怎么配置?
    拆机的主要芯片图片在数码之家有

    谢谢大神

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注