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里应该怎么配置?
    拆机的主要芯片图片在数码之家有

    谢谢大神

发表评论

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