4、U-Boot网络驱动移植:以太网控制器驱动适配、PHY芯片驱动配置、网络命令调试

网络,是嵌入式设备的命脉。没有网络,你的板子就是个孤岛。

U-Boot的网络驱动移植,说白了就是让bootloader能跟外界通信。我见过太多工程师,内核跑得飞起,U-Boot的网络却死活不通。嗯,这章我们就来彻底搞定它。

4.1 网络驱动栈的整体架构

先看一张图,把U-Boot的网络栈理清楚。从上到下,一共四层:

U-Boot 网络驱动栈架构 应用层:ping / tftp / dhcp / nfs 协议层:ARP / IP / UDP / ICMP 网络核心层:net_loop / net_send_packet 以太网驱动层:eth_ops 结构体 PHY驱动层:phy_driver 结构体 关键点 • 驱动层核心是 eth_ops • PHY 驱动独立于 MAC • 协议层由 U-Boot 自带 • 我们只需适配最下面两层

看到没?我们真正需要动手的,只有最下面两层:以太网控制器驱动和PHY芯片驱动。上面的协议栈,U-Boot已经帮你写好了。

4.2 以太网控制器驱动适配

U-Boot的以太网驱动,核心是一个叫 eth_ops 的结构体。你想想看,它就像一张接口清单,你填好,系统就能用。

4.2.1 eth_ops 结构体

这个结构体定义在 include/net.h 里。我挑几个最重要的说:

函数指针 作用 必须实现?
start 初始化硬件,启动网络接口 是
stop 关闭网络接口,释放资源 是
send 发送一个数据包 是
recv 接收一个数据包 是
write_hwaddr 写入MAC地址到硬件 推荐实现
free_pkt 释放接收缓冲区 可选

核心要点:start/send/recv/stop 这四个函数,是U-Boot网络驱动的四根柱子。少一个,网络就起不来。

4.2.2 实际移植步骤

以我手头一个 i.MX6ULL 板子为例,它的以太网控制器是 FEC (Fast Ethernet Controller)。U-Boot 源码里已经有 drivers/net/fec_mxc.c,但板级适配还得我们自己来。

具体怎么做?三步走:

  1. 使能驱动配置:在 include/configs/your_board.h 里加上宏定义
  2. 注册设备:在板级初始化函数里调用 fecmxc_initialize
  3. 配置管脚:确保IOMUX把以太网管脚配成功能模式

看一段配置代码:

/* include/configs/my_imx6ull.h */
#define CONFIG_FEC_MXC
#define CONFIG_FEC_XCV_TYPE     RMII
#define CONFIG_FEC_MXC_PHYADDR  0x01
#define CONFIG_ETHPRIME         "FEC"

/* 板级初始化文件 board/my_company/my_board.c */
int board_eth_init(struct bd_info *bis)
{
    int ret = -1;

    /* 配置FEC的IOMUX管脚 */
    imx_iomux_v3_setup_pad(MX6_PAD_GPIO1_IO06__ENET_REF_CLK);
    imx_iomux_v3_setup_pad(MX6_PAD_GPIO1_IO07__ENET_MDC);
    /* ... 其他管脚 ... */

    /* 初始化FEC控制器 */
    ret = fecmxc_initialize(bis);
    if (ret < 0)
        printf("FEC init failed\n");

    return ret;
}

个人经验:我习惯在 board_eth_init 里先打印一下PHY地址,确认硬件连接没问题。用 md 命令读一下PHY寄存器,比瞎猜强多了。

4.3 PHY芯片驱动配置

PHY芯片,就是物理层收发器。它负责把数字信号变成模拟信号,送到网线上去。

U-Boot 里 PHY 驱动框架已经很成熟了。你只要告诉它:你的PHY是什么型号,挂在哪个MDIO总线上,地址是多少。

4.3.1 PHY驱动匹配流程

U-Boot 启动时,会扫描MDIO总线,读取每个PHY的 PHY_IDENTIFIER 寄存器(寄存器2和3),然后跟驱动列表里的 phy_driver->uid 做匹配。

匹配上了,就加载对应的驱动。匹配不上?嗯,那就用通用PHY驱动,功能受限,但至少能通。

PHY型号 UID (32位) U-Boot驱动文件
LAN8720A 0x0007C0F0 drivers/net/phy/lan87xx.c
KSZ8081 0x00221560 drivers/net/phy/ksz8xxx.c
RTL8211F 0x001CC916 drivers/net/phy/realtek.c
DP83848 0x20005C90 drivers/net/phy/dp83848.c

4.3.2 配置PHY的两种方式

方式一:在板级头文件里直接指定

/* 最简单粗暴的方式 */
#define CONFIG_PHY_LAN87XX
#define CONFIG_FEC_MXC_PHYADDR  0x01

方式二:通过设备树描述(如果U-Boot支持DM)

/* 设备树节点示例 */
&fec1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_fec1>;
    phy-mode = "rmii";
    phy-handle = <&ethphy0>;
    status = "okay";

    mdio {
        #address-cells = <1>;
        #size-cells = <0>;

        ethphy0: ethernet-phy@1 {
            compatible = "ethernet-phy-id0007.c0f0";
            reg = <0x01>;
        };
    };
};

我曾经踩过的坑:有一次PHY地址配成了0x00,但实际硬件是0x01。U-Boot扫描不到PHY,网络死活不通。查了两天才发现,是原理图上的地址线拉法跟我想的不一样。记住:PHY地址不是猜的,要用万用表量,或者读寄存器确认。

4.4 网络命令调试

驱动写好了,怎么验证?U-Boot提供了一套网络命令,非常实用。

4.4.1 常用网络命令一览

命令 用途 典型用法
ping 测试网络连通性 ping 192.168.1.100
tftp 通过TFTP下载文件 tftp 0x80800000 uImage
dhcp 自动获取IP地址 dhcp
nfs 挂载NFS文件系统 nfs 0x80800000 /nfs/uImage
mdio 读写PHY寄存器 mdio list / mdio read 0x01 0x00

4.4.2 调试三板斧

网络不通怎么办?别慌,按顺序来:

  1. 先看PHY:mdio list 看看能不能扫到PHY。再 mdio read 0x01 0x00 读寄存器0(BMCR),看看bit 15是不是1(表示复位中)。
  2. 再看链路:读PHY寄存器1(BMSR),bit 2是链接状态。为1表示网线插好了。
  3. 最后ping:设置好IP,ping 服务器IP。通了,万事大吉。

调试口诀:先PHY,再MAC,最后协议栈。一层一层排查,别跳步。

4.4.3 一个完整的调试案例

假设你敲了 ping 192.168.1.100,结果卡住了。我会这么做:

# 第一步:检查PHY是否存在
=> mdio list
PHY 0x01: OUI = 0x0007, Model = 0x20, Rev = 0x01
  --> 嗯,PHY地址0x01,型号LAN8720A,没问题

# 第二步:检查链接状态
=> mdio read 0x01 0x01
Read from MDIO: 0x796D
  --> bit 2 = 1,链接正常

# 第三步:设置IP并ping
=> setenv ipaddr 192.168.1.10
=> setenv serverip 192.168.1.100
=> ping 192.168.1.100
Using FEC device
host 192.168.1.100 is alive
  --> 通了!

如果 mdio list 没输出?那问题大概率在硬件:管脚配置错了,或者PHY没上电。我曾经遇到过,PHY的复位引脚被拉低了,芯片一直处于复位状态。量一下电压,就发现了。

4.5 常见问题与避坑指南

  • PHY扫描不到:检查PHY地址、MDIO上拉电阻、复位时序。我习惯在PHY复位后加个10ms延时。
  • 能ping通但tftp超时:多半是MTU问题,或者服务器防火墙没关。试试 tftp -l 小文件。
  • MAC地址全是FF:没设置 ethaddr 环境变量。用 setenv ethaddr 00:11:22:33:44:55 设一个。
  • 速率协商不对:强制固定速率试试。在PHY驱动里把 autoneg 关掉,设成100M全双工。

我的习惯:每次移植新板子,我都会在 board_eth_init 里加一段调试打印,把PHY的ID、链接状态、速率都打出来。这样一上电就知道硬件有没有问题,不用猜。

网络驱动移植,说难不难,说简单也不简单。关键是思路清晰,工具用好。记住:PHY是基础,MAC是桥梁,命令是验证手段。这三样搞定了,你的板子就能上网了。