Chinaunix首页 | 论坛 | 博客
  • 博客访问: 663411
  • 博文数量: 121
  • 博客积分: 4034
  • 博客等级: 上校
  • 技术积分: 1439
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-28 12:42
文章分类

全部博文(121)

文章存档

2017年(8)

2016年(10)

2013年(2)

2012年(3)

2011年(18)

2010年(80)

分类: LINUX

2010-07-22 17:14:07


当配置成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,详情可以参考.*/
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:

阅读(4421) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~