首先看一下对start.S的修改:
在ldr pc, _start_armboot前添加下面内容。
#ifdef CONFIG_S3C2410_NAND_BOOT
bl copy_myself
@ jump to ram
ldr r1, =on_the_ram
add pc, r1, #0
nop
nop
1: b 1b @ infinite loop
on_the_ram:
#endif
在http://blog.chinaunix.net/u/29387/showart_244343.html中提到注释掉一部分relocate代码,但似乎注释的又不彻底,保留了清BSS段的代码。一个疑问是:注释掉这些内容是必须的吗?不过从出发点来说,这段代码确实是没有什么用了。
下面我们来看一下copy_myself都做了哪些事情。此处参考了vivi的copy_myself代码,一些变量的定义需要添加,后面会给出,这里直接给出
这些变量或宏所表达的意义。
#ifdef CONFIG_S3C2410_NAND_BOOT
copy_myself:
mov r10, lr @r10保存返回地址
@ reset NAND @初始化nand,主要是设置相关的控制器
mov r1, #NAND_CTL_BASE @NAND_CTL_BASE=0x4e000000,它是和nand相关的特殊寄存器组的基地址
ldr r2, =0xf830 @ initial value 0x1111,1000,0011,0000,enable nand flash controller Initialize ECC
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]
bic r2, r2, #0x800 @ enable chip,屏蔽[11],0 : NAND flash nFCE = L (active),NFCE是2410的管脚,与nand
str r2, [r1, #oNFCONF] @的NFCE相连
mov r2, #0xff @ RESET command
strb r2, [r1, #oNFCMD] @ 只传送一个字节到oNFCMD
mov r3, #0 @ wait
1: add r3, r3, #0x1
cmp r3, #0xa
blt 1b @ 延时10个指令周期
2: ldr r2, [r1, #oNFSTAT] @ wait ready,oNFSTAT的位[0]标志nand flash的状态,只读,取决于R/nB管脚。
tst r2, #0x1 @1 = NAND Flash memory ready to operate
beq 2b
ldr r2, [r1, #oNFCONF]
orr r2, r2, #0x800 @ disable chip
str r2, [r1, #oNFCONF]
@ get read to call C functions (for nand_read())
ldr sp, DW_STACK_START @ setup stack pointer, DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
mov fp, #0 @ no previous frame, so fp=0????????????????
@ copy UBOOT to RAM
ldr r0, =UBOOT_RAM_BASE @UBOOT_RAM_BASE=0x33f00000
mov r1, #0x0
mov r2, #0x30000 @ 0x30000=192K
bl nand_read_ll @此处nand_read_ll没有给出传递参数,这里猜想其参数依次是r0~r2种的值,这也是最合理的解释
tst r0, #0x0 @此处猜想汇编调用C函数的返回值赋给r0。关于汇编调用C函数的问题,有待考证。
beq ok_nand_read
#ifdef CONFIG_DEBUG_LL
bad_nand_read:
ldr r0, STR_FAIL
ldr r1, SerBase
bl PrintWord
1: b 1b @ infinite loop
#endif
ok_nand_read:
#ifdef CONFIG_DEBUG_LL
ldr r0, STR_OK
ldr r1, SerBase
bl PrintWord
#endif @ 此段代码打印调试信息,前提是定义了CONFIG_DEBUG_LL,我们没有定义它,跳过!
@ verify
mov r0, #0
ldr r1, =UBOOT_RAM_BASE
mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes,只验证前4K的内容,一点启示,这里只验证了前4k,并且根据
go_next: @要求我们应该把所有搬运代码的代码段包含在这前
@4k之 中,代码本身并没有问题,关键是所调用
ldr r3, [r0], #4 @的C函数以及相关头文件是否包含在了其中
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4 @S标志着根据结果更新N和Z,
beq done_nand_read
bne go_next
notmatch: @问题会是出在这儿吗?这儿有一个死循环!
#ifdef CONFIG_DEBUG_LL
sub r0, r0, #4
ldr r1, SerBase
bl PrintHexWord
ldr r0, STR_FAIL
ldr r1, SerBase
bl PrintWord
#endif
1: b 1b
done_nand_read:
#ifdef CONFIG_DEBUG_LL
ldr r0, STR_OK
ldr r1, SerBase
bl PrintWord
#endif
mov pc, r10
@ clear memory
@ r0: start address
@ r1: length
mem_clear:
mov r2, #0
mov r3, r2
mov r4, r2
mov r5, r2
mov r6, r2
mov r7, r2
mov r8, r2
mov r9, r2
clear_loop:
stmia r0!, {r2-r9}
subs r1, r1, #(8 * 4)
bne clear_loop
mov pc, lr
#endif @ CONFIG_S3C2410_NAND_BOOT
还要在start.S中添加以下内容,用于定义栈地址变量。
#ifdef CONFIG_S3C2410_NAND_BOOT
.align 2
DW_STACK_START:
.word STACK_BASE+STACK_SIZE-4
#endif
在start.S中,我们调用了nand_read_ll函数,它在nand_read.c中实现,该文件是由我们在/board/mike2410目录下新建的
#include <config.h>
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCMD __REGb(NF_BASE + 0x4)
#define NFADDR __REGb(NF_BASE + 0x8)
#define NFDATA __REGb(NF_BASE + 0xc)
#define NFSTAT __REGb(NF_BASE + 0x10)
@定义了NF相关寄存器
#define BUSY 1 @这个BUSY有啥用呢???困惑!呵呵,屏蔽掉NFSTAT的前31位,只inline void wait_idle(void) { @保留最后一位
int i;
while(!(NFSTAT & BUSY)) @如果忙,就延时一会儿
for(i=0; i<10; i++);
}
#define NAND_SECTOR_SIZE 512
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
/* low level nand read function */
int
nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{ @功能:将以start_addr为起始地址,大小为size的数据段copy到以buf int i, j; @为起始地址的内存中
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return -1; /* invalid alignment */
}
/* chip Enable */
NFCONF &= ~0x800;
for(i=0; i<10; i++);
for(i=start_addr; i < (start_addr + size);) {
/* READ0 */
NFCMD = 0; @开始读数据
/* Write Address */
NFADDR = i & 0xff;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff; @对此处的理解要参考K9S1208的手册,i 对应了一个32位地址,但k9s1208只有date/addr/cmd @共用的八根地址线,要分批次发送到nand flash。
wait_idle();
for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
*buf = (NFDATA & 0xff);
buf++; @数据以字节为单位传送到buf中
}
}
/* chip Disable */
NFCONF |= 0x800; /* chip disable */
return 0;
}
修改makefile, COBJS:=mike2410.o flash.o改为COBJS:=mike2410.o flash.o nand_read.o。
