第4章:U-Boot移植与裁剪——DDR/TF卡/网络驱动裁剪

各位同学,欢迎来到第四章。这一章我们聊聊U-Boot的移植与裁剪。说实话,U-Boot移植是嵌入式Linux开发中最容易让人“劝退”的一环。我刚开始做海思项目时,光是让U-Boot在板子上跑起来就折腾了整整一周。但别怕,掌握了方法,这事儿其实挺有规律的。

4.1 U-Boot源码获取——从哪开始?

先说说源码。海思官方一般会提供配套的U-Boot源码包,比如u-boot-2016.11.tgz这种。我个人习惯去海思的开发者社区或者SDK包里找,别去网上随便下载通用版,因为海思的芯片有很多私有外设,通用U-Boot根本认不出来。

我的经验:拿到源码后,先别急着编译。先看看board/hisilicon/目录下有没有你芯片型号对应的文件夹。比如Hi3516DV300,对应的就是board/hisilicon/hi3516dv300。没有的话,就得自己新建一个,复制相近型号的配置来改。

解压命令很简单:

tar -xzf u-boot-2016.11.tgz
cd u-boot-2016.11/

嗯,这里要注意:海思的U-Boot通常基于某个官方版本打了很多补丁。你解压后最好先看看README文件,里面会说明支持哪些芯片、有哪些已知问题。我曾经因为没看README,直接编译,结果发现DDR初始化代码根本不对,白忙活半天。

4.2 板级配置修改——让U-Boot认识你的板子

板级配置,说白了就是告诉U-Boot:你的板子用的是什么CPU、多少内存、串口接在哪个引脚上。这部分我建议从include/configs/目录下手,找到对应芯片的头文件,比如hi3516dv300.h

打开这个文件,你会看到一堆宏定义。核心要改的有这几个:

  • CONFIG_SYS_TEXT_BASE:U-Boot的加载地址。海思芯片通常放在0x40000000附近,但具体要看你的DDR映射。
  • CONFIG_NR_DRAM_BANKS:DDR的bank数量。大部分板子就1个bank,但有些双通道设计会有2个。
  • CONFIG_SYS_SDRAM_BASE:DDR的起始地址。海思一般是0x40000000。
  • CONFIG_SYS_LOAD_ADDR:下载内核时的默认加载地址。我习惯设成0x42000000。
避坑指南:我曾经把CONFIG_SYS_TEXT_BASE设错了,结果U-Boot一启动就死机。后来用JTAG调试才发现,它把自己加载到了DDR的保留区域,被硬件写保护了。所以改这个值之前,一定要确认你的DDR地址映射表。

举个例子,一个典型的配置片段:

#define CONFIG_SYS_TEXT_BASE        0x40000000
#define CONFIG_NR_DRAM_BANKS        1
#define CONFIG_SYS_SDRAM_BASE       0x40000000
#define CONFIG_SYS_SDRAM_SIZE       0x20000000  /* 512MB */
#define CONFIG_SYS_LOAD_ADDR        0x42000000

改完这些,还要检查CONFIG_BOOTARGSCONFIG_BOOTCOMMAND。这两个决定了U-Boot怎么启动内核。我一般会先设成从TF卡启动,方便调试:

#define CONFIG_BOOTARGS  "console=ttyAMA0,115200 root=/dev/mmcblk0p2 rw"
#define CONFIG_BOOTCOMMAND "mmc read 0x42000000 0x800 0x4000; bootm 0x42000000"

4.3 DDR驱动裁剪——内存初始化是关键

DDR驱动,是U-Boot移植里最头疼的部分。海思芯片的DDR控制器通常集成在内部,初始化代码在arch/arm/cpu/armv7/hisi/目录下。你想想看,如果DDR没配好,U-Boot连自己都跑不起来。

裁剪DDR驱动,核心是改ddr_init.cddr_training.c。主要参数包括:

参数 说明 常见值
DDR频率 内存运行频率 1066MHz / 1333MHz
CAS延迟 列地址选通延迟 CL=9 / CL=11
时序参数 tRCD、tRP、tRAS等 根据DDR颗粒手册
ODT配置 片上端接电阻 40Ω / 60Ω

我记得有一次,客户说板子偶尔启动失败。查了半天,发现是DDR训练时序太紧,温度一高就出错。后来把tRCD从5放宽到6,问题就解决了。所以裁剪时别一味追求高性能,稳定性更重要。

警告:DDR参数改错可能导致板子完全无法启动,甚至烧坏DDR颗粒。建议先用海思官方的DDR测试工具验证参数,再集成到U-Boot里。

4.4 TF卡驱动裁剪——从卡启动的必经之路

TF卡驱动,说白了就是让U-Boot能读写SD卡。海思芯片的SD/MMC控制器驱动在drivers/mmc/hisi_sdhci.c里。裁剪时主要关注两点:

  • 时钟频率:初始化时用低速(400KHz),正常读写切到高速(25MHz或50MHz)。我建议先设成25MHz,稳定后再往上提。
  • 电压范围:TF卡支持2.7V-3.6V,但海思芯片通常固定输出3.3V。如果卡不识别,检查一下电压匹配。

配置项一般在include/configs/里:

#define CONFIG_MMC
#define CONFIG_GENERIC_MMC
#define CONFIG_HISI_SDHCI
#define CONFIG_MMC_SDMA
#define CONFIG_MMC_BOOT_PARTITION 1

嗯,这里有个坑:有些TF卡支持UHS-I模式,但海思的老芯片不支持。如果你用了高速卡,U-Boot可能会在初始化时卡死。我遇到过这种情况,解决办法是在驱动里强制降级到普通模式:

/* 在hisi_sdhci.c中强制关闭UHS */
static void hisi_sdhci_set_uhs(struct sdhci_host *host, bool enable) {
    if (!enable) {
        /* 强制使用3.3V信号,不启用UHS */
        sdhci_writew(host, SDHCI_CTRL_3_3V, SDHCI_POWER_CONTROL);
    }
}

4.5 网络驱动裁剪——让U-Boot能联网

网络驱动,主要是为了用TFTP下载内核。海思芯片常用的是drivers/net/hisi_eth.c。裁剪时,先确认你的PHY芯片型号。比如我用的是RTL8211F,那就要在配置里打开对应的PHY支持:

#define CONFIG_PHY_REALTEK
#define CONFIG_PHY_RTL8211F
#define CONFIG_ETH_PRIME "hisi_eth"

网络驱动的裁剪,我建议保留最基本的pingtftp命令就够了。像dhcpnfs这些,如果不用就关掉,能省不少空间:

/* 裁剪网络命令 */
#undef CONFIG_CMD_DHCP
#undef CONFIG_CMD_NFS
#define CONFIG_CMD_PING
#define CONFIG_CMD_TFTP
我的习惯:裁剪网络驱动时,我会先保留完整的调试信息。等确认网络能正常工作后,再把DEBUG宏关掉。这样万一出问题,还能回头查日志。

最后,别忘了检查MAC地址。海思芯片的MAC地址通常存储在OTP里,但有些板子没有烧录。我建议在U-Boot里加一个默认MAC:

#define CONFIG_ETHADDR         00:11:22:33:44:55
#define CONFIG_ETH1ADDR        00:11:22:33:44:56

当然,量产时还是要从EEPROM或OTP读取,这里只是方便调试。

小结

这一章我们聊了U-Boot移植与裁剪的四个核心点:源码获取、板级配置、DDR驱动、TF卡和网络驱动。说白了,U-Boot移植就是让bootloader认识你的硬件。每一步都有坑,但只要你按照“先验证、后裁剪”的原则来,就不会出大问题。

下一章,我们会深入内核裁剪,讲讲怎么把Linux内核瘦身到适合海思芯片的大小。到时候见!