当配置成nand flash启动时,memory map 为:
The boot code is transferred into 4-kbytes Steppingstone during reset. After the transfer, the boot code will be executed on the Steppingstone.
由于这种机制,需要在uboot的binary的前4k具有以下功能,初始化中断矢量、设定CPU的工作模式为SVC32模式、屏蔽看门狗、屏蔽中断,初始化时钟、把整个u-boot重定向到外部SDRAM、跳到主要的C函数入口,还有一个最关键的就有把nand flash中的uboot copy到内存中,然后执行, 这种机制uboot默认是不支持的,是需要自己写code支持。
开始会从cpu/arm920t/start.S中的_start出执行,然后跳转到start_code,在对硬件初始化完成和RELOCATE之间添加从nand flash到ram搬code的动作,搬到ram的地址,必须和编译地址相对应,否则,当pc指针跳到ram后就会异常。
下面是我添加的code:
226 #ifdef CONFIG_S3C2440_NAND_BOOT 227 #define NAND_CTL_BASE 0x4E000000 228 /* Offset */ 229 #define oNFCONF 0x00 230 #define oNFCONT 0x04 231 #define oNFCMD 0x08 232 #define oNFSTAT 0x20 233 #define LENGTH_UBOOT 0x40000 234 @ reset NAND 235 mov r1, #NAND_CTL_BASE /* bit0: config buswidth 0:8bit, 1:16bit*/ /* bit4~6: TWRPH1, bit8~10: TWRPH0, bit12~13:TACLS*/ /* 具体这三个参数起到什么作用,请看程序后的时序图*/ 236 ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) ) 237 str r2, [r1, #oNFCONF] 238 ldr r2, [r1, #oNFCONF] 239 /* bit0: 1: NAND Flash Controller Enable*/ /* bit1: Reg_nCE,0: Force nFCE to low(Enable chip select)*/ /* 1: Force nFCE to High(Disable chip select), 也相当于设置的片选*/ /* bit4: 1: Initialize ECC decoder/encoder*/ 240 ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control 241 str r2, [r1, #oNFCONT] 242 ldr r2, [r1, #oNFCONT] 243 /* bit2: clean busy status.*/ /*When RnB low to high transition is occurred, this value set and*/ /*issue interrupt if enabled. To clear this value write ‘1’.*/ /*0: RnB transition is not detected,1: RnB transition is detected*/ /*这一位的作用:当忙时为0,当忙后自动设置为1,然后写入1,清除忙后设置为1的状态*/ 244 ldr r2, =(0x6) @ RnB Clear 245 str r2, [r1, #oNFSTAT] 246 ldr r2, [r1, #oNFSTAT] 247 /* reset command is oxff*/ 248 mov r2, #0xff @ RESET command 249 strb r2, [r1, #oNFCMD] 250 /* 等待busy结束 */ 251 mov r3, #0 @ wait 252 nand1: 253 add r3, r3, #0x1 254 cmp r3, #0xa 255 blt nand1 256 nand2: 257 ldr r2, [r1, #oNFSTAT] @ wait ready 258 tst r2, #0x4 259 beq nand2 260 261 ldr r2, [r1, #oNFCONT] 262 orr r2, r2, #0x2 @ Flash Memory Chip Disable 263 str r2, [r1, #oNFCONT] 264 265 @ get read to call C functions (for nand_read()) 266 ldr sp, DW_STACK_START @ setup stack pointer 267 mov fp, #0 @ no previous frame, so fp=0 268 269 @ copy U-Boot to RAM /*TEXT_BASE = 0x33F80000,为uboot的连接地址, */ /*可以使用命令”arm-linux-objdump -D u-boot |less“查看连接地址*/ 270 ldr r0, =TEXT_BASE 271 mov r1, #0x0 /*LENGTH_UBOOT为uboot的长度,这里是个宏,为0x40000*/ 272 mov r2, #LENGTH_UBOOT /*nand_read_ll就是拷贝的函数,下面会涉及到*/ 273 bl nand_read_ll 274 tst r0, #0x0 275 beq ok_nand_read 276 bad_nand_read: 277 loop2: 278 b loop2 @ infinite loop 279 ok_nand_read: 280 @ verify 281 mov r0, #0 282 ldr r1, =TEXT_BASE /*这里的verify是和Steppingstone中的4K相比*/ /*Steppingstone中的code是在reset后cpu自己操作从nand flash中读取的*/ 283 mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes 284 go_next: 285 ldr r3, [r0], #4 286 ldr r4, [r1], #4 287 teq r3, r4 288 bne notmatch 289 subs r2, r2, #4 /*当copy成功后,直接跳到stack_setup,无需作relocate*/ /*relocate是在ram中code的地址和连接地址不一样是,拷贝code的,是从nor flash或ram中拷贝到ram中*/ /*stack_setup是建立uboot需要的堆栈*/ 290 beq stack_setup 291 bne go_next 292 notmatch: 293 loop3: 294 b loop3 @ infinite loop 295 #endif
从上面的code可以看出,在start.S中只是初始化和verify,copy code是调用了一个c语言的函数nand_read_ll完成的,函数是在board/mini2440/nand_read.c中完成的,这个c文件是后来为了读取nand flash我们自己建立的, 不是uboot的部分:
118 /* low level nand read function */ 119 int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) 120 { 121 int i, j; 122 123 if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) 124 { 125 return -1; /* invalid alignment */ 126 } 127 /* chip Enable */ 128 nand_select(); 129 nand_clear_RnB(); 130 for (i=0; i<10; i++); 131 for (i=start_addr; i < (start_addr + size);) 132 { 133 j = nand_read_page_ll(buf, i); 134 i += j; 135 buf += j; 136 } 137 138 /* chip Disable */ 139 nand_deselect(); 140 141 return 0; 142 }
85 static int nand_read_page_ll(unsigned char *buf, unsigned long addr) 86 { 87 unsigned short *ptr16 = (unsigned short *)buf; 88 unsigned int i, page_num; 89 nand_clear_RnB(); 90 NFCMD = NAND_CMD_READ0; 91 #if (NAND_PAGE_SIZE == 512) 92 /* Write Address */ 93 NFADDR = addr & 0xff; 94 NFADDR = (addr >> 9) & 0xff; 95 NFADDR = (addr >> 17) & 0xff; 96 NFADDR = (addr >> 25) & 0xff; 97 #elif (NAND_PAGE_SIZE == 2048) 98 page_num = addr >> 11; /* addr / 2048 */ 99 /* Write Address */ /*写地址需要5个周期,由于是从头开始读取,所以前两个为0,详情可以参考nand flash 基础操作 .*/ 100 NFADDR = 0; 101 NFADDR = 0; 102 NFADDR = page_num & 0xff; 103 NFADDR = (page_num >> 8) & 0xff; 104 NFADDR = (page_num >> 16) & 0xff; 105 NFCMD = NAND_CMD_READSTART; 106 #else 107 #error "unsupported nand page size" 108 #endif 109 nand_wait(); 110 for (i = 0; i < NAND_PAGE_SIZE; i++) 111 { 112 *buf = (NFDATA & 0xff); 113 buf++; 114 } 115 return NAND_PAGE_SIZE; 116 }
上面的读函数是不会check是不是坏块的,nand_read.c中是有check是坏块的函数,但是没有使用,这个以后有必要添加。
部分函数:
26 #define nand_select() (NFCONT &= ~(1 << 1)) 27 #define nand_deselect() (NFCONT |= (1 << 1)) 28 #define nand_clear_RnB() (NFSTAT |= NFSTAT_BUSY) 30 31 static inline void nand_wait(void) 32 { 33 int i; 34 35 while (!(NFSTAT & NFSTAT_BUSY)) 36 for (i=0; i<10; i++); 37 }
现在我做的dc421,是自己写的一个应用程序ubl,copy code从nand flash到sdram中, 然后跳到sdram中执行uboot。
如果你使用的是网上下的标准的uboot有可能启动不起来。
在u-boot1.3.3及以上版本Makefile有一定的变化,使得对于24x0处理器从nand启动的遇到问题,无法运行 lowlevel_init。其实这个问题是由于编译器将我们自己添加的用于nandboot的子函数nand_read_ll放到了4K之后造成的(到这不理解的话,请仔细看看24x0处理器nandboot原理)。在运行失败后,可利用LED调试发现u-boot根本没有完成自我拷贝,然后看了 uboot根目录下的System.map文件就可知道原因。
解决办法其实很简单: 需要修改uboot根目录下的Makefile:
#__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))
改为:
__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst $(obj),,$(LIBS))
steppingstone跳转到ram
U-BOOT是怎样从4Ksteppingstone跳到RAM中执行的,关键在于:
ldr pc, _start_armboot _start_armboot: .word start_armboot
这两条语句,ldr pc, _start_armboot指令把_start_armboot这个标签的地方存放的内容(也即是start_armboot)移到PC寄存器里面,start_armboot是一个函数地址,在编译的时候给分配了一个绝对地址,所以上面语句实际上是完成了一个绝对地址的跳转。而我一直不明白的为什么在start.S里面有很多BL,B跳转语句都没有跳出4Ksteppingstone,原因是他们都是相对于PC的跳转,而不是绝对地址的跳转。还有要补充一下LDR,MOV,LDR伪指令的区别。
LDR R0,0x12345678 //把地址0x12345678存放的内容放到R0里面 MOV R0,#x //把立即数x放到R0里面,x必须是一个8 bits的数移到偶数次得到的数。 LDR R0,=0x12345678 //把立即数0x12345678放到R0里面
跳转到ram以后, uboot的启动就算已经全部完成, 接下来就是对cpu以外的chips初始化,当然也包括nand flash,下面就详细的讲解nand flash driver: nand flash uboot 驱动研究