我是靠谱客的博主 醉熏龙猫,最近开发中收集的这篇文章主要介绍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各方法对应。

最后

以上就是醉熏龙猫为你收集整理的5-->详解《switch 数据接收驱动框架、mtk7621集成交换芯片mt7530》之一的全部内容,希望文章能够帮你解决5-->详解《switch 数据接收驱动框架、mtk7621集成交换芯片mt7530》之一所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部