第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。
举个例子,一个典型的配置片段:
#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_BOOTARGS和CONFIG_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.c或ddr_training.c。主要参数包括:
| 参数 | 说明 | 常见值 |
|---|---|---|
| DDR频率 | 内存运行频率 | 1066MHz / 1333MHz |
| CAS延迟 | 列地址选通延迟 | CL=9 / CL=11 |
| 时序参数 | tRCD、tRP、tRAS等 | 根据DDR颗粒手册 |
| ODT配置 | 片上端接电阻 | 40Ω / 60Ω |
我记得有一次,客户说板子偶尔启动失败。查了半天,发现是DDR训练时序太紧,温度一高就出错。后来把tRCD从5放宽到6,问题就解决了。所以裁剪时别一味追求高性能,稳定性更重要。
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"
网络驱动的裁剪,我建议保留最基本的ping和tftp命令就够了。像dhcp、nfs这些,如果不用就关掉,能省不少空间:
/* 裁剪网络命令 */
#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内核瘦身到适合海思芯片的大小。到时候见!