个人项目记录(一)uboot移植:基于i.MX6ULL的嵌入式Linux终端系统构建与多子系统控制器驱动—将 NXP 官方 U-Boot 2017.03 移植到韦东山IMX6ULLPro并支持网络功能
在韦东山100ASK IMX6ULL Pro开发板上移植U-Boot 2017.03并支持网络功能本文记录的是的是我目前正在做的项目基于i.MX6ULL的嵌入式Linux终端系统构建与多子系统控制器驱动开发的uboot移植部分将 NXP 官方 U-Boot 2017.03 移植到百问网100ASKIMX6ULL Pro 开发板并支持网络功能的完整过程包括源码获取、板级文件创建、网络驱动适配、问题排查与解决以及最终的内核启动验证。文章目录在韦东山100ASK IMX6ULL Pro开发板上移植U-Boot 2017.03并支持网络功能一、移植信息1.1 硬件信息1.2 软件版本1.3 完整移植流程二、获取NXP官方U-Boot源码2.1 确定版本2.2 找到对应的NXP仓库分支2.3 下载源码三、首次编译与启动测试3.1 确定defconfig3.2 编译3.3 烧写到SD卡3.4 首次启动检查检查结果四、添加自己的板子4.1 复制并重命名为自己名字的文件4.2 复制后需要修改文件的内容五、网络驱动移植5.1 硬件架构理解5.2 头文件分析与修改**修改一PHY驱动使能****修改二ENET1的PHY地址**5.3 板级C文件分析与修改5.4 PHY芯片的驱动层修改5.5 设备树修改5.6 Kconfig 配置六、测试与验证6.1 网络功能验证6.2 启动内核验证七、uboot网络移植过程中的踩坑记录与经验总结7.1 Kconfig 与头文件冲突7.2 DM_ETH 框架的 MAC 地址问题7.3 PHY 硬件复位的必要性7.4 启动时 No ethernet found 不代表网络不工作一、移植信息1.1 硬件信息开发板百问网 100ASK IMX6ULL Pro韦东山版核心板MYC-Y6ULX米尔科技搭载 i.MX6ULL SoCDDR512MB DDR3MT41K128M16JT-125存储4GB eMMC SD卡槽网络双路以太网均使用 LAN8720A PHY芯片RMII接口ENET1 的 PHYU6在核心板上ENET2 的 PHYU11在底板上1.2 软件版本U-Boot版本2017.03NXP BSP分支imx_v2017.03_4.9.88_2.0.0_ga交叉编译工具链arm-linux-gnueabihf-Buildroot 2020.02 提供的 gcc 7.5.01.3 完整移植流程获取芯片原厂 U-Boot 源码 ↓ 用原厂参考板的 defconfig 编译烧到自己板子上启动 ↓ 在 U-Boot 命令行检查各项基础功能DDR、SD/eMMC、串口 ↓ 在 U-Boot 中添加自己的板子复制并重命名相关文件 ↓ 对比原理图找出硬件差异 ↓ 针对差异修改代码网络、LCD、其他外设 ↓ 编译、烧写、测试、调试 ↓ 验证通过U-Boot 能正常启动 Linux 内核移植完成二、获取NXP官方U-Boot源码2.1 确定版本先正常从EMMC启动一次开发板通过查看开发板原有U-Boot的启动打印信息确定版本U-Boot 2017.03 (Jun 03 2020 - 13:12:42 0800)同时内核启动信息显示内核版本为 4.9.88。2.2 找到对应的NXP仓库分支芯片原厂通常在 GitHub 或官网提供基于主线 U-Boot 修改的 BSP 版本。NXP的U-Boot仓库地址https://github.com/nxp-imx/uboot-imx仓库中nxp-imx是NXP公司的GitHub官方账号所有分支都是NXP在原始U-Boot基础上修改过的版本。有些分支名带nxp/前缀、有些不带这只是命名风格不统一内容都是NXP修改后的uboot。NXP 的分支命名规则是imx_v{uboot版本}_{内核版本}_{BSP发布号}在仓库的分支搜索框中搜索4.9.88找到NXP官方发布的适配4.9.88内核的2017.03版Ubootimx_v2017.03_4.9.88_2.0.0_gaga General Availability正式发布版。2.3 下载源码gitclone-bimx_v2017.03_4.9.88_2.0.0_ga --single-branch https://github.com/nxp-imx/uboot-imx.git# 或者在 GitHub 上切换到对应分支后点 Code → Download ZIP下载ZIP压缩包同时也下载了对应的内核源码后续内核移植使用gitclone-bimx_4.9.88_2.0.0_ga --single-branch https://github.com/nxp-imx/linux-imx.git三、首次编译与启动测试将下载好的源码拷贝到虚拟机3.1 确定defconfig在源码的configs/目录下查找与 SoC 型号匹配的 defconfiglsconfigs/|grepmx6ull输出中包含mx6ull_14x14_evk_defconfig这是NXP官方 i.MX6ULL EVK 评估板的配置。韦东山的开发板基于相同的SoC理论上硬件配置最接近这个EVK所以选用它。也可以查看韦东山提供的手册给的编译uboot时的命令发现他编译时用的是mx6ull_14x14_evk_defconfig这个config证明他就是基于这个名字的原厂配置改的。3.2 编译makedistcleanmakemx6ull_14x14_evk_defconfigmake-j$(nproc)编译成功后生成u-boot-dtb.imx。3.3 烧写到SD卡始终用 SD 卡启动来做移植开发eMMC 里的原始系统不会被破坏拔掉 SD 卡就能恢复。将TF卡插入USB读卡器插入电脑连接到虚拟机在虚拟机中把编译好的uboot镜像烧录到TF卡中# 确认SD卡设备名lsblk# 输出显示 sdb 是SD卡sdb1 是其分区# # 如果 SD 卡被自动挂载了文件系统先卸载SD卡文件系统sudoumount/media/book/3361-3634# 烧写U-Boot到SD卡i.MX6ULL的BootROM规定从1KB偏移处读取单位 1024 字节sudoddifu-boot-dtb.imxof/dev/sdbbs1024seek1convfsync3.4 首次启动检查将烧录好的TF卡插入开发板TF卡槽切换拨码开关到 SD 卡启动上电后通过串口观察打印信息检查打印信息U-Boot 2017.03 (Apr 12 2026 - 01:41:12 -0400) //版本和编译时间确认是你刚编译的 CPU: Freescale i.MX6ULL rev1.1 696 MHz (running at 396 MHz) DRAM: 512 MiB //DDR 容量是否正确 MMC: FSL_SDHC: 0, FSL_SDHC: 1 //SD 卡和 eMMC 是否识别 Display: TFT43AB (480x272) In: serial //串口正常 Out: serial Err: serial Net: No ethernet found. //网络状态然后进入命令行后手动检查存储设备mmc dev0# 切换到 SD 卡mmc info# 查看信息mmc dev1# 切换到 eMMCmmc info如果 DDR、串口、存储都正常说明 SoC 级别初始化没有问题接下来只需处理板级外设差异。检查结果功能状态说明DDR正常512 MiB 识别正确SD卡 (mmc0)正常mmc info 显示SD卡信息eMMC (mmc1)正常mmc info 显示eMMC信息串口正常能正常交互LCD不正常参数不匹配默认480x272需要根据实际屏幕调整因为项目不涉及LCD所以本次不做网络不正常未工作No ethernet found需要移植结论基础功能正常需要做板级外设移植中的移植网络。四、添加自己的板子4.1 复制并重命名为自己名字的文件# defconfigcpconfigs/mx6ull_14x14_evk_defconfig configs/mx6ull_myboard_defconfig# 头文件cpinclude/configs/mx6ull_14x14_evk.h include/configs/mx6ull_myboard.h# 板级目录cp-rboard/freescale/mx6ull_14x14_evk board/freescale/mx6ull_myboard# 设备树cparch/arm/dts/imx6ull-14x14-evk.dts arch/arm/dts/imx6ull-myboard.dts4.2 复制后需要修改文件的内容defconfig把里面涉及旧板子名的配置项如CONFIG_TARGET_xxx、CONFIG_DEFAULT_DEVICE_TREE改成新名字。头文件修改#ifndef宏定义守卫名称。板级目录下的文件Kconfig 注册编辑arch/arm/cpu/armv7/mx6/Kconfig路径因 SoC 而异参考原有的config条目添加你自己的 config 条目及source来源。设备树相关在arch/arm/dts/Makefile中添加自己设备树的 dtb 的编译条目头文件中更新fdt_file环境变量里的 dtb 文件名为自己的设备树defconfig 中更新CONFIG_DEFAULT_DEVICE_TREE为自己的设备树板级 .c 文件中的显示信息checkboard()函数中的板子名打印可以改成自己的。编译验证makedistcleanmakemx6ull_myboard_defconfigmake-j$(nproc)编译通过就说明板子添加成功。此时功能和 EVK 完全一样。五、网络驱动移植5.1 硬件架构理解网络分两层硬件SoC 内部的 MAC 控制器如 i.MX6ULL 的 FEC芯片原厂已经写好驱动不需要改外部 PHY 芯片如 LAN8720A、KSZ8081通过标准 RMII 接口与 MAC 连接RMII 数据接口是标准的所有 PHY 芯片都一样。硬件差异的来源是 PHY 芯片的额外控制引脚引脚功能是否需要关注nRST复位低电平有效是——通常和芯片原厂的不一样我们具体的板子可能接到不同的 GPIOPHYAD0/1/2地址选择是——我们具体的板子连的上下拉决定地址值具体是什么可能与芯片原厂的地址值不一样nINT中断输出U-Boot 中不需要轮询模式MODE0/1/2工作模式选择硬件电阻决定软件不管XTAL1/CLKIN参考时钟通常和芯片原厂的参考板一致确认即可一致就不需要修改5.2 头文件分析与修改通过 grep 找到网络相关的宏定义grep-nPHY\|FEC\|ENET\|CONFIG_PHY\|CONFIG_FECinclude/configs/mx6ull_myboard.h发现需要修改的部分修改一PHY驱动使能NXP EVK 使用 KSZ8081Micrel公司我的板子使用 LAN8720ASMSC公司需要将其改成我的网络芯片的公司提供的驱动的使能。// 修改前#defineCONFIG_PHY_MICREL// 修改后#defineCONFIG_PHY_SMSC修改二ENET1的PHY地址什么是PHY地址SoC通过MDIO管理总线和PHY芯片通信读写PHY内部寄存器来配置速率、查询链路状态等。MDIO总线上可以挂多个PHY每个PHY有一个5位地址0~31就像I2C从机地址一样。U-Boot需要知道PHY的地址才能通过MDIO找到它。怎么查PHY地址由芯片的特定引脚在复位时刻的电平决定。不同PHY芯片的地址引脚不同以LAN8720A为例只有一个地址引脚PHYAD0pin 10和RXER复用复位时 PHYAD0 0下拉到GND→ PHY地址 0复位时 PHYAD0 1上拉到VDD→ PHY地址 1在原理图中找到PHY芯片的地址引脚看它通过电阻接到了VDD还是GND就能确定地址。如果有多个地址引脚如KSZ8081有PHYAD[2:0]需要看每个引脚的状态组合成地址值。怎么改在头文件中找到CONFIG_FEC_MXC_PHYADDR或类似的宏定义改成你板子上PHY的实际地址。如果有两路网络如 ENET1 和 ENET2可能有两个地址需要分别配置。对于我的开发板从原理图确认如下核心板上ENET1 : LAN8720A 的 PHYAD0 引脚pin 10通过电阻下拉到 DGND所以 ENET1的PHY 地址为 0芯片原厂提供的ENET1地址为2需要修改。 底板上ENET2的PHYAD0引脚上拉连接到VDDPHY地址为1与芯片原厂提供的ENET2地址相同不需要修改。// 修改前#defineCONFIG_FEC_MXC_PHYADDR0x2// 修改后#defineCONFIG_FEC_MXC_PHYADDR0x0修改三添加默认MAC地址和IP到环境变量U-Boot 2017.03 使用 DM_ETH 框架要求必须设置 MAC 地址。在CONFIG_EXTRA_ENV_SETTINGS宏中添加地址环境变量根据自己虚拟机和电脑的网络地址对应设置ethaddr00:04:9f:04:d2:35\0\eth1addr00:04:9f:04:d2:36\0\ipaddr192.168.5.9\0\serverip192.168.5.11\0\5.3 板级C文件分析与修改PHY复位分为硬件复位和软件复位软件复位在刚刚使能的PHY芯片厂家提供的驱动中由芯片厂家已经做在自己的驱动代码里了我们需要实现的是在开发板上电时使得CPU能找到这个PHY芯片的硬件复位所以硬件复位是需要做在板级.c文件里的。通读整个mx6ull_myboard.c识别网络相关代码被#ifdef CONFIG_FEC_MXC包裹的部分发现有两个函数setup_fec 函数配置 FEC MAC 控制器的参考时钟。通过对比硬件原理图后确认我的板子的时钟方案与NXP公司的一致SoC 提供 50MHz REF_CLK 给 PHY不需要修改时钟配置部分。但需要添加 PHY 硬件复位代码因为原厂代码中没有 PHY 复位的 GPIO 操作。NXP EVK 的 PHY 复位是通过一个 74HC595 移位寄存器间接控制的在设备树中以 gpio expander 形式定义我的板子没有 74HC595PHY 复位引脚直接接到 SoC 的 GPIO 上所以需要在setup_fec中手动添加 GPIO 复位代码之所以在这里添加是因为我们需要实现的是在开发板上电时使得CPU能找到这个PHY芯片的硬件复位这个函数就是上电时执行的初始化所以放在这里最合适。查看我们的硬件原理图找到我们的 PHY 复位引脚底板原理图ENET2核心板原理图 (ENET1)ENET1核心板 U6RST 引脚连到 SoC 的SNVS_TAMPER9GPIO5_IO09ENET2底板 U11RST 引脚通过网络标号ENET2_nRST连到 SoC 的SNVS_TAMPER6GPIO5_IO06添加的复位代码#defineENET1_RESET_GPIOIMX_GPIO_NR(5,9)//定义引脚#defineENET2_RESET_GPIOIMX_GPIO_NR(5,6)// 在 setup_fec 函数的 enable_enet_clk(1) 之后参照LAN8720A芯片手册的复位要求添加硬件复位操作if(fec_id0){//这是ENET2的复位gpio_request(ENET1_RESET_GPIO,enet1_reset);gpio_direction_output(ENET1_RESET_GPIO,0);mdelay(20);gpio_direction_output(ENET1_RESET_GPIO,1);mdelay(100);}else{//这是ENET1的复位gpio_request(ENET2_RESET_GPIO,enet2_reset);gpio_direction_output(ENET2_RESET_GPIO,0);mdelay(20);gpio_direction_output(ENET2_RESET_GPIO,1);mdelay(100);}原代码中有一行phy_write(phydev, MDIO_DEVAD_NONE, 0x1f, 0x8190)这是针对 KSZ8081 的特定寄存器配置。LAN8720A 的寄存器定义不同直接删掉这行。5.4 PHY芯片的驱动层修改在drivers/net/phy/phy.c的genphy_update_link函数中添加 LAN8720A 的软复位补丁。LAN8720A 在某些情况下首次链路协商时需要额外的软复位才能正常建立链路,这是这个芯片的额外步骤。#ifdefCONFIG_PHY_SMSCstaticintlan8720_flag0;intbmcr_reg0;if(lan8720_flag0){bmcr_regphy_read(phydev,MDIO_DEVAD_NONE,MII_BMCR);phy_write(phydev,MDIO_DEVAD_NONE,MII_BMCR,BMCR_RESET);while(phy_read(phydev,MDIO_DEVAD_NONE,MII_BMCR)0X8000){udelay(100);}phy_write(phydev,MDIO_DEVAD_NONE,MII_BMCR,bmcr_reg);lan8720_flag1;}#endif5.5 设备树修改设备树中的PHA地址要和头文件里保持一致也要修改ENET1的PHY地址。修改arch/arm/dts/imx6ull-myboard.dts中 ENET1 的 PHY 地址// 修改前 ethphy0: ethernet-phy2 { reg 2; }; // 修改后 ethphy0: ethernet-phy0 { reg 0; };ENET2 的 PHY 地址reg 1与实际一致不需要改。网络引脚配置pinctrl_enet1、pinctrl_enet2是 RMII 标准专用引脚不需要改。5.6 Kconfig 配置这是移植中遇到的最大坑。做完以上所有代码修改后编译烧录启动开发板后发现网络仍然不工作No ethernet found。经过排查发现U-Boot 2017.03 处于从头文件定义配置向Kconfig管理配置的过渡期。CONFIG_PHYLIB、CONFIG_PHY_SMSC、CONFIG_FEC_MXC虽然在头文件中用#define定义了但实际已被 Kconfig 接管。使用grep命令检查.config里这些宏定义的配置发现这些选项都是not set。说明被 Kconfig 覆盖了需要通过make menuconfig来使能。grepCONFIG_XXX.config通过make menuconfig使能Device Drivers → Ethernet PHY (physical media interface) support → [*] SMSC PHY support → [*] Network device support → FEC Ethernet controller → [*]选上后重新make编译FEC会询问 MDIO 基地址输入0x020B4000ENET2_BASE_ADDR。现在的uboot镜像就是完全修改好以后的镜像了。因为我们使能这些配置是用menuconfig使能的配置只保存在.config里为了防止之后make distclean后配置消失需要保存配置到defconfig源文件中这样每次make defconfig后生成的配置,config 都是我们完全改好之后的配置保存配置到defconfig防止 distclean 后丢失makesavedefconfigcpdefconfig configs/mx6ull_myboard_defconfig //改名替换掉我们自己的defconfig# 然后手动确认 defconfig 中 CONFIG_DEFAULT_DEVICE_TREE 等是否正确配置是否保存成功六、测试与验证6.1 网络功能验证编译烧录后在U-Boot命令行测试ping192.168.5.11 ethernet020b4000 WaitingforPHY auto negotiation to complete....doneUsing ethernet020b4000 devicehost192.168.5.11 is alivePHY 自动协商完成ping 成功网络移植完成。mdio list FEC1:1- SMSC LAN8710/LAN8720--ethernet020b4000MDIO 总线上正确识别了 LAN8720A PHY。网络移植成功关于启动时显示No ethernet found这是 DM_ETH 框架的正常行为懒加载机制不影响实际网络功能。通过dm tree可以看到两个 eth 设备都已注册只是尚未 probe。关于只显示一个 PHY 设备头文件中CONFIG_FEC_ENET_DEV1指定了当前只使用 ENET2。setup_fec只初始化了一个网口这是 NXP 原版代码的设计。两个网口的底层配置PHY 驱动、地址、复位 GPIO都已在代码中实现切换CONFIG_FEC_ENET_DEV为 0 即可使用 ENET1。6.2 启动内核验证这是 U-Boot 移植的最终验证——U-Boot 的核心任务就是启动 Linux 内核。这里因为我们是在SD卡里启动UBOOT此时SD卡中还没有内核和设备树 根文件系统所以通过SD卡启动三秒内进入uboot命令行在uboot命令行中使用命令加载emmc中的内核 设备树 挂载emmc中的根文件系统并使用bootz命令启动内核验证我们SD卡中的uboot是否能启动内核mmc dev1lsmmc1:2 /boot39327100ask_imx6ull-14x14.dtb7924872zImageext2load mmc1:2 0x80800000 /boot/zImage# 从 eMMC 加载内核和设备树到内存ext2load mmc1:2 0x83000000 /boot/100ask_imx6ull-14x14.dtbsetenv bootargsconsolettymxc0,115200 root/dev/mmcblk1p2 rootwait rw# 设置内核启动参数bootz 0x80800000 - 0x83000000# 启动内核内核成功启动进入Linux shell。U-Boot移植验证通过。七、uboot网络移植过程中的踩坑记录与经验总结7.1 Kconfig 与头文件冲突现象头文件里明确写了#define CONFIG_PHYLIB和#define CONFIG_PHY_SMSC但编译后检查.config发现都是not set。原因U-Boot 2017.03 处于配置系统过渡期部分配置项已被 Kconfig 接管。Kconfig 的优先级高于头文件的#define。解决通过make menuconfig手动使能。修改后用make savedefconfig保存到 defconfig 文件防止make distclean后丢失。经验遇到定义了但不生效的情况第一步是grep xxx .config检查实际编译配置。7.2 DM_ETH 框架的 MAC 地址问题现象PHYLIB 和 FEC 都使能后ping 时报Error: ethernet020b4000 address not set。原因2017版 U-Boot 启用了 DM_ETH设备模型以太网框架要求环境变量中必须有ethaddr否则网络设备拒绝工作。旧版2016不用 DM_ETH没有这个要求。解决在头文件的CONFIG_EXTRA_ENV_SETTINGS中添加默认ethaddr和eth1addr。7.3 PHY 硬件复位的必要性现象所有配置都正确但mdio list为空MDIO 总线上找不到 PHY。原因PHY 芯片没有被硬件复位。LAN8720A 上电后如果 RST 引脚没有经历正确的复位时序可能不会进入正常工作状态。NXP EVK 通过 74HC595 间接控制复位我的板子是直接 GPIO 控制但代码中没有复位操作。解决在setup_fec函数中添加 GPIO 复位代码拉低20ms→拉高→等待100ms。7.4 启动时 “No ethernet found” 不代表网络不工作现象启动信息显示Net: No ethernet found但手动执行ping时网络正常工作。原因DM_ETH 是懒加载的启动时eth_initialize()只是注册设备不执行 probe。No ethernet found只是这个阶段的打印实际使用网络命令时设备才会被 probe。验证用dm tree命令可以看到eth设备已注册但未 probe显示[ ]而非[]。