作为一名嵌入式开发工程师,我最近在使用Rockchip SDK提供的U-Boot时遇到了网络功能无法正常使用的问题。经过一番折腾,终于成功调通了U-Boot的网络功能,现在把整个过程记录下来,希望能帮到遇到同样问题的朋友。
Rockchip的SDK通常采用buildroot方式整体编译U-Boot和Kernel,或者提供简单的shell脚本指导用户编译和烧录。这种方式虽然方便,但默认启用了"快启模式",导致U-Boot的很多功能被精简掉了,包括网络支持。对于需要通过网络加载内核或进行TFTP传输的开发场景来说,这显然不够用。
厂商提供的SDK通常采用两种方式:
这两种方式都默认启用了"快启模式",这种模式下U-Boot会直接加载Kernel的DTB,省略了很多功能,包括网络支持。这样做的目的是为了加快启动速度,但对于开发调试来说就不够灵活了。
提示:快启模式下,如果不烧录Kernel,U-Boot启动时会报"read kernel dtb失败"和"no ethnet found"等错误。这不是U-Boot本身的问题,而是打包方式导致的。
要使用U-Boot的网络功能(如TFTP加载内核),必须关闭快启模式。快启模式下,U-Boot会直接加载Kernel的DTB,如果update.img不包含Kernel,就会导致各种错误。
关闭快启模式后,U-Boot会使用自己的设备树配置,可以独立支持网络功能,不再依赖Kernel的DTB。
首先需要修改U-Boot的设备树文件(u-boot/arch/arm/dts/rk3288.dtsi),调整以太网控制器的配置:
c复制ethernet@ff290000 {
rgmii_pins: rgmii-pins {
rockchip,pins = <3 RK_PD6 3 &pcfg_pull_none>,
<3 RK_PD7 3 &pcfg_pull_none>,
<3 RK_PD2 3 &pcfg_pull_none>,
<3 RK_PD3 3 &pcfg_pull_none>,
<3 RK_PD4 3 &pcfg_pull_none>,
<3 RK_PD5 3 &pcfg_pull_none>,
<3 RK_PD0 3 &pcfg_pull_none>,
<3 RK_PD1 3 &pcfg_pull_none>,
<4 RK_PA0 3 &pcfg_pull_none>,
<4 RK_PA5 3 &pcfg_pull_none>,
<4 RK_PA6 3 &pcfg_pull_none>,
<4 RK_PB1 3 &pcfg_pull_none>,
<4 RK_PA4 3 &pcfg_pull_none>,
<4 RK_PA1 3 &pcfg_pull_none>,
<4 RK_PA3 3 &pcfg_pull_none>;
};
phy_int: phy-int {
rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
};
phy_pmeb: phy-pmeb {
rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
};
phy_rst: phy-rst {
rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_output_high>;
};
};
这里我们删除了RMII配置,直接使用RGMII模式。两者的主要区别如下:
| 特性 | RMII | RGMII |
|---|---|---|
| 速率支持 | 10/100Mbps | 10/100/1000Mbps |
| 数据位宽 | 2位 | 4位 |
| 时钟频率 | 50MHz | 125MHz |
| 时钟机制 | 单沿采样 | 双沿采样 |
| 适用场景 | 低成本嵌入式设备 | 高速网络设备 |
接下来需要修改GMAC的配置,这里我们直接从Linux Kernel 6.0.8版本的设备树中提取了已验证可用的配置:
c复制&gmac {
compatible = "rockchip,rk3288-gmac";
reg = <0xff290000 0x10000>;
interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq";
rockchip,grf = <&grf>;
clocks = <&cru SCLK_MAC>,
<&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>,
<&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>,
<&cru ACLK_GMAC>, <&cru PCLK_GMAC>;
clock-names = "stmmaceth",
"mac_clk_rx", "mac_clk_tx",
"clk_mac_ref", "clk_mac_refout",
"aclk_mac", "pclk_mac";
assigned-clocks = <&cru SCLK_MAC>;
assigned-clock-parents = <&ext_gmac>;
clock_in_out = "input";
pinctrl-names = "default";
pinctrl-0 = <&rgmii_pins>, <&phy_rst>, <&phy_pmeb>, <&phy_int>;
phy-supply = <&vcc_lan>;
phy-mode = "rgmii";
snps,reset-active-low;
snps,reset-delays-us = <0 10000 1000000>;
snps,reset-gpio = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>;
tx_delay = <0x1d>;
rx_delay = <0x16>;
status = "okay";
};
电源管理部分需要特别注意vcc_lan的配置:
c复制vcc_lan: REG8 {
regulator-name = "vcc_lan";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
关键点是必须设置regulator-always-on,这个配置默认是关闭的。我在调试过程中就因为这个配置没开,导致网络一直无法正常工作,排查了很久才发现问题。
在U-Boot的配置文件中需要开启以下选项:
code复制CONFIG_ETH_DESIGNWARE=y
CONFIG_GMAC_ROCKCHIP=y
CONFIG_DM_ETH=y
这些配置确保了U-Boot能够正确识别和使用Rockchip的GMAC以太网控制器。
通过分析启动日志发现,Rockchip的U-Boot默认使用Android镜像格式,并且会初始化Kernel的DTB。如果镜像中不包含Kernel,就会出现各种错误。
关闭快启模式需要对U-Boot源代码进行以下修改:
具体修改点包括:
修改完成后重新编译并烧录U-Boot,应该能看到以下变化:
可能原因:
解决方案:
可能原因:
解决方案:
可能原因:
解决方案:
在U-Boot命令行中,以下命令非常有用:
ping:测试网络连通性dhcp:自动获取IP地址tftp:测试文件传输md:查看内存内容mm:修改内存内容fdt命令查看和修改设备树在实际项目中,我遇到的最棘手的问题就是电源管理配置不正确导致网络时好时坏。后来通过仔细检查设备树和测量实际电压,才发现是某个regulator没有正确启用。
在调通网络后,可以进一步实现通过NFS挂载根文件系统:
在实际开发中,我发现通过U-Boot的网络功能可以大大提升开发效率。特别是当需要频繁修改和测试内核时,使用TFTP加载内核比每次烧录要快得多。此外,网络功能也为远程调试和自动化测试提供了可能。
调试过程中最重要的经验是:一定要仔细查看硬件参考手册和数据手册,确保软件配置与硬件设计一致。很多时候问题都出在一些细节上,比如某个引脚的复用功能没配置对,或者某个时钟源选择不正确。