1. 项目缘起与整体方案拆解
RK3588 这颗芯片在嵌入式圈子里火了好几年,八核 A76/A55 架构、6TOPS NPU、多路 PCIe 和以太网控制器,做边缘计算网关、NVR、工业控制板几乎是首选。但真到产品落地阶段,很多人会卡在一个看似简单的地方:板子本身只有一个千兆网口,项目却要求四个千兆口做交换。这时候就得外挂交换芯片,而 TRL8367s 是 Realtek 家族里被大量采用的一颗 8 口千兆交换芯片,支持二层转发、VLAN、QoS,性价比高,资料也相对好找。
我这次做的项目是一台工业边缘网关,主控 RK3588,通过 RGMII 接口挂了一颗 TRL8367s,对外提供四个千兆网口。需求很明确:四个口之间要能二层互通,同时其中一个口要能和 RK3588 的 CPU 侧通信,让上层系统能管理这台设备。听起来不复杂,但实际调试过程中,DTS 配置、PHY 地址、RGMII 时序、二层模式这几个环节任何一个出问题,都会导致网络不通或者丢包严重。
这篇文章我会把整个实战过程拆开讲,从硬件连接到 DTS 配置,再到二层模式的原理和验证方法,尽量把每一步的“为什么”说清楚。适合正在用 RK3588 做多网口方案的嵌入式工程师,也适合对交换芯片配置感兴趣的网络方向开发者。即使你用的是其他主控或交换芯片,思路也是通用的。
先说一下整体架构。RK3588 的 GMAC 控制器通过 RGMII 总线和 TRL8367s 的某个端口相连,这个端口在交换芯片内部被配置为“CPU 口”或者叫“上行口”。TRL8367s 的其余端口接外部 RJ45。数据流向是这样的:外部设备从某个网口进来,交换芯片根据 MAC 地址表决定是转发到另一个外部口,还是送到 CPU 口交给 RK3588 处理。二层模式的意思是交换芯片自己完成 MAC 学习和转发,不需要 CPU 参与每个包的处理,这样吞吐能跑满千兆,CPU 占用也低。
为什么选二层模式而不是三层?因为三层路由需要 CPU 参与路由决策,RK3588 虽然性能强,但四个千兆口全速跑三层转发,CPU 负载会很高,而且延迟不稳定。二层交换是硬件转发,延迟低、吞吐高,适合做纯交换或者桥接场景。如果项目需要跨网段路由,那可以在 RK3588 上做,但那是另一个话题了。
2. 硬件连接与关键信号确认
2.1 RGMII 接口的引脚映射
RK3588 的 GMAC 支持 RGMII、RMII、SGMII 等多种模式,我们用的是 RGMII,因为千兆速率下 RGMII 只需要 12 根信号线,比 GMII 的 24 根省一半引脚。RGMII 的关键信号包括:
- TXD[3:0]:发送数据,4 位
- TXC:发送时钟,125MHz
- TX_CTL:发送控制,复用为 TXEN 和 TXERR
- RXD[3:0]:接收数据
- RXC:接收时钟
- RX_CTL:接收控制,复用为 RXDV 和 RXERR
- MDC/MDIO:管理接口,用于配置 PHY 和交换芯片寄存器
这里有个容易踩的坑:RGMII 的时钟延迟模式。RGMII 有两种时序模式,一种是时钟和数据同时输出,接收端自己延迟采样;另一种是发送端延迟时钟,接收端用延迟后的时钟采样。RK3588 的 GMAC 和 TRL8367s 都支持内部延迟,但两边必须匹配。我见过有人两边都开了延迟,结果数据采样错位,ping 都通不了。
实际连接时,RK3588 的 GMAC1 接到 TRL8367s 的 Port 6,这个端口在芯片内部默认就是 RGMII 接口。TRL8367s 的 Port 0 到 Port 4 是内置 PHY 的千兆口,可以直接接 RJ45。Port 5 和 Port 6 是 RGMII/SGMII 复用,我们只用 Port 6 做 CPU 口,Port 5 悬空。
2.2 复位与时钟电路
TRL8367s 需要一个 25MHz 晶振作为参考时钟,内部 PLL 倍频到 125MHz 给 RGMII 用。复位引脚要接 RK3588 的一个 GPIO,上电后拉低至少 10ms 再拉高,确保芯片完成内部初始化。这个复位时序很关键,如果复位时间不够,芯片可能工作不稳定,表现为部分端口不通或者丢包。
我用的复位 GPIO 是 GPIO3_A6,在 DTS 里配置为输出,默认拉高,驱动加载时先拉低再拉高。实测下来,复位脉冲宽度给 20ms 比较稳妥,datasheet 写的是最小 10ms,但留点余量没坏处。
MDC/MDIO 总线上,TRL8367s 的 PHY 地址由硬件引脚决定。Port 0 到 Port 4 的 PHY 地址通常是 0 到 4,CPU 口 Port 6 的地址可能是 6 或者 0x1C,具体看芯片的 strapping 引脚。我这块板子 Port 6 的地址是 6,所以在 DTS 里要写对,否则 MDIO 读不到寄存器。
3. DTS 配置详解与逐行解析
3.1 GMAC 节点配置
RK3588 的 DTS 里,GMAC 节点需要配置 PHY 模式、时钟、引脚复用等。下面是我实际用的配置片段:
&gmac1 { phy-mode = "rgmii-id"; clock_in_out = "output"; snps,reset-gpio = <&gpio3 RK_PA6 GPIO_ACTIVE_LOW>; snps,reset-active-low; snps,reset-delays-us = <0 20000 100000>; assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1>; assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>, <&cru SCLK_GMAC1>; pinctrl-names = "default"; pinctrl-0 = <&gmac1_miim &gmac1_tx_bus2 &gmac1_rx_bus2 &gmac1_rgmii_clk &gmac1_rgmii_bus>; tx_delay = <0x2a>; rx_delay = <0x1a>; phy-handle = <&rgmii_phy>; status = "okay"; };逐行解释一下。phy-mode = "rgmii-id"表示 RGMII 模式,并且 PHY 侧内部延迟(id 是 internal delay 的缩写)。这里要注意,RK3588 的 GMAC 驱动会根据这个属性决定是否启用内部延迟。如果写成rgmii,两边都不延迟,那就要靠 PCB 走线等长来保证时序,一般不建议。
clock_in_out = "output"表示 GMAC 输出时钟给 PHY,也就是 RK3588 提供 TXC 和 RXC。有些设计是 PHY 提供时钟,那就写input。这个要根据硬件设计来,写反了时钟就没有。
snps,reset-gpio和snps,reset-delays-us是复位时序,<0 20000 100000>表示延时 0us 拉低,20000us 后拉高,再等 100000us 后访问 PHY。这个延时给足,避免 PHY 还没准备好就被访问。
tx_delay和rx_delay是 RGMII 的延迟值,单位是 0.1ns 左右,具体看 RK3588 的 TRM。我实测下来 tx_delay 给 0x2a、rx_delay 给 0x1a 比较稳,但不同板子走线不同,这个值需要根据眼图或者丢包率来调。调的时候可以先从默认值开始,ping 大包看丢包,然后微调。
3.2 PHY 节点与 MDIO 配置
TRL8367s 的 CPU 口在系统里表现为一个 PHY,需要单独定义一个 PHY 节点:
&mdio1 { rgmii_phy: ethernet-phy@6 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <0x6>; realtek,led-link = <0x1>; realtek,led-act = <0x1>; }; };reg = <0x6>就是 PHY 地址,必须和硬件 strapping 一致。compatible用标准的 c22 就行,TRL8367s 的 CPU 口 PHY 寄存器兼容标准。LED 配置是可选的,根据实际需求来。
这里有个细节:TRL8367s 的 CPU 口在芯片内部其实是一个 RGMII 到交换核心的接口,但它对外表现为一个标准 PHY,有标准的 BMCR、BMSR 寄存器。所以 Linux 的通用 PHY 驱动能识别它,不需要额外写驱动。这也是选这颗芯片的原因之一,软件适配成本低。
3.3 交换芯片的 DSA 还是纯二层
这里要做一个关键决策:是用 DSA(Distributed Switch Architecture)框架,还是把交换芯片当成一个纯二层的黑盒,只通过 CPU 口通信?
DSA 的好处是每个外部口在 Linux 里都是一个独立的 netdev,可以做 VLAN、桥接、流量控制,管理粒度细。但 DSA 需要交换芯片驱动支持,TRL8367s 的 DSA 驱动在内核里是有的,但配置复杂,而且 RK3588 的 GMAC 和 DSA 的配合需要额外调试。
纯二层模式就简单多了:交换芯片自己完成二层转发,CPU 口就是一个普通的网口,Linux 看到的是 eth1 或者类似的设备。四个外部口之间的通信完全由芯片硬件处理,CPU 不感知。这种模式适合不需要精细管理的场景,配置简单,稳定性高。
我这次选的是纯二层模式,因为项目需求就是四个口互通,不需要 VLAN 隔离,也不需要每个口单独统计。如果你需要 VLAN 或者端口镜像,那还是得上 DSA。
4. 二层模式原理与寄存器配置
4.1 二层转发的基本流程
二层交换的核心是 MAC 地址表。芯片收到一个包,提取源 MAC 和目的 MAC,查表决定从哪个口转发。如果目的 MAC 在表里,就单播转发到对应口;如果不在,就泛洪到所有口(除了入端口)。同时,芯片会学习源 MAC 和入端口的对应关系,写入地址表。
TRL8367s 的地址表大小是 2K 条目,支持自动老化,默认老化时间是 300 秒。这些参数可以通过寄存器配置,但默认值一般够用。地址表的学习和老化都是硬件自动完成的,不需要 CPU 干预。
CPU 口在二层模式下的角色是:如果目的 MAC 是 RK3588 的 MAC,或者包需要上送 CPU(比如 ARP、DHCP),芯片会把包送到 CPU 口。反过来,RK3588 发出的包从 CPU 口进入芯片,芯片根据目的 MAC 决定从哪个外部口转发出去。
4.2 关键寄存器配置
TRL8367s 的寄存器分两类:PHY 寄存器和交换核心寄存器。PHY 寄存器通过 MDIO 访问,交换核心寄存器通过间接方式访问,先写地址寄存器,再读写数据寄存器。
二层模式需要配置的几个关键寄存器:
- 端口使能:确保 Port 0 到 Port 4 和 Port 6 都使能,Port 5 如果不用就关闭。
- CPU 口配置:Port 6 要配置为 CPU 口,设置 tag 模式或者透传模式。透传模式下,CPU 口收到的包不带 tag,就是普通以太网包。
- VLAN 配置:如果不需要 VLAN,就把所有端口设为同一个 VLAN,或者关闭 VLAN 功能。
- 流控:千兆口建议开启流控,避免拥塞丢包。
这些配置在纯二层模式下,其实很多是芯片的默认值。TRL8367s 上电后默认就是所有端口使能、二层转发开启。所以如果你只是做简单的交换,可能不需要改任何寄存器,直接就能工作。但为了稳定,我还是建议显式配置一下 CPU 口的模式。
4.3 为什么不需要额外驱动
纯二层模式下,Linux 只需要驱动 RK3588 的 GMAC 和 CPU 口的 PHY,交换芯片本身对系统是透明的。GMAC 驱动会通过 MDIO 读取 PHY 的状态,协商速率和双工模式。CPU 口 PHY 协商到 1000M 全双工后,GMAC 就以千兆速率和交换芯片通信。
交换芯片内部,CPU 口和外部口之间的转发是硬件完成的,不需要软件参与。所以系统里看不到四个外部口,只能看到一个 eth 设备。这也是为什么这种方案简单稳定的原因。
5. 实操验证与调试过程
5.1 上电后的第一轮检查
板子上电后,第一件事是看内核启动日志里 GMAC 和 PHY 的识别情况。用dmesg | grep -i eth可以看到类似这样的输出:
[ 2.345678] rk_gmac-dwmac fe1c0000.ethernet: IRQ eth_lpi not found [ 2.345789] rk_gmac-dwmac fe1c0000.ethernet: no regulator found [ 2.345890] rk_gmac-dwmac fe1c0000.ethernet: clock input or output? output [ 2.346012] rk_gmac-dwmac fe1c0000.ethernet: TX delay(0x2a) [ 2.346123] rk_gmac-dwmac fe1c0000.ethernet: RX delay(0x1a) [ 2.346234] rk_gmac-dwmac fe1c0000.ethernet: integrated PHY? no [ 2.346345] rk_gmac-dwmac fe1c0000.ethernet: cannot get clock [ 2.346456] rk_gmac-dwmac fe1c0000.ethernet: init phy failed如果看到init phy failed,说明 MDIO 读不到 PHY。这时候要检查 PHY 地址对不对、复位时序够不够、MDC/MDIO 有没有接反。我遇到过 MDC 和 MDIO 接反的情况,现象就是读不到 PHY,换过来就好了。
如果 PHY 识别成功,会看到attached PHY driver之类的日志,然后eth0或者eth1就出现了。用ip link能看到设备状态。
5.2 速率协商与连通性测试
PHY 识别成功后,用ethtool eth1看协商结果:
Settings for eth1: Supported ports: [ TP ] Supported link modes: 10baseT/Half 10baseT/Full 100baseT/Half 100baseT/Full 1000baseT/Full Speed: 1000Mb/s Duplex: Full Link detected: yes如果 Speed 显示 100Mb/s 或者 10Mb/s,说明 RGMII 时序有问题,或者 PHY 协商没到千兆。这时候先检查 tx_delay 和 rx_delay,用ping -s 1472 -f打大包看丢包率,然后微调延迟值。
连通性测试分两步:先测 CPU 口和外部口的通信,再测外部口之间的通信。CPU 口测试就是 RK3588 ping 外部口接的 PC。外部口之间测试就是两个 PC 分别接两个外部口,互相 ping。如果 CPU 口通但外部口之间不通,说明交换芯片的转发没工作,检查端口使能和 VLAN 配置。
5.3 性能测试与瓶颈分析
用 iperf3 测吞吐。CPU 口和外部口之间跑 iperf3,能跑到 940Mbps 左右就是正常的,因为千兆线速加上协议开销,实际吞吐就是 940 左右。如果只有 500Mbps 或者更低,可能是 RGMII 时序问题导致重传,或者 CPU 性能瓶颈。
外部口之间跑 iperf3,应该也是 940Mbps 左右,而且 CPU 占用应该很低,因为转发是硬件完成的。如果 CPU 占用高,说明包被上送到 CPU 了,检查交换芯片的 CPU 口配置,可能 tag 模式不对。
我实测下来,四个外部口之间全速跑,CPU 占用不到 5%,说明二层转发确实在硬件里完成。CPU 口和外部口之间跑,CPU 占用大概 20% 到 30%,这是正常的,因为数据要经过 GMAC 和协议栈。
6. 常见问题与排查速查表
6.1 PHY 识别失败
现象:内核日志显示init phy failed,ip link看不到 eth 设备。
排查步骤:
- 检查 PHY 地址是否和硬件 strapping 一致,用 MDIO 工具读寄存器确认。
- 检查复位 GPIO 是否配置正确,复位脉冲宽度是否够。
- 检查 MDC/MDIO 是否接反,用示波器看波形。
- 检查 25MHz 晶振是否起振,用示波器测频率。
6.2 协商不到千兆
现象:ethtool显示 Speed 为 100Mb/s 或 10Mb/s。
排查步骤:
- 检查 RGMII 延迟配置,调整 tx_delay 和 rx_delay。
- 检查 PCB 走线是否等长,RGMII 对走线长度敏感。
- 检查 PHY 的 strapping 引脚是否强制了速率。
- 换一根网线试试,有时候是网线质量问题。
6.3 外部口之间不通
现象:CPU 口能通,但两个外部口接的 PC 互相 ping 不通。
排查步骤:
- 检查交换芯片端口使能寄存器,确保所有外部口都使能。
- 检查 VLAN 配置,确保所有端口在同一个 VLAN。
- 检查地址表是否学习到了 MAC,用交换芯片的调试命令看地址表。
- 检查流控配置,有时候流控会导致丢包。
6.4 丢包严重
现象:ping 大包丢包率高,iperf3 吞吐低。
排查步骤:
- 调整 RGMII 延迟,这是最常见的原因。
- 检查电源是否稳定,交换芯片对电源噪声敏感。
- 检查散热,芯片过热会导致性能下降。
- 检查是否有环路,二层环路会导致广播风暴。
6.5 常见问题速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| PHY 识别失败 | PHY 地址错误 | 核对 strapping,修改 DTS reg |
| PHY 识别失败 | 复位时序不足 | 增加 reset-delays-us |
| 协商不到千兆 | RGMII 延迟不对 | 调整 tx_delay/rx_delay |
| 外部口不通 | 端口未使能 | 配置端口使能寄存器 |
| 外部口不通 | VLAN 隔离 | 统一 VLAN 或关闭 VLAN |
| 丢包严重 | 时序问题 | 调延迟,看眼图 |
| 丢包严重 | 电源噪声 | 加滤波电容,检查 LDO |
| CPU 占用高 | 包上送 CPU | 检查 CPU 口 tag 模式 |
7. 实操心得与避坑经验
第一个心得:RGMII 延迟不要照抄别人的值。不同板子走线长度不同,延迟值必须自己调。我的方法是先给一个中间值,然后 ping 大包,看丢包率,往丢包少的方向调。调的时候每次改 0x02 或者 0x04,改完重新加载驱动或者重启。
第二个心得:复位时序宁长勿短。datasheet 写最小 10ms,我给 20ms,多等 10ms 不影响启动速度,但能避免很多玄学问题。我遇到过复位给 10ms 偶尔不启动的情况,加到 20ms 就稳了。
第三个心得:MDIO 总线上不要挂太多设备。如果板子上还有其他 PHY,MDIO 的负载电容会变大,波形变差,导致读写失败。这时候可以降低 MDC 频率,或者加缓冲器。
第四个心得:二层模式下,交换芯片的配置其实很少,大部分用默认值就行。但 CPU 口的模式一定要确认,透传模式和 tag 模式的行为完全不同。透传模式下,CPU 口收到的包就是普通以太网包,协议栈直接处理。tag 模式下,包前面会多 4 个字节的 tag,协议栈不认识,需要驱动处理。我一开始没注意这个,导致 ping 不通,后来改成透传模式就好了。
第五个心得:性能测试要用 iperf3 而不是 ping。ping 只能测连通性和大致延迟,吞吐必须用 iperf3。而且 iperf3 要跑多线程,单线程可能跑不满千兆。我一般用iperf3 -c <ip> -P 4 -t 30,四个线程跑 30 秒,看总吞吐。
第六个心得:如果项目需要 VLAN,建议还是上 DSA。纯二层模式下做 VLAN 需要直接操作交换芯片寄存器,配置复杂而且容易出错。DSA 框架虽然学习曲线陡,但配置清晰,管理方便。
最后说一个调试技巧:TRL8367s 有调试寄存器,可以看每个端口的收发包统计、地址表内容、VLAN 表等。这些寄存器通过 MDIO 间接访问,需要先写地址再读数据。我一般写个脚本,封装读写函数,调试的时候很方便。具体寄存器地址参考 datasheet 的寄存器章节,这里就不列了,因为版本不同可能有差异。
整个项目从硬件设计到软件调试,大概花了两周时间,其中大部分时间花在 RGMII 延迟调整和二层模式验证上。现在板子跑得很稳,四个千兆口全速转发,CPU 占用低,满足工业网关的需求。如果你也在做类似方案,希望这篇经验能帮你少走弯路。