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
最新推荐文章于 2022-10-02 20:51:37 发布
【转自:
http://wdqfirst.blog.163.com/blog/static/113347411200951994622538/】