IMX6Q 启动过程详细分析

一.预览

本文主要对IMX6Q的启动过程进行分析,主要参考文档来自NXP官方文档IMX6DQRM.pdf,使用的uboot为NXP官方提供uboot-imx,使用的开发板为迅为iTOP-i.MX6。NXP官方文档IMX6DQRM.pdf对启动过程的描述在第8章,本文主要参考第8章。

二.关键词

 IVT      image vector table

DCD     device configuration data

三.启动过程

imx6q上电复位后,从芯片内部ROM开始执行。内部ROM包含代码,可以 引导启动。这个内部ROM代码首先会检查BOOT_MODE[1:0]来确定引导模式,而BOOT_MODE[1:0]状态由芯片的BOOT_MODE的管脚确定,在iTOP-i.MX6开发板上已经固定为10,即内部引导。

BOOT_MODE[1:0]                Boot Type
                   00                       Boot From Fuses
                   01                       Serial Downloader
                   10                       Internal Boot
                   11                        Reserved

在确定了引导模式之后,接下来就确定引导设备(uboot的存储位置)。在iTOP-i.MX6开发板上可通过拨码开关设置引导设备,这里拨码开关实际是利用imx6q芯片的管脚来设置引导设备,具体设置方法请看IMX6DQRM.pdf的8.5节。iTOP-i.MX6开发板可以设置从eMMC(板上flash)或SD卡为引导设备,这里设置eMMC引导设备。

在确定了引导设备eMMC之后,内部ROM代码会去eMMC上读取镜像,我们的镜像(uboot,内核,文件系统)都存储在eMMC上。在eMMC上首先存储的是uboot。在uboot-imx的源文件有board/freescale/mx6q_topeet/flash_header.S文件(mx6q_topeet对应iTOP-i.MX6开发板,在board/freescale/mx6q_sabresd/flash_header.S也有此文件),再看board/freescale/u-boot.lds,可以发现如下,flash_header.S代码是存储在start.S代码的前面。

    .text       :
    {
      /* WARNING - the following is hand-optimized to fit within    */
      /* the sector layout of our flash chips!    XXX FIXME XXX    */
      board/freescale/mx6q_topeet/flash_header.o    (.text.flasheader)
      cpu/arm_cortexa8/start.o
      board/freescale/mx6q_topeet/libmx6q_topeet.a    (.text)
      lib_arm/libarm.a        (.text)
      net/libnet.a            (.text)
      drivers/mtd/libmtd.a        (.text)
      drivers/mmc/libmmc.a        (.text)

      . = DEFINED(env_offset) ? env_offset : .;
      common/env_embedded.o(.text)

      *(.text)
    }

在其他arm开发板上uboot都是从cpu/arm_cortexa8/start.S开始运行,这里flash_header.S存储在start.S之前,会在start.S之前运行是怎么回事呢?

要回答这个问题,我们可以看官方文档IMX6DQRM.pdf的第8.6节。在内部ROM代码读取镜像时,会先读取IVT(镜像向量表)、boot data、DCD(设备配置数据)。flash_header.S内的代码就是IVT、boot data和DCD。在flash_header.S内先有0x400字节的偏移(这个偏移量是IMX6DQRM.pdf的第8.6.1小节有说明,eMMC启动是偏移0x400字节),然后是IVT、boot data和DCD的描述。

内部ROM代码先偏移0x400字节读取IVT,再根据IVT的内容找到boot data和DCD,实际IVT保存了boot data和DCD的地址。内部ROM代码读取并执行上述内容后,知道了uboot镜像(start.S开始的)的起始地址和长度,对DDR进行了初始化设置,接下来就可以导入uboot镜像。

整个过程:上电复位->内部ROM代码->芯片基本初始化(时钟,缓存等)->确定引导模式->确定引导设备->从引导设备上偏移一定地址后读取IVT->在IVT内找到boot data和DCD->根据boot data确定uboot的起始地址和长度->根据DCD设置相关外设,包括DDR内存->导入uboot。

IVT、boot data和DCD的数据结构在官方文档IMX6DQRM.pdf的第8.6节有详细说明。 

四. flash_header.S注释

/* 这里仅有flash_header.S的部分代码,详细请看源文件 */
#include <config.h>
#include <asm/arch/mx6.h>

#ifdef	CONFIG_FLASH_HEADER
#ifndef CONFIG_FLASH_HEADER_OFFSET
# error "Must define the offset of flash header"
#endif
/* 数据变大端宏定义 */
#define CPU_2_BE_32(l) \
       ((((l) & 0x000000FF) << 24) | \
	(((l) & 0x0000FF00) << 8)  | \
	(((l) & 0x00FF0000) >> 8)  | \
	(((l) & 0xFF000000) >> 24))
/* DCD数据写入宏定义 */
#define MXC_DCD_ITEM(i, addr, val)   \
dcd_node_##i:                        \
        .word CPU_2_BE_32(addr) ;     \
        .word CPU_2_BE_32(val)  ;     \

.section ".text.flasheader", "x"
	b	_start
	.org	CONFIG_FLASH_HEADER_OFFSET /*在eMMC中IVT偏移0x400字节*/

/* IVT 数据结构 */
ivt_header:       .word 0x402000D1 /* Tag=0xD1, Len=0x0020, Ver=0x40 */
app_code_jump_v:  .word _start     /* 从uboot开始执行的第一条指令的绝对地址 */
reserv1:          .word 0x0
dcd_ptr:          .word dcd_hdr    /* DCD的绝对地址 */
boot_data_ptr:	  .word boot_data  /* boot data 的绝对地址 */
self_ptr:         .word ivt_header /* IVT 的绝对地址 */
#ifdef CONFIG_SECURE_BOOT
app_code_csf:     .word __hab_data /* CSF文件的绝对地址,与安全boot相关,这里没有 */
#else
app_code_csf:     .word 0x0
#endif
reserv2:          .word 0x0

/* Boot data structure */
boot_data:        .word TEXT_BASE  /* Absolute address of the image */
#ifdef CONFIG_SECURE_BOOT
image_len:        .word __hab_data_end - TEXT_BASE + CONFIG_FLASH_HEADER_OFFSET
#else
image_len:        .word _end_of_copy  - TEXT_BASE + CONFIG_FLASH_HEADER_OFFSET
#endif
plugin:           .word 0x0

/* DCD */
#if defined CONFIG_MX6DL_DDR3
#if defined CONFIG_DDR_32BIT
/* DCD(device configuration data) header*/
dcd_hdr:          .word 0x40E001D2 /* Tag=0xD2, Len=59*8 + 4 + 4, Ver=0x40 */
/* Write data command */
write_dcd_cmd:    .word 0x04DC01CC /* Tag=0xCC, Len=59*8 + 4, Param=0x04 */
/* IOMUX Control (IOMUXC) registers */
MXC_DCD_ITEM(1, IOMUXC_BASE_ADDR + 0x774, 0x000C0000)

......

MXC_DCD_ITEM(26, IOMUXC_BASE_ADDR + 0x47c, 0x00000030)
/* MMDC(Multi-mode DDR controller) register set */
MXC_DCD_ITEM(27, MMDC_P0_BASE_ADDR + 0x800, 0xA1390003)

......

MXC_DCD_ITEM(59, MMDC_P0_BASE_ADDR + 0x01c, 0x00000000)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章