nand flash uboot 启动

当配置成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 驱动研究

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值