I.MX6ULL_Linux_系统篇(18) uboot移植

原厂uboot

编译

        uboot 的移植并不是说我们完完全全的从零开始将 uboot 移植到我们现在所使用的开发板或者开发平台上。这个对于我们来说基本是不可能的,这个工作一般是半导体厂商做的, 半导体厂商负责将 uboot 移植到他们的芯片上,因此半导体厂商都会自己做一个开发板,这个开发板就叫做原厂开发板,比如大家学习STM32的时候听说过的discover开发板就是ST自己做的。半导体厂商会将 uboot 移植到他们自己的原厂开发板上,测试好以后就会将这个 uboot 发布出去,这就是大家常说的原厂 BSP 包。我们一般做产品的时候就会参考原厂的开发板做硬件,然后在原厂提供的 BSP 包上做修改,将 uboot 和 linux kernel 移植到我们的硬件上。这个就是uboot 移植的一般流程:
①、在 uboot 中找到参考的开发平台,一般是原厂的开发板。
②、参考原厂开发板移植 uboot 到我们所使用的开发板上。

        我们以 NXP 官方的 I.MX6ULL EVK 开发板为蓝本,将 NXP 官方的 uboot 移植到正点原子的 I.MX6ULL 开发板上, NXP 官方的uboot为uboot-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2 将源码存放至服务器上。在移植之前,我们先编译一下 NXP 官方 I.MX6ULL EVK 开发板对应的 uboot,首先是配置uboot, configs 目录下有很多跟 I.MX6UL/6ULL 有关的配置如图所示:

从图中可以看出有很多的默认配置文件,其中以mx6ull 开头的是 I.MX6ULL 开发板的。 I.MX6ULL 有 9x9mm 和 14x14mm 两种尺寸的,所以我们可以看到会有mx6ull_9x9和mx6ull_14x14开头的默认配置文件。我们使用的是14x14mm的芯片,所以关注 mx6ull_14x14 开头的默认配置文件。正点原子的 I.MX6ULL 有 EMMC 和NAND 两 个 版 本 的 , 因 此 我 们 最 终 只 需 要 关 注 mx6ull_14x14_evk_emmc_defconfig 和mx6ull_14x14_evk_nand_defconfig 这两个配置文件就行了。本章我们讲解 EMMC 版本的移植
(NAND 版本移植很多类似),所以使用 mx6ull_14x14_evk_emmc_defconfig 作为默认配置文件。

找到 NXP 官方 I.MX6ULL EVK 开发板对应的默认配置文件以后就可以编译一下,使用如下命令编译 uboot:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_evk_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

编译完成以后结果如图所示,从图中可以看出,编译成功:

编译完成以后会生成 u-boot.bin、 u-boot.imx 等文件,但是这些文件是 NXP 官方 I.MX6ULLEVK 开发板。能不能用到正点原子的 I.MX6ULL 开发板上呢?试一下不就知道了!

测试

将 imxdownload 软件拷贝到 uboot 源码根目录下,然后使用 imxdownload 软件将 u-boot.bin烧写到 SD 卡中,烧写命令如下:

chmod 777 imxdownload //给予 imxdownload 可执行权限
./imxdownload u-boot.bin /dev/sdd //烧写到 SD 卡中,不能烧写到/dev/sda 或 sda1 里面

烧写完成以后将 SD 卡插入 I.MX6U-ALPHA 开发板的 TF 卡槽中,最后设置开发板从 SD卡启动。打开 SecureCRT,设置好开发板所使用的串口并打开,复位开发板, SecureCRT 接收到如下图所示信息:

从图中可以看出, uboot 启动正常,虽然我们用的是 NXP 官方 I.MX6ULL 开发板的uboot,但是在正点原子的 I.MX6ULL 开发板上是可以正常启动的。而且 DRAM 识别正确,为
512MB,如果用的 NAND 版本的核心版的话 uboot 启动会失败!因为 NAND 核心版用的 256MB的 DRAM。

emmc接口验证

检查一下 SD 卡和 EMMC 驱动是否正常,使用命令 mmc list 列出当前的 MMC 设备,结果如图所示:

 从图中可以看出当前有两个 MMC 设备,检查每个 MMC 设备信息,先检查 MMC 设备 0,输入如下命令:

mmc dev 0
mmc info

从图中可以看出, mmc 设备 0 是 SD 卡, SD 卡容量为 14.8GB,这个和我所使用的SD 卡信息相符,说明 SD 卡驱动正常。再来检查 MMC 设备 1,输入如下命令:

mmc dev 1
mmc info

从图中可以看出, mmc 设备 1 为 EMMC,容量为 7.3GB,说明 EMMC 驱动也成功,SD 卡和 EMMC 的驱动都没问题。

LCD 接口验证

如果 uboot 中的 LCD 驱动正确的话,启动 uboot 以后 LCD 上应该会显示出 NXP 的 logo,如下图所示:

如果你用的不是正点原子的 4.3 寸 480x272 分辨率的屏幕的话,那么 LCD 就不会显示所示 logo 界面。因为 NXP 官方 I.MX6ULL 开发板的屏幕就是 4.3 寸 480x272 分辨率
的,所以 uboot 默认 LCD 驱动是 4.3 寸 480x272 分辨率的。如果使用其他分辨率的 LCD 就需要修改 LCD 驱动,这里我们先不修改 LCD 驱动了,稍后我们在讲解如何修改 uboot 中的 LCD驱动,我们只需要记得, uboot 的 LCD 需要修改就行了。

网口验证

uboot 启动的时候提示“Board Net Initialization Failed”和“No ethernet found.”这两行,说明网络驱动也有问题,那更别说 ping 一下主机了,说明当前 uboot 的网络部驱动也是有问题的,这是因为正点原子开发板的网络芯片复位引脚和 NXP 官方开发板不一样,因此需要修改驱动。

总结一下 NXP 官方 I.MX6ULL EVK 开发板的 uboot 在正点原子 EMMC 版本 I.MX6ULL开发板上的运行情况:
①、 uboot 启动正常, DRAM 识别正确, SD 卡和 EMMC 驱动正常。
②、 uboot 里面的 LCD 驱动默认是给 4.3 寸 480x272 分辨率的,如果使用的其他分辨率的屏幕需要修改驱动。
③、网络不能工作,识别不出来网络信息,需要修改驱动。

接下来我们要做的工作如下:
①、前面我们一直使用着 NXP 官方开发板的 uboot 配置,接下来需要在 uboot 中添加我们自己的开发板,也就是正点原子的 I.MX6ULL 开发板。
②、解决 LCD 驱动和网络驱动的问题。
 

移植

添加defconfig配置文件

在 configs 目录下,复制 mx6ull_14x14_evk_emmc_defconfig,重命名为 mx6ull_alientek_emmc_defconfig,命令如下:

cd configs
cp mx6ull_14x14_evk_emmc_defconfig mx6ull_alientek_emmc_defconfig

查看mx6ull_14x14_evk_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

将mx6ull_alientek_emmc_defconfig中的内容修改为如下:

1 CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_alientek_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK"
2 CONFIG_ARM=y
3 CONFIG_ARCH_MX6=y
4 CONFIG_TARGET_MX6ULL_ALIENTEK_EMMC=y
5 CONFIG_CMD_GPIO=y

可以看到第一行扩展选项是一个路径从mx6ullevk修改为了mx6ull_alientek_emmc,该路径在board目录下,imximage.cfg是什么呢,是添加到u-boot.bin的头部信息,因为后面我们要把board目录下的board源码也要复制一份,所以这里是提前为了board复制做准备。同时修改的还有第四行,每一个board,都有一个target配置,属于最顶层的配置,如果该选项没有有我们的板子对应,则源码不会编译,这里的选项后面要在arch/arm/Kconfig(大概路径,不同板子不绝对)文件中定义。其实这里可以不修改,后面在menuconfig中自定义选项!

添加开发板对应的头文件

在目录include/configs 下添加I.MX6ULL-ALPHA开发板对应的头文件,复制include/configs/mx6ullevk.h(对于怎么确定该头文件对应于board,可以在board下的Kconfig找到依据),并重命名为 mx6ull_alientek_emmc.h,命令如下:

cp include/configs/mx6ullevk.h mx6ull_alientek_emmc.h

拷贝完成以后将.h的宏修改掉,否则宏重复:

#ifndef __MX6ULLEVK_CONFIG_H
#define __MX6ULLEVK_CONFIG_H

->

#ifndef __MX6ULL_ALIENTEK_EMMC_CONFIG_H
#define __MX6ULL_ALIENTEK_EMMC_CONFIG_H

mx6ull_alientek_emmc.h 里面有很多宏定义,这些宏定义基本用于配置 uboot,也有一些I.MX6ULL 的配置项目。如果我们自己要想使能或者禁止 uboot 的某些功能,那就在
mx6ull_alientek_emmc.h 里面做修改即可。 mx6ull_alientek_emmc.h 里面的内容比较多,去掉一些用不到的配置,精简后的内容如下:

1 /*
2 * Copyright (C) 2016 Freescale Semiconductor, Inc.
3 *
4 * Configuration settings for the Freescale i.MX6UL 14x14 EVK board.
5 *
6 * SPDX-License-Identifier: GPL-2.0+
7 */
8 #ifndef __MX6ULL_ALEITENK_EMMC_CONFIG_H
9 #define __MX6ULL_ALEITENK_EMMC_CONFIG_H
10
11
12 #include <asm/arch/imx-regs.h>
13 #include <linux/sizes.h>
14 #include "mx6_common.h"
15 #include <asm/imx-common/gpio.h>
16
......
28
29 #define is_mx6ull_9x9_evk() CONFIG_IS_ENABLED(TARGET_MX6ULL_9X9_EVK)
30
31 #ifdef CONFIG_TARGET_MX6ULL_9X9_EVK
32 #define PHYS_SDRAM_SIZE SZ_256M
33 #define CONFIG_BOOTARGS_CMA_SIZE "cma=96M "
34 #else
35 #define PHYS_SDRAM_SIZE SZ_512M
36 #define CONFIG_BOOTARGS_CMA_SIZE ""
37 /* DCDC used on 14x14 EVK, no PMIC */
38 #undef CONFIG_LDO_BYPASS_CHECK
39 #endif
40
41 /* SPL options */
42 /* We default not support SPL
43 * #define CONFIG_SPL_LIBCOMMON_SUPPORT
44 * #define CONFIG_SPL_MMC_SUPPORT
45 * #include "imx6_spl.h"
46 */
47
48 #define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
49
50 #define CONFIG_DISPLAY_CPUINFO
51 #define CONFIG_DISPLAY_BOARDINFO
52
53 /* Size of malloc() pool */
54 #define CONFIG_SYS_MALLOC_LEN (16 * SZ_1M)
55
56 #define CONFIG_BOARD_EARLY_INIT_F
57 #define CONFIG_BOARD_LATE_INIT
58
59 #define CONFIG_MXC_UART
60 #define CONFIG_MXC_UART_BASE UART1_BASE
61
62 /* MMC Configs */
63 #ifdef CONFIG_FSL_USDHC
64 #define CONFIG_SYS_FSL_ESDHC_ADDR USDHC2_BASE_ADDR
65
66 /* NAND pin conflicts with usdhc2 */
67 #ifdef CONFIG_SYS_USE_NAND
68 #define CONFIG_SYS_FSL_USDHC_NUM 1
69 #else
70 #define CONFIG_SYS_FSL_USDHC_NUM 2
71 #endif
72 #endif
73
74 /* I2C configs */
75 #define CONFIG_CMD_I2C
76 #ifdef CONFIG_CMD_I2C
77 #define CONFIG_SYS_I2C
78 #define CONFIG_SYS_I2C_MXC
79 #define CONFIG_SYS_I2C_MXC_I2C1 /* enable I2C bus 1 */
80 #define CONFIG_SYS_I2C_MXC_I2C2 /* enable I2C bus 2 */
81 #define CONFIG_SYS_I2C_SPEED 100000
82
......
89
90 #define CONFIG_SYS_MMC_IMG_LOAD_PART 1
91
92 #ifdef CONFIG_SYS_BOOT_NAND
93 #define CONFIG_MFG_NAND_PARTITION "mtdparts=gpminand:64m(boot),16m(kernel),16m(dtb),1m(misc),-(rootfs) "
94 #else
95 #define CONFIG_MFG_NAND_PARTITION ""
96 #endif
97
98 #define CONFIG_MFG_ENV_SETTINGS \
99 "mfgtool_args=setenv bootargs console=${console},${baudrate} " \
......
111 "bootcmd_mfg=run mfgtool_args;bootz ${loadaddr} ${initrd_addr}
${fdt_addr};\0" \
112
113 #if defined(CONFIG_SYS_BOOT_NAND)
114 #define CONFIG_EXTRA_ENV_SETTINGS \
115 CONFIG_MFG_ENV_SETTINGS \
116 "panel=TFT43AB\0" \
......
126 "bootz ${loadaddr} - ${fdt_addr}\0"
127
128 #else
129 #define CONFIG_EXTRA_ENV_SETTINGS \
130 CONFIG_MFG_ENV_SETTINGS \
131 "script=boot.scr\0" \
......
202 "fi;\0" \
203
204 #define CONFIG_BOOTCOMMAND \
205 "run findfdt;" \
......
216 "else run netboot; fi"
217 #endif
218
219 /* Miscellaneous configurable options */
220 #define CONFIG_CMD_MEMTEST
221 #define CONFIG_SYS_MEMTEST_START 0x80000000
222 #define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_MEMTEST_START +
0x8000000)
223
224 #define CONFIG_SYS_LOAD_ADDR CONFIG_LOADADDR
225 #define CONFIG_SYS_HZ 1000
226
227 #define CONFIG_STACKSIZE SZ_128K
228
229 /* Physical Memory Map */
230 #define CONFIG_NR_DRAM_BANKS 1
231 #define PHYS_SDRAM MMDC0_ARB_BASE_ADDR
232
233 #define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM
234 #define CONFIG_SYS_INIT_RAM_ADDR IRAM_BASE_ADDR
235 #define CONFIG_SYS_INIT_RAM_SIZE IRAM_SIZE
236
237 #define CONFIG_SYS_INIT_SP_OFFSET \
238 (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
239 #define CONFIG_SYS_INIT_SP_ADDR \
240 (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)
241
242 /* FLASH and environment organization */
243 #define CONFIG_SYS_NO_FLASH
244
......
255
256 #define CONFIG_SYS_MMC_ENV_DEV 1 /* USDHC2 */
257 #define CONFIG_SYS_MMC_ENV_PART 0 /* user area */
258 #define CONFIG_MMCROOT "/dev/mmcblk1p2" /* USDHC2 */
259
260 #define CONFIG_CMD_BMODE
261
......
275
276 /* NAND stuff */
277 #ifdef CONFIG_SYS_USE_NAND
278 #define CONFIG_CMD_NAND
279 #define CONFIG_CMD_NAND_TRIMFFS
280
281 #define CONFIG_NAND_MXS
282 #define CONFIG_SYS_MAX_NAND_DEVICE 1
283 #define CONFIG_SYS_NAND_BASE 0x40000000
284 #define CONFIG_SYS_NAND_5_ADDR_CYCLE
285 #define CONFIG_SYS_NAND_ONFI_DETECTION
286
287 /* DMA stuff, needed for GPMI/MXS NAND support */
288 #define CONFIG_APBH_DMA
289 #define CONFIG_APBH_DMA_BURST
290 #define CONFIG_APBH_DMA_BURST8
291 #endif
292
293 #define CONFIG_ENV_SIZE SZ_8K
294 #if defined(CONFIG_ENV_IS_IN_MMC)
295 #define CONFIG_ENV_OFFSET (12 * SZ_64K)
296 #elif defined(CONFIG_ENV_IS_IN_SPI_FLASH)
297 #define CONFIG_ENV_OFFSET (768 * 1024)
298 #define CONFIG_ENV_SECT_SIZE (64 * 1024)
299 #define CONFIG_ENV_SPI_BUS CONFIG_SF_DEFAULT_BUS
300 #define CONFIG_ENV_SPI_CS CONFIG_SF_DEFAULT_CS
301 #define CONFIG_ENV_SPI_MODE CONFIG_SF_DEFAULT_MODE
302 #define CONFIG_ENV_SPI_MAX_HZ CONFIG_SF_DEFAULT_SPEED
303 #elif defined(CONFIG_ENV_IS_IN_NAND)
304 #undef CONFIG_ENV_SIZE
305 #define CONFIG_ENV_OFFSET (60 << 20)
306 #define CONFIG_ENV_SECT_SIZE (128 << 10)
307 #define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE
308 #endif
309
310
311 /* USB Configs */
312 #define CONFIG_CMD_USB
313 #ifdef CONFIG_CMD_USB
314 #define CONFIG_USB_EHCI
315 #define CONFIG_USB_EHCI_MX6
316 #define CONFIG_USB_STORAGE
317 #define CONFIG_EHCI_HCD_INIT_AFTER_RESET
318 #define CONFIG_USB_HOST_ETHER
319 #define CONFIG_USB_ETHER_ASIX
320 #define CONFIG_MXC_USB_PORTSC (PORT_PTS_UTMI | PORT_PTS_PTW)
321 #define CONFIG_MXC_USB_FLAGS 0
322 #define CONFIG_USB_MAX_CONTROLLER_COUNT 2
323 #endif
324
325 #ifdef CONFIG_CMD_NET
326 #define CONFIG_CMD_PING
327 #define CONFIG_CMD_DHCP
328 #define CONFIG_CMD_MII
329 #define CONFIG_FEC_MXC
330 #define CONFIG_MII
331 #define CONFIG_FEC_ENET_DEV 1
332
333 #if (CONFIG_FEC_ENET_DEV == 0)
334 #define IMX_FEC_BASE ENET_BASE_ADDR
335 #define CONFIG_FEC_MXC_PHYADDR 0x2
336 #define CONFIG_FEC_XCV_TYPE RMII
337 #elif (CONFIG_FEC_ENET_DEV == 1)
338 #define IMX_FEC_BASE ENET2_BASE_ADDR
339 #define CONFIG_FEC_MXC_PHYADDR 0x1
340 #define CONFIG_FEC_XCV_TYPE RMII
341 #endif
342 #define CONFIG_ETHPRIME "FEC"
343
344 #define CONFIG_PHYLIB
345 #define CONFIG_PHY_MICREL
346 #endif
347
348 #define CONFIG_IMX_THERMAL
349
350 #ifndef CONFIG_SPL_BUILD
351 #define CONFIG_VIDEO
352 #ifdef CONFIG_VIDEO
353 #define CONFIG_CFB_CONSOLE
354 #define CONFIG_VIDEO_MXS
355 #define CONFIG_VIDEO_LOGO
356 #define CONFIG_VIDEO_SW_CURSOR
357 #define CONFIG_VGA_AS_SINGLE_DEVICE
358 #define CONFIG_SYS_CONSOLE_IS_IN_ENV
359 #define CONFIG_SPLASH_SCREEN
360 #define CONFIG_SPLASH_SCREEN_ALIGN
361 #define CONFIG_CMD_BMP
362 #define CONFIG_BMP_16BPP
363 #define CONFIG_VIDEO_BMP_RLE8
364 #define CONFIG_VIDEO_BMP_LOGO
365 #define CONFIG_IMX_VIDEO_SKIP
366 #endif
367 #endif
368
369 #define CONFIG_IOMUX_LPSR
370
......
375 #endif

从代码中可以看出, mx6ull_alientek_emmc.h 文件中基本都是“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 的大小,如果用的 NXP 官方的 9X9 EVK 开发板的话 DRAM 大小就为 256MB。否则的话默认为 512MB,
正点原子的 I.MX6U-ALPHA 开发板用的是 512MB DDR3。
第 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 的分区设置,如果使用 NAND 的话,默认的 NAND 分区为:"mtdparts=gpmi-nand:64m(boot),16m(kernel),16m(dtb),1m(misc),-(rootfs) ",一般我们并不使用uboot的分区表信息,而是在kernel中自定义分区表。

第 98~111 行,宏 CONFIG_MFG_ENV_SETTINGS 定义了一些环境变量,使用 MfgTool 烧写系统时候会用到这里面的环境变量。
第 113~202 行 , 通 过 条 件 编 译 来 设 置 宏 CONFIG_EXTRA_ENV_SETTINGS , 宏CONFIG_EXTRA_ENV_SETTINGS 也是设置一些环境变量,此宏会设置 bootargs 这个环境变
量,后面我们会详细分析这个宏定义。
第 204~217 行,设置宏 CONFIG_BOOTCOMMAND,此宏就是设置环境变量 bootcmd 的值。后面会详细的分析这个宏定义。
第 220~222 行,设置命令 memtest 相关宏定义,比如使能命令 memtest,设置 memtest 测试的内存起始地址和内存大小。
第 224 行,宏 CONFIG_SYS_LOAD_ADDR 表示 linux kernel 在 DRAM 中的加载地址,也就是 linux kernel 在 DRAM 中的存储首地址, CONFIG_LOADADDR=0X80800000。
第 225 行,宏 CONFIG_SYS_HZ 为系统时钟频率,这里为 1000Hz。
第 227 行,宏 CONFIG_STACKSIZE 为栈大小,这里为 128KB。
第 230 行,宏 CONFIG_NR_DRAM_BANKS 为 DRAM BANK 的数量, I.MX6ULL 只有一个 DRAM BANK,我们也只用到了一个 BANK,所以为 1。
第 231 行,宏 PHYS_SDRAM 为 I.MX6ULL 的 DRAM 控制器 MMDC0 所管辖的 DRAM 范围起始地址,也就是 0X80000000。
第 233 行,宏 CONFIG_SYS_SDRAM_BASE 为 DRAM 的起始地址。
第 234 行,宏 CONFIG_SYS_INIT_RAM_ADDR 为 I.MX6ULL 内部 IRAM 的起始地址(也就是 OCRAM 的起始地址),为 0X00900000。
第 235 行,宏 CONFIG_SYS_INIT_RAM_SIZE 为 I.MX6ULL 内部 IRAM 的大小(OCRAM的大小),为 0X00040000=128KB。
第 237~240 行,宏 CONFIG_SYS_INIT_SP_OFFSET 和 CONFIG_SYS_INIT_SP_ADDR 与初始 SP 有关,第一个为初始 SP 偏移,第二个为初始 SP 地址。
第256行,宏CONFIG_SYS_MMC_ENV_DEV为默认的MMC设备,这里默认为USDHC2,也就是 EMMC。
第 257 行,宏 CONFIG_SYS_MMC_ENV_PART 为模式分区,默认为第 0 个分区。
第 258 行,宏 CONFIG_MMCROOT 设置进入 linux 系统的根文件系统所在的分区,这里设置为"/dev/mmcblk1p2",也就是 EMMC 设备的第 2 个分区。第 0 个分区保存 uboot,第 1 个分
区保存 linux 镜像和设备树,第 2 个分区为 Linux 系统的根文件系统。
第 277~291 行,与 NAND 有关的宏定义,如果使用 NAND 的话。
第 293 行,宏 CONFIG_ENV_SIZE 为环境变量大小,默认为 8KB。
第 294~308 行,宏 CONFIG_ENV_OFFSET 为环境变量偏移地址,这里的偏移地址是相对于存储器的首地址。如果环境变量保存在 EMMC 中的话,环境变量偏移地址为 12*64KB。如
果环境变量保存在 SPI FLASH 中的话,偏移地址为 768*1024。如果环境变量保存在 NAND 中的话,偏移地址为 60<<20(60MB),并且重新设置环境变量的大小为 128KB。
第 312~323 行,与 USB 相关的宏定义。
第 325~342 行,与网络相关的宏定义,比如使能 dhcp、 ping 等命令。第 331 行的宏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 接口。
第 344~END,剩下的都是一些配置宏,比如 CONFIG_VIDEO 宏用于开启 LCD,CONFIG_VIDEO_LOGO 使能 LOGO 显示, CONFIG_CMD_BMP 使能 BMP 图片显示指令。这样就可以在 uboot 中显示图片了,一般用于显示 logo。

关于 mx6ull_alientek_emmc.h 就讲解到这里,其中以 CONFIG_CMD 开头的宏都是用于使能相应命令的,其他的以 CONFIG 开头的宏都是完成一些配置功能的。以后会频繁的和
mx6ull_alientek_emmc.h 这个文件打交道,如果用过一些新版本的uboot话,大家可以看出新版本将大部分config项都放到了menuconfig中,配置头文件会越来越精简。

添加board板级文件夹

uboot 中每个板子都有一个对应的文件夹来存放板级文件,比如开发板上外设驱动文件等等。 NXP 的 I.MX 系列芯片的所有板级文件夹都存放在 board/freescale 目录下,在这个目录下有个名为 mx6ullevk 的文件夹,这个文件夹就是 NXP 官方 I.MX6ULL EVK 开发板的板级文件夹。复制 mx6ullevk,将其重命名为 mx6ull_alientek_emmc,命令如下:

cd board/freescale/
cp mx6ullevk/ -r mx6ull_alientek_emmc

进 入 mx6ull_alientek_emmc 目 录 中 , 将 其 中 的 mx6ullevk.c 文 件 重 命 名 为mx6ull_alientek_emmc.c,命令如下:

cd mx6ull_alientek_emmc
mv mx6ullevk.c mx6ull_alientek_emmc.c

我们还需要对 mx6ull_alientek_emmc 目录下的文件做一些修改:

修改 Makefile 文件(因为.c文件名字改了,所以Makefile也要改):

1 # (C) Copyright 2015 Freescale Semiconductor, Inc.
2 #
3 # SPDX-License-Identifier: GPL-2.0+
4 #
5 
6 obj-y := mx6ull_alientek_emmc.o
7 
8 extra-$(CONFIG_USE_PLUGIN) := plugin.bin
9 $(obj)/plugin.bin: $(obj)/plugin.o
10 $(OBJCOPY) -O binary --gap-fill 0xff $< $@

重点是第 6 行的 obj-y,改为 mx6ull_alientek_emmc.o,这样才会编译 mx6ull_alientek_emmc.c这个文件。

修改 mx6ull_alientek_emmc 目录下的 imximage.cfg 文件

PLUGIN board/freescale/mx6ullevk/plugin.bin 0x00907000

改为

PLUGIN board/freescale/mx6ull_alientek_emmc /plugin.bin 0x00907000

修改 mx6ull_alientek_emmc 目录下的 Kconfig 文件

1 if TARGET_MX6ULL_ALIENTEK_EMMC
2 
3 config SYS_BOARD
4 default "mx6ull_alientek_emmc"
5 
6 config SYS_VENDOR
7 default "freescale"
8 
9 config SYS_SOC
10 default "mx6"
11
12 config SYS_CONFIG_NAME
13 default "mx6ull_alientek_emmc"
14
15 endif

第12,13行指定的就是include/configs目录下头文件的名字,第一行定义了if TARGET_xxxxxx,所以board目录下的文件要被使能编译要定义TARGET宏

MAINTAINERS 文件一般记录一些作者信息,可不修改。

添加图形化配置支持

修改文件arch/arm/cpu/armv7/mx6/Kconfig(如果用的 I.MX6UL 的话,应该修改 arch/arm/Kconfig 这个文件),在 207 行加入如下内容:

1 config TARGET_MX6ULL_ALIENTEK_EMMC
2 bool "Support mx6ull_alientek_emmc"
3 select MX6ULL
4 select DM
5 select DM_THERMAL

在最后一行的 endif 的前一行添加如下内容:

source "board/freescale/mx6ull_alientek_emmc/Kconfig"

这样就定义了TARGET宏,并且将board下的界面选项添加到了menuconfig中,至此要移植的东西都copy修改完毕,可以编译测试以下是否复制成功。

使用board配置编译 uboot

2 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
3 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_alientek_emmc_defconfig
4 make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- 

编译完查看board目录下的.c是否被编译成了.o,并且进行烧录测试。

驱动修改

LCD 驱动修改

一般 uboot 中修改驱动基本都是在 xxx.h 和 xxx.c 这两个文件中进行的, xxx 为板子名称,比如 mx6ull_alientek_emmc.h 和 mx6ull_alientek_emmc.c 这两个文件。
一般修改 LCD 驱动重点注意以下几点:
①、 LCD 所使用的 GPIO,查看 uboot 中 LCD 的 IO 配置是否正确。
②、 LCD 背光引脚 GPIO 的配置。
③、 LCD 配置参数是否正确。
正点原子的 I.MX6U-ALPHA 开发板 LCD 原理图和 NXP 官方 I.MX6ULL 开发板一致,也就是 LCD 的 IO 和背光 IO 都一样的,所以 IO 部分就不用修改了。需要修改的之后 LCD 参数,打开文件 mx6ull_alientek_emmc.c,找到如下所示内容:

1 struct display_info_t const displays[] = {{
2 .bus = MX6UL_LCDIF1_BASE_ADDR,
3 .addr = 0,
4 .pixfmt = 24,
5 .detect = NULL,
6 .enable = do_enable_parallel_lcd,
7 .mode = {
8 .name = "TFT43AB",
9 .xres = 480,
10 .yres = 272,
11 .pixclock = 108695,
12 .left_margin = 8,
13 .right_margin = 4,
14 .upper_margin = 2,
15 .lower_margin = 4,
16 .hsync_len = 41,
17 .vsync_len = 10,
18 .sync = 0,
19 .vmode = FB_VMODE_NONINTERLACED
20 } } };

根据自己的屏幕参数酌情修改,详细修改过程请参考原子教程!

网络驱动修改

I.MX6UL/ULL 有两个网络接口 ENET1 和 ENET2,正点原子的 I.MX6U-ALPHA 开发板提供了这两个网络接口,其中 ENET1 和 ENET2 都使用 LAN8720A 作为 PHY 芯片。 NXP 官方的
I.MX6ULL EVK 开发板使用 KSZ8081 这颗 PHY 芯片, 但是一般来说,PHY驱动是通用的,只要芯片工作,基本可以在不修改驱动的情况下适配到board。网络部分原理图如下:

 ENET1 的网络 PHY 芯片为 LAN8720A,通过 RMII 接口与 I.MX6ULL 相连,正点原子I.MX6U-ALPHA 开发板的 ENET1 引脚与 NXP 官方的 I.MX6ULL EVK 开发板基本一样,唯独复位引脚不同。从图中可以看出,正点原子 I.MX6U-ALPHA 开发板的 ENET1 复位引脚ENET1_RST 接到了 I.M6ULL 的 SNVS_TAMPER7 这个引脚上。LAN8720A 内部是有寄存器的, I.MX6ULL 会读取 LAN8720 内部寄存器来判断当前的物理链接状态、连接速度(10M 还是 100M)和双工状态(半双工还是全双工)。 I.MX6ULL 通过 MDIO接口来读取 PHY 芯片的内部寄存器, MDIO 接口有两个引脚, ENET_MDC 和 ENET_MDIO,ENET_MDC 提供时钟, ENET_MDIO 进行数据传输。一个 MDIO 接口可以管理 32 个 PHY 芯片,同一个 MDIO 接口下的这些 PHY 使用不同的器件地址来做区分, MIDO 接口通过不同的器件地址即可访问到相应的 PHY 芯片。 I.MX6U-ALPHA 开发板 ENET1 上连接的 LAN8720A器件地址为 0X0,所示我们要修改 ENET1 网络驱动的话重点就三点:
①、 ENET1 复位引脚初始化。
②、 LAN8720A 的器件 ID。
③、 LAN8720 驱动


关于 ENET2 网络驱动的修改也注意一下三点:
①、 ENET2 的复位引脚, ENET2 的复位引脚 ENET2_RST 接到了I.MX6ULL 的 SNVS_TAMPER8 上。
②、 ENET2 所使用的 PHY 芯片器件地址, PHY 器件地址为 0X1。
③、 LAN8720 驱动, ENET1 和 ENET2 都使用的 LAN8720,所以驱动肯定是一样的。
 

PHY 地址修改

首先修改 uboot 中的 ENET1 和 ENET2 的 PHY 地址和驱动,打开 mx6ull_alientek_emmc.h这个文件,找到如下代码:

325 #ifdef CONFIG_CMD_NET
326 #define CONFIG_CMD_PING
327 #define CONFIG_CMD_DHCP
328 #define CONFIG_CMD_MII
329 #define CONFIG_FEC_MXC
330 #define CONFIG_MII
331 #define CONFIG_FEC_ENET_DEV 1
332
333 #if (CONFIG_FEC_ENET_DEV == 0)
334 #define IMX_FEC_BASE ENET_BASE_ADDR
335 #define CONFIG_FEC_MXC_PHYADDR 0x2
336 #define CONFIG_FEC_XCV_TYPE RMII
337 #elif (CONFIG_FEC_ENET_DEV == 1)
338 #define IMX_FEC_BASE ENET2_BASE_ADDR
339 #define CONFIG_FEC_MXC_PHYADDR 0x1
340 #define CONFIG_FEC_XCV_TYPE RMII
341 #endif
342 #define CONFIG_ETHPRIME "FEC"
343
344 #define CONFIG_PHYLIB
345 #define CONFIG_PHY_MICREL
346 #endif

第 331 行的宏 CONFIG_FEC_ENET_DEV 用于选择使用哪个网口,默认为 1,也就是选择ENET2。第 335 行为 ENET1 的 PHY 地址,默认是 0X2,第 339 行为 ENET2 的 PHY 地址,默
认为 0x1。根据前面的分析可知,正点原子的 I.MX6U-ALPHA 开发板 ENET1 的 PHY 地址为0X0, ENET2 的 PHY 地址为 0X1,所以需要将第 335 行的宏 CONFIG_FEC_MXC_PHYADDR
改为 0x0。
第 345 行定了一个宏 CONFIG_PHY_MICREL,此宏用于使能 uboot 中 Micrel 公司的 PHY驱动, KSZ8081 这颗 PHY 芯片就是 Micrel 公司生产的,不过 Micrel 已经被 Microchip 收购了。
如果要使用 LAN8720A,那么就得将 CONFIG_PHY_MICREL 改为 CONFIG_PHY_SMSC,也就是使能 uboot 中的 SMSC 公司中的 PHY 驱动,因为 LAN8720A 就是 SMSC 公司生产的。所
以示例代码 33.2.7.1 有三处要修改:
①、修改 ENET1 网络 PHY 的地址。
②、修改 ENET2 网络 PHY 的地址。
③、使能 SMSC 公司的 PHY 驱动。
修改后的网络 PHY 地址参数如下所示:

325 #ifdef CONFIG_CMD_NET
326 #define CONFIG_CMD_PING
327 #define CONFIG_CMD_DHCP
328 #define CONFIG_CMD_MII
329 #define CONFIG_FEC_MXC
330 #define CONFIG_MII
331 #define CONFIG_FEC_ENET_DEV 1
332
333 #if (CONFIG_FEC_ENET_DEV == 0)
334 #define IMX_FEC_BASE ENET_BASE_ADDR
335 #define CONFIG_FEC_MXC_PHYADDR 0x0
336 #define CONFIG_FEC_XCV_TYPE RMII
337 #elif (CONFIG_FEC_ENET_DEV == 1)
338 #define IMX_FEC_BASE ENET2_BASE_ADDR
339 #define CONFIG_FEC_MXC_PHYADDR 0x1
340 #define CONFIG_FEC_XCV_TYPE RMII
341 #endif
342 #define CONFIG_ETHPRIME "FEC"
343
344 #define CONFIG_PHYLIB
345 #define CONFIG_PHY_SMSC
346 #endif

删除74LV595 的驱动代码

uboot 中网络 PHY 芯片地址修改完成以后就是网络复位引脚的驱动修改了,打开mx6ull_alientek_emmc.c,找到如下代码:

#define IOX_SDI IMX_GPIO_NR(5, 10)
#define IOX_STCP IMX_GPIO_NR(5, 7)
#define IOX_SHCP IMX_GPIO_NR(5, 11)
#define IOX_OE IMX_GPIO_NR(5, 8)

示例代码中以 IOX 开头的宏定义是 74LV595 的相关 GPIO,因为 NXP 官方I.MX6ULL EVK 开发板使用 74LV595 来扩展 IO,两个网络的复位引脚就是由 74LV595 来控制的。正点原子的 I.MX6U-ALPHA 开发板并没有使用 74LV595,因此我们将示例代码中的代码删除掉,替换为如下所示代码:

#define ENET1_RESET IMX_GPIO_NR(5, 7)
#define ENET2_RESET IMX_GPIO_NR(5, 8)

ENET1 的复位引脚连接到 SNVS_TAMPER7 上,对应 GPIO5_IO07, ENET2 的复位引脚连接到 SNVS_TAMPER8 上,对应 GPIO5_IO08。继续在 mx6ull_alientek_emmc.c 中找到如下代码:

static iomux_v3_cfg_t const iox_pads[] = {
    /* IOX_SDI */
    MX6_PAD_BOOT_MODE0__GPIO5_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL),
    /* IOX_SHCP */
    MX6_PAD_BOOT_MODE1__GPIO5_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL),
    /* IOX_STCP */
    MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
    /* IOX_nOE */
    MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
};

同理,示例代码是 74LV595 的 IO 配置参数结构体,将其删除掉。继续在mx6ull_alientek_emmc.c 中找到函数 iox74lv_init,如下所示:

static void iox74lv_init(void)
{
int i;
gpio_direction_output(IOX_OE, 0);
for (i = 7; i >= 0; i--) {
gpio_direction_output(IOX_SHCP, 0);
gpio_direction_output(IOX_SDI, seq[qn_output[i]][0]);
udelay(500);
gpio_direction_output(IOX_SHCP, 1);
udelay(500);
}
......
/*
* shift register will be output to pins
*/
gpio_direction_output(IOX_STCP, 1);
};
void iox74lv_set(int index)
{
int i;
for (i = 7; i >= 0; i--) {
gpio_direction_output(IOX_SHCP, 0);
if (i == index)
gpio_direction_output(IOX_SDI, seq[qn_output[i]][0]);
else
gpio_direction_output(IOX_SDI, seq[qn_output[i]][1]);
udelay(500);
gpio_direction_output(IOX_SHCP, 1);
udelay(500);
}
......
/*
* shift register will be output to pins
*/
gpio_direction_output(IOX_STCP, 1);
};

iox74lv_init 函数是 74LV595 的初始化函数, iox74lv_set 函数用于控制 74LV595 的 IO 输出电平,将这两个函数全部删除掉!在 mx6ull_alientek_emmc.c 中找到 board_init 函数,此函数是板子初始化函数,会被board_init_r 调用, board_init 函数内容如下:

int board_init(void)
{
......
imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads));
iox74lv_init();
......
return 0;
}

board_init 会调用 imx_iomux_v3_setup_multiple_pads 和 iox74lv_init 这两个函数来初始化74lv595 的 GPIO,将这两行删除掉。至此, mx6ull_alientek_emmc.c 中关于 74LV595 芯片的驱
动代码都删除掉了,接下来就是添加 I.MX6U-ALPHA 开发板两个网络复位引脚了。

添加开发板网络复位引脚驱动

在 mx6ull_alientek_emmc.c 中找到如下所示代码,新增651和667行:

640 static iomux_v3_cfg_t const fec1_pads[] = {
641 MX6_PAD_GPIO1_IO06__ENET1_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
642 MX6_PAD_GPIO1_IO07__ENET1_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
......
649 MX6_PAD_ENET1_RX_ER__ENET1_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
650 MX6_PAD_ENET1_RX_EN__ENET1_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
651 MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
652 };
653
654 static iomux_v3_cfg_t const fec2_pads[] = {
655 MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
656 MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),
......
665 MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
666 MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
667 MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
668 };

继续在文件 mx6ull_alientek_emmc.c 中找到函数 setup_iomux_fec,修改代码为如下:

668 static void setup_iomux_fec(int fec_id)
669 {
670 if (fec_id == 0)
671 {
672
673 imx_iomux_v3_setup_multiple_pads(fec1_pads,
674 ARRAY_SIZE(fec1_pads));
675
676 gpio_direction_output(ENET1_RESET, 1);
677 gpio_set_value(ENET1_RESET, 0);
678 mdelay(20);
679 gpio_set_value(ENET1_RESET, 1);
680 }
681 else
682 {
683 imx_iomux_v3_setup_multiple_pads(fec2_pads,
684 ARRAY_SIZE(fec2_pads));
685 gpio_direction_output(ENET2_RESET, 1);
686 gpio_set_value(ENET2_RESET, 0);
687 mdelay(20);
688 gpio_set_value(ENET2_RESET, 1);
689 }
690 }

示例代码中第 676 行~679 行和第 685 行~688 行分别对应 ENET1 和 ENET2 的复位 IO 初始化,将这两个 IO 设置为输出并且硬件复位一下 LAN8720A,这个硬件复位很重要!否则可能导致 uboot 无法识别 LAN8720A。

修改 drivers/net/phy/phy.c 文件中的函数 genphy_update_link

uboot 中的 LAN8720A 驱动有点问题,打开文件drivers/net/phy/phy.c,找到函数 genphy_update_link,这是个通用 PHY 驱动函数,此函数用于更新 PHY 的连接状态和速度。使用 LAN8720A 的时候需要在此函数中添加一些代码,修改后的函数 genphy_update_link 如下所示:

221 int genphy_update_link(struct phy_device *phydev)
222 {
223 unsigned int mii_reg;
224
225 #ifdef CONFIG_PHY_SMSC
226 static int lan8720_flag = 0;
227 int bmcr_reg = 0;
228 if (lan8720_flag == 0) {
229 bmcr_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
230 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
231 while(phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR) & 0X8000) {
232 udelay(100);
233 }
234 phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr_reg);
235 lan8720_flag = 1;
236 }
237 #endif
238
239 /*
240 * Wait if the link is up, and autonegotiation is in progress
241 * (ie - we're capable and it's not done)
242 */
243 mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
......
291
292 return 0;
293 }

225 行~237 行就是新添加的代码,为条件编译代码段,只有使用 SMSC 公司的 PHY 这段代码才会执行(目前只测试了 LAN8720A, SMSC 公司其他的芯片还未测试)。第 229 行读取
LAN8720A 的 BMCR 寄存器(寄存器地址为 0),此寄存器为 LAN8720A 的配置寄存器,这里先读取此寄存器的默认值并保存起来。 230 行向寄存器 BMCR 寄存器写入 BMCR_RESET(值为
0X8000),因为 BMCR 的 bit15 是软件复位控制位,因此 230 行就是软件复位 LAN8720A,复位完成以后此位会自动清零。第 231~233 行等待 LAN8720A 软件复位完成,也就是判断 BMCR
的 bit15 位是否为 1,为 1 的话表示还没有复位完成。第 234 行重新向 BMCR 寄存器写入以前的值,也就是 229 行读出的那个值。

至此网络的复位引脚驱动修改完成,重新编译 uboot,然后将 u-boot.bin 烧写到 SD 卡中并启动, uboot 启动信息如图所示:

从图中可以看到“Net: FEC1”这一行,提示当前使用的 FEC1 这个网口,也就是 ENET2。在 uboot 中使用网络之前要先设置几个环境变量,命令如下:

setenv ipaddr 192.168.1.55 //开发板 IP 地址
setenv ethaddr b8:ae:1d:01:00:00 //开发板网卡 MAC 地址
setenv gatewayip 192.168.1.1 //开发板默认网关
setenv netmask 255.255.255.0 //开发板子网掩码
setenv serverip 192.168.1.250 //服务器地址,也就是 Ubuntu 地址
saveenv //保存环境变量

设置好环境变量以后就可以在 uboot 中使用网络了,用网线将 I.MX6U-ALPHA 上的 ENET2与电脑或者路由器连接起来,保证开发板和电脑在同一个网段内,通过 ping 命令来测试一下网
络连接,命令如下:

ping 192.168.1.250

从图可以看出,有“host 192.168.1.250 is alive”这句,说明 ping 主机成功,说明ENET2 网络工作正常。

其他修改项

在 uboot 启动信息中会有“Board: MX6ULL 14x14 EVK”这一句,也就是说板子名字为“ MX6ULL 14x14 EVK”,要将其改为我们所使用的板子名字,比如“ MX6ULL ALIENTEK
EMMC”或者“MX6ULL ALIENTEK NAND”。打开文件 mx6ull_alientek_emmc.c,找到函数checkboard,将其改为如下所示内容:

int checkboard(void)
{
if (is_mx6ull_9x9_evk())
puts("Board: MX6ULL 9x9 EVK\n");
else
puts("Board: MX6ULL ALIENTEK EMMC\n");
return 0;
}

从图可以看出, Board 变成了“MX6ULL ALIENTEK EMMC”。至此 uboot 的驱动部分就修改完成了, uboot 移植也完成了, uboot 的最终目的就是启动 Linux 内核,所以需要通过启动 Linux 内核来判断 uboot 移植是否成功。在启动 Linux 内核之前我们先来学习两个重要的环境变量 bootcmd 和 bootargs。

bootcmd 和 bootargs 环境变量

uboot 中有两个非常重要的环境变量 bootcmd 和 bootargs,接下来看一下这两个环境变量。bootcmd 和 bootagrs 是采用类似 shell 脚本语言编写的,里面有很多的变量引用,这些变量其实都是 环境变量,有很多是NXP自己定义的 。文件mx6ull_alientek_emmc.h中的宏CONFIG_EXTRA_ENV_SETTINGS 保存着这些环境变量的默认值,内容如下:

113 #if defined(CONFIG_SYS_BOOT_NAND)
114 #define CONFIG_EXTRA_ENV_SETTINGS \
115 CONFIG_MFG_ENV_SETTINGS \
116 "panel=TFT43AB\0" \
117 "fdt_addr=0x83000000\0" \
118 "fdt_high=0xffffffff\0" \
......
126 "bootz ${loadaddr} - ${fdt_addr}\0"
127
128 #else
129 #define CONFIG_EXTRA_ENV_SETTINGS \
130 CONFIG_MFG_ENV_SETTINGS \
131 "script=boot.scr\0" \
132 "image=zImage\0" \
133 "console=ttymxc0\0" \
134 "fdt_high=0xffffffff\0" \
135 "initrd_high=0xffffffff\0" \
136 "fdt_file=undefined\0" \
......
194 "findfdt="\
195 "if test $fdt_file = undefined; then " \
196 "if test $board_name = EVK && test $board_rev = 9X9; then " \
197 "setenv fdt_file imx6ull-9x9-evk.dtb; fi; " \
198 "if test $board_name = EVK && test $board_rev = 14X14; then " \
199 "setenv fdt_file imx6ull-14x14-evk.dtb; fi; " \
200 "if test $fdt_file = undefined; then " \
201 "echo WARNING: Could not determine dtb to use; fi; " \
202 "fi;\0" \

宏 CONFIG_EXTRA_ENV_SETTINGS 是个条件编译语句,使用 NAND 和 EMMC 的时候宏 CONFIG_EXTRA_ENV_SETTINGS 的值是不同的。

环境变量 bootcmd

bootcmd 在前面已经说了很多次了, bootcmd 保存着 uboot 默认命令, uboot 倒计时结束以后就会执行 bootcmd 中的命令。这些命令一般都是用来启动 Linux 内核的,比如读取 EMMC 或
者 NAND Flash 中的 Linux 内核镜像文件和设备树文件到 DRAM 中,然后启动 Linux 内核。可以在 uboot 启动以后进入命令行设置 bootcmd 环境变量的值。如果 EMMC 或者 NAND 中没有
保存 bootcmd 的值,那么 uboot 就会使用默认的值,板子第一次运行 uboot 的时候都会使用默认值来设置 bootcmd 环境变量。默认环境变量保存在 include/env_default.h。

NXP 官方设置的 CONFIG_BOOTCOMMAND 值如下:

204 #define CONFIG_BOOTCOMMAND \
205 "run findfdt;" \
206 "mmc dev ${mmcdev};" \
207 "mmc dev ${mmcdev}; if mmc rescan; then " \
208 "if run loadbootscript; then " \
209 "run bootscript; " \
210 "else " \
211 "if run loadimage; then " \
212 "run mmcboot; " \
213 "else run netboot; " \
214 "fi; " \
215 "fi; " \
216 "else run netboot; fi"

看起来很复杂的样子!因为 uboot 使用了类似 shell 脚本语言的方式来编写的,此处省略分析,自行把环境变量带入即可。最终分析结果:

#define CONFIG_BOOTCOMMAND \
"mmc dev 1;" \
"fatload mmc 1:1 0x80800000 zImage;" \
"fatload mmc 1:1 0x83000000 imx6ull-alientek-emmc.dtb;" \
"bootz 0x80800000 - 0x83000000;"

或者可以直接在 uboot 中设置 bootcmd 的值,这个值就是保存到 EMMC 中的,命令如下:

setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ullalientek-emmc.dtb; bootz 80800000 - 83000000;'

环境变量 bootargs

bootargs 保存着 uboot 传递给 Linux 内核的参数

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=0~n,y=1~n)表示 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 的话就需要设置此选项,指
定根文件系统的类型。bootargs 常设置的选项就这三个,后面遇到其他选项的话再讲解。
 

启动 Linux 测试

uboot 已经移植好了, bootcmd 和 bootargs 这两个重要的环境变量也讲解了,接下来就要测试一下 uboot 能不能完成它的工作:启动 Linux 内核。我们测试直接从 EMMC 启动。

从 EMMC 启动也就是将编译出来的 Linux 镜像文件 zImage 和设备树文件保存在 EMMC中, uboot 从 EMMC 中读取这两个文件并启动,这个是我们产品最终的启动方式。但是我们目
前还没有讲解如何移植 linux 和设备树文件,以及如何将 zImage 和设备树文件保存到 EMMC中。不过大家拿到手的 I.MX6U-ALPHA 开发板(EMMC 版本)已经将 zImage 文件和设备树文件
烧写到了 EMMC 中,所以我们可以直接读取来测试。先检查一下 EMMC 的分区 1 中有没有zImage 文件和设备树文件,输入命令“ls mmc 1:1”,结果如图所示:

从图中可以看出,此时 EMMC 分区 1 中存在 zimage 和 imx6ull-alientek-emmc.dtb这两个文件,所以我们可以测试新移植的 uboot 能不能启动 linux 内核。设置 bootargs 和 bootcmd这两个环境变量,设置如下:

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000;'
saveenv

设置好以后直接输入 boot,或者 run bootcmd 即可启动 Linux 内核,如果 Linux 内核启动成功的话就会输出如图所示的启动信息:

移植流程总结

1.获取原厂uboot源码,或原厂SDK,BSP开发包。(同时要得到交叉编译工具)

2.编译原厂代码,烧录至要移植的开发板

3.测试原厂代码在开发板运行的情况

        3.1若启动异常,甚至不能启动,要排查主要硬件是否一致,如DDR,启动方式等。

        3.2若能启动,部分驱动异常,则记录下异常的部分

4.复制原厂defconfig,board,include/configs/xxx.h文件并重命名(视情况修改),通常还需要在arch/$(ARCH)/Kconfig添加TARGET目标选项(参考原厂配置)

        4.1使用设备树的一般要复制一份设备树

5.编译复制后的新board,查看board对应目录的.c文件是否编译为.o,烧录测试是否正常

6.根据第三步测试情况开始修改源码以及menuconfig选项以适配board驱动/功能

7.测试,如有异常继续修改

8.测试完成适配,移植完成

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Absorbed_w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值