概述
前边的章节中介绍到如果要移植uboot的话,最好的参考就是由官方提供的demo。
1、移植
1.1 添加board对应的板级文件夹
uboot 中每个板子都有一个对应的文件夹来存放板级文件,比如开发板上外设驱动文件等等。 NXP 的 I.MX 系列芯片的所有板级文件夹都存放在 board/freescale 目录下,在这个目录下有个名为 mx6ullevk 的文件夹,这个文件夹就是 NXP 官方 I.MX6ULL EVK 开发板的板级文件夹。
-
复制 mx6ullevk,将其重命名为 mx6ull_alientek_emmc
-
进 入 mx6ull_alientek_emmc 目 录 中 , 将 其 中 的 mx6ullevk.c 文 件 重 命 名 为mx6ull_alientek_emmc.c
-
由于修改了c文件名称,因此需要修改Makefile文件,修改如下:obj-y := mx6ull_alientek_emmc.o
-
修改imximage.cfg 文件,imx选择从内部的bootrom启动时,芯片会执行内部的 boot ROM 代码,这段 boot ROM 代码会进行硬件初始化(一部分外设),然后从 boot 设备(就是存放代码的设备、比如SD/EMMC、 NAND)中将代码拷贝出来复制到指定的 RAM 中,一般是 DDR。而我们编译好的bin文件还需要在头部加一些信息,才能够被识别,而这些信息就是这个imximage.cfg文件。此处的改动并不影响实际的结果,因为并未使用此插件,为保持统一而修改
-
修改Kconfig文件,如下 (make menuconfig时使用,同时Makefile.autoconf也会读取BOARD和NAME信息,用于路径和文件的匹配)
-
修改MAINTAINERS 文件,如下 (暂未知此文件用处)
由此可见此处的修改基本都是由于文件路径、名称的变更导致的修改
1.2 添加board配置文件
在 configs 目录下创建默认配置文件,复制 mx6ull_14x14_evk_emmc_defconfig,然后重命名为 mx6ull_alientek_emmc_defconfig,原文件如下:
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ullevk/imximage.cfg,MX6ULL_EVK_EMMC_REWORK"
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_14X14_EVK=y
CONFIG_CMD_GPIO=y
在之前的章节中有讲到过include/config.h文件是生成出来的,是由scripts/Makefile.autoconf 脚本生成的,而此脚本会读取xxx_defconfig的信息,从而需要对几个参数进行修改,修改后的如下:
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_alientek_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK"
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_ALIENTEK_EMMC=y
CONFIG_CMD_GPIO=y
可以看到主要是修改了CONFIG_SYS_EXTRA_OPTIONS和CONFIG_TARGET_MX6ULL_ALIENTEK_EMMC=y,主要还是名称和路径的修改
生成的include/config.h如下:
#define CONFIG_IMX_CONFIG board/freescale/mx6ull_alientek_emmc/imximage.cfg
#define CONFIG_MX6ULL_EVK_EMMC_REWORK 1
#define CONFIG_BOARDDIR board/freescale/mx6ull_alientek_emmc
#include
#include
#include
#include
#include
- CONFIG_IMX_CONFIG : 读取xxx_defconfig的信息CONFIG_SYS_EXTRA_OPTIONS,生成宏
- CONFIG_MX6ULL_EVK_EMMC_REWORK :同上
- CONFIG_BOARDDIR :从1.1中读取Kconfig中的SYS_BOARD信息生成
- #include :从1.1中读取Kconfig中的SYS_CONFIG_NAME信息生成
- 其余几个头文件为固定包含
注:前边讲到make defconfig时会生成.config配置文件,此文件虽与xxx_defconfig相关,但是不仅仅是此文件!还会去相应的arch下寻找相应的kconfig文件来生成.config文件,基于一个config序列选择哪被使能,是个递归查找的过程!具体过程在scripts/Kconfig文件夹内(eg:arch/arm/Kconfig、cmd/Kconfig、drivers/core/Kconfig等等,.config的生成与配置Kconfig息息相关,xxx_defconfig只是判断是否需要使能),流程较复杂,笔者未详细查看,感兴趣的可以自行查看。各个配置得相关描述在根路径的README中有介绍!
1.3 添加board的相应头文件
在 目 录 include/configs下添 加自己borad对应的头文件,复制 include/configs/mx6ullevk.h,并重命名为mx6ull_alientek_emmc.h(此名字要与1.1中配置的SYS_CONFIG_NAME一致)。修改了头文件名称,自然还有修改头文件内预防多此包含的预编译宏的名字。
mx6ull_alientek_emmc.h中包含很多宏定义,基本是用于配置uboot和IMX6ULL的,此文件内容较多,如下所示:
从上述代码可以看到,此文件中基本都是“CONFIG_”开头的宏定义,这也说明 mx6ull_alientek_emmc.h 文件的主要功能就是配置或者裁剪 uboot。如果需要某个功能的话就在里面添加这个功能对应的 CONFIG_XXX 宏即可,如果不需要某个功能的话就删除掉对应的宏即可。
- 14行:添加了头文件 mx6_common.h,如果在 mx6ull_alientek_emmc.h 中没有发现有配置某个功能或命令,但是实际却存在的话,可以到mx6_common.h 文件里面去找一下
- 29~39行:设置DRAM大小,宏 PHYS_SDRAM_SIZE 就是板子上 DRAM 的大小,根据板子型号进行设置,我们得板子使用得是512MB
- 48行:定义CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG是为了向环境中添加描述某些运行时确定的硬件信息的环境变量,例如board_name、board_rev
- 50行:定义宏 CONFIG_DISPLAY_CPUINFO, uboot 启动的时候可以输出 CPU 信息
- 51行:定义宏 CONFIG_DISPLAY_BOARDINFO, uboot 启动的时候可以输出板子信息
- 54行:CONFIG_SYS_MALLOC_LEN 为 malloc 内存池大小,这里设置为 16MB
- 56行:定义宏 CONFIG_BOARD_EARLY_INIT_F,这样 board_init_f 函数就会调用board_early_init_f 函数
- 57行:定义宏 CONFIG_BOARD_LATE_INIT,这样 board_init_r 函数就会调用board_late_init 函数
- 59~60行:使能 I.MX6ULL 的串口功能,宏 CONFIG_MXC_UART_BASE 表示串口寄存器基地址,这里使用的串口 1,基地址为UART1_BASE, UART1_BASE 定义在文件arch/arm/include/asm/arch-mx6/imx-regs.h 中
- 63~64行:EMMC接在I.MX6ULL的USDHC2上,宏CONFIG_SYS_FSL_ESDHC_ADDR为 EMMC 所使用接口的寄存器基地址,也就是 USDHC2 的基地址
- 67~72行:跟 NAND 相关的宏,因为 NAND 和 USDHC2 的引脚冲突,因此如果使用NAND 的只能使用一个 USDHC 设备(SD 卡)。如果没有使用 NAND,那么就有两个 USDHC 设备(EMMC 和 SD 卡),宏 CONFIG_SYS_FSL_USDHC_NUM 表示 USDHC 数量。 EMMC 版本的核心版没有用到 NAND,所以 CONFIG_SYS_FSL_USDHC_NUM=2
- 75~81行:和 I2C 有关的宏定义,用于控制使能哪个 I2C, I2C 的速度为多少
- 92~96行:NAND 的分区设置
- 98~111行:宏 CONFIG_MFG_ENV_SETTINGS 定义了一些环境变量,使用 MfgTool 烧写系统时候会用到这里面的环境变量
- 112~197行:通 过 条 件 编 译 来 设 置 宏 CONFIG_EXTRA_ENV_SETTINGS , 宏CONFIG_EXTRA_ENV_SETTINGS 也是设置一些环境变量,此宏会设置 bootargs 这个环境变量
- 199~213行:设置环境变量 bootcmd,第三课中详细介绍过
- 216~218行:设置命令 memtest 相关宏定义,比如使能命令 memtest,设置 memtest 测试的内存起始地址和内存大小
- 220行:宏 CONFIG_SYS_LOAD_ADDR 表示 linux kernel 在 DRAM 中的加载地址,也就是 linux kernel 在 DRAM 中的存储首地址, CONFIG_LOADADDR=0X80800000
- 221行:宏 CONFIG_SYS_HZ 为系统时钟频率,这里为 1000Hz
- 223行:宏 CONFIG_STACKSIZE 为栈大小,这里为 128KB
- 226行:宏 CONFIG_NR_DRAM_BANKS 为 DRAM BANK 的数量, I.MX6ULL 只有一个 DRAM BANK,我们也只用到了一个 BANK,所以为 1
- 227行:宏 PHYS_SDRAM 为 I.MX6ULL 的 DRAM 控制器 MMDC0 所管辖的 DRAM 范围起始地址,也就是 0X80000000
- 229行:宏 CONFIG_SYS_SDRAM_BASE 为 DRAM 的起始地址
- 230~231行:宏 CONFIG_SYS_INIT_RAM_ADDR 为 I.MX6ULL 内部 IRAM 的起始地址(也就是 OCRAM 的起始地址),为 0X00900000。宏 CONFIG_SYS_INIT_RAM_SIZE 为 I.MX6ULL 内部 IRAM 的大小(OCRAM的大小),为 0X00040000=128KB
- 233~236行:宏 CONFIG_SYS_INIT_SP_OFFSET 和 CONFIG_SYS_INIT_SP_ADDR 与初始 SP 有关,第一个为初始 SP 偏移,第二个为初始 SP 地址
- 252~254行:宏CONFIG_SYS_MMC_ENV_DEV为默认的MMC设备,这里默认为USDHC2,也就是 EMMC。宏CONFIG_SYS_MMC_ENV_PART 为模式分区,默认为第 0 个分区。宏 CONFIG_MMCROOT 设置进入 linux 系统的根文件系统所在的分区,这里设置为"/dev/mmcblk1p2",也就是 EMMC 设备的第 2 个分区。第 0 个分区保存 uboot,第 1 个分区保存 linux 镜像和设备树,第 2 个分区为 Linux 系统的根文件系统
- 256行:bMODE,IMX6专用,用于强制从特定介质启动
- 258~270行:spi相关配置,未使用
- 272~287行:nand相关配置,未使用
- 289行:宏 CONFIG_ENV_SIZE 为环境变量大小,默认为 8KB
- 290~304行:宏 CONFIG_ENV_OFFSET 为环境变量偏移地址,这里的偏移地址是相对于存储器的首地址。如果环境变量保存在 EMMC 中的话,环境变量偏移地址为 1264KB。如果环境变量保存在 SPI FLASH 中的话,偏移地址为 7681024。如果环境变量保存在 NAND 中的话,偏移地址为 60<<20(60MB),并且重新设置环境变量的大小为 128KB
- 307~319行:usb相关配置
- 321~342行:与网络相关的宏定义,比如使能 dhcp、 ping 等命令。宏CONFIG_FEC_ENET_DEV 指定 uboot 所使用的网口, I.MX6ULL 有两个网口,为 0 的时候使用 ENET1,为 1 的时候使用 ENET2。宏 IMX_FEC_BASE 为 ENET 接口的寄存器首地址,宏CONFIG_FEC_MXC_PHYADDR 为网口 PHY 芯片的地址。宏 CONFIG_FEC_XCV_TYPE 为PHY 芯片所使用的接口类型, I.MX6U-ALPHA 开发板的两个 PHY 都使用的 RMII 接口。
- 365行:应该对此进行定义。否则无法保存环境文件。
- OTHER
1.4 修改 U-Boot 图形界面配置文件
uboot 是支持图形界面配置,修改文件arch/arm/cpu/armv7/mx6/Kconfig(如果用的 I.MX6UL 的话,应该修改 arch/arm/Kconfig 这个文件),添加如下内容
1.5 网络驱动修改
网络在uboot开发调试中至关重要,因此网络驱动的移植修改也是uboot必须完成的东西,但是外设驱动和硬件相关性较大(芯片选型、连接方式等),因此此处不讲解移植网络的细节,仅介绍一些通用的框架和几个关键点,驱动的具体写法还是自己参考相应的手册。
I.MX6UL/ULL 内部有个以太网MAC外设,也就是 ENET,需要外接一个PHY芯片来实现网络通信功能,也就是内部 MAC+外部 PHY 芯片的方案。也有一些内部不带MAC的CPU,它们就使用一些MAC+PHY的芯片,例如DM9000就是一个MAC+PHY芯片,也就是外部MAC+外部PHY。采用内部MAC的CPU在网络传输的效率和速度上占有绝对优势。
I.MX6UL/ULL 有两个网络接口 ENET1 和 ENET2。
mx6ull_alientek_emmc.h的321~342行是关于网络的配置。CONFIG_FEC_ENET_DEV 用于选择使用哪个网口,默认为 1,也就是选择
ENET2。CONFIG_FEC_MXC_PHYADDR为 ENET1 的 PHY 地址,默认是 0X2,根据实际原理图设置此值。
根据选择的PHY芯片的类型配置相应的驱动,因为 LAN8720A 就是 SMSC 公司生产的,因此此处选择将 CONFIG_PHY_MICREL 改为 CONFIG_PHY_SMSC。
按实际原理图及芯片修改完配置及代码后,进入到uboot后,需要设置相应的几个环境变量,如下:
setenv ipaddr 192.168.1.55 //开发板 IP 地址
setenv ethaddr 00:04:9f:04:d2:35 //开发板网卡 MAC 地址
setenv gatewayip 192.168.1.1 //开发板默认网关
setenv netmask 255.255.255.0 //开发板子网掩码
setenv serverip 192.168.1.250 //服务器地址,也就是 Ubuntu 地址
saveenv //保存环境变量
确认能够ping之后,网络驱动修改完成。
1.6 bootcmd 和 bootargs 环境变量
uboot 中有两个非常重要的环境变量 bootcmd 和 bootargs,接下来看一下这两个环境变量。bootcmd 和 bootagrs 是采用类似 shell 脚本语言编写的,里面有很多的变量引用,这些变量其实都 是 环 境 变 量 , 有 很 多 是 NXP 自 己 定 义 的 。
1.6.1 bootcmd
bootcmd 保存着 uboot 默认命令, uboot 倒计时结束以后就会执行 bootcmd 中的命令。这些命令一般都是用来启动 Linux 内核的,比如读取 EMMC 或者 NAND Flash 中的 Linux 内核镜像文件和设备树文件到 DRAM 中,然后启动 Linux 内核。在第三章中有详细介绍,此处不做展开讲解
1.6.2 bootargs
bootargs 保存着 uboot 传递给 Linux 内核的参数,在上一小节讲解 bootcmd 的时候说过,bootargs 环境变量是由 mmcargs 设置的, mmcargs 环境变量如下:
mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot}
其中 console=ttymxc0, baudrate=115200, mmcroot=/dev/mmcblk1p2 rootwait rw,因此将mmcargs 展开以后就是:
mmcargs=setenv bootargs console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw
可以看出环境变量 mmcargs 就是设置 bootargs 的值为“ console= ttymxc0, 115200 root=/dev/mmcblk1p2 rootwait rw”, bootargs 就是设置了很多的参数的值,这些参数 Linux 内核会使用到,常用的参数有:
- console
console 用来设置 linux 终端(或者叫控制台),也就是通过什么设备来和 Linux 进行交互,是串口还是 LCD 屏幕?如果是串口的话应该是串口几等等。一般设置串口作为 Linux 终端,这样我们就可以在电脑上通过 SecureCRT 来和 linux 交互了。这里设置 console 为 ttymxc0,因为 linux启动以后 I.MX6ULL 的串口 1 在 linux 下的设备文件就是/dev/ttymxc0,在 Linux 下,一切皆文件。ttymxc0 后面有个“,115200”,这是设置串口的波特率, console=ttymxc0,115200 综合起来就是设置 ttymxc0(也就是串口 1)作为 Linux 的终端,并且串口波特率设置为 115200
- root
root 用来设置根文件系统的位置, root=/dev/mmcblk1p2 用于指明根文件系统存放在mmcblk1 设备的分区 2 中。 EMMC 版本的核心板启动 linux 以后会存在/dev/mmcblk0、/dev/mmcblk1、 /dev/mmcblk0p1、 /dev/mmcblk0p2、 /dev/mmcblk1p1 和/dev/mmcblk1p2 这样的文件,其中/dev/mmcblkx(x=0~n)表示 mmc 设备,而/dev/mmcblkxpy(x=0n,y=1n)表示 mmc 设备x 的分区 y。在 I.MX6U-ALPHA 开发板中/dev/mmcblk1 表示 EMMC,而/dev/mmcblk1p2 表示EMMC 的分区 2。
root 后面有“rootwait rw”, rootwait 表示等待 mmc 设备初始化完成以后再挂载,否则的话mmc 设备还没初始化完成就挂载根文件系统会出错的。 rw 表示根文件系统是可以读写的,不加rw 的话可能无法在根文件系统中进行写操作,只能进行读操作。
- rootfstype
此选项一般配置 root 一起使用, rootfstype 用于指定根文件系统类型,如果根文件系统为ext 格式的话此选项无所谓。如果根文件系统是 yaffs、 jffs 或 ubifs 的话就需要设置此选项,指定根文件系统的类型。
2、总结
- 不管是购买的开发板还是自己做的开发板,基本都是参考半导体厂商的 dmeo 板,而半导体厂商会在他们自己的开发板上移植好 uboot、 linux kernel 和 rootfs 等,最终制作好 BSP包提供给用户。我们可以在官方提供的 BSP 包的基础上添加我们的板子,也就是俗称的移植
- 我们购买的开发板或者自己做的板子一般都不会原封不动的照抄半导体厂商的 demo板,都会根据实际的情况来做修改,既然有修改就必然涉及到 uboot 下驱动的移植
- 一般 uboot 中需要解决串口、 NAND、 EMMC 或 SD 卡、网络和 LCD 驱动,因为 uboot的主要目的就是启动 Linux 内核,所以不需要考虑太多的外设驱动
- 在 uboot 中添加自己的板子信息,根据自己板子的实际情况来修改 uboot 中的驱动