一、nand啟動和nor啟動:[1]
CPU從0x00000000位置開始運行程序。
1、nand啟動:
如果將S3C2440配置成從NANDFLASH啟動(將開發板的啟動開關拔到nand端,此時OM0管腳拉低)S3C2440的Nand控制器會自動把Nandflash中的前4K代碼數據搬到內部SRAM中(地址為0x40000000),同時還把這塊SRAM地址映射到了0x00000000地址。CPU從0x00000000位置開始運行程序。
2、如果將S3C2440配置成從Norflash啟動(將開發的啟動開關拔到nor端,此時OM0管腳拉高),0x00000000就是norflash實際的起始地址,norflash中的程序就從這里開始運行,不涉及到數據拷貝和地址映射
3、總結:
nand啟動時,地址0x00000000為內部SRAM映射的地址;
nor啟動時,地址0x00000000為norflash的實際起始地址。
向Norflash中寫數據需要特定的命令時序,而向內存中寫數據可以直接向內存地址賦值。
二、判斷是從nand啟動還是從norflash啟動:
1.根據硬件接線,
引腳OM1、OM0 : 00: Nand-boot 01: 16-bit 10: 32-bit 11: Test mode
總線寬度和等待控制寄存器(BWSCON)0x48000000 BWSCON_bit[2:1] Indicate data bus width for bank 0 (read only).
The states are selected by OM[1:0] pins 。(01 = 16-bit, 10 = 32-bit ...)
what's done before copy?
ResetHandler ;WTCON watch dog disable ;INTMSK ;INTSUBMSK ;To reduce PLL lock time, adjust the LOCKTIME register. ;Setting value Fclk:Hclk:Pclk ;Configure UPLL ;Configure MPLL ;Check if the boot is caused by the wake-up from SLEEP mode. ;In case of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler. ;Set memory control registers ;Initialize stacks bl InitStacks ; Setup IRQ handler ldr r0,=HandleIRQ ;This routine is needed ldr r1,=IsrIRQ ;if there isn t 'subs pc,lr,#4' at 0x18, 0x1c str r1,[r0]
now copy:
;=========================================================== ;// 判斷是從nor啟動還是從nand啟動 ;=========================================================== ldr r0, =BWSCON ldr r0, [r0] ands r0, r0, #6 ;0110 bne NORRoCopy ;BWSCON的[2:1]反映了外部引腳OM[1:0]. ;bne:若OM[1:0] != 00, 是從NOR FLash啟動. ;若OM[1:0]==00,則為Nand Flash Mode. NandFlashMode adr r0, ResetEntry ;注意adr得到的是相對地址,非絕對地址. Cpu剛啟動時,ResetEntry==0. cmp r0, #0 ;再比較入口是否為0地址處 bne InitRamZero ;如果不是0,直接初始化bss段,進入CEntry. ;nop ;=========================================================== ;如果ResetEntry==0,說明是cpu剛啟動(注意此處是nand啟動),那就應該將nand中的代碼搬運到sdram中。 ;=========================================================== nand_boot_beg bl ClearSdram ;將內存清零。從內存起始地址--->指定的足夠大的范圍,不超過內存的實際大小。 mov r5, #NFCONF ;nand控制器初始化 ;set clk value ldr r0, =(7<<12):OR:(7<<8):OR:(7<<4) str r0, [r5] ;enable control ldr r0, =(0<<13):OR:(0<<12):OR:(0<<10):OR:(0<<9):OR:(0<<8):OR:(1<<6):OR:(1<<5):OR:(1<<4):OR:(1<<1):OR:(1<<0) str r0, [r5, #4] bl ReadNandID ;讀nandId,從而判斷nand芯片的種類. r5 = nandId mov r6, #0 ldr r0, =0xecF1 cmp r5, r0 beq %F1 ;if(nandId==0xecf1){r6=0;//addr_cycle=4}else{r6=1;//addr_cycle=5} mov r6, #1 ;Nandaddr(尋址周期 0:4 1:5) 1 bl ReadNandStatus ;r1 = ret_of_ReadNandStatus ,這里似乎沒有用。 mov r8, #0 ;page_addr = r8 = 0; ldr r9, =ResetEntry ;r9 = size_copyed = pBuff = 0; mov r10,#64 ;+081010 feiling nPages_need_to_copy=64(128KB); 2 ands r0, r8, #0x3f ;R0 = R8 & 0X3F ; 如果是第一頁(mov r8, #0),本式子equal 0; bne %F3 mov r0, r8 ;如果是第一頁,則檢測壞塊 bl CheckBadBlk ;unsigned int CheckBadBlk(unsigned int page_addr) cmp r0, #0 addne r8, r8, #64 ;每塊的頁數 r8 同時也做計數用。 addne r10,r10,#64 ;+081010 feiling if(is_bad_block){page_addr+=64;nPages_need_to_copy+=64;} bne %F4 3 mov r0, r8 mov r1, r9 ;r1 = r9 = size_copyed bl ReadNandPage add r9, r9, #2048 ;size_copyed+=2048 add r8, r8, #1 ;page_addr+1 4 cmp r8, r10 ;要拷貝的頁數 081010 pht . if(page_addr < nPages_need_to_copy ){copy_loop;} bcc %B2 mov r5, #NFCONF ;DsNandFlash ldr r0, [r5, #4] bic r0, r0, #1 str r0, [r5, #4] ldr pc, =InitRamZero ;此處跳轉到內存空間 LDR 裝載數據,尋址靈活。 但不改變PSR ;要裝載一個被存儲的‘狀態’並正確的恢復它 可以這樣寫:ldr r0, [base] 換行 moves pc, r0 ;============================================================================================= ;若是從NAND啟動,則先清零內存,再從nand[0 ~ user_set_size]拷貝到內存(ro 和.data),再初始化bss段,進入main。 ;若是從NOR啟動,同樣是先清零,后拷貝,再初始化bss段,進入main。為了考慮jlink等調試的情況,避免二次拷貝,才使代碼顯得復雜。
;其實可以不管,直接全部拷貝過來,nor拷貝比nand拷貝更簡單,逐個字節復制即可。;============================================================================================= NORRoCopy ;copy_proc_from_nor_to_sdram bl ClearSdram ;clear all sdram needed adr r0, ResetEntry ;判斷是否在ROM中運行,ROM即RO指定的地址,從NOR啟動時ResetEntry為0 ldr r2, BaseOfROM ;如果相等,說明是jlink調試,調試器將程序.ro段直接下載到了內存,就不需再拷貝。 cmp r0, r2 ;pFrom = r0 = ResetEntry(活的) ; pTo = r2 = BaseOfROM(鏈接文件寫死的) ;pEnd = TopOfROM(鏈接文件寫死的) beq NORRwCopy ;if(ResetEntry==BaseOfROM){skip RoCopyLoop ,directly do RwCopy;} RoCopyLoop ldr r3, TopOfROM ; 0 ldmia r0!, {r4-r7} stmia r2!, {r4-r7} ;mem_ResetEntry----> mem_BaseOfROM ; pFrom+=4;pTo+=4; cmp r2, r3 ;if(pTo<pEnd){copy_loop;} bcc %B0 NORRwCopy ;拷貝.data段(已初始化的全局變量、靜態變量等),它在固件里占有空間。 ldr r0, TopOfROM ;根據鏈接文件sct, TopOfROM == BaseOfRW ldr r1, BaseOfROM ; sub r0, r0, r1 ;pFrom = r0 = (TopOfROM - BaseOfROM) ldr r2, BaseOfRW ;pTo = BaseOfRW ,pEnd = BaseOfZero ldr r3, BaseOfZero 0 cmp r2, r3 ;if(r2<r3){ ldrcc r1, [r0], #4 ; r1 = [r0] ; r0+=4; strcc r1, [r2], #4 ; [r2] = r1 ; r2+=4; ;} bcc %B0
InitRamZero ;初始化Bss段,之后立即進入CEntry mov r0, #0 ldr r2, BaseOfZero ldr r3, EndOfBSS 1 cmp r2, r3 ;清零bss段,bss段(未初始化的全局變量、靜態變量)在bin文件中不占空間,只有占位符,因此需要在系統初始化時,手動初始化(一般memset為0); strcc r0, [r2], #4 bcc %B1 ldr pc, =CEntry ;goto compiler address CEntry bl Main ;Don t use main() because ...... b .
ClearSdram:在拷貝程序到內存之前,先清內存。
;========================================================= ClearSdram mov r1,#0 mov r2,#0 mov r3,#0 mov r4,#0 mov r5,#0 mov r6,#0 mov r7,#0 mov r8,#0 ldr r9,=0x00700000 ;size of ram to clear ldr r0,=0x30000000 0 stmia r0!,{r1-r8} subs r9,r9,#32 bne %B0 BX lr
2、根據 “向norflash寫入數據需要一定的命令序列,而向內存中寫數據可以直接向內存地址賦值” 這一點來區別:
//int bBootFrmNORFlash(void) : 判斷是否從norflash啟動。 //ret==1 :norflash啟動 //ret==0 :nandflash啟動。(或者是jlink調試的情況。) //說明:該函數應用范圍有限,只針對於bootloader最初的stage1。 int bBootFrmNORFlash(void) { volatile unsigned int *pdw = (volatile unsigned int *)0; //volatile unsigned int dwVal; /* * 無論是從NOR Flash還是從NAND Flash啟動, * 地址0處為指令"b Reset", 機器碼為0xEA00000B, * 對於從NAND Flash啟動的情況,其開始4KB的代碼會復制到CPU內部4K內存中, * 對於從NOR Flash啟動的情況,NOR Flash的開始地址即為0。 * 對於NOR Flash,必須通過一定的命令序列才能寫數據, * 所以可以根據這點差別來分辨是從NAND Flash還是NOR Flash啟動: * 向地址0寫入一個數據,然后讀出來,如果沒有改變的話就是NOR Flash * 這僅僅針對於初始階段,norflash啟動時,最終也要將程序加載到SDRAM中運行。因此該函數應用范圍是有局限性的。 */ dwVal = *pdw; *pdw = 0x12345678; if (*pdw != 0x12345678) { return 1; } else { *pdw = dwVal;//測試完后要還原數據。 return 0; } }
參考:
1、uboot如何檢測XC2440是從Nand或Nor啟動 http://blog.chinaunix.net/uid-22030783-id-3347621.html