5-->详解《switch 数据接收驱动框架、mtk7621集成交换芯片mt7530》之一

一、 MTK7621 网络通讯原理简述

本篇博文分析的是mtk7621的芯片所内嵌的交换芯片mt7530的驱动程序,MTK7621采用内部的 MDIO 接口管理MT7530 的 switch 芯片;MT7530包含多个7个 PHY 接口,其中第7个口连接到MTK7621芯片的eth0网口。MTK7621通过MDIO 进行寄存器读写配置使用,逻辑框图如下。

                                            ------------------
                                            |  CPU /mtk7621  |
                                            |   -----------  |
                                            |   | MAC/ephy   |  
                                            |___|__||_____|__|
                                                   ||                           
                                            RGMII/ ||  RXP/TXP
                                            MII    ||
                                                   ||
   ------------------------------------------------||--------- 
   |   Switch  MT7530                              ||        |
   |                                               ||        |
   |                                               ||        |
   |   |-----|   |-----|   |-----|   |-----|    |-----|      |
   ____|_____|___|_____|___|_____|___|_____|____|_____|______|
         PHY1      PHY2      PHY3      PHY4      PHY/MAC

二、通过设备树看 MT7530 交换芯片

  • 1.linux 内核源码相对路径:
OpenWrt/mtk7621-19.07/build_dir/target-mipsel_24kc_musl/linux-ramips_mt7621/linux-4.14.200
  • 2.设备树文件相对路径:
/OpenWrt/mtk7621-19.07$ ls target/linux/ramips/dts/ |grep 7621
AP-MT7621A-V60.dts
MT7621.dts
mt7621.dtsi
U7621-06-256M-16M.dts
U7621-06-256M-64M.dts
U7621-06-512M-64M.dts
U7621-06.dtsi
  • 3.mt7621.dtsi 文件内容
    文件名称: target/linux/ramips/dts/mt7621.dtsi
 ethernet: ethernet@1e100000 {
                compatible = "mediatek,mt7621-eth";   # 对应的驱动程序 soc_mt7621.c 文件中
                reg = <0x1e100000 0x10000>;
                #address-cells = <1>;
                #size-cells = <1>;
                resets = <&rstctrl 6 &rstctrl 23>;
                reset-names = "fe", "eth";
                interrupt-parent = <&gic>;
                interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>;

                mediatek,switch = <&gsw>;  #交换芯片 mt7530

                mdio-bus {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        phy1f: ethernet-phy@1f {  # 内部 MDIO 总线描述
                                reg = <0x1f>;
                                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 {
                compatible = "mediatek,mt7621-gsw";   # 对应驱动程序 gsw_mt7621.c 文件中。
                reg = <0x1e110000 0x8000>;
                interrupt-parent = <&gic>;
                interrupts = <GIC_SHARED 23 IRQ_TYPE_LEVEL_HIGH>;
        };
  • 4.驱动文件位置
    检索驱动文件: $ ls drivers/net/ethernet/mediatek/
built-in.o    gsw_mt7620.c  mdio.c         mdio_rt2880.h    mtk_debugfs.o  mtk_offload.h  soc_rt3050.c
esw_rt3050.c  gsw_mt7620.h  mdio.h         modules.builtin  mtk_eth_soc.c  mtk_offload.o  soc_rt3883.c
esw_rt3050.h  gsw_mt7621.c  mdio_mt7620.c  mt7530.c         mtk_eth_soc.h  soc_mt7620.c
ethtool.c     gsw_mt7621.o  mdio_mt7620.o  mt7530.h         mtk_eth_soc.o  soc_mt7621.c
ethtool.h     Kconfig       mdio.o         mt7530.o         mtk-eth-soc.o  soc_mt7621.o
ethtool.o     Makefile      mdio_rt2880.c  mtk_debugfs.c    mtk_offload.c  soc_rt2880.c

三、网口与交换芯片如何关联起来? 网口驱动加载。

MT7621 的片上网口驱动 soc_mt7621.c 文件中,eth 驱动方法结构体定义如下:

static struct fe_soc_data mt7621_data = {
	.init_data = mt7621_init_data,           /*  芯片初始化  */
	.reset_fe = mt7621_fe_reset,
	.set_mac = mt7621_set_mac,
	.fwd_config = mt7621_fwd_config,         /* Vlan 转发配置    */
	.tx_dma = mt7621_tx_dma,
	.switch_init = mtk_gsw_init,            /*  关联 MT7530 交换芯片,初始化配置         */
	.switch_config = mt7621_gsw_config,     /*  配置 MT7530 芯片、并 probe MT7530 驱动 */
	.reg_table = mt7621_reg_table,
	.pdma_glo_cfg = FE_PDMA_SIZE_16DWORDS,
	.rx_int = RT5350_RX_DONE_INT,
	.tx_int = RT5350_TX_DONE_INT,
	.status_int = (MT7621_FE_GDM1_AF | MT7621_FE_GDM2_AF),
	.checksum_bit = MT7621_L4_VALID,
	.has_carrier = mt7620_has_carrier,      /* mdio_mt7621.c 状态检测 */
	.mdio_read = mt7620_mdio_read,          /* mdio 总线读取操作   */
	.mdio_write = mt7620_mdio_write,        /* mdio 总线写操作     */
	.mdio_adjust_link = mt7620_mdio_link_adjust, /* mdio_mt7621.c 连接检测 */
};
/* mtk7621-eth 驱动程序入口处 */
const struct of_device_id of_fe_match[] = {
	{ .compatible = "mediatek,mt7621-eth", .data = &mt7621_data },
	{},
};
MODULE_DEVICE_TABLE(of, of_fe_match);

mtk7621 片上的eth驱动就包含这 switch 芯片的驱动内容, mt7530 的驱动挂载是由 mt7621_gsw_config 函数触发。
在这里插入图片描述
由源码调用关系,mt7530操作函数主要是 vlan 和 port 的操作,如:mt7530_get_vlan_ports 函数,最终调用 mdiobus_read/mdio_write 函数实现操作内部芯片mt7530 的目的。

switch 交换芯片驱动加载

mtk7621 片上交换芯片设备名称mt7621-gsw ,驱动程序 gsw_mt7621.c 文件中。

   gsw: gsw@1e110000 {
                compatible = "mediatek,mt7621-gsw";   # 对应驱动程序 gsw_mt7621.c 文件中。
                reg = <0x1e110000 0x8000>;
                interrupt-parent = <&gic>;
                interrupts = <GIC_SHARED 23 IRQ_TYPE_LEVEL_HIGH>;
        };

在这里插入图片描述
mtk7621_gsw 驱动实现的是 gsw 设备实例 与 网口设备的绑定,卸载 mt7621-gsw 驱动,实际上是移除 gsw 与 网口间关系。

mt7621-eth 初始化分析
  • mt7621 驱动支持的芯片操作函数集合
static struct fe_soc_data mt7621_data = {
	.init_data = mt7621_init_data,
	.reset_fe = mt7621_fe_reset,
	.set_mac = mt7621_set_mac,
	.fwd_config = mt7621_fwd_config,
	.tx_dma = mt7621_tx_dma,
	.switch_init = mtk_gsw_init,                /* switch 芯片初始化 */
	.switch_config = mt7621_gsw_config,
	.reg_table = mt7621_reg_table,
	.pdma_glo_cfg = FE_PDMA_SIZE_16DWORDS,
	.rx_int = RT5350_RX_DONE_INT,
	.tx_int = RT5350_TX_DONE_INT,
	.status_int = (MT7621_FE_GDM1_AF | MT7621_FE_GDM2_AF),
	.checksum_bit = MT7621_L4_VALID,
	.has_carrier = mt7620_has_carrier,
	.mdio_read = mt7620_mdio_read,
	.mdio_write = mt7620_mdio_write,
	.mdio_adjust_link = mt7620_mdio_link_adjust,
};
  • mtk_gsw_init 初始化
int mtk_gsw_init(struct fe_priv *priv)
{
	struct device_node *np = priv->switch_np;
	struct platform_device *pdev = of_find_device_by_node(np);
	struct mt7620_gsw *gsw;

	if (!pdev)
		return -ENODEV;
	if (!of_device_is_compatible(np, mediatek_gsw_match->compatible))
		return -EINVAL;
	gsw = platform_get_drvdata(pdev);
	
/* 申请中断 */
	priv->soc->swpriv = gsw;
	if (gsw->irq) {
		request_irq(gsw->irq, gsw_interrupt_mt7621, 0,
			    "gsw", priv);
		disable_irq(gsw->irq);
	}
/* mt7621-hw 硬件初始化 */
	mt7621_hw_init(gsw, np);
	if (gsw->irq)
		enable_irq(gsw->irq);
	return 0;
}
  • 初始内容如下
static void mt7621_hw_init(struct mt7620_gsw *gsw, struct device_node *np)
{
	u32 i;
	u32 val;

	/* wardware reset the switch */
	fe_reset(RST_CTRL_MCM);
	mdelay(10);

	/* reduce RGMII2 PAD driving strength */
	rt_sysc_m32(3 << 4, 0, SYSC_PAD_RGMII2_MDIO);

	/* gpio mux - RGMII1=Normal mode */
	rt_sysc_m32(BIT(14), 0, SYSC_GPIO_MODE);

	/* set GMAC1 RGMII mode */
	rt_sysc_m32(3 << 12, 0, SYSC_REG_CFG1);

	/* enable MDIO to control MT7530 ,设置 MDIO 控制 MT7530 */
	rt_sysc_m32(3 << 12, 0, SYSC_GPIO_MODE);

	/* turn off all PHYs */
	for (i = 0; i <= 4; i++) {
		val = _mt7620_mii_read(gsw, i, 0x0);
		val |= BIT(11);
		_mt7620_mii_write(gsw, i, 0x0, val);
	}

	/* reset the switch */
	mt7530_mdio_w32(gsw, 0x7000, 0x3);
	usleep_range(10, 20);

	/* (GE1, Force 1000M/FD, FC OFF, MAX_RX_LENGTH 1536) */
	mtk_switch_w32(gsw, 0x2305e30b, GSW_REG_MAC_P0_MCR);
	mt7530_mdio_w32(gsw, 0x3600, 0x5e30b);

	/* (GE2, Link down) , 关闭 GE2 口,此接口暂时未使用 */
	mtk_switch_w32(gsw, 0x8000, GSW_REG_MAC_P1_MCR);

	/* Set switch max RX frame length to 2k */
	mt7530_mdio_w32(gsw, GSW_REG_GMACCR, 0x3F0B);

	/* Enable Port 6, P5 as GMAC5, P5 disable */
	val = mt7530_mdio_r32(gsw, 0x7804);
	val &= ~BIT(8);
	val |= BIT(6) | BIT(13) | BIT(16);
	mt7530_mdio_w32(gsw, 0x7804, val);

	val = rt_sysc_r32(0x10);
	val = (val >> 6) & 0x7;
	if (val >= 6) {
		/* 25Mhz Xtal - do nothing */
	} else if (val >= 3) {
		/* 40Mhz */

		/* disable MT7530 core clock */
		_mt7620_mii_write(gsw, 0, 13, 0x1f);
		_mt7620_mii_write(gsw, 0, 14, 0x410);
		_mt7620_mii_write(gsw, 0, 13, 0x401f);
		_mt7620_mii_write(gsw, 0, 14, 0x0);
        /* 省略部分代码 */ 
	} else {
		/* 20Mhz Xtal - TODO */
	}

	/* RGMII */
	_mt7620_mii_write(gsw, 0, 14, 0x1);

	/* set MT7530 central align */
/* 省略部分代码 */ 
	/* delay setting for 10/1000M */
/* 省略部分代码 */ 
	/* lower Tx Driving*/
/* 省略部分代码 */ 

	/* turn on all PHYs */
	for (i = 0; i <= 4; i++) {
		val = _mt7620_mii_read(gsw, i, 0);
		val &= ~BIT(11);
		_mt7620_mii_write(gsw, i, 0, val);
	}

	/* enable irq ,打开中断接收允许  */
	mt7530_mdio_w32(gsw, 0x7008, 0x1f);
	val = mt7530_mdio_r32(gsw, 0x7808);
	val |= 3 << 16;
	mt7530_mdio_w32(gsw, 0x7808, val);
}

本篇描述 mtk7621 芯片 eth 网口、switch交换芯片之间关系,驱动加载关系;在此 mtk7621 具备数据接收与发送功能,下一篇分享网络协议栈数据接收过程

当开启 switch 交换口时(例如,通过 ifconfig eth0.2 up),mtk7621_ops 中的 mt7530_set_port 方法会被调用;设置端口、配置vlan 的 vid 号等操作,与mtk7621_ops各方法对应。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值