dm348_再论不平等

2022-09-21 10:12:14 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

参看:UBI – Unsorted Block Images

参看:DM36x UBL PLL配置

UBL 前两篇文章中我们有提到过了。

参看:DM368开发 — 文件烧写

参看:DM368开发 — Bootloader 开发

简单点来说,UBL 主要功能是实现将 U-boot 代码拷贝到 DDR2 内存中,建立运行环境并引导U-boot。

但是现在我有个问题,我想让 DM368 开发板运行在 432 Mhz,目前它的状态是 AR, 297 Mhz 、DDR 为243Mhz。

具体操作为,修改 /psp/flash-utils/DM36x/Common/Src/device.c 相关的设置。

一、修改内核电源电压

当然,DM368主频大小除了与UBL有关外,还与ARM内核电源电压有关。 当为1.2v时,主频不能达到432Mhz的,只有为1.35v的时候才能达到。所以需要将 ARM 内核电源电压设为1.35v。

我用的电源管理芯片是TVP65023RSB,这个芯片该如何配置,使其生成1.35v呢?

我使用 I2C 工具 ,可以看到 0x48 The TPS65023 has a 7-bit address:?1001000, other addresses are available upon contact with the factory 则 tps64023的设备地址应为 0x48 ,说明有这个 I2C 设备的。

代码语言:javascript复制
root@dm368-evm:~# i2cdetect -y 1 
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- 08 -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- UU -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- UU -- -- 
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 
70: -- -- -- UU -- -- -- --

通过i2ctool修改寄存器: 主要有关的寄存器为05和06如下图:

代码语言:javascript复制
i2cset -f -y 1 0x48 0x05 0x80
i2cget -f -y 1 0x48 0x05

i2cset -f -y 1 0x48 0x06 0x16
i2cget -f -y 1 0x48 0x06

OK!!! 有电压1.35v。

到这步又有问题了,通过I2Ctool可以获得1.35v,但是掉电后会恢复默认的1.2v。

上面的使用i2c的方法不适用,只能使用加电阻分压器的方法。具体参看datasheet。或者硬件设计的时候换一种电源管理芯片。 最后的解决也正是用了后者。

二、修改 UBL 源码

修改电压以后,就可以烧写 ubl_DM36x_ARM432_DDR340_OSC24_NAND.bin,这个可以在网上找到的。

问题是如果自行,修改 /psp/flash-utils/DM36x/Common/Src/device.c 相关的设置,该如果操作。

参考网址: How can I modify Leopardboard DM368 running on 432MHz Timing DDR DM368 MT47H64M16HR-25E IT:H DM368 (Performance & Power Consumption) DDR2/mDDR Memory Controller User’s Guide Setting up AM35x SDRC registers

参看:DM36x to DM368 NAND UBL porting guide

About this Guide

This is reference guide to port UBL for DM368 using DM365 UBL code base. This guide helps to configure PLLs to run ARM@432 and DDR@340 with 24MHz crystal oscillator. Modify PLL1, PLL2 and DDR setup function in DM36x/Common/src/device.c as explained in below sections.

PLL1 Setup

Modify DEVICE_PLL1Init(PLL1_Mult) function for 680MHz by replacing configurations of PLL1 multipliers, pre and post divisors as below

代码语言:javascript复制
 //Program the Multiper and Pre-Divider for PLL1 PLL1->PLLM = 0x55; // VCO will 24*2M/N 1 PLL1->PREDIV = 0x8000|0x5;   // Post divider setting for PLL1   PLL1->PLLDIV1 = 0x801B; PLL1->PLLDIV2 = 0x8001; PLL1->PLLDIV3 = 0x8001; // POST DIV 680/2 = 340Mhz -> MJCP and HDVICP bus interface clock PLL1->PLLDIV4 = 0x8003; // POST DIV 680/4 = 170Mhz -> EDMA/Peripheral CFG0(1/2 MJCP/HDVICP bus interface clk) PLL1->PLLDIV5 = 0x8001; // POST DIV 680/2 = 340Mhz -> VPSS PLL1->PLLDIV6 = 0x8008; // POST DIV 680/9 = 75.6 Mhz -> VENC     PLL1->PLLDIV7 = 0x8000; // POST DIV 680/1 = 680Mhz -> DDRx2(with internal divider of 2, clock boils down to 340 Mhz) PLL1->PLLDIV8 = 0x8006; // POST DIV 680/7= 97Mhz-> MMC0/SD0 PLL1->PLLDIV9 = 0x801B; // POST DIV 680/28 = 24.3Mhz-> CLKOUT

PLL2 Setup

Modify DEVICE_PLL2Init()function for 432MHz by replacing configurations PLL2 multipliers, pre and post divisor as below

代码语言:javascript复制
 //Program the Multiper and Pre-Divider for PLL2 PLL2->PLLM = 0x9; // VCO will 24*2M/N 1 = 432Mhz PLL2->PREDIV = 0x8000|0x0;   // Post divider setting for PLL2 PLL2->PLLDIV1 = 0x8011; PLL2->PLLDIV2 = 0x8000; // POST DIV 432/1=432 Mhz -> ARM926/(HDVICP block) clk PLL2->PLLDIV3 = 0x8001; PLL2->PLLDIV4 = 0x8014; // POST DIV 432/21= 20.5714 Mhz->VOICE Codec clk PLL2->PLLDIV5 = 0x800F; // POST DIV 432/16=27 Mhz -> VENC(For SD modes, requires )

NOTE

  1. For configuration details of PLL Controllers (PLL1 and PLL2) look into TMS320DM36x ARM Subsystem Reference Guide (literature number SPRUFG5).
  2. Make sure PLLC1_SYSCLK6 is selected for HD modes and is done by configuring VPSS_CLK_CTRL register(i.e. VPSS_CLK_CTRL = 0x18) in drivers/media/video/davinci/davinci_platform.c. VENC requires clock of 74.25Mhz for HD modes to work properly. HD output is tested on TV with above derived clock of 68Mhz.
  3. Make sure PLLC2_SYSCLK5 is selected for SD modes and is done by configuring VPSS_CLK_CTRL register(i.e. VPSS_CLK_CTRL = 0x38) in drivers/media/video/davinci/davinci_platform.c. VENC requires clock of 27Mhz for SD modes to work properly.

DDR2 Setup

Modify DEVICE_DDR2Init() for 340MHZ by replacing SDR bank and timing configurations as below

代码语言:javascript复制
 DDR->DDRPHYCR = 0x000000C6; DDR->SDBCR = 0x00D34A32; //Program SDRAM Bank Config Register DDR->SDBCR = 0x0053CA32;   DDR->SDTIMR =0x576D7D12; //Program SDRAM Timing Control Register1 DDR->SDTIMR2 =0x422EC742; //Program SDRAM Timing Control Register2   DDR->PBBPR = 0x000000FE;   DDR->SDBCR = 0x08534832; //Program SDRAM Bank Config Register   DDR->SDRCR = 0xA5C; //Program SDRAM Refresh Control Register

NOTE The timing configuration done above are specific to DDR part present on the evm’s. Please refer DDR device data sheet for information.

Build steps

  1. Open DM36x/CCS/UBL/UBL.pjt UBL project.
  2. Make sure you selected BOOT_NAND configuration from active configuration drop down.
  3. Build the project and new binary at DM36xCCSUBLUBL_DM36x_NAND.bin does the PLL configurations to run ARM@432 and DDR@340.

我的修改部分:

代码语言:javascript复制
	//Program the Multiper and Pre-Divider for PLL1
	//cjk add down
	// PLL1->PLLM   =   0x51;   // VCO will 24*2M/N 1 = 486Mhz
	//PLL1->PREDIV =   0x8000|0x7; 
	 
	 PLL1->PLLM   =   0x55;   // VCO will 24*2M/N 1
   PLL1->PREDIV =   0x8000|0x5;
	 //cjk add up
	 
	 
	 //cjk add down
#if 0
	    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
#endif
			PLL1->PLLDIV1 = 0x801B;
      PLL1->PLLDIV2 = 0x8001;
      PLL1->PLLDIV3 = 0x8001;   // POST DIV 680/2 = 340Mhz  -> MJCP and HDVICP bus interface clock
      PLL1->PLLDIV4 = 0x8003;   // POST DIV 680/4 = 170Mhz  -> EDMA/Peripheral CFG0(1/2 MJCP/HDVICP bus interface clk)
      PLL1->PLLDIV5 = 0x8001;   // POST DIV 680/2 = 340Mhz  -> VPSS
      PLL1->PLLDIV6 = 0x8008;   // POST DIV 680/9 = 75.6 Mhz -> VENC
 
 
      PLL1->PLLDIV7 = 0x8000;   // POST DIV 680/1 = 680Mhz -> DDRx2(with internal divider of 2, clock boils down to 340 Mhz)
      PLL1->PLLDIV8 = 0x8006;   // POST DIV 680/7= 97Mhz-> MMC0/SD0
      PLL1->PLLDIV9 = 0x801B;   // POST DIV 680/28 = 24.3Mhz-> CLKOUT
//cjk add up

//cjk add down
	 //PLL2->PLLM   =   0x63;   // VCO will 24*2M/N 1 = 594Mhz
	 //PLL2->PREDIV =   0x8000|0x7; 
	  PLL2->PLLM   =   0x9;   // VCO will 24*2M/N 1 = 432Mhz
    PLL2->PREDIV =   0x8000|0x0;
	 //cjk add up
	 
	 	//cjk add down
		#if 0
     PLL2->PLLDIV2 = 0x8001;   // 594/2 =297 Mhz -> ARM 
	 PLL2->PLLDIV4 = 0x801C;   // POST DIV 594/29 = 20.48 -> VOICE
	 PLL2->PLLDIV5 = 0x8007;   // POST DIV 594/8 = 74.25 ->VIDEO HD
	 #endif
	  PLL2->PLLDIV1 = 0x8011;
     PLL2->PLLDIV2 = 0x8000;   // POST DIV 432/1=432 Mhz  -> ARM926/(HDVICP block) clk
     PLL2->PLLDIV3 = 0x8001;
     PLL2->PLLDIV4 = 0x8014;   // POST DIV 432/21= 20.5714 Mhz->VOICE Codec clk
     PLL2->PLLDIV5 = 0x800F;   // POST DIV 432/16=27 Mhz  -> VENC(For SD modes, requires )
		//cjk add up      
		
		
		
  //cjk add down
  #if 0  
 	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
  #endif 
   DDR->DDRPHYCR = 0x000000C6;
   DDR->SDBCR = 0x00D34A32;        //Program SDRAM Bank Config Register
   DDR->SDBCR = 0x0053CA32;
 
   DDR->SDTIMR  =0x576D7D12;       //Program SDRAM Timing Control Register1
   DDR->SDTIMR2 =0x422EC742;       //Program SDRAM Timing Control Register2
 
   DDR->PBBPR = 0x000000FE;
 
   DDR->SDBCR = 0x08534832;        //Program SDRAM Bank Config Register
 
   DDR->SDRCR = 0xA5C;             //Program SDRAM Refresh Control Register
   //cjk add up

三、UBL 编译

参看:TI davinci DM368 UBL 编译方法

四、UBL源码分析

参看: UBL descriptor

参看:DM36X 的UBL移植

DM365是的启动方式有两种,通过BOOTSEL[2:0]引脚决定。当其为001时,直接从AEMIF上启 动,比如NOR和OneNAND。除此之外皆是从RBL启动,顺序为RBL-UBL-UBOOT-KERNEL,比如NAND,串口,SD卡等。RBL会 搜寻block1到block24去找UBL,关于RBL启动的详细细节可以参考用户指南关于ARM子系统的那篇文档,很详尽,下面只分析UBL的源码。 UBL源码在PSP包里的board_utilitiesflash_utils目录下,主要是COMMON目录和各子平台的目录如DM36x等,内中除了UBL的源码外还有CCS下JTAG的擦除烧写源码,串口烧写源码等。下面只分析UBL的启动代码。 入门代码是汇编文件start.S,主要是切换操作模式,建立堆栈等,然后跳转到main函数,进入到Commonublsrc目录下的C文件ubl.c中。main函数如下: // Main entry pointvoid main(void){ // Call to real boot function code LOCAL_boot(); // Jump to entry point DEBUG_printString("rnJumping to entry point at "); DEBUG_printHexInt(gEntryPoint); DEBUG_printString(".rn"); APPEntry = (void(*)(void)) gEntryPoint; (*APPEntry)(); } main函数主要调用了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(devString); DEBUG_printString(" initialization failed!rn"); asm(" MOV PC, #0"); } else { DEBUG_printString(devString); DEBUG_printString(" initialization passed!rn"); } // 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("rnBooting Catalog Boot LoaderrnBootMode = "); // Select Boot Mode#if defined(UBL_NAND) { //Report Bootmode to host DEBUG_printString("NANDrn"); // 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) { //Report Bootmode to host DEBUG_printString("NOR rn"); // 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) { //Report Bootmode to host DEBUG_printString("SD/MMC rn"); // 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 { //Report Bootmode to host DEBUG_printString("UARTrn"); 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 DEVICE_pinmuxControl(1,0xFFFFFFFF,0x00145555);// All Video Outputs DEVICE_pinmuxControl(2,0xFFFFFFFF,0x000000DA);// EMIFA DEVICE_pinmuxControl(3,0xFFFFFFFF,0x00180000);// SPI0, SPI1, UART1, I2C, SD0, SD1, McBSP0, CLKOUTs DEVICE_pinmuxControl(4,0xFFFFFFFF,0x55555555);// MMC/SD0 instead of MS, SPI0 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函数决定复用引脚的功能选择,详见数据手册查看引脚功能。 接着调用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;} 继续在DEVICE_init函数中,下面是调用DEVICE_DDR2Init函数来配置DDR控制器,这是 UBL中重要的一部分,如果硬件电路需要更换内存芯片的话,需要在UBL中修改这个函数,即按照芯片手册来配置DDR控制寄存器中的相关参数,比如时 序,BANK数,页大小等。这个函数主要是操作SYS模块和DDR模块的相关寄存器来配置内存,函数中调用的DEVICE_LPSCTransition 函数用来实现模块的电源时钟状态的改变,函数内容如下: 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;} 至此,DEVICE_init函数结束,程序返回至LOCAL_boot函数中,接着就调用NANDBOOT_copy函数了。 下面继续分析,由于后面的代码和函数量相对的多且复杂,所以不再贴上代码,只说流程,只要把程序源码打开对着看很容易就明白了。 在DEVICE_init()这个大的平台初始化函数结束以后,下面要做的工作就是将NAND的中UBOOT复制到DDR中并且跳转到那里,然后UBL的历史使命结束,UBOOT的执行开始,那么就是调用这个函数,NANDBOOT_copy()。 NANDBOOT_copy()函数主要分三大块,第一大块是调用NAND_open()函数对NAND控制器和NAND芯片进行初始化,它传递的参数是CE的地址(一般是CE0)和总线位宽(一般是8位)。好,我们跳到NAND_open()函数中。 NAND_open()函数在commondriversrcnand.c中,与平台无关。首先定义一个NAND_InfoHandle结构 hNandInfo,这个结构包含了所有与NAND有关的参数,比如厂商ID,设备ID,基址,位宽,块数,页数每块,页大小及与ECC,BB有关的一些 函数。然后对这个hNandInfo进行赋值,这里最重要的是把 DEVICE_NAND_PAGE_layout,DEVICE_NAND_ECC_info,DEVICE_NAND_BB_info,DEVICE_NAND_CHIP_infoTable 这四大全局结构赋给了hNandInfo的相关字段。这四大全局结构在每个平台目录下都有定义(比如dm36xcommonsrc device_nand.c),编译不同平台的UBL,会将不同平台的四大全局结构传递给nand.c中使用,这样就做到了NAND的驱动分离中平台无 关部分和平台有关部分,这种思想也贯穿在整个LINUX的架构中,先不提这个。然后,操作AEMIF寄存器使能NAND的哪一个CE中,这个由传递的基址 决定,一般是CE0,并使能这段片选之上有ECC功能。 接着调用NAND_reset()函数对NAND芯片进行复位,这个函数本身很简单,就是先发复位命令0xFF,再等待操作完成,懂得NAND操作过程的 会很容易这个操作。但是这里多说一点,一般我们遇到的芯片操作NAND,其CPU内部会有一个NAND控制器,对NAND的操作会通过这个寄存器来操作, 发命令发地址等都是操作这些寄存器来完成。但是DM365不是这样,它没有实质上的NAND控制器,它还是将NAND当做是一个类RAM一样的操作,通过 总线上的时序来完成。CLE和ALE连在地址总线A2和A1上,这样的话发命令实质上就是在总线地址0x00000010u上写值(注意DM365的地址 线问题,有个32位问题),发地址实质就是在总线地址0x00000008u上写值,读写数据实质就是在总线地址0x00000000u上读写值。这些地 址的操作隐含着CLE和ALE的高低电平,再加上配好的时序参数就把NAND的操作弄成了类RAM的操作。这种操作以前没有碰到过,TI的工程师很牛。 接着调用LOCAL_flashGetDetails()函数,这个函数很重要,它会得到NAND的很多详细信息。首先它会判断NAND是否是ONFI, 这个没有细究过,跳过不管。然后它会向NAND发读ID命令,从而得到NAND的厂商ID和设备ID值。有了这两个值就好办了,通过一个循环把它们通四全 大局结构中的DEVICE_NAND_CHIP_infoTable中定义的各种NAND的资料进行对比,通过ID来定位是哪一种NAND,然后就得出了 页数,块数,页大小等重要信息。另外,还要区分NAND是大型还是小型(一般看页大小,大于2K为大),因为它们的地址周期不同。这个函数后面还有一些东 西,没有深究。调用完成后再复位一下NAND,整个NAND_open()函数就结束了。 NAND_open()函数完成后,会调用NAND_readPage()函数从第25块开始一直搜索到第50块,只读第0页。因为UBOOT放在第25 块开始的地方,这是手册规定的,而且第0页放一些启动信息等等。通过MAGIC_NUMBER来判断是否有效,这个知识点详见手册。一旦 MAGIC_NUMBER正确,就会将后面的几个字段,比如UBOOT的进入点,页数,UBOOT在哪一个块,哪一个页,UBOOT的装载点等信息就会得 到。而后循环调用NAND_readPage()函数将整个UBOOT从NAND拷贝到DDR里,最后将刚才得到的UBOOT的进入点地址复制到 gEntryPoint变量中。然后主函数跳转到这里,从此UBL结束,UBOOT正式启动。 这里的分析没有涉及到坏块处理,ECC校验的部分,一方面现在太忙没时间细看。另一方面UBL不是重点,要想深究这个东西,还是到Linux内核里的 NAND驱动中深究,这里能用就行了。还有就是一开始担心的是我们项目用到的NAND是512B每页的老式NAND,担心UBL不支持,需要修改UBL源 码。后来读了UBL源码以后,特别是平台相关的device_nand.c文件,才发现TI的工程师已经把该考虑的都考虑的,都能用,老外就是牛X。不像 国内的代码,根本没有普适性和跨平台性。UBL整个源码,架构较清晰,注释也多,代码整体很完整和美观,很有参考和学习价值。读了UBL源码后,其实很容 易就能读懂NANDEraser,NANDWriter等的源码了,说白了就是平台初始化加NAND读写,呵呵。 五、DM36X 的UBL移植 参看:DAVINCI DM365-DM368开发攻略——U-BOOT-2010.12及UBL的移植 关于UBL的移植,本人打算单独写一篇文章的,但是UBL和UBOOT太紧密了,是TI davinci芯片的特点,所以放到一起讲。我们重点放在NAND BOOT的移植,这个UBL的版本是V1.50,在dvsdk_dm368_4_02_00_06pspflash-utilsDM36x和flash-utilsCommon目录下,Common目录里有非常多东西,包括UBL的驱动源码、工具、脚本等等。我们主要关注arch,drivers,src,ubl。UBL的main()函数在dvsdk_dm368_4_02_00_06pspflash-utilsCommonublsrcubl.c里,这几个文件夹打开看看就明白什么意思了,这里不罗嗦。 DM36x下有CCS、Common,GNU三个文件夹: CCS文件夹: 这里边的程序需要在TI CCS下编译,通过仿真器和JTAG在DM36X的板子上调试和烧写NAND FLASH或NOR FLASH,有烧写Writer的应用程序,用CCS打开工程文件,会连接到dvsdk_dm368_4_02_00_06pspflash-utilsCommon drivers里。 Common文件夹:Common里有核心的文件device.c和device_nand.c。device.c是最重要的文件,这里初始化很多系统的东西,见DEVICE_init(): 1、屏蔽所有中断; 2、清除中断标志; 3、DEVICE_PSCInit(),Power and Sleep Controller; 4、主芯片管脚复用的设置DEVICE_pinmuxControl(),DM36X的管脚复用很多,很复杂,一共5个PINMUX寄存器需配置; 5、DEVICE_PLL1Init(),PPL1配置,见SPRUSG5A.pdf的35页开始的介绍,使用不同的频率的DM36X,这些值都不同,不过TI已经提供参数参考,我们的DM365核心板是:ARM297_DDR243_OSC24,DM368核心板是:ARM432_DDR340_OSC24; 6、DEVICE_PLL2Init(),PPL2的配置,使用同上,不同频率的值不同; 7、DEVICE_DDR2Init()的配置,市场上不同的DDR2内存芯片需要不同的参数配置,就在这个函数内。 8、DEVICE_EMIFInit(),这个针对NAND FLASH接口或NOR FLASH接口的访问时序配置; 9、DEVICE_UART0Init()的配置,这个就是我们调试DM36X串口的设置,我们使用UART0来调试LINUX,这里配置不好,后面的开发不用调试了。 10、DEVICE_TIMER0Init()定时器TIMER0的设置; 11、DEVICE_I2C0Init()的设置; GNU的文件夹: 这个就是在LINUX环境下编译UBL的环境,修改dvsdk_dm368_4_02_00_06pspflash-utilsDM36xGNUubl下的makefile,把 #$(MAKE) -C build TYPE=nor注释掉,只保留$(MAKE) -C build TYPE=nand,然后是make clean和 make生产ubl_DM36x_nand.bin的文件; 如果出现:device.c:(.text 0x2ec): undefined reference to `__aeabi_uidiv’和device.c:(.text 0x2e8): undefined reference to `__aeabi_uidivmod’的BUG,就是DDR_Get_Val()函数里边的除法和求余的语句和你的编译器不配置造成的。 result = ((parm * freq) / 10000) – 1;和if(((parm * freq) % 10000)),我们对参数的求值直接: tRFC = xxx; //DDR_Get_Val(DDR_T_RFC, DDR_FREQ); tRP = xxx; //DDR_Get_Val(DDR_T_RP, DDR_FREQ); tRCD = xxx; //DDR_Get_Val(DDR_T_RCD, DDR_FREQ); tWR = xxx; //DDR_Get_Val(DDR_T_WR, DDR_FREQ); tRAS = xxx; //DDR_Get_Val(DDR_T_RAS, DDR_FREQ); tRC = xxx; //DDR_Get_Val(DDR_T_RC, DDR_FREQ); tRRD = xxx; //DDR_Get_Val(DDR_T_RRD, DDR_FREQ); tWTR = xxx; //DDR_Get_Val(DDR_T_WTR, DDR_FREQ); 不用DDR_Get_Val()函数求值,这样就可以编译通过了。后来发觉TI的 UBL compile error in the dvsdk_dm365-evm_4_02_00_06_setuplinux 里也有人这人解决,呵呵,没想到本人的解决办法和一个网友一样的。本人记得调试三星2440 UBOOT的时候,有人点到过,这里本人忘记在什么地方改了。

// Main entry pointvoid main(void){ // Call to real boot function code LOCAL_boot(); // Jump to entry point DEBUG_printString("rnJumping to entry point at "); DEBUG_printHexInt(gEntryPoint); DEBUG_printString(".rn"); APPEntry = (void(*)(void)) gEntryPoint; (*APPEntry)(); }

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(devString); DEBUG_printString(" initialization failed!rn"); asm(" MOV PC, #0"); } else { DEBUG_printString(devString); DEBUG_printString(" initialization passed!rn"); } // 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("rnBooting Catalog Boot LoaderrnBootMode = "); // Select Boot Mode#if defined(UBL_NAND) { //Report Bootmode to host DEBUG_printString("NANDrn"); // 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) { //Report Bootmode to host DEBUG_printString("NOR rn"); // 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) { //Report Bootmode to host DEBUG_printString("SD/MMC rn"); // 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 { //Report Bootmode to host DEBUG_printString("UARTrn"); UARTBOOT_copy(); } #endif DEBUG_printString(" DONE"); UTIL_waitLoop(10000); DEVICE_TIMER0Stop(); return E_PASS;}

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 DEVICE_pinmuxControl(1,0xFFFFFFFF,0x00145555);// All Video Outputs DEVICE_pinmuxControl(2,0xFFFFFFFF,0x000000DA);// EMIFA DEVICE_pinmuxControl(3,0xFFFFFFFF,0x00180000);// SPI0, SPI1, UART1, I2C, SD0, SD1, McBSP0, CLKOUTs DEVICE_pinmuxControl(4,0xFFFFFFFF,0x55555555);// MMC/SD0 instead of MS, SPI0 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;}

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)); } } }

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); }

Uint32 DEVICE_EMIFInit(){ AEMIF->AWCCR= 0xff; AEMIF->A1CR= 0x40400204; AEMIF->NANDFCR|= 1; AEMIF->A2CR= 0x00a00505; return E_PASS; }

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;}

// Main entry pointvoid main(void){ // Call to real boot function code LOCAL_boot(); // Jump to entry point DEBUG_printString("rnJumping to entry point at "); DEBUG_printHexInt(gEntryPoint); DEBUG_printString(".rn"); APPEntry = (void(*)(void)) gEntryPoint; (*APPEntry)(); }

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(devString); DEBUG_printString(" initialization failed!rn"); asm(" MOV PC, #0"); } else { DEBUG_printString(devString); DEBUG_printString(" initialization passed!rn"); } // 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("rnBooting Catalog Boot LoaderrnBootMode = "); // Select Boot Mode#if defined(UBL_NAND) { //Report Bootmode to host DEBUG_printString("NANDrn"); // 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) { //Report Bootmode to host DEBUG_printString("NOR rn"); // 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) { //Report Bootmode to host DEBUG_printString("SD/MMC rn"); // 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 { //Report Bootmode to host DEBUG_printString("UARTrn"); UARTBOOT_copy(); } #endif DEBUG_printString(" DONE"); UTIL_waitLoop(10000); DEVICE_TIMER0Stop(); return E_PASS;}

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 DEVICE_pinmuxControl(1,0xFFFFFFFF,0x00145555);// All Video Outputs DEVICE_pinmuxControl(2,0xFFFFFFFF,0x000000DA);// EMIFA DEVICE_pinmuxControl(3,0xFFFFFFFF,0x00180000);// SPI0, SPI1, UART1, I2C, SD0, SD1, McBSP0, CLKOUTs DEVICE_pinmuxControl(4,0xFFFFFFFF,0x55555555);// MMC/SD0 instead of MS, SPI0 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;}

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)); } } }

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); }

Uint32 DEVICE_EMIFInit(){ AEMIF->AWCCR= 0xff; AEMIF->A1CR= 0x40400204; AEMIF->NANDFCR|= 1; AEMIF->A2CR= 0x00a00505; return E_PASS; }

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;}

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/170235.html原文链接:https://javaforall.cn

0 人点赞