LV04-01-IMX6ULL启动流程-01-启动方式

本文主要是I.MX6ULL启动流程——启动方式的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows版本 windows11
Ubuntu版本 Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
Linux开发板 正点原子 i.MX6ULL Linux 阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
Win32DiskImager Win32DiskImager v1.0
点击查看本文参考资料
分类 网址 说明
官方网站 https://www.arm.com/ ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档
https://www.nxp.com.cn/ NXP官方网站
https://www.nxpic.org.cn/NXP 官方社区
https://u-boot.readthedocs.io/en/latest/u-boot官网
https://www.kernel.org/linux内核官网
点击查看相关文件下载
分类 网址 说明
NXP https://github.com/nxp-imx NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库
nxp-imx/linux-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga NXP linux内核仓库tags中的rel_imx_4.1.15_2.1.0_ga
nxp-imx/uboot-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga NXP u-boot仓库tags中的rel_imx_4.1.15_2.1.0_ga
I.MX6ULL i.MX 6ULL Applications Processors for Industrial Products I.MX6ULL 芯片手册(datasheet,可以在线查看)
i.MX 6ULL Applications ProcessorReference Manual I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网)
Source Code https://elixir.bootlin.com/linux/latest/source linux kernel源码
https://elixir.bootlin.com/u-boot/latest/source uboot源码

一开始,我们在体验系统的时候就需要使用拨码开关,令系统从eMMC启动或者从SD卡启动,那么,imx6ull芯片上电的时候,它怎么知道从哪启动的?

一、手册内容解读

首先我们先看参考手册:《i.MX 6ULL Applications Processor Reference Manual 》的Chapter 8 System Boot ,这一部分就是专门讲解I.MX6ULL启动相关内容的章节。

1. boot ROM概述

I.MX6ULL芯片内部有一个 boot ROM,上电后 boot ROM 上的程序就会运行。它会根据 BOOT_MODE[1:0]的值,以及 eFUSE 或 GPIO 的值决定后续的启动流程。

说明: eFUSE 即熔丝,只能烧写一次,一般正式发布产品时烧写最终值;平时调试时通过 GPIO 来设置开发板的启动方式。

boot ROM 上的程序功能强大,可以从 USB 口或串口下载程序并把它烧写到Flash 等设备上,也可以从 SD 卡或 EMMC、 Flash 等设备上读出程序、运行程序。

那么考虑一个问题:boot ROM 是从 USB 口下载、运行程序,还是从 SD 卡等设备上读出、运行程序,谁决定? 我们接着往下看。

2. boot ROM是下载还是读出?

2.1 由什么决定下载还是读出?

还是上面的问题:boot ROM 是从 USB 口下载、运行程序,还是从 SD 卡等设备上读出、运行程序,谁决定?

答案是由 BOOT_MODE[1:0] 的值来决定的,这个boot ROM是下载还是读出,其实就是imx6ull的启动方式,这两个寄存器的值来自于2个引脚BOOT_MODE1、 BOOT_MODE0。这 2 个引脚在上电时是输入引脚,芯片启动后采集这 2 个引脚的值,存入 BOOT_MODE 寄存器。以后这 2 个引脚就可以用于其他功能,不会影响到 BOOT_MODE 寄存器。 BOOT_MODE[1:0]的值确定了 4 种启动模式:

image-20230716074402242

在正点原子的开发板中,这两个引脚的原理图如下:

image-20230716074826207

其中 BOOT_MODE1 和 BOOT_MODE0 在芯片内部是有 100KΩ下拉电阻的,所以默认是0。 BOOT_MODE1 和 BOOT_MODE0 这两个引脚我们也接到了底板的拨码开关上,这样我们就可以通过拨码开关来控制 BOOT_MODE1 和 BOOT_MODE0 的高低电平。以 BOOT_MODE1为例,当我们把 BOOT_CFG 的第一个开关拨到“ON”的时候,就相当于 BOOT_MODE1 引脚通过 R88 这个 10K 电阻接到了 3.3V 电源,芯片内部的 BOOT_MODE1 又是 100K 下拉电阻接地,因此此时 BOOT_MODE1 的电压就是 100/(10+100)*3.3V= 3V,这是个高电平, 因此 BOOT_CFG 的中的 8 个开关拨到 “ON” 就是高电平,拨到 “OFF” 就是低电平。

2.2 四种模式

2.2.1 00 模式

也就是从 FUSE 启动,在我们的开发过程中很少用到。简单介绍一下。

在这种模式下, GPIO的值被忽略。boot ROM 会根据 eFUSE 的值来选择启动设备、设置启动设备。但是,对于刚出厂的芯片 eFUSE 值可能是错乱的、不适合我们的设备的,那这怎么办?eFUSE 中有一个值 BT_FUSE_SEL,它的出厂值是0,表示 eFUSE 未被烧写。 boot ROM 程序发现 BT_FUSE_SEL 为 0 时,它会通过 USB 或串口来下载程序;发现 BT_FUSE_SEL 为 1 时,才会根据eFUSE 的值选择启动设备,读出、运行该设备上的程序。

2.2.2 01 模式

就是串行下载模式。 此模式下boot ROM 程序可以通过 USB 或串口下载、运行程序。这种模式可以将代码下载到板子上的外置存储设备中,我们可以使用 OTG1 这个 USB口向开发板上的 SD/EMMC、 NAND 等存储设备下载代码。我们需要将 BOOT_MODE1 拨到“OFF”,将 BOOT_MODE0 拨到“ON”。开发板出厂时,一般就是通过这个模式下载、烧写出厂程序的。

2.2.3 10 模式

称之为内部模式(内部BOOT模式),简单地说就是从 SD 卡、 EMMC 等设备启动程序。当 BOOT_MODE1 为 1, BOOT_MODE0 为 0 的时候此模式使能,在此模式下,芯片会执行内部的 boot ROM 代码,这段 boot ROM 代码会进行硬件初始化(一部分外设),然后从 boot 设备(就是存放代码的设备、比如 SD/EMMC、 NAND)中将代码拷贝出来复制到指定的 RAM 中,一般是 DDR。

当我们设置 BOOT 模式为“内部 BOOT 模式”以后, I.MX6U 内部的 boot ROM 代码就会执行,这个 boot ROM 代码都会做什么处理呢?首先肯定是初始化时钟, boot ROM 设置的系统时钟如图:

image-20230909104803582

在图中 BT_FREQ 模式为 0,可以看到, boot ROM 会将 I.MX6U 的内核时钟设置为396MHz, 也就是主频为 396Mhz。 System PLL=528Mhz, USB PLL=480MHz, AHB=132MHz,IPG=66MHz。关于 I.MX6U 的系统时钟,我们后面会详细学习。

内部 boot ROM 为了加快执行速度会打开 MMU 和 Cache,下载镜像的时候 L1 ICache 会打开,验证镜像的时候 L1 DCache、 L2 Cache 和 MMU 都会打开。一旦镜像验证完成, boot ROM就会关闭 L1 DCache、 L2 Cache 和 MMU。

中断向量偏移会被设置到 boot ROM 的起始位置,当 boot ROM 启动了用户代码以后就可以重新设置中断向量偏移了。一般是重新设置到我们用户代码的开始地方,关于中断的内容后面会详细学习。

2.2.4 11 模式

11模式一般是保留的。

2.3 支持从哪些设备启动?

可以看手册的《Chapter 8 System Boot →8.1 Overview 》

image-20241031064903128

当 BOOT_MODE 设置为内部 BOOT 模式以后,可以从以下设备中启动:

(1)接到 EIM 接口的 CS0 上的 16 位 NOR Flash。

(2)接到 EIM 接口的 CS0 上的 OneNAND Flash。

(3)接到 GPMI 接口上的 MLC/SLC NAND Flash, NAND Flash 页大小支持 2KByte、 4KByte和 8KByte, 8 位宽。

(4) QuadSPI(QSPI) Flash。

(5)接到 USDHC 接口上的 SD/MMC/eSD/SDXC/eMMC 等设备。

(6)SPI 接口的 NOR flash 和 EEPROM。

总的来说就是支持这一些:NOR flash、NAND flash、OneNAND flash、SD/MMC、Serial (SPI) NOR flash and EEPROM、QuadSPI (QSPI) flash 。

这些启动设备如何选择呢? I.MX6U 提供了 eFUSE 和 GPIO 配置两种。

3. 如何选择和设置启动设备?

3.1 怎么区分eFUSE和GPIO的情况?

00 模式下是通过 eFUSE 的值选择启动设备,我们不关心。10 模式下既可以通过 eFUSE 的值也可以通过 GPIO 的值来选择启动设备(谁说的?一开始没找到,后看翻了手册还真有说明):

image-20230716081521843

但是到底通过谁来决定? 上图其实已经给了答案:eFUSE 中有一个值 BT_FUSE_SEL,它的初始值为 0,表示 eFUSE 未被烧写。在 10 模式下,当 BT_FUSE_SEL 为 0 时就会通过 GPIO 来选择启动设备;当 BT_FUSE_SEL 为 1 时就会通过 eFUSE 来选择启动设备。 BT_FUSE_SEL 默认也就是0,在开发阶段,我们使用 GPIO 来选择设备啦。

3.2 选择启动设备

通过 eFUSE 或 GPIO 不仅能选择启动设备,还可以设置启动设备。为什么还需要设置?比如 Nand Flash 参数各有不同, 有些的页大小是 2048,有些是 4096。这些参数不同, boot ROM 程序读 Nand Flash 的方法就不同,我们必须把这些参数告诉 boot ROM:通过 eFUSE 或 GPIO 来标明这些参数。

首先看看要设置哪些 eFUSE 或 GPIO 来选择不同的启动设备。我们既可以使用 eFUSE 也可以使用 GPIO 来选择启动设备,GPIO 可以覆盖 eFUSE 的值。

哪些 GPIO 覆盖哪些 eFUSE?这可以查看《i.MX 6ULL Applications Processor Reference Manual 》中Chapter 8: System Boot 里的 GPIO boot overrides 。选择启动设备后,还需要标明一些参数。比如选择 EMMC 启动时, EMMC 接在哪一个接口, eSDHC1 还是 eSDHC2?它的速度如何?比如选择 TF 卡启动时, TF卡接在哪一个接口, eSDHC1 还是 eSDHC2?它的速度如何?假设使用 EMMC 启动,或是 TF 卡启动,怎么设置 eFUSE 或 GPIO?这些信息可以查询《i.MX 6ULL Applications Processor Reference Manual 》的Chapter 5:Fusemap。

正如启动模式由 BOOT_MODE[1:0]来选择一样,启动设备是通过BOOT_CFG1[7:0]、 BOOT_CFG2[7:0]和 BOOT_CFG4[7:0]这 24 个配置 IO,这 24 个配置 IO 刚好对应着 LCD 的 24 根数据线 LCD_DATA0~LCDDATA23,当启动完成以后这 24 个 IO 就可以作为 LCD 的数据线使用。这 24 根线和BOOT_MODE1、 BOOT_MODE0 共同组成了 I.MX6U的启动选择引脚,下图列出了一小部分:

image-20230716082623499

图中所示的是BOOT_CFG[7:4],这四个引脚的的值是在串行模式下决定从NOR/OneNAND、QSPI、SD/eSD/SDXC、MMC/eMMC等设备启动,这几个引脚对应的就是LCD1_DATA[7:4]这几个GPIO。这几个书要是选择启动设备,剩下的引脚主要是用于设置启动设备。

3.3 设置启动设备?

选择启动设备后,还需要标明一些参数。比如选择EMMC启动时,EMMC接在哪一个接口,eSDHC1还是eSDHC2?它的速度如何?选择TF卡启动时,TF卡接在哪一个接口,eSDHC1还是eSDHC2?它的速度如何?假设使用EMMC启动,或是TF卡启动,怎么设置eFUSE或GPIO?这些信息可以查询 i.MX6ULL 参考手册《Chapter 5: Fusemap》:

image-20230716090343139

前边我们知道 BOOT_MODE[1:0] 设置启动模式(下边的0b表示位):

  • 当 BOOT_MODE 设置为 0b00 时,通过 eFUSE 选择启动设备,通过 eFUSE 获得设备的参数。

  • 当 BOOT_MODE 设置为 0b10 时,通过 eFUSE 或 GPIO 来选择启动设备,获得设备的参数;使用 eFUSE 还是 GPIO 由 eFUSE 中的 BT_FUSE_SEL 决定,它默认是 0,表示使用 GPIO。

以 BOOT_MODE 为 0b10 为例,我们看一下要设置为 SD 卡、 TF 卡启动的话要怎么搞:

选择启动的设备为SD/TF卡

(1)设置 eFUSE 的 BOOT_CFG1[7:5]为 0b010 ;

(2)查看i.MX6ULL参考手册的《8.3.2 GPIO boot overrides 》确定 BOOT_CFG1[7:5]对应的GPIO 为 LCD1_DATA07~05,把这 3 个引脚设置为 0b010。

根据 SD 卡、 TF 卡的性能,可以设置 eFUSE 或 GPIO 来表示它能否提供更高的速度:

设置SD/TF卡参数

(1)设置 eFUSE 的 BOOT_CFG1[4:0]

(2)查看i.MX6ULL参考手册的《8.3.2 GPIO boot overrides 》确定 BOOT_CFG1[4:0]对应的GPIO 为 LCD1_DATA04~00,设置这些引脚。

(3)IMX6ULL 有两个 SD 卡、 TF 卡接口,使用哪一个接口?设置 eFUSE 的 BOOT_CFG2[4:3]可以确定使用 eSDHC1 或 eSDHC2。

image-20230716090753530

(4)查看i.MX6U参考手册的《8.3.2 GPIO boot overrides 》确定 BOOT_CFG2[4:3]对应的GPIO 为 LCD1_DATA12~11,设置这些引脚

二、ALPHA板中的启动方式

前边我们知道选择启动设备的时候要调整这 24 个 IO 的高低电平,这得多复杂啊?其实不然,虽然有 24 个 IO,但是实际需要调整的只有那几个 IO,其它的 IO 全部下拉接地即可,也就是设置为 0。打开 I.MX6U-ALPHA 开发板的核心板原理图,这 24 个 IO 的默认设置如图所示:

image-20230716083416304

大部分的 IO 都接地了,只有几个 IO 接高,尤其是 BOOT_CFG4[7:0]这 8 个 IO 都 10K 电阻下拉接地,所以我们压根就不需要去关注BOOT_CFG4[7:0]。我们需要重点关注的就只剩下了 BOOT_CFG2[7:0]和 BOOT_CFG1[7:0]这 16 个 IO。

image-20230716091307001

BOOT_CFG1[7:0]和 BOOT_CFG2[7:0]这 16 个 IO 还能不能在减少呢?我们打开 I.MX6U-ALPHA 开发板的底板原理图,底板上启动设备选择拨码开关原理图如图所示:

image-20230716091358040

除 了 BOOT_MODE1 和 BOOT_MODE0必须引出来,LCD_DATA3~LCDDATA7、 LCD_DATA11 这 6 个 IO 也被引出来了,可以通过拨码开关来设置其对应的高低电平,拨码开关拨到“ON”就是 1,拨到“OFF”就是 0。其中 LCD_DATA11 就是 BOOT_CFG2[3], LCD_DATA3~LCD_DATA7 就是BOOT_CFG1[3]~BOOT_CFG1[7],这 6 个IO 的配置含义如表:

image-20230716091809953

BOOT IO 含义, I.MX6U-ALPHA 开发板从 SD 卡、 EMMC、 NAND 启动的时候拨码开关各个位设置方式如下表

1 2 3 4 5 6 7 8 启动设备
0 1 x x x x x x 串行下载,可以通过 USB 烧写镜像文件。
1 0 0 0 0 0 1 0 SD 卡启动。
1 0 1 0 0 1 1 0 EMMC 启动。
1 0 0 0 1 0 0 1 NAND FLASH 启动。

doc.embedfire.com/linux/imx6/base/zh/latest/bare_metal/before_developing.html#