RK3568+YT9215交换芯片调试实战:从硬件检查到吞吐优化
简介:面向嵌入式驱动开发工程师,这份资源聚焦瑞芯微RK3568与YT9215交换机芯片的驱动配置与调试,适合需要快速理解硬件接口选型、Linux驱动框架以及数据包收发链路的开发者参考,尤其是正从事智能电视盒、工业控制、网络设备等相关项目的软硬件人员。压缩包共2个文件,核心为1个C源文件和1个头文件,整体仅4KB,代码量精简却覆盖设备初始化、寄存器配置、读写操作及中断处理等关键驱动模块,便于直接阅读、移植或作为调试基线。目前已有4836人学习下载,具有不错的参考热度。借助其中结构体定义与函数实现,读者能理清RK3568与YT9215之间的通信机制,并快速定位驱动调试中的常见问题,为后续性能优化和功能扩展提供清晰起点,也可在此基础上结合内核日志、GDB等工具做进一步验证。 干嵌入式这几年,凡是要做网关、工业路由板,"主控SoC + 交换芯片"这套组合就是绕不开的活儿。这次调的是瑞芯微 RK3568 配上裕太微 YT9215,上板之后从硬件检查到内核 DTS 配置,再到跑吞吐、查丢包,前前后后折腾了小两周。这篇文章不打算铺背景,直接把我调试 YT9215 交换机芯片时踩过的坑、验证过的做法、以及排查思路写出来,给正在做 RK3568 方案或者同类"多网口产品"的兄弟一个参考。
先说项目场景:板子上需要提供 8 个千兆网口,RK3568 本身只有两个 GMAC,一个口负责接外网,另一个口要扩展出 8 口切换到内部局域网,于是选了 YT9215 这颗交换芯片。它内部集成了交换核心和多个 PHY,对外提供一个 RGMII 或者 SGMII/QSGMII 的上行接口,主控只需要把一个 GMAC 口接过去,剩下的 8 个电口全交给交换芯片管,CPU 负载和外围器件数量都能压下来。
1. 项目整体思路与方案选型
1.1 为什么选 RK3568 + YT9215 这套组合
RK3568 相信大家不陌生,四核 Cortex-A55,带双千兆 GMAC,跑 Linux 或者 OpenHarmony 都行,最大的优势是外设接口全、功耗适中、成本可控。但真正做网络设备的人都知道,RK3568 原生只能出两路 GMAC,一旦产品要出 4 口、8 口甚至更多网口,就必然要外接交换芯片。
YT9215 在工业以太网领域不算新面孔了,我选择它有几个原因:一是裕太微这颗芯片是纯国产方案,供货和资料都好谈;二是它内部自带了交换核心和 PHY,不像有些方案还要外挂独立的 PHY,外围电路能省不少;三是对外支持 RGMII/SGMII/QSGMII 多种上行模式,和 RK3568 的 GMAC 对接非常灵活。
选型这里我要特别给一个建议:不要只盯着芯片手册上写支持多少口。真正要做方案选型,必须先想清楚"数据面上去之后,CPU 要不要参与转发"。如果只是局域网内部交换,YT9215 这种硬交换芯片完全够用,CPU 几乎不参与;如果要做三层路由、ACL、QoS 这类功能,就得确认交换芯片本身支不支持硬件加速,或者 CPU 上行带宽够不够。我这次项目其实只需要二层交换,CPU 只负责一个外网上行口和 web 管理面,所以 YT9215 的架构完全够用。
1.2 接口关系与系统架构
从硬件拓扑上看,RK3568 的 GMAC1 接到 YT9215 的上行口,两者之间用 RGMII 连接,四根数据线 TXD[3:0]、RXD[3:0] 加上 TXC、RXC、TX_CTL、RX_CTL,一共 12 根信号线。YT9215 的 MDC/MDIO 也接到 RK3568 的 GMAC1 对应引脚上,这样内核可以直接通过 MDIO 总线去读交换芯片的 PHY 寄存器。
这里要注意一个问题:YT9215 实际上会向上行口暴露出来的是某个内部 PHY 的地址,而它的 8 个下联口,则是另外的 PHY 地址。对我而言,主控内核只关心上行口这一个"虚拟 PHY",只要这个 PHY 能 link up,数据通路就通了。其余的交换配置,比如 VLAN、端口隔离、镜像,通常是 YT9215 内部的管理接口(通过 MDIO 写私有寄存器)来做,不是标准 PHY 驱动的职责范围。
系统框图这部分不用画得太复杂,脑子里有个概念就行:CPU(RK3568 GMAC1) ➜ RGMII ➜ YT9215 上行口 ➜ 内部交换核心 ➜ 8 个下联电口。数据走的是硬交换,CPU 不逐包处理。
2. 硬件检查:上电时序、复位和 MDIO 地址
2.1 上电时序和复位引脚控制
硬件坑永远是调试的第一道坎,尤其是交换芯片这种大器件,上电时序不对,后面软件再怎么改也白搭。YT9215 的复位脚、时钟、电源域必须按规格书时序来。我当时拿到第一版板子,现象是内核 MDIO 完全读不到 YT9215 的 PHY ID,用示波器抓复位脚,发现复位释放时间和电源稳定之间差了不止一个数量级,导致芯片根本没正确启动。
实践的结论是:YT9215 的复位最好用一颗 GPIO 控制,不要直接挂在 RC 复位电路上。这样软件在初始化时可以主动控制复位时序。我在 RK3568 的 DTS 里给复位脚申请了一个 GPIO,uboot 起来之后先拉低复位至少 10ms,再拉高,然后等 100ms 左右再操作 MDIO。这个时序要求是裕太微规格书里明确写的,实际调试中把它做成了固定的初始化流程。
时钟方面也要注意:YT9215 需要一路 25MHz 的参考时钟,可以来自有源晶振,也可以由 RK3568 的 GMAC 时钟输出提供。我最初想省一个晶振,让 RK3568 的 clk 输出 25MHz 给交换芯片,结果发现 RGMII 的时钟抖动参数不过关,低速通信看着能通,跑 iperf 多线程时丢包率明显偏高。后来老老实实加了颗 25MHz 有源晶振给 YT9215,问题才消停。涉及高速接口,时钟源稳不稳,直接影响整条链路的信号质量,别省这个成本。
2.2 MDIO 地址配置与上下拉电阻
MDIO 能不能扫到 PHY,最先要确认的就是 PHY 地址。YT9215 的 PHY 地址通常由外部引脚的电平配置决定。按照规格书,把地址引脚按需上拉或下拉,我板子上把上行口 PHY 地址配成了 0x04。
这里有个隐蔽问题:RK3568 GMAC1 的 MDIO 总线如果同时还挂了别的 PHY,比如有人会把外网口的 PHY 也挂在同一条 MDIO 上,要注意地址冲突。YT9215 内部有 8 个下联口 PHY,它们也有各自的地址段。调试初期我直接用 uboot 的 mii 命令扫描了一遍 0-31 地址,结果扫出来一串 PHY ID,一度以为芯片挂了。其实是它内部所有 PHY 都共享同一条 MDIO,扫描器把它们全部列出来了。不要惊慌,确认上行口对应的 PHY 地址能读到 ID 即可。
MDIO 的 MDC 时钟频率建议在调试初期放低一点,比如 2.5MHz 左右。RK3568 的 GMAC 驱动会默认配置 MDC 分频,如果 MDIO 线上的寄生电容比较大、上拉阻值偏高,高速模式容易误码。我当时在 uboot 里直接用 mii 命令,发现有些地址读出来只是偶尔成功,降低 MDC 频率之后稳定多了。
2.3 中断脚与灯控
YT9215 还有一个 link 状态变化中断脚,可以接到 RK3568 的 GPIO 上,这样网线插拔时内核能感知到状态变化。但看不少现成方案里,这个中断并不接,而是靠内核 PHY 驱动轮询。原因很简单:交换芯片和 PHY 的中断处理机制比较烦,8 个口的状态变化会聚合成同一个中断事件,CPU 去读 status 寄存器区分是哪个口变的,反而比轮询更麻烦。
我这次没有用中断,内核里就是常规的 PHY 轮询,状态变化延迟 1-2 秒,对产品来说完全够用。如果你非要接中断,记得确认 GPIO 的中断触发类型,YT9215 这里一般是下降沿触发,而且必须把中断脚配置成输入、使能内部上拉,防止浮空误触发。
3. Linux 内核设备树配置与驱动适配
3.1 GMAC 节点与 MDIO 配置
设备树是 RK3568 平台绕不开的一环。RK3568 有两个 GMAC:gmac0 和 gmac1。我这次把 gmac1 接 YT9215,gmac0 留着接外网。DTS 里最关键的就是 phy-mode、phy-handle、以及 mdio 子节点。
以我的实际配置为例:
&gmac1 {
status = "okay";
phy-mode = "rgmii";
phy-handle = <&yt9215_phy>;
snps,reset-gpio = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>;
snps,reset-delay-us = <10000>;
snps,reset-active-low;
tx-internal-delay-ps = <2000>;
rx-internal-delay-ps = <2000>;
mdio {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
yt9215_phy: ethernet-phy@4 {
reg = <4>;
};
};
};
这里有几个点要说明。phy-mode 必须和硬件实际接线一致,如果是 RGMII,RK3568 会按 RGMII 的时序来驱动信号。YT9215 上行口工作在 RGMII 模式时,硬件上不要忘了做 2ns 左右的 delay 补偿,这个 delay 可以在 PCB 布线时通过走线长度实现,也可以在 DTS 里配 tx/rx-internal-delay-ps。我这边板上没走等长差分 delay,全靠 DTS 配了 2000ps,实测也能工作,但不建议完全依赖内部 delay,最好还是硬件上预留调节电阻。
3.2 RGMII 的 delay 配置到底怎么定
RGMII 调试最容易翻车的就是 TXC/RXC 的 delay。RGMII 协议本身要求数据相对于时钟有一个 2ns 的偏移,通常由发送端在时钟上做 delay(PCB 走线或芯片内部)。如果 delay 没配对,现象非常有迷惑性:千兆模式下 ping 不出去,自己看寄存器 link 又是 up 的;降成百兆反而正常。
我建议的排查顺序:先强制千兆模式,然后单独试一组 delay 参数组合。RK3568 的 GMAC 支持在 DTS 里配置 tx-internal-delay-ps 和 rx-internal-delay-ps,我这里的经验值是 2000ps 起步,如果本地 ping 小包偶尔超时,就试着加大到 2500ps,或者减小到 1500ps。最直接的方式是用电阻在板上预留 delay 选项——用 0 欧电阻选择时钟线上是否串电阻来加 delay,这样调试时不用反复改 DTS 重新编译,直接焊电阻试。
另外特别注意:RK3568 的两个 GMAC 对 delay 的处理方式不完全一样,gmac0 和 gmac1 的时钟树独立,不能用同一个参数盲目套用。我这次调试时把 gmac0 外网口的 delay 参数复制到 gmac1 上,结果整个链路跑不起来,白白浪费了半天。
3.3 内核识别 PHY ID 的确认方法
DTS 配好之后,别急着直接进系统,先在 uboot 里确认 MDIO 通信是否正常。RK3568 的 uboot 自带 mii 命令,操作很简单:
mii info
mii read 4 2
mii read 4 3
mii read 4 2 和 4 3 分别读 PHY 的 ID 寄存器 2 和 3。如果是 YT9215,读出来的 ID 应该和规格书一致。注意不同芯片型号的 ID 可能有差异,能读到非 0xffff、非 0x0000 的稳定值,基本就说明 MDIO 通路已经通了。
如果这里读不到,不用急着往下看驱动问题,回到硬件检查:复位先做一遍、MDC 频率降一降、确认 MDIO 上拉电阻没焊错。MDIO 调试我认为是整块板子最基础的"体检项目",这里过了,后面内核起来才有谱。
4. 调试过程实录:从系统起来到打满千兆
4.1 内核日志与 ethtool 现象观察
设备树和驱动都就绪后,启动内核,重点观察 dmesg 里 GMAC 的初始化日志。正常情况应该能看到类似 "stmmaceth ... eth0: Link is Up - 1Gbps/Full" 的打印。如果 Link 一直 up 不起来,先用 ethtool eth0 看 speed 和 duplex:
ethtool eth0
这里我想提醒一个容易忽视的点:YT9215 作为交换芯片,它的上行口默认很可能是通过内部寄存器配置的静态模式,不会像普通 PHY 那样去自动协商。也就是你要先通过 MDIO 把上行口的工作模式强制成 1Gbps Full、和主控侧一致,然后内核这条链路才能协商成功。我一开始没往这个方向想,以为 PHY 驱动会自动处理协商,结果 ethtool 一直显示 100Mbps 甚至 down。后来在 uboot 初始化脚本里先通过 mii 写 YT9215 的私有寄存器,把上行口强制设成 1Gbps Full,再启动内核,一切正常。
4.2 网络吞吐与丢包验证
链路通了只是开始,真正验证这套方案能不能用,还得上 iperf。我用一台 PC 直连 YT9215 的某个下联口,板子上行口连 RK3568,然后分别测上行、下行和双向吞吐:
iperf3 -s # 在 RK3568 板上运行
iperf3 -c <板子IP> # 在 PC 上运行
单线程 UDP 测试时,我发现一旦速率超过 600Mbps,丢包就开始明显。排查了好久,最后定位到 RK3568 的 GMAC1 DMA 接收描述符数量不够。默认内核配置可能只分配了 256 个 descriptor,在高速 UDP 小包场景下 CPU 处理不过来,就会丢包。把内核里 stmmac 的 RX descriptor 数量调大,或者开启 RPS(Receive Packet Steering),问题立刻缓解。
如果是 TCP 吞吐上不去,优先看中断绑定。RK3568 的 GMAC 中断默认都打在一个 CPU 核上,多队列能力一般,跑满千兆时单核会接近 100%。解决办法一个是打开网卡的 multi-queue,另一个是给中断绑定到多个核。数据面性能优化是个系统工程,但第一步永远是确认瓶颈在 CPU 还是 DMA,别一上来就怀疑交换芯片。
4.3 交换机芯片私有寄存器调试
YT9215 的私有寄存器操作是实现"交换功能"的核心。厂商 SDK 或驱动手册里会提供一段通过 MDIO 写私有寄存器的方法,主要是写扩展寄存器:
- 先往地址寄存器写入目标寄存器地址
- 再往数据寄存器写入数值
- 读操作同理
这套机制和标准 PHY 寄存器访问是分开的。我平时调试喜欢直接在 uboot 里写一个简短的 mii 操作脚本,把常用初始化序列固化下来,比如关闭或开启某个下联口、设置 VLAN 端口成员、设置上行口强制速率。这样在 uboot 阶段就能把交换芯片初始化好,再进内核验证整机功能,出现问题时可以直接排除系统驱动的干扰。
如果你拿到的 SDK 不方便移植到内核,可以用一个更简单的方案:在 uboot 引导阶段用一串 mii 命令初始化交换芯片。虽然看起来不够优雅,但在产品开发早期做功能验证非常高效。等系统跑稳了,再考虑把初始化逻辑移植到内核驱动里。
4.4 我遇到的典型问题与排查记录
为了让你少走弯路,我把这次调试过程中遇到的几个问题整理成了表,方便对照:
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| MDIO 读不到 YT9215 任何寄存器 | 复位未释放、MDC 频率过高、地址引脚配置错 | 检查复位时序、降低 MDC 频率、核对地址引脚电平 |
| PHY ID 能读到,但内核 link 一直 down | 上行口工作模式未强制、RGMII delay 不匹配 | 先通过 MDIO 强制上行口 1Gbps Full,再试 delay 参数 |
| 网线插上后 link 状态响应慢 | 未接中断、轮询间隔太长 | 属正常现象,可接受;也可选择接 link 中断脚 |
| 千兆模式下 ping 丢包,百兆正常 | RGMII TXC/RXC delay 不对 | 逐个调整 tx/rx-internal-delay-ps,配合示波器看眼图 |
| 高速 UDP 大量丢包 | DMA descriptor 不足或 CPU 单核瓶颈 | 增大 RX descriptor、开启 RPS、绑定中断到多核 |
| 双向吞吐远低于千兆 | 硬件信号质量差、时钟抖动大 | 检查 25MHz 晶振质量、RGMII 走线阻抗、delay 参数 |
4.5 设备树选择与多平台适配的额外提醒
既然热搜里提到"OpenHarmony 的 RK3568 有许多设备树到底咋选",这里多聊两句。RK3568 的平台代码里通常会带多个板级 DTS,比如 EVB、NVR、Tablet 等,它们的差异主要是外设引脚复用和电源配置不一样。你拿到的开发板或者项目底板,设备树不能随便选,必须对照原理图确认 gmac、mdio、gpio、电源等引脚复用是否匹配。
我自己调试时就犯过一个低级错误:选了个默认 NVR 的 DTS,结果 GMAC1 的 TXD/RXD 引脚被复用成了其他功能,导致 MDIO 上电时序都正常,就是数据线不通。这个排查花了大半天,最后回到 trm 引脚复用表才发现是设备树选错了。
如果你的项目也是从参考板改的,建议从头到尾梳理一遍:把原理图里所有用到的外设引脚,在 DTS 的 pinctrl 节点里逐个核对。宁可多花两小时核引脚,也别等板子起不来再一根一根量线。
5. 调试工具和高效工作流
5.1 串口与网络层面的快速验证
调试这类网络设备,串口是命脉。我用的是 SecureCRT 的串口会话,波特率 115200,连 RK3568 的调试串口。这里有个小经验:uboot 阶段和内核阶段最好用同一个串口会话,方便完整看启动日志。早期你需要在 uboot 和内核之间反复切换配置,如果串口拔来拔去,特别容易漏掉关键日志。
内核起来之后,网络验证我习惯先看最简单的状态:
ip link
ping -c 4 <peer_ip>
ping 通了再上 iperf。很多人一上来就跑 iperf,结果链路本身就是时通时断的,最后花了大把时间查性能问题,其实是物理层的问题。基础验证一定要按步骤来。
5.2 Linux 下 MDIO 读写的小工具
除了 ethtool,Linux 下还有一个好用的工具叫 mdio-tools,能在用户态直接读写 MDIO 寄存器,比反复改内核驱动方便得多。在板子上装好后,可以这样验证:
mdio read eth0 0x04 0x02
mdio write eth0 0x04 0x00 0x1000
它的好处是支持直接写 YT9215 的私有寄存器访问序列,调试交换芯片配置非常直观。如果你要快速验证某个寄存器的作用,不用重编内核,一条命令就搞定。我在调 YT9215 的私有寄存器时,基本就是靠这个工具和 uboot 的 mii 命令双管齐下。
5.3 抓包和日志的思路
网络功能调通之后,最好把抓包工具也准备好。如果 RK3568 上不方便跑图形化 Wireshark,可以用 tcpdump 配合 PC 端 Wireshark 分析。我之前遇到一个"疑似丢包"的问题,tcpdump 抓下来看 PC 端明明收到了数据,应用层统计却少了,后来发现是应用层收包缓冲区太小导致的,跟链路无关。
这类问题的排查逻辑很简单:先确认链路层丢没丢,再确认 socket 层丢没丢。不要一看到"丢包"就怪交换芯片和驱动。链路层可以用 tcpdump 统计收到的包数,和 iperf 报出的包数做对比,就能定位到底丢在哪一段。
6. 经验总结与个人体会
这次 RK3568 和 YT9215 的调试,虽然中间遇到不少坑,但整体走完之后,我对"主控+交换芯片"这套组合的理解又深了一层。
核心体会有三点:
第一,硬件基础决定软件上限。上电时序、时钟质量、RGMII delay 这些硬件层面的东西,每一项都会在后续调试中以各种奇怪的方式冒出来。如果硬件设计阶段能多做一点预留,比如通过电阻配置 delay、通过 GPIO 控制复位、把 MDIO 上拉电阻留在板上,后面软件调试会轻松很多。
第二,分层的排查逻辑永远是最有效率的。从 MDIO 读寄存器开始,到 link up,再到吞吐性能,一步一步来,每一步确认无误后再进入下一步。跳过链路层直接调性能,是最容易浪费时间的方式。我这次在 UDP 丢包上就吃过这个亏,一开始怀疑交换芯片性能,折腾了一圈才发现是 CPU 侧 DMA 配置的问题。
第三,厂商 SDK 和内核控制面的平衡很重要。YT9215 这类交换芯片的私有配置,不需要也不建议一股脑全塞进内核 PHY 驱动里。功能验证阶段在 uboot 里用 mii 命令做初始化,产品化阶段再把稳定可靠的初始化序列移植成内核驱动或者用户态工具管理,维护成本会低很多。尤其涉及 VLAN、端口镜像这类业务功能,用一个用户态管理程序去控制交换芯片,比塞在驱动里更灵活。
如果你也在做类似的 RK3568 多网口方案,或者正在纠结 YT9215 的调试问题,希望这篇文章里的细节能帮上忙。踩坑不可怕,可怕的是踩完之后记录下来的步骤不够清晰。我这套流程基本是通用的:先确认硬件时序,再用 MDIO 读寄存器建立基准,然后调设备树让内核识别,最后做性能验证。按照这个顺序来,大多数问题都能被拆解成一个个可定位的小问题。
最后再分享一个小技巧:调试 RGMII 信号质量,有条件的话上个示波器看眼图,比盲改 delay 参数有效率得多。没示波器的情况下,就把 delay 参数做成可配置的,编译一次内核,用 ethtool 配合 mdio-tools 反复试组合,也能找到可用的工作点。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)