DM365的UBL源码分析
来源:互联网 发布:复杂json解析 编辑:程序博客网 时间:2024/06/13 00:16
// Main entry point
void main(void)
{
// Call to real boot function code
LOCAL_boot();
// Jump to entry point
DEBUG_printString("\r\nJumping to entry point at ");
DEBUG_printHexInt(gEntryPoint);
DEBUG_printString(".\r\n");
APPEntry = (void(*)(void)) gEntryPoint; /*
UBL结束,gEntryPoint将u-boot入口
交给APPEntry
*/
(*APPEntry)();
}
U-boot一般存在于DEVICE_NAND_UBL_SEARCH_START_BLOCK以后块的第0页,ubl试着从 DEVICE_NAND_UBL_SEARCH_START_BLOCK块向后搜索每块的第0页,找到后,前24个字节分别记录着u-boot描述,如入口函数等
//DM36x/CCS/NANDWriter/src/nandwriter.c nandwriter()函数中
// Fill in NandBoot header,rxBuf为刚搜到的页
gNandBoot.entryPoint = *(((Uint32*)(&rxBuf[4])));/* The first "long" is entry point for Application ,u-boot主程序将从这里开始执行*/
gNandBoot.numPage =*(((Uint32*)(&rxBuf[8])));/* The second "long" is the number of pages ,代码总页数,有多少数据要载入到DDR*/
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 ,一般情况,程序放在这个地址开始加载*/
根据以上信息一次读入每一页,然后将u-boot入口传递给gEntryPoint。
main函数主要调用了LOCAL_boot函数来进行实质的引导功能,下面是此函数的内容:
static Uint32 LOCAL_boot(void)
{
DEVICE_BootMode bootMode;
// Read boot mode 从BOOTCFG系统寄存器读出,得到目前BOOTSEL[0..2]
bootMode = DEVICE_bootMode();
if (bootMode== DEVICE_BOOTMODE_UART)
{
// Wait until the RBL is done using the UART.
//对于通过UART启动的,这些代码应该是存在于uart设备上
while((UART0->LSR& 0x40) == 0 );
DEVICE_init函数来进行平台的最底层初始化,包括电源域,时钟,DDR,EMIF,UART,I2C,TIMER等
}
// Platform Initialization
if ( DEVICE_init()!= E_PASS ) /**/
对全局变量currMemPtr赋值
{
DEBUG_printString(devString);
DEBUG_printString(" initialization failed!\r\n");
asm(" MOV PC, #0");
}
else
{
DEBUG_printString(devString);
DEBUG_printString(" initialization passed!\r\n");
}
// Set RAM pointer to beginning of RAM space
UTIL_setCurrMemPtr(0); /**/
// Send some information to host
DEBUG_printString("TI UBL Version: ");
DEBUG_printString(UBL_VERSION_STRING);
DEBUG_printString("\r\nBooting Catalog Boot Loader\r\nBootMode = ");
// Select Boot Mode
#if defined(UBL_NAND)
{
//Report Bootmode to host
DEBUG_printString("NAND\r\n");
// Copy binary image application from NAND to RAM
//
NANDBOOT_copy()首先打开 NandFlash设备,将NandFlash的硬件信息放在hNandInfo数据结构内。移植ubl时需要修改与hNandInfo数据结构相关的参数,比如EMIF地址(EMIFStart = 0x02000000 在ubl.cmd;) DEVICE_NAND_CHIP_infoTable结构中的页大小、块数、块中的页数、... if (NANDBOOT_copy()!= E_PASS)
{
DEBUG_printString("NAND Boot failed.\r\n");
LOCAL_bootAbort();
}
}
#elif defined(UBL_NOR)
{
//Report Bootmode to host
DEBUG_printString("NOR \r\n");
// Copy binary application image from NOR to RAM
if (NORBOOT_copy()!= E_PASS)
{
DEBUG_printString("NOR Boot failed.\r\n");
LOCAL_bootAbort();
}
}
#elif defined(UBL_SD_MMC)
{
//Report Bootmode to host
DEBUG_printString("SD/MMC \r\n");
// Copy binary of application image from SD/MMC card to RAM
if (SDMMCBOOT_copy()!= E_PASS)
{
DEBUG_printString("SD/MMC Boot failed.\r\n");
LOCAL_bootAbort();
}
}
#else
{
//Report Bootmode to host
DEBUG_printString("UART\r\n");
UARTBOOT_copy();
}
#endif
DEBUG_printString(" DONE");
UTIL_waitLoop(10000);
DEVICE_TIMER0Stop();
return E_PASS;
}
先通过调用DEVICE_bootMode函数来判断启动方式(通过读取SYS寄存器实现),而后调用了DEVICE_init函数来进行平台的最底层初始化,包括电源域,时钟,DDR,EMIF,UART,I2C,TIMER等。
而后通过UTIL_setCurrMemPtr函数对全局变量currMemPtr赋值,以后用到。接着通过判断不同的引导方式,采取不同的处理办法,以 NAND启动为例,将调用NANDBOOT_copy函数。此函数将NAND中的某些内容(就是UBOOT)搬移到RAM中,而后 UBL结束,控制权正式交给UBOOT。
看看UBL对平台的初始化,主要是调用了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作为SD1的clk,McBsp开启,MMCSD0关闭
DEVICE_pinmuxControl(1,0xFFFFFFFF,0x00145555);// All Video Outputs,视频Cout0-Cout7作为色度信号输出使能,场消隐/行消隐同步信号使能,LCD的OE功能关闭
DEVICE_pinmuxControl(2,0xFFFFFFFF,0x000000DA);// EMIFA,总线使能,但是CE0没有使能,0xDA可能在合众达板子上运行有问题,因为他将ce0设置成GPIO,这样nandflash失效了,我想可能是TI原版有个cpld,在合众达的测试程序,值为0x55。
DEVICE_pinmuxControl(3,0xFFFFFFFF,0x00180000);// SPI0, SPI1, UART1, I2C, SD0, SD1, McBSP0, CLKOUTs,串口1使能,其他均作为GPIO,网卡没使能
DEVICE_pinmuxControl(4,0xFFFFFFFF,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;
}
首先屏蔽和清除中断,然后调用DEVICE_PSCInit函数实现对各模块的电源时钟使能,实质是调用PSC电源时钟管理模块的寄存器实现,函数内容如下:
void DEVICE_PSCInit()
{
unsigned char i=0;
unsigned char lpsc_start;
unsigned char lpsc_end,lpscgroup,lpscmin,lpscmax;
unsigned int PdNum= 0;
lpscmin =0;
lpscmax =2;
for(lpscgroup=lpscmin; lpscgroup <=lpscmax; lpscgroup++){
if(lpscgroup==0)
{
lpsc_start = 0;// Enabling LPSC 3 to 28 SCR first
lpsc_end = 28;
}
else if(lpscgroup == 1){ /* Skip locked LPSCs [29-37] */
lpsc_start = 38;
lpsc_end = 47;
} else {
lpsc_start = 50;
lpsc_end = 51;
}
//NEXT=0x3, Enable LPSC's
for(i=lpsc_start; i<=lpsc_end; i++){
PSC->MDCTL[i]|= 0x3;
}
//Program goctl to start transition sequence for LPSCs
PSC->PTCMD= (1<<PdNum);
//Wait for GOSTAT = NO TRANSITION from PSC for Pdomain 0
while(!(((PSC->PTSTAT>> PdNum)& 0x00000001) == 0));
//Wait for MODSTAT = ENABLE from LPSC's
for(i=lpsc_start; i<=lpsc_end; i++){
while(!((PSC->MDSTAT[i]& 0x0000001F) == 0x3));
}
}
}
然后调用DEVICE_pinmuxControl函数决定复用引脚的功能选择,详见数据手册查看引脚功能。
接着调用DM36x/common/src/device.c下的DEVICE_PLL1Init函数实现了PLL1的配置,预分频,倍频,后分频,分频到各个模块,其设置顺序可以参看用户指南ARM子系统文档,有详细的介绍,PLL2类似,函数内容如下:
Uint32 DEVICE_PLL1Init(Uint32 PLLMult)
{
unsigned int CLKSRC=0x0;
unsigned int j;
/*Power up the PLL*/
PLL1->PLLCTL&= 0xFFFFFFFD;
PLL1->PLLCTL&= 0xFFFFFEFF;
PLL1->PLLCTL|= CLKSRC<<8;
/*Set PLLENSRC '0', PLL Enable(PLLEN) selection is controlled through MMR*/
PLL1->PLLCTL&= 0xFFFFFFDF;
/*Set PLLEN=0 => PLL BYPASS MODE*/
PLL1->PLLCTL&= 0xFFFFFFFE;
UTIL_waitLoop(150);
// PLLRST=1(reset assert)
PLL1->PLLCTL|= 0x00000008;
UTIL_waitLoop(300);
/*Bring PLL out of Reset*/
PLL1->PLLCTL&= 0xFFFFFFF7;
//Program the Multiper and Pre-Divider for PLL1
PLL1->PLLM = 0x51; // VCO will 24*2M/N+1 = 486Mhz
PLL1->PREDIV= 0x8000|0x7;
PLL1->SECCTL= 0x00470000; // Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 1
PLL1->SECCTL= 0x00460000; // Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 0
PLL1->SECCTL= 0x00400000; // Assert TENABLE = 0, TENABLEDIV = 0, TINITZ = 0
PLL1->SECCTL= 0x00410000; // Assert TENABLE = 0, TENABLEDIV = 0, TINITZ = 1
//Program the PostDiv for PLL1
PLL1->POSTDIV= 0x8000;
// Post divider setting for PLL1
PLL1->PLLDIV2= 0x8001;
PLL1->PLLDIV3= 0x8001; // POST DIV 486/2 -> MJCP/HDVICP
PLL1->PLLDIV4= 0x8003; // POST DIV 486/4 -> EDMA/EDMA CFG
PLL1->PLLDIV5= 0x8001; // POST DIV 486/2 -> VPSS
PLL1->PLLDIV6= 0x8011; // 27Mhz POST DIV 486/18 -> VENC
PLL1->PLLDIV7= 0x8000; // POST DIV 486/2 -> DDR
PLL1->PLLDIV8= 0x8003; // POST DIV 486/4 -> MMC0/SD0
PLL1->PLLDIV9= 0x8001; // POST DIV 486/2 -> CLKOUT
UTIL_waitLoop(300);
/*Set the GOSET bit */
PLL1->PLLCMD= 0x00000001; // Go
UTIL_waitLoop(300);
/*Wait for PLL to LOCK */
while(!(((SYSTEM->PLL0_CONFIG)& 0x07000000) == 0x07000000));
/*Enable the PLL Bit of PLLCTL*/
PLL1->PLLCTL|= 0x00000001;// PLLEN=0
return E_PASS;
}
Uint32 DEVICE_PLL2Init()
{
...
// Post divider setting for PLL2
PLL2->PLLDIV2= 0x8001; // 594/2 =297 Mhz -> ARM
PLL2->PLLDIV4= 0x801C; // POST DIV 594/29 = 20.48 -> VOICE
PLL2->PLLDIV5= 0x8007;
...
}
Uint32 DEVICE_DDR2Init()
{
DEVICE_LPSCTransition(LPSC_DDR2,0,PSC_ENABLE);
SYSTEM->VTPIOCR= (SYSTEM->VTPIOCR)& 0xFFFF9F3F;
// Set bit CLRZ (bit 13)
SYSTEM->VTPIOCR= (SYSTEM->VTPIOCR)| 0x00002000;
// Check VTP READY Status
while( !(SYSTEM->VTPIOCR& 0x8000));
// Set bit VTP_IOPWRDWN bit 14 for DDR input buffers)
//SYSTEM->VTPIOCR = SYSTEM->VTPIOCR | 0x00004000;
// Set bit LOCK(bit7) and PWRSAVE (bit8)
SYSTEM->VTPIOCR= SYSTEM->VTPIOCR| 0x00000080;
// Powerdown VTP as it is locked (bit 6)
// Set bit VTP_IOPWRDWN bit 14 for DDR input buffers)
SYSTEM->VTPIOCR= SYSTEM->VTPIOCR| 0x00004040;
// Wait for calibration to complete
UTIL_waitLoop( 150 );
// Set the DDR2 to synreset, then enable it again
DEVICE_LPSCTransition(LPSC_DDR2,0,PSC_SYNCRESET);
DEVICE_LPSCTransition(LPSC_DDR2,0,PSC_ENABLE);
DDR->DDRPHYCR= 0x000000C5;
DDR->SDBCR = 0x08D34832; //Program SDRAM Bank Config Register
DDR->SDBCR = 0x0853C832;
DDR->SDTIMR=0x3C934B51; //Program SDRAM Timing Control Register1
DDR->SDTIMR2=0x4221C72; //Program SDRAM Timing Control Register2
DDR->PBBPR = 0x000000FE;
DDR->SDBCR = 0x08534832; //Program SDRAM Bank Config Register
DDR->SDRCR = 0x00000768; //Program SDRAM Refresh Control Register
DEVICE_LPSCTransition(LPSC_DDR2,0,PSC_SYNCRESET);
DEVICE_LPSCTransition(LPSC_DDR2,0,PSC_ENABLE);
return E_PASS;
}
void DEVICE_LPSCTransition(Uint8 module, Uint8 domain, Uint8 state)
{
// Wait for any outstanding transition to complete
while ( (PSC->PTSTAT)& (0x00000001 << domain));
// If we are already in that state, just return
if (((PSC->MDSTAT[module])& 0x1F) == state)return;
// Perform transition
PSC->MDCTL[module]= ((PSC->MDCTL[module])& (0xFFFFFFE0))| (state);
PSC->PTCMD |= (0x00000001<< domain);
// Wait for transition to complete
while ( (PSC->PTSTAT)& (0x00000001 << domain));
// Wait and verify the state
while (((PSC->MDSTAT[module])& 0x1F) != state);
}
而后调用DEVICE_EMIFInit函数来配置EMIF模块,这个模块用来接外存,比如NAND,NOR等。DM365有两个片选空间,如果某一空间配置成NAND,则需要在寄存器中设置,其函数内容如下:
Uint32 DEVICE_EMIFInit()
{
AEMIF->AWCCR= 0xff;
AEMIF->A1CR= 0x40400204;
AEMIF->NANDFCR|= 1;
AEMIF->A2CR= 0x00a00505;
return E_PASS;
}
而后调用DEVICE_UART0Init函数来配置串口0,调用DEVICE_TIMER0Init函数来配置TIMER0,调用 DEVICE_I2C0Init函数来配置I2C控制器,都是操作某一模块的控制寄存器实现,具体如何设置可以参考相关模块的手册,这三个函数的内容如下:
Uint32 DEVICE_UART0Init()
{
UART0->PWREMU_MGNT= 0; // Reset UART TX & RX components
UTIL_waitLoop( 100 );
UART0->MDR = 0x0;
UART0->DLL = 0xd; // Set baud rate
UART0->DLH = 0;
UART0->FCR = 0x0007; // Clear UART TX & RX FIFOs
UART0->FCR = 0x0000; // Non-FIFO mode
UART0->IER = 0x0007; // Enable interrupts
UART0->LCR = 0x0003; // 8-bit words
// 1 STOP bit generated,
// No Parity, No Stick paritiy,
// No Break control
UART0->MCR = 0x0000; // RTS & CTS disabled,
// Loopback mode disabled,
// Autoflow disabled
UART0->PWREMU_MGNT= 0xE001; // Enable TX & RX componenets
return E_PASS;
}
Uint32 DEVICE_I2C0Init()
{
I2C0->ICMDR= 0; // Reset I2C
I2C0->ICPSC= 26; // Config prescaler for 27MHz
I2C0->ICCLKL= 20; // Config clk LOW for 20kHz
I2C0->ICCLKH= 20; // Config clk HIGH for 20kHz
I2C0->ICMDR|= I2C_ICMDR_IRS;// Release I2C from reset
return E_PASS;
}
Uint32 DEVICE_TIMER0Init()
{
// Put timer into reset
TIMER0->EMUMGT_CLKSPD= 0x00000003;
TIMER0->TCR= 0x00000000;
// Enable TINT0, TINT1 interrupt
TIMER0->INTCTL_STAT= 0x00000001;
// Set to 64-bit GP Timer mode, enable TIMER12 & TIMER34
TIMER0->TGCR= 0x00000003;
// Reset timers to zero
TIMER0->TIM12= 0x00000000;
TIMER0->TIM34= 0x00000000;
// Set timer period (5 second timeout = (24000000 * 5) cycles = 0x07270E00)
TIMER0->PRD34= 0x00000000;
TIMER0->PRD12= 0x07270E00;
return E_PASS;
}
- DM365的UBL源码分析
- DM365的UBL源码分析
- DM365的UBL源码分析
- DM365的UBL源码分析
- DM365的UBL源码分析(转)
- DM365的UBL源码分析和移植
- dm365启动分析以及RBL、UBL、Uboot的简单介绍
- DM365启动之—RBL、UBL分析
- DM365启动之—RBL、UBL分析
- UBL descriptor ti dm365 引导分析 RBL,UBLU-BOOT
- UBL descriptor ti dm365 引导分析 RBL,UBLU-BOOT
- UBL descriptor ti dm365 引导分析 RBL,UBLU-BOOT
- dm365 ubl splash logo
- CCS 3.3 编译 DM365 ubl
- DM365的BSP源码分析-基于2.6.18内核
- DAVINCI DM365-DM368开发攻略——U-BOOT-2010.12及UBL的移植
- DAVINCI DM365-DM368开发攻略——U-BOOT-2010.12及UBL的移植
- DAVINCI DM365-DM368开发攻略——U-BOOT-2010.12及UBL的移植
- HTTP1.0与HTTP1.1的区别
- 强大的web电子表格控件dhtmlxSpreadsheet免费下载地址
- Hex、bin、axf、elf格式文件小结
- Qt5.3.1 MinGW482 release静态版编译结果、过程及QtCreator配置分享
- ListView嵌套GridView使用详解及注意事项
- DM365的UBL源码分析
- SAP IDOC 开发介绍
- 资源在另一个编辑器中打开解决
- eclipse ssh插件 (struts2 spring3 hibernate4)
- Other flag Linker
- poj 3311 Hie with the Pie 【旅行商+回原点】
- gvim 特殊的编辑指令("dw")
- QML类型说明-LevelAdjust
- 对比MFC ,Winform ,WPF