1 U-Boot簡介 2 U-Boot主要目錄結構 3 U-Boot支持的主要功能 4 移植前的準備 (1)、首先讀讀uboot自帶的readme文件,瞭解了一個大概。
(2)、看看common.h,這個文件定義了一些基本的東西,幷包含了一些必要的頭文件。再看看flash.h,這個文件裏面定義了 flash_info_t爲一個struct。包含了flash的一些屬性定義。並且定義了所有的flash的屬性,其中,AMD的有:AMD_ID_LV320B,定義爲“#define AMD_ID_LV320B 0x22F922F9”。
(3)、對於“./borad/at91rm9200dk/flash.c”的修改,有以下的方面:
“void flash_identification(flash_info_t *info)”這個函數的目的是確認flash的型號。注意的是,這個函數裏面有一些宏定義,直接讀寫了flash。並獲得ID號。 (4)、修改:”./board/at91rm9200dk/config.mk”爲
TEXT_BASE=0x21f80000 爲TEXT_BASE=0x21f00000 (當然,你應該根據自己的板子來修改,和一級boot的定義的一致即可)。 (5)、再修改”./include/configs/at91rm9200dk.h”爲
修改flash和SDRAM的大小。 (6)、另外一個要修改的文件是:
./borad/at91rm9200dk/flash.c。這個文件修改的部分比較的多。 a. 首先是OrgDef的定義,加上目前的flash。 b. 接下來,修改”#define FLASH_BANK_SIZE 0x200000”爲自己flash的 容量 c. 在修改函數flash_identification(flash_info_t * info)裏面的打印信息,這部分將在u-boot啓動的時候顯示。 d. 然後修改函數flash_init(void)裏面對一些變量的賦值。 e. 最後修改的是函數flash_print_info(flash_info_t * info)裏面實際打印的函數信息。 f. 還有一個函數需要修改,就是:“flash_erase”,這個函數要檢測先前知道的flash類型是否匹配,否則,直接就返回了。把這裏給註釋掉。 (7)、接下來看看SDRAM的修改。 這個裏面對於“SIZE”的定義都是基於字節計算的。 只要修改”./include/configs/at91rm9200dk.h”裏面的 “#define PHYS_SDRAM_SIZE 0X200000”就可以了。注意,SIZE是以字節爲單位的。 (8)、還有一個地方要注意
就是按照目前的設定,一級boot把u_boot加載到了SDRAM的空間爲:21F00000 -> 21F16B10,這恰好是SDRAM的高端部分。另外,BSS爲21F1AE34。 (9)、編譯後,可以寫入flash了。 a. 壓縮這個u-boot.bin “gzip –c u-boot.bin > u-boot.gz” 壓縮後的文件大小爲: 43Kbytes b. 接着把boot.bin和u-boot.gz燒到flash裏面去。 Boot.bin大約11kBytes,在flash的0x1000 0000 ~ 0x1000 3fff
6. U-Boot移植方法 7. U-Boot移植主要修改的文件 8. U-Boot移植要點 下面以移植u-boot 到44B0開發板的步驟爲例,移植中上僅需要修改和硬件相關的部分。在代碼結構上: 3. u-boot 的體系結構 1) 總體結構 u-boot 是一個層次式結構。從上圖也可以看出,做移植工作的軟件人員應當提供串口驅動(UART Driver),以太網驅動(Ethernet Driver),Flash 驅動(Flash 驅動),USB 驅動(USB Driver)。目前,通過USB 口下載程序顯得不是十分必要,所以暫時沒有移植USB 驅動。驅動層之上是u-boot 的應用,command 通過串口提供人機界面。我們可以使用一些命令做一些常用的工作,比如內存查看命令md。 Kermit 應用主要用來支持使用串口通過超級終端下載應用程序。TFTP 則是通過網絡方式來下載應用程序,例如uclinux 操作系統。 2) 內存分佈 在flash rom 中內存分佈圖ev44b0ii 的flash 大小2M(8bits),現在將0-40000 共256k 作爲u-boot 的存儲空間。由於u-boot 中有一些環境變量,例如ip 地址,引導文件名等,可在命令行通過setenv 配置好,通過saveenv 保存在40000-50000(共64k)這段空間裏。如果存在保存好的環境變量,u-boot 引導將直接使用這些環境變量。正如從代碼分析中可以看到,我們會把flash 引導代碼搬移到DRAM 中運行。下圖給出u-boot 的代碼在DRAM中的位置。引導代碼u-boot 將從0x0000 0000 處搬移到0x0C700000 處。特別注意的由於ev44b0ii uclinux 中斷向量程序地址在0x0c00 0000 處,所以不能將程序下載到0x0c00 0000 出,通常下載到0x0c08 0000 處。 4. start.S 代碼結構 1) 定義入口 一個可執行的Image 必須有一個入口點並且只能有一個唯一的全局入口,通常這個入口放在Rom(flash)的0x0 地址。例如start.S 中的 .globl _start _start: 值得注意的是你必須告訴編譯器知道這個入口,這個工作主要是修改連接器腳本文件(lds)。 2) 設置異常向量(Exception Vector) 異常向量表,也可稱爲中斷向量表,必須是從0 地址開始,連續的存放。如下面的就包括了復位(reset),未定義處理(undef),軟件中斷(SWI),預去指令錯誤(Pabort),數據錯誤 (Dabort),保留,以及IRQ,FIQ 等。注意這裏的值必須與uclinux 的vector_base 一致。這就是說如果uclinux 中vector_base(include/armnommu/proc-armv/system.h)定義爲0x0c00 0000,則HandleUndef 應該在 0x0c00 0004。 b reset //for debug ldr pc,=HandleUndef ldr pc,=HandleSWI ldr pc,=HandlePabort ldr pc,=HandleDabort b . ldr pc,=HandleIRQ ldr pc,=HandleFIQ ldr pc,=HandleEINT0 /*mGA H/W interrupt vector table*/ ldr pc,=HandleEINT1 ldr pc,=HandleEINT2 ldr pc,=HandleEINT3 ldr pc,=HandleEINT4567 ldr pc,=HandleTICK /*mGA*/ b . b . ldr pc,=HandleZDMA0 /*mGB*/ ldr pc,=HandleZDMA1 ldr pc,=HandleBDMA0 ldr pc,=HandleBDMA1 ldr pc,=HandleWDT ldr pc,=HandleUERR01 /*mGB*/ b . b . ldr pc,=HandleTIMER0 /*mGC*/ ldr pc,=HandleTIMER1 ldr pc,=HandleTIMER2 ldr pc,=HandleTIMER3 ldr pc,=HandleTIMER4 ldr pc,=HandleTIMER5 /*mGC*/ b . b . ldr pc,=HandleURXD0 /*mGD*/ ldr pc,=HandleURXD1 ldr pc,=HandleIIC ldr pc,=HandleSIO ldr pc,=HandleUTXD0 ldr pc,=HandleUTXD1 /*mGD*/ b . b . ldr pc,=HandleRTC /*mGKA*/ b . b . b . b . b . /*mGKA*/ b . b . ldr pc,=HandleADC /*mGKB*/ b . b . b . b . b . /*mGKB*/ b . b . ldr pc,=EnterPWDN 作爲對照:請看以上標記的值: .equ HandleReset, 0xc000000 .equ HandleUndef,0xc000004 .equ HandleSWI, 0xc000008 .equ HandlePabort, 0xc00000c .equ HandleDabort, 0xc000010 .equ HandleReserved, 0xc000014 .equ HandleIRQ, 0xc000018 .equ HandleFIQ, 0xc00001c /*the value is different with an address you think it may be. *IntVectorTable */ .equ HandleADC, 0xc000020 .equ HandleRTC, 0xc000024 .equ HandleUTXD1, 0xc000028 .equ HandleUTXD0, 0xc00002c .equ HandleSIO, 0xc000030 .equ HandleIIC, 0xc000034 .equ HandleURXD1, 0xc000038 .equ HandleURXD0, 0xc00003c .equ HandleTIMER5, 0xc000040 .equ HandleTIMER4, 0xc000044 .equ HandleTIMER3, 0xc000048 .equ HandleTIMER2, 0xc00004c .equ HandleTIMER1, 0xc000050 .equ HandleTIMER0, 0xc000054 .equ HandleUERR01, 0xc000058 .equ HandleWDT, 0xc00005c .equ HandleBDMA1, 0xc000060 .equ HandleBDMA0, 0xc000064 .equ HandleZDMA1, 0xc000068 .equ HandleZDMA0, 0xc00006c .equ HandleTICK, 0xc000070 .equ HandleEINT4567, 0xc000074 .equ HandleEINT3, 0xc000078 .equ HandleEINT2, 0xc00007c .equ HandleEINT1, 0xc000080 .equ HandleEINT0, 0xc000084 3) 初始化CPU 相關的pll,clock,中斷控制寄存器 依次爲關閉watch dog timer,關閉中斷,設置LockTime,PLL(phase lock loop),以及時鐘。 這些值(除了LOCKTIME)都可從Samsung 44b0 的手冊中查到。 ldr r0,WTCON //watch dog disable ldr r1,=0x0 str r1,[r0] ldr r0,INTMSK ldr r1,MASKALL //all interrupt disable str r1,[r0] /***************************************************** * Set clock control registers * *****************************************************/ ldr r0,LOCKTIME ldr r1,=800 // count = t_lock * Fin (t_lock=200us, Fin=4MHz) = 800 str r1,[r0] ldr r0,PLLCON /*temporary setting of PLL*/ ldr r1,PLLCON_DAT /*Fin=10MHz,Fout=40MHz or 60MHz*/ str r1,[r0] ldr r0,CLKCON ldr r1,=0x7ff8 //All unit block CLK enable str r1,[r0] 4) 初始化內存控制器 內存控制器,主要通過設置13 個從1c80000 開始的寄存器來設置,包括總線寬度, 8 個內存bank,bank 大小,sclk,以及兩個bank mode。 /***************************************************** * Set memory control registers * *****************************************************/ memsetup: adr r0,SMRDATA ldmia r0,{r1-r13} ldr r0,=0x01c80000 //BWSCON Address stmia r0,{r1-r13} 5) 將rom 中的程序複製到RAM 中 首先利用PC 取得bootloader 在flash 的起始地址,再通過標號之差計算出這個程序代 碼的大小。這些標號,編譯器會在連接(link)的時候生成正確的分佈的值。取得正 確信息後,通過寄存器(r3 到r10)做爲複製的中間媒介,將代碼複製到RAM 中。 relocate: /* * relocate armboot to RAM */ adr r0, _start /* r0 <- current position of code */ ldr r2, _armboot_start ldr r3, _armboot_end sub r2, r3, r2 /* r2 <- size of armboot */ ldr r1, _TEXT_BASE /* r1 <- destination address */ add r2, r0, r2 /* r2 <- source end address */ /* * r0 = source address * r1 = target address * r2 = source end address */ copy_loop: ldmia r0!, {r3-r10} stmia r1!, {r3-r10} cmp r0, r2 ble copy_loop 6) 初始化堆棧 進入各種模式設置相應模式的堆棧。 InitStacks: /*Don't use DRAM,such as stmfd,ldmfd...... SVCstack is initialized before*/ mrs r0,cpsr bic r0,r0,#0X1F orr r1,r0,#0xDB /*UNDEFMODE|NOINT*/ msr cpsr,r1 /*UndefMode*/ ldr sp,UndefStack orr r1,r0,#0XD7 /*ABORTMODE|NOINT*/ msr cpsr,r1 /*AbortMode*/ ldr sp,AbortStack orr r1,r0,#0XD2 /*IRQMODE|NOINT*/ msr cpsr,r1 /*IRQMode*/ ldr sp,IRQStack orr r1,r0,#0XD1 /*FIQMODE|NOINT*/ msr cpsr,r1 /*FIQMode*/ ldr sp,FIQStack bic r0,r0,#0XDF /*MODEMASK|NOINT*/ orr r1,r0,#0X13 msr cpsr,r1 /*SVCMode*/ ldr sp,SVCStack 7) 轉到RAM 中執行 使用指令ldr,pc,RAM 中C 函數地址就可以轉到RAM 中去執行。 5. 系統初始化部分 1. 串口部分 串口的設置主要包括初始化串口部分,值得注意的串口的Baudrate 與時鐘MCLK 有很大關係,是通過:rUBRDIV0=( (int)(MCLK/16./(gd ->baudrate) + 0.5) -1 )計算得出。這可以在手冊中查到。其他的函數包括髮送,接收。這個時候沒有中斷,是通過循環等待來判斷是否動作完成。 例如,接收函數: while(!(rUTRSTAT0 & 0x1)); //Receive data read return RdURXH0(); 2. 時鐘部分 實現了延時函數udelay。 這裏的get_timer 由於沒有使用中斷,是使用全局變量來累加的。 3. flash 部分 flash 作爲內存的一部分,讀肯定沒有問題,關鍵是flash 的寫部分。 Flash 的寫必須先擦除,然後再寫。 unsigned long flash_init (void) { int i; u16 manId,devId; //first we init it as unknown,even if you forget assign it below,it's not a problem for (i=0; i < CFG_MAX_FLASH_BANKS; ++i){ flash_info[i].flash_id = FLASH_UNKNOWN; flash_info[i].sector_count=CFG_MAX_FLASH_SECT; } /*check manId,devId*/ _RESET(); _WR(0x555,0xaa); _WR(0x2aa,0x55); _WR(0x555,0x90); manId=_RD(0x0); _WR(0x555,0xaa); _WR(0x2aa,0x55); _WR(0x555,0x90); devId=_RD(0x1); _RESET(); printf("flashn"); printf("Manufacture ID=%4x(0x0004), Device ID(0x22c4)=%4xn",manId,devId); if(manId!=0x0004 && devId!=0x22c4){ printf("flash check faliluren"); return 0; }else{ for (i=0; i < CFG_MAX_FLASH_BANKS; ++i){ flash_info[i].flash_id=FLASH_AM160T;/*In fact it is fujitu,I only don't want to modify common files*/ } } /* Setup offsets */ flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]); /* zhangyy comment #if CFG_MONITOR_BASE >= CFG_FLASH_BASE //onitor protection ON by default flash_protect(FLAG_PROTECT_SET, CFG_MONITOR_BASE, CFG_MONITOR_BASE+monitor_flash_len-1, &flash_info[0]); #endif */ flash_info[0].size =PHYS_FLASH_SIZE; return (PHYS_FLASH_SIZE); } flash_init 完成初始化部分,這裏的主要目的是檢驗flash 的型號是否正確。 int flash_erase (flash_info_t *info, int s_first, int s_last) { volatile unsigned char *addr = (volatile unsigned char *)(info->start[0]); int flag, prot, sect, l_sect; //ulong start, now, last; u32 targetAddr; u32 targetSize; /*zyy note:It is required and can't be omitted*/ rNCACHBE0=( (0x2000000>>12)<<16 )|(0>>12); //flash area(Bank0) must be non-cachable area. rSYSCFG=rSYSCFG & (~0x8); //write buffer has to be off for proper timing. if ((s_first < 0) || (s_first > s_last)) { if (info->flash_id == FLASH_UNKNOWN) { printf ("- missingn"); } else { printf ("- no sectors to erasen"); } return 1; } if ((info->flash_id == FLASH_UNKNOWN) || (info->flash_id > FLASH_AMD_COMP)) { printf ("Can't erase unknown flash type - abortedn"); return 1; } prot = 0; for (sect=s_first; sect<=s_last; ++sect) { if (info->protect[sect]) { prot++; } } if (prot) { printf ("- Warning: %d protected sectors will not be erased!n", prot); } else { printf ("n"); } l_sect = -1; /* Disable interrupts which might cause a timeout here */ flag = disable_interrupts(); /* Start erase on unprotected sectors */ for (sect = s_first; sect<=s_last; sect++) { if (info->protect[sect] == 0) {/* not protected */ targetAddr=0x10000*sect; if(targetAddr<0x1F0000) targetSize=0x10000; else if(targetAddr<0x1F8000) targetSize=0x8000; else if(targetAddr<0x1FC000) targetSize=0x2000; else targetSize=0x4000; F29LV160_EraseSector(targetAddr); l_sect = sect; if(!BlankCheck(targetAddr, targetSize)) printf("BlankCheck Errorn"); } } /* re-enable interrupts if necessary */ if (flag) enable_interrupts(); /* wait at least 80us - let's wait 1 ms */ udelay (1000); /* *We wait for the last triggered sector */ if (l_sect < 0) goto DONE; DONE: printf (" donen"); return 0; } int BlankCheck(int targetAddr,int targetSize) { int i,j; for(i=0;i{ j=*((u16 *)(i+targetAddr)); if( j!=0xffff) { printf("E:%x=%xn",(i+targetAddr),j); return 0; } } return 1; } flash_erase 擦除flash,BlankCheck 則檢查該部分內容是否擦除成功。 /*----------------------------------------------------------------------- *Write a word to Flash, returns: * 0 - OK * 1 - write timeout * 2 - Flash not erased */ static int write_word (flash_info_t *info, ulong dest, ulong data) { volatile u16 *tempPt; /*zhangyy note:because of compatiblity of function,I use low & hi*/ u16 low = data & 0xffff; u16 high = (data >> 16) & 0xffff; low=swap_16(low); high=swap_16(high); tempPt=(volatile u16 *)dest; _WR(0x555,0xaa); _WR(0x2aa,0x55); _WR(0x555,0xa0); *tempPt=high; _WAIT(); _WR(0x555,0xaa); _WR(0x2aa,0x55); _WR(0x555,0xa0); *(tempPt+1)=low; _WAIT(); return 0; } wirte_word 則想flash 裏面寫入unsigned long 類型的data,因爲flash 一次只能寫入16bits,所以這裏分兩次寫入 |
一個全面介紹uBoot的blog
【轉自:http://wdqfirst.blog.163.com/blog/static/113347411200951994622538/】
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.