加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

DM365启动之—RBL、UBL分析

发布时间:2020-12-15 06:43:00 所属栏目:百科 来源:网络整理
导读:DM365 启动之— RBL 、 UBL 分析 ? 这段时间项目刚刚完成,下个项目还在等公司的安排,希望还是 DAVINCI 平台吧,其实呢,也无所谓,只是对 DAVINCI 还是稍稍有点感情,难得有点时间,鬼使神差的看起 UBL 的源代码来了,顺便做点笔记,看了总得留点痕迹吧,

DM365启动之—RBLUBL分析?

这段时间项目刚刚完成,下个项目还在等公司的安排,希望还是DAVINCI平台吧,其实呢,也无所谓,只是对DAVINCI还是稍稍有点感情,难得有点时间,鬼使神差的看起UBL的源代码来了,顺便做点笔记,看了总得留点痕迹吧,写的不好,大家多多指教哦,呵呵,费话有点多,转正题吧

系统加电或复位后,CPU通常都从某个由CPU制造商预先安排的地址上取指令。DM365提供了各种各样的启动方式,总体上可分为从外部存储器接口AEMIF(NOR Flash/OneNand)引导启动和从ARM内部ROMAIROM)引导启动两种模式。引导启动模式由BTSEL[2:0]引脚的设置状态。

BTSEL[2:0]=001时,系统加电/复位后ARM处理器从AEMIF?执行引导启动代码,即从外部存储器OneNandNor Flash启动。

AIROM支持以下启动模式

BTSEL[2:0]=000ARM NAND Boot

BTSEL[2:0]=010ARM MMC/SD Boot

BTSEL[2:0]=011ARM UART Boot

BTSEL[2:0]=100,??ARM USB Boot

BTSEL[2:0]=101ARM SPI Boot

BTSEL[2:0]=110ARM EMAC Boot

BTSEL[2:0]=111ARM HPI Boot?

ARM ROM bootloader (RBL)?为内部ROM固化的bootloader

?

xxxxxxxxxxxxxxxxxxxxxxxxx

?


由于DM365处理器AIRAM空间只有32KBNAND Flash不支持XIP技术等原因,所以DaVinci EVM采取AIROM启动方式,要想完成从NAND Flash引导启动,操作系统的任务至少需要三个阶段代码,启动流程见下图:?????

xxxxxxxxxxxxxxxxxxxxxxx

?

ARM NAND Boot模式为例,下面为RBL详细流程:

1、初始化RAM1的高2K栈空间(0x7800-0x7fff)RAM的最后4个字节(0x7ffc-0x8000),来于写UBL的块号。

2、禁止所有中断,IRQFIQ

3、外部引脚DEEPSLEEPZ/GIO0在芯片为NAND模式启动复位时必须被置高。

4、从ROM的表中读出NAND的设备ID和参数。

5、根据NAND flash的参数初始化NAND区域。

6、从BLOCKSOnly Page 0 of blocks 1 to 24 will be read and searched for the

magic number)中搜索UBL?幻数magic number),读出幻数(magic number?是为了确保当前块可用,当找到有效的?UBL幻数magic number)后,把相应的块号(block number)写到ARM?内部RAM最后4个字节地址上(0x7ffc-0x8000)。

7UBL描述符由以下参数组成(所有UBL参数位宽都是32)

??? -入口点地址:加载UBL之后的绝对入口点,必须在0x0020-0x781C之间。

??? -UBL占用的NAND的页数:必须是相邻的页,可以跨越多个块,总字节数必须小于等于30KBIRAM大小为32K?最高2K用于栈空间)。

??? -UBL的起始块:可以与UBL描述符在同一个块。

??? -UBL的起始页:不可以与UBL描述符在同一页,因为加载的都是完整的页。

8、使能硬件ECC错误检测,复制UBLNAND flashIRAM,如果检测到一个4ECC的读错误,UBL将通过ECC纠正算法来纠正错误。如果是由其他的错误导致读失败的,指示符会继续在下一个新的块中搜索直到找到UBL描述符,一直搜索到block 24。没有的话就从SD卡启动。

9、在UBL入口处把控制权移交给UBL

10NAND的安全启动模式是在PLL旁通模式中完成的,它不使用快速EMIFDMA或者I-Cache。在其他模式下,使用以上的一种组合。例如,在UBL_MAGIC_PLL_DMA_IC_FAST模式下激活其他四个设置,它因该是最快的NAND启动模式。

以下是启动流图:

?xxxxxxxxxxx

????????

UBL源码在PSP包里的board_utilities/flash_utils目录下,主要是COMMON目录和各子平台的目录如DM36x等,其中除了UBL的源码外还有CCSJTAG的擦除烧写源码,串口烧写源码等。

入门代码是汇编文件start.S,主要是切换操作模式,建立堆栈等,然后跳转到main函数,进入到board_utilities/flash_utils/Common/ubl/src目录下的C文件?ubl.c中。

main函数主要调用了LOCAL_boot函数来进行实质的引导功能,然后跳转到entrypoint执行Uboot。在LOCAL_boot函数中主要是Device_init()NANDBOOT_copy()两个函数。

Device_init()函数来进行平台的最底层初始化,包括电源域,时钟,DDREMIFUARTI2CTIMER?。首先屏蔽和清除中断,然后调用DEVICE_PSCInit函数实现对各模块的电源时钟使能,实质是调用PSC电源时钟管理模块的寄存器实现;然后调用DEVICE_pinmuxControl函数决定复用引脚的功能选择;接着调用DM36x/common/src/device.c下的DEVICE_PLL1Init函数、DEVICE_PLL1Init函数实现了PLL1PLL2的配置,预分频,倍频,后分频,分频到各个模块;接着调用DEVICE_DDR2Init函数来配置DDR控制器,这是UBL中重要的一部分,如果硬件电路需要更换内存芯片的话,需要在UBL中修改这个函数,即按照芯片手册来配置DDR控制寄存器中的相关参数,比如时序,BANK数,页大小等。而后调用DEVICE_EMIFInit函数来配置EMIF模块,调用DEVICE_UART0Init函数来配置串口0,调用DEVICE_TIMER0Init函数来配置TIMER0,调用?DEVICE_I2C0Init函数来配置I2C控制器,都是操作某一模块的控制寄存器实现。

当读取到启动模式配置寄存器(BOOTCFG)值时,如果BTSEL[2:0]=000,则调用NAND初始化函数NAND_init()及复制代码函数NANDBOOT_copy()将存储在NAND中紧随其后的Bootload代码复制到DDR2中。

下面为源代码分析。

注:在说明源代码的时候,为了缩短篇幅,删除了代码的部分DEBUG信息

?

// Main entry point

void main(void)

{

??// Call to real boot function code

??LOCAL_boot();

??// Jump to entry point

??APPEntry = (void (*)(void)) gEntryPoint;??/*UBL结束,交还入口地址,执行U-BOOT*/

??(*APPEntry)();?

}

?

函数实体唯一调用了LOCAL_boot()函数,下面我们来看看,里面具体做了什么,下面为LOCAL_boot()函数源码。

static Uint32 LOCAL_boot(void)

{

??DEVICE_BootMode bootMode;

?

??// Read boot mode

??bootMode = DEVICE_bootMode();

??if (bootMode == DEVICE_BOOTMODE_UART) {

????// Wait until the RBL is done using the UART.

????while((UART0->LSR & 0x40) == 0 );

??}

?

??// Platform Initialization

??if ( DEVICE_init() != E_PASS ) {

????DEBUG_printString(" initialization failed!rn");

????asm(" MOV PC,#0");

??}else{

????//DEBUG_printString(" initialization passed!rn");

??}

?

??// Set RAM pointer to beginning of RAM space

??UTIL_setCurrMemPtr(0);

?

??// Select Boot Mode

#ifdefined(UBL_NAND) {

????// Copy binary image application from NAND to RAM

????if (NANDBOOT_copy() != E_PASS) {

??????DEBUG_printString("NAND Boot failed.rn");

??????LOCAL_bootAbort();

????}

??}

#elif defined(UBL_NOR) {

????// Copy binary application image from NOR to RAM

????if (NORBOOT_copy() != E_PASS){

??????DEBUG_printString("NOR Boot failed.rn");

??????LOCAL_bootAbort();

????}

??}

#elif defined(UBL_SD_MMC) {

????// Copy binary of application image from SD/MMC card to RAM

????if (SDMMCBOOT_copy() != E_PASS){

??????DEBUG_printString("SD/MMC Boot failed.rn");

??????LOCAL_bootAbort();

????}

??}

#else {

????UARTBOOT_copy();?????

??}

#endif

?

??DEVICE_TIMER0Stop();

??return E_PASS;???

?

程序流程还是很简单,先通过调用DEVICE_bootMode函数来判断启动方式(通过读取BOOTCFG的值),而后调用了DEVICE_init函数来进行平台的最底层初始化,包括电源域,时钟,DDREMIFUARTI2CTIMER等,都是操作某一模块的控制寄存器实现。

?????接着通过判断不同的引导方式,采取不同的处理办法,以?NAND启动为例,将调用NANDBOOT_copy函数。此函数将NAND中的某些内容(就是UBOOT)搬移到RAM中,而后?UBL结束,控制权正式交给UBOOT。接下来我们来分析下DEVICE_initNANDBOOT_copy的具体实现,DEVICE_init源代码如下:

Uint32 DEVICE_init()

{
??? Uint32 status = E_PASS;
????
??? // Mask all interrupts
??? AINTC->INTCTL = 0x4;
??? AINTC->EABASE = 0x0;
??? AINTC->EINT0 = 0x0;
??? AINTC->EINT1 = 0x0;????????
????
??? // Clear all interrupts
??? AINTC->FIQ0 = 0xFFFFFFFF;
??? AINTC->FIQ1 = 0xFFFFFFFF;
??? AINTC->IRQ0 = 0xFFFFFFFF;
??? AINTC->IRQ1 = 0xFFFFFFFF;
????
#ifndef SKIP_LOW_LEVEL_INIT
??? POR_RESET();
??? // System PSC setup - enable all
??? DEVICE_PSCInit();
???/*
管脚复用的配置*/?
?? DEVICE_pinmuxControl(0,0xFFFFFFFF,0x00FD0000); // All Video Inputs
Y0-Y7全部作为video in(不作???????GPIO),GIO43作为SD1clkMcBsp开启,MMCSD0关闭

?? DEVICE_pinmuxControl(1,0x00145555); // All Video Outputs,视频Cout0-Cout7作为色度信号输出使能,场消隐/行消隐同步信号使能,LCDOE功能关闭?? DEVICE_pinmuxControl(2,0x000000DA); // EMIFA,总线使能,?? DEVICE_pinmuxControl(3,0x00180000); // SPI0,SPI1,UART1,I2C,SD0,SD1,McBSP0,CLKOUTs,串口1使能,其他均作为GPIO,网卡没使能?? DEVICE_pinmuxControl(4,0x55555555); //SI1-SPI4使能,MMCSD1?使能
????
??? GPIO->DIR02 &= 0xfeffffff;
??? GPIO->CLRDATA02 = 0x01000000;
????
????
// System PLL setup
??? if (status == E_PASS) status |= DEVICE_PLL1Init(PLL1_Mult);
??? // DDR PLL setup
??? if (status == E_PASS) status |= DEVICE_PLL2Init();
??? // DDR2 module setup
??? if (status == E_PASS) status |= DEVICE_DDR2Init();
#endif
????
??? // AEMIF Setup
??? if (status == E_PASS) status |= DEVICE_EMIFInit();
??? // UART0 Setup
??? if (status == E_PASS) status |= DEVICE_UART0Init();
??? // TIMER0 Setup
??? if (status == E_PASS) status |= DEVICE_TIMER0Init();
??? // I2C0 Setup
??? if (status == E_PASS) status |= DEVICE_I2C0Init();
????
??? return status;
}

?

接着我们来看NANDBOOT_copy()UBL的主要工作都在此函数中实现。

// Function to find out where the application is and copy to RAM

Uint32?NANDBOOT_copy()

{

??NAND_InfoHandle hNandInfo;

??Uint32 count,blockNum;

??Uint32 i;

??Uint32 magicNum;

??Uint8 *rxBuf;????// RAM receive buffer

??Uint32 block,page;

??Uint32 readError = E_FAIL;

??Bool failedOnceAlready = FALSE;

?

??// Maximum application size is 16 MBAllocate memory from the ad-hoc heap

??rxBuf = (Uint8*)UTIL_allocMem((APP_IMAGE_SIZE>>1));

??blockNum = DEVICE_NAND_UBL_SEARCH_START_BLOCK;

?

??// NAND Initialization打开?NandFlash设备,将NandFlash的硬件信息放在hNandInfo数据结构内。

??hNandInfo = NAND_open(EMIFStart,(Uint8) DEVICE_emifBusWidth());

??if (hNandInfo == NULL) {

???????DEBUG_printString("hNandInfo == NULLn");

????return E_FAIL;

??}

???

NAND_startAgain:

??if (blockNum > DEVICE_NAND_UBL_SEARCH_END_BLOCK) {

????return E_FAIL;??// NAND boot failed and return fail to main

??}

?

??/*Read data about Application starting at START_APP_BLOCK_NUM,Page 0 and possibly going until block END_APP_BLOCK_NUM,Page 0*/

???/*U-boot一般存在于DEVICE_NAND_UBL_SEARCH_START_BLOCK以后块的第0页,ubl试着从?DEVICE_NAND_UBL_SEARCH_START_BLOCK块向后搜索每块的第0页,找到后,前24个字节分别记录着u-boot描述,如入口函数等,并把记录存入rxBuf中。*/

??for(count=blockNum; count <= DEVICE_NAND_UBL_SEARCH_END_BLOCK; count++) {???

????if(NAND_readPage(hNandInfo,count,rxBuf) != E_PASS)

??????continue;

????magicNum = ((Uint32 *)rxBuf)[0];

????/* Valid magic number found */

????if((magicNum & 0xFFFFFF00) == MAGIC_NUMBER_VALID) {

??????blockNum = count;

??????break;

????}

??}

?

??// Never found valid header in any page 0 of any of searched blocks

??if (count > DEVICE_NAND_UBL_SEARCH_END_BLOCK) {

????DEBUG_printString("No valid boot image found!rn");

????return E_FAIL;

??}

?

??// Fill in NandBoot header

??gNandBoot.entryPoint = *(((Uint32 *)(&rxBuf[4]))); /* The first "long" is entry point for Application*/

??gNandBoot.numPage = *(((Uint32 *)(&rxBuf[8])));??/* The second "long" is the number of pages */

??gNandBoot.block = *(((Uint32 *)(&rxBuf[12])));???/* The third "long" is the block where Application is stored in NAND */

??gNandBoot.page = *(((Uint32 *)(&rxBuf[16])));???/* The fourth "long" is the page number where Application is stored in NAND */

??gNandBoot.ldAddress = *(((Uint32 *)(&rxBuf[20])));???/* The fifth "long" is the Application load address */

?

??// If the application is already in binary format,then our received buffer can point to the specified load address

??// instead of the temp location used for storing an S-record

??// Checking for the UBL_MAGIC_DMA guarantees correct usage with the

??// Spectrum Digital CCS flashing tool,flashwriter_nand.out

??if ((magicNum == UBL_MAGIC_BIN_IMG) || (magicNum == UBL_MAGIC_DMA)) {

????// Set the copy location to final run location

????rxBuf = (Uint8 *)gNandBoot.ldAddress;

????// Free temp memory rxBuf used to point to

????UTIL_setCurrMemPtr((void *)((Uint32)UTIL_getCurrMemPtr() - (APP_IMAGE_SIZE>>1)));

??}

?

NAND_retry:

??/* initialize block and page number to be used for read */

??block = gNandBoot.block;

??page = gNandBoot.page;

?

// Perform the actual copying of the application from NAND to RAM

for(i=0;i<gNandBoot.numPage;i++) {

// if page goes beyond max number of pages increment block number and reset page number

if(page >= hNandInfo->pagesPerBlock) {

page = 0;

block++;

}

??readError = NAND_readPage(hNandInfo,block,page++,(&rxBuf[i*(hNandInfo->dataBytesPerPage)]));??/* Copy the data */

?

??// We attempt to read the app data twice.??If we fail twice then we go look for a new

??// application header in the NAND flash at the next block.

??if(readError != E_PASS) {

?????if(failedOnceAlready) {

????????blockNum++;

????????goto NAND_startAgain;

??????} else {

?????????failedOnceAlready = TRUE;

?????????goto NAND_retry;

??????}

????}

}

?

// Application was read correctly,so set entrypoint

gEntryPoint = gNandBoot.entryPoint;

?

return E_PASS;

}

?

到此,UBL的工作全部完全,接下来的工作交给U-BOOT

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读