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)

 

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