S&T的笔记 https://bbs.21ic.com/?600909 [收藏] [复制] [RSS] science and technology!

日志

U-Boot启动过程完全分析(4)

已有 966 次阅读2011-12-16 03:18 |个人分类:ARM|系统分类:ARM| U-Boot

9)复制U-Boot第二阶段代码到RAM


       cpu/arm920t/start.S原来的代码是只支持从NOR Flash启动的,经过修改现在U-BootNOR FlashNAND Flash上都能启动了,实现的思路是这样的:


 


       bl    bBootFrmNORFlash /*  判断U-Boot是在NAND Flash还是NOR Flash启动  */


       cmp       r0, #0          /*  r0存放bBootFrmNORFlash函数返回值,若返回0表示NAND Flash启动,否则表示在NOR Flash启动  */


       beq nand_boot         /*  跳转到NAND Flash启动代码  */


 


/*  NOR Flash启动的代码  */


       b     stack_setup         /* 跳过NAND Flash启动的代码 */


 


nand_boot:


/*  NAND Flash启动的代码  */


 


stack_setup:       


       /* 其他代码 */


 


       其中bBootFrmNORFlash函数作用是判断U-Boot是在NAND Flash启动还是NOR Flash启动,若在NOR Flash启动则返回1,否则返回0根据ATPCS规则,函数返回值会被存放在r0寄存器中,因此调用bBootFrmNORFlash函数后根据r0的值就可以判断U-BootNAND Flash启动还是NOR Flash启动bBootFrmNORFlash函数在board/samsung/mini2440/nand_read.c中定义如下:


int bBootFrmNORFlash(void)


{


    volatile unsigned int *pdw = (volatile unsigned int *)0;


    unsigned int dwVal;


  


    dwVal = *pdw;         /* 先记录下原来的数据 */


    *pdw = 0x12345678;


    if (*pdw != 0x12345678)       /* 写入失败,说明是在NOR Flash启动 */


    {


        return 1;     


    }


    else                                   /* 写入成功,说明是在NAND Flash启动 */


    {


        *pdw = dwVal;        /* 恢复原来的数据 */


        return 0;


    }


}


     无论是从NOR Flash还是从NAND Flash启动,地址0处为U-Boot的第一条指令“ b    start_code”


       对于从NAND Flash启动的情况,其开始4KB的代码会被自动复制到CPU内部4K内存中,因此可以通过直接赋值的方法来修改。


       对于从NOR Flash启动的情况,NOR Flash的开始地址即为0,必须通过一定的命令序列才能向NOR Flash中写数据,所以可以根据这点差别来分辨是从NAND Flash还是NOR Flash启动:向地址0写入一个数据,然后读出来,如果发现写入失败的就是NOR Flash,否则就是NAND Flash


       下面来分析NOR Flash启动部分代码:


208      adr  r0, _start              /* r0 <- current position of code   */


209      ldr   r1, _TEXT_BASE            /* test if we run from flash or RAM */


 


/* 判断U-Boot是否是下载到RAM中运行,若是,则不用 再复制到RAM中了,这种情况通常在调试U-Boot时才发生 */


210      cmp      r0, r1      /*_start等于_TEXT_BASE说明是下载到RAM中运行 */


211      beq stack_setup


212  /* 以下直到nand_boot标号前都是NOR Flash启动的代码 */


213      ldr   r2, _armboot_start


214      ldr   r3, _bss_start


215      sub  r2, r3, r2              /* r2 <- size of armboot            */


216      add r2, r0, r2              /* r2 <- source end address         */


217  /* 搬运U-Boot自身到RAM*/


218  copy_loop:


219      ldmia     r0!, {r3-r10} /* 从地址为[r0]NOR Flash中读入8个字的数据 */


220      stmia      r1!, {r3-r10} /* r3r10寄存器的数据复制给地址为[r1]的内存 */


221      cmp       r0, r2                    /* until source end addreee [r2]    */


222      ble  copy_loop


223      b     stack_setup         /* 跳过NAND Flash启动的代码 */


       下面再来分析NAND Flash启动部分代码:


nand_boot:


    mov r1, #NAND_CTL_BASE 


    ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )


    str r2, [r1, #oNFCONF]   /* 设置NFCONF寄存器 */


 


       /* 设置NFCONT,初始化ECC/解码器,禁止NAND Flash片选 */


    ldr r2, =( (1<<4)|(0<<1)|(1<<0) )


    str r2, [r1, #oNFCONT] 


 


    ldr r2, =(0x6)           /* 设置NFSTAT */


str r2, [r1, #oNFSTAT]


 


       /* 复位命令,第一次使用NAND Flash前复位 */


    mov r2, #0xff           


    strb r2, [r1, #oNFCMD]


    mov r3, #0              


 


    /* 为调用C函数nand_read_ll准备堆栈 */


    ldr sp, DW_STACK_START  


    mov fp, #0              


    /* 下面先设置r0r2,然后调用nand_read_ll函数将U-Boot读入RAM */


    ldr r0, =TEXT_BASE      /* 目的地址:U-BootRAM的开始地址 */


    mov r1, #0x0               /* 源地址:U-BootNAND Flash中的开始地址 */


    mov r2, #0x30000          /* 复制的大小,必须比u-boot.bin文件大,并且必须是NAND Flash块大小的整数倍,这里设置为0x30000192KB */


    bl  nand_read_ll                 /* 跳转到nand_read_ll函数,开始复制U-BootRAM */


tst  r0, #0x0                     /* 检查返回值是否正确 */


beq stack_setup


bad_nand_read:


loop2: b loop2    //infinite loop


 


.align 2


DW_STACK_START: .word STACK_BASE+STACK_SIZE-4


       其中NAND_CTL_BASEoNFCONF等在include/configs/mini2440.h中定义如下:


#define NAND_CTL_BASE  0x4E000000  // NAND Flash控制寄存器基址


 


#define STACK_BASE  0x33F00000     //base address of stack


#define STACK_SIZE  0x8000         //size of stack


 


#define oNFCONF  0x00      /* NFCONF相对于NAND_CTL_BASE偏移地址 */


#define oNFCONT  0x04      /* NFCONT相对于NAND_CTL_BASE偏移地址*/


#define oNFADDR  0x0c     /* NFADDR相对于NAND_CTL_BASE偏移地址*/


#define oNFDATA  0x10      /* NFDATA相对于NAND_CTL_BASE偏移地址*/


#define oNFCMD   0x08     /* NFCMD相对于NAND_CTL_BASE偏移地址*/


#define oNFSTAT  0x20        /* NFSTAT相对于NAND_CTL_BASE偏移地址*/


#define oNFECC   0x2c              /* NFECC相对于NAND_CTL_BASE偏移地址*/


       NAND Flash各个控制寄存器的设置在S3C2440的数据手册有详细说明,这里就不介绍了。


       代码中nand_read_ll函数的作用是在NAND Flash中搬运U-BootRAM,该函数在board/samsung/mini2440/nand_read.c中定义。


       NAND Flash根据page大小可分为2种: 512B/page2048B/page的。这两种NAND Flash的读操作是不同的。因此就需要U-Boot识别到NAND Flash的类型,然后采用相应的读操作,也就是说nand_read_ll函数要能自动适应两种NAND Flash


       参考S3C2440的数据手册可以知道:根据NFCONF寄存器的Bit3AdvFlash (Read only))和Bit2 PageSize (Read only))可以判断NAND Flash的类型。Bit2Bit3NAND Flashblock类型的关系如下表所示:


2.4 NFCONFBit3Bit2NAND Flash的关系

















Bit2    Bit3


0


1


0


256 B/page


512 B/page


1


1024 B/page


2048 B/page


 


       由于的NAND Flash只有512B/page2048 B/page这两种,因此根据NFCONF寄存器的Bit3即可区分这两种NAND Flash了。


       完整代码见board/samsung/mini2440/nand_read.c中的nand_read_ll函数,这里给出伪代码:


int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)


{


//根据NFCONF寄存器的Bit3来区分2NAND Flash


       if( NFCONF & 0x8 )        /* Bit1,表示是2KB/pageNAND Flash */


       {


              ////////////////////////////////////


              读取2K block NAND Flash


              ////////////////////////////////////


 


       }


       else                      /* Bit0,表示是512B/pageNAND Flash */


       {


              /////////////////////////////////////


              读取512B block NAND Flash


              /////////////////////////////////////


 


       }


    return 0;


}


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)