热门关键字:  ubuntu  分区  函数  Fedora  linux系统进程

从nand启动的uboot

来源: 作者: 时间:2008-07-31 Tag: 点击:
    我的开发板只有nand flash,但uboot不支持从nand flash启动,要移植uboot到自己的开发板上,需要对源码做一些修改,这里先来分析一下《ARM嵌入式linux系统开发从入门到精通》中给出的代码,虽然按照这个步骤编译出的二进制文件还有一些问题,但分析一下有助于之后对uboot的调试。由于uboot不支持从nand flash启动,所以将程序复制到DRAM里面去需要新加代码实现,一般通过copy_myself函数来实现。

      首先看一下对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。

最新评论共有 0 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册