FL2440开发板的U-boot-2010.09版本移植(七)NAND Flash启动支持

时间:2021-08-13 17:11:39

        从NAND Flash启动的原理很简单,就是利用S3C2440内部4K大小的SRAM,存储在NAND Flash中的代码不能被执行,而S3C2440在从NAND Flash启动把NAND Flash的前4k代码复制到SRAM中运行,U-boot支持从NAND Flash启动的方法就是利用这前4K代码完成SDRAM的初始化(SDRAM有64M),然后还要完成从U-boot代码从NAND Flash中复制到SDRAM中,然后再跳转到SDRAM中去运行完整的U-boot。

      为了便于系统启动的方便,可以在start.S文件中添加代码以识别系统是从NAND Flash启动还是从NOR Flash启动,从S3C2440芯片手册中可以看到

到OM[1:0]都为0时,说明是从NAND Flash启动,01和10都是从NOR Flash启动,OM[1:0]就是寄存器BWSCON的第2位~第1位(DW0)

  nand启动的移植主要是一、在start.S中添加对nand启动的判断和跳转;二、编写nand_read.c的读取nand函数集,这个函数在链接文件中被指定放在前4k;

一、添加NOR Flash启动和NAND Flash启动的识别

修改arch/arm/cpu/arm920t/start.S,首先将217行附近修改为:

[cpp]  view plain copy
  1. #ifndef CONFIG_SKIP_LOWLEVEL_INIT  
  2.     bl  cpu_init_crit  
  3. #endif  
  4.   
  5. #define BWSCON 0x48000000  
  6.         ldr     r0, =BWSCON  
  7.         ldr     r0, [r0]  
  8.         ands    r0, r0, #0x6  
  9.         tst     r0, #0x0  
  10.         bne     norflash_boot             /*OM[1:0] != 0, 跳转到NOR FLASH 启动处*/  
  11. /*判断uboot是从nand flash启动还是从 nor flash启动*/  

★★★★★★Important★★★★★★

上面这段代码经Andrew实验发现有问题。即只能在Nand中启动,不能在Nor中启动;

查阅了有关资料后,注释掉了第9行    “tst     r0, #0x0 ”

变成:
  1. #ifndef CONFIG_SKIP_LOWLEVEL_INIT  
  2.     bl  cpu_init_crit  
  3. #endif  
  4.   
  5. #define BWSCON 0x48000000  
  6.         ldr     r0, =BWSCON  
  7.         ldr     r0, [r0]  
  8.         ands    r0, r0, #0x6  
  9.         //tst     r0, #0x0  
  10.         bne     norflash_boot             /*OM[1:0] != 0, 跳转到NOR FLASH 启动处*/  
  11. /*判断uboot是从nand flash启动还是从 nor flash启动*/  

之后再编译运行,在Nand和Nor中都能够单独启动了。

★★★★★★Important★★★★★★

在220行附近将:

[cpp]  view plain copy
  1. #ifndef CONFIG_SKIP_RELOCATE_UBOOT  
  2. relocate:  

修改为

[html]  view plain copy
  1. norflash_boot:  
  2. #ifndef CONFIG_SKIP_RELOCATE_UBOOT  
  3. relocate:  

二、添加NAND Flash的U-boot代码从NAND FLash到SDRAM搬移的代码

★★★★★★Important★★★★★★   

注意FL2440可能使用三星和现代的两款不同的NandFlash芯片,下面的代码是三星的;

如果是现代的Nand(拆下核心板看看),就要按照FL2440自带光盘里的说明进行修改,不然Nand使用会有异常!!!

FL官方提供的bootloader也需要修改;

根据Andrew对官方文件nand_lowlevel.c进行Merge的结果,两款芯片只有ID号不同,其它参数都相同,因此在官方文件nand_lowlevel.c中有这么一处修改:

456行:

if(i==0xecda){
//改为
if((i==0xecda) || (i==0xadda)){

只是添加了现代ID号的支持。

在U-boot-2010-9的版本中,我们只需要对/board/fl2440/nand_read_save.c中的241行添加芯片ID:

} else if (nand_id == 0xecf1 || /* Samsung K9F1G08U0B */
nand_id == 0xecda || /* Samsung K9F2G08U0B */
nand_id == 0xecd3 || /* Samsung K9K8G08 */
nand_id == 0xadda) /* hynix HY27UF082G2B */ {

 虽然上面的nand_read_save.c代码实际编译中没有用到,但如果U-boot中有型号信息确认的代码(如FL自带的bootloader一样),则一定要添加上去。

★★★★★★Important★★★★★★   


在前面修改的 bne norflash_boot ,227行后添加

[cpp]  view plain copy
  1. /*****************************nand boot**************************/  
  2. nandflash_boot:  
  3. #define LENGTH_UBOOT 0x40000  
  4. #define NAND_CTL_BASE 0x4e000000  
  5. #define oNFCONF 0x00  
  6. #define oNFCONT 0x04  
  7. #define oNFCMD  0x08  
  8. #define oNFSTAT 0x20  
  9.   
  10.         @reset NAND  
  11.         mov     r1,#NAND_CTL_BASE  
  12.         ldr     r2,=((7<<12)|(7<<8)|(7<<4))  
  13.         str     r2,[r1,#oNFCONF]  
  14.         ldr     r2,[r1,#oNFCONF]  
  15.           
  16.         ldr     r2,=((1<<4)|(1<<1)|(1<<0)) @Active low CE control  
  17.         str     r2,[r1,#oNFCONT]  
  18.         ldr     r2,[r1,#oNFCONT]  
  19.           
  20.         @ get read to call C functions  
  21.         ldr     sp,DW_STACK_START   @setup stack point  
  22.         mov     fp,#0               @no previous frame, so fp = 0  
  23.           
  24.         @copy Uboot to ram  
  25.         ldr     r0, =TEXT_BASE  
  26.         mov     r1,#0x0  
  27.         mov     r2,#LENGTH_UBOOT  
  28.         bl      nand_read_ll  
  29.         tst     r0,#0x0  
  30.         beq     ok_nand_read  
  31.   
  32. bad_nand_read:  
  33. loop2:  
  34.         b       loop2     @infinite loop  
  35.   
  36. ok_nand_read:  
  37.         @verify  
  38.         mov     r0,#0  
  39.         ldr     r1,=TEXT_BASE  
  40.         mov     r2,#0x400     @ compare 4k code from sram to sdram  
  41.   
  42. go_next:  
  43.         ldr     r3, [r0], #4  
  44.         ldr     r4, [r1], #4  
  45.         teq     r3, r4  
  46.         bne     notmatch  
  47.         subs    r2,r2,#4  
  48.         tst     r2,#0x0   @do not forget the instruction if have not this command the uboot can't break the loop  
  49.         beq     stack_setup  
  50.         bne     go_next  
  51.   
  52. notmatch:  
  53. loop3:  
  54.         b       loop3 @infinite loop  
  55. /*****************************nand boot**************************/  

上面这部分代码首先初始化了NAND Flash寄存器,然后进行了一个函数调用(这个函数中完成了代码搬移)后面则是对复制出来的数据进行一个简单的校验。在327行附近添加为:

[cpp]  view plain copy
  1. _start_armboot: .word start_armboot  
  2. #define  STACK_BASE 0x33f00000  
  3. #define  STACK_SIZE 0x10000  
  4.         .align 2  
  5. DW_STACK_START: .word STACK_BASE+STACK_SIZE-4  

添加函数的栈调用空间

三、添加C语言从NAND Flash搬移代码部分

首先在board/fl2440目录下新建一个名为nand_read.c的文件,其内容如下:

[cpp]  view plain copy
  1. /*  
  2.  * vivi/s3c2410/nand_read.c: Simple NAND read functions for booting from NAND 
  3.  * 
  4.  * Copyright (C) 2002 MIZI Research, Inc. 
  5.  * 
  6.  * Author: Hwang, Chideok <hwang@mizi.com> 
  7.  * Date  : $Date: 2002/08/14 10:26:47 $ 
  8.  * 
  9.  * $Revision: 1.6 $ 
  10.  * $Id: param.c,v 1.9 2002/07/11 06:17:20 nandy Exp  
  11.  * 
  12.  */  
  13.   
  14. #include <config.h>  
  15.   
  16. #define __REGb(x)   (*(volatile unsigned char *)(x))  
  17. #define __REGi(x)   (*(volatile unsigned int *)(x))  
  18. #define NF_BASE     0x4e000000  
  19.   
  20. /*S3C2440与S3C2440 nandflash控制寄存器地址不同需要进行修改*/  
  21. #define NFCONF      __REGi(NF_BASE + 0x0)  
  22. #define NFCONT          __REGi(NF_BASE + 0x4)  
  23. #define NFCMD       __REGb(NF_BASE + 0x8)  
  24. #define NFADDR      __REGb(NF_BASE + 0xc)  
  25. #define NFDATA      __REGb(NF_BASE + 0x10)  
  26. #define NFSTAT      __REGb(NF_BASE + 0x20)  
  27.   
  28. #define NAND_CHIP_ENABLE (NFCONT &= ~(1<<1))  
  29. #define NAND_CHIP_DISABLE (NFCONT |= (1<<1))  
  30. #define NAND_CLEAR_RB (NFSTAT |= (1<<2))  
  31. #define NAND_DETECT_RB {while(! (NFSTAT&(1<<2)));}  
  32. #define NAND_ECC_CLEAR (NFCONT |= 0x10)  
  33. /*see data sheet P193*/  
  34.   
  35. #define BUSY 1  
  36. static inline void wait_idle(void) {  
  37.     int i;  
  38.     while(!(NFSTAT & BUSY))  
  39.       for(i=0; i<10; i++);  
  40. }  
  41.   
  42. /*根据fl2440的nand flash 作相应修改*/  
  43. #define NAND_SECTOR_SIZE    2048  
  44. #define NAND_BLOCK_MASK     (NAND_SECTOR_SIZE - 1)  
  45.   
  46. /* low level nand read function */  
  47.  int  
  48. nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)  
  49. {  
  50.     int i, j;  
  51.     int pagenum;  
  52.   
  53.     if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {  
  54.         return -1;  /* invalid alignment */  
  55.     }  
  56.   
  57.     /* chip Enable */  
  58.     NAND_CHIP_ENABLE;  
  59.       
  60.     for(i = start_addr; i < (start_addr + size);) {  
  61.       /* READ0 */  
  62.   
  63.       NAND_CLEAR_RB;  
  64.       for(j = 0; j < 10; j++);  
  65.         
  66.       pagenum = i >> 11;  
  67.       /* Write Address  
  68.         该步骤详见nand flash(k9f2g08u0a)手册p17 
  69.         参考fl2440开发板nand_lowlevel.c文件中ReadPage函数 
  70.       */  
  71.       NFCMD = 0x0;  
  72.         
  73.       NFADDR = 0;  
  74.       NFADDR = 0;  
  75.       NFADDR = pagenum & 0xff;  
  76.       NFADDR = (pagenum >> 8) & 0xff;  
  77.       NFADDR = (pagenum >> 16) & 0xff;  
  78.       /*如果不理解见数据手册nand flashP9*/  
  79.   
  80.       NFCMD = 0x30;  
  81.       wait_idle();  
  82.   
  83.       for(j=0; j < NAND_SECTOR_SIZE; j++) {  
  84.           *buf = (NFDATA & 0xff);  
  85.            buf++;  
  86.       }  
  87.        
  88.      i += NAND_SECTOR_SIZE;  
  89.    
  90.     }  
  91.   
  92.     NAND_CHIP_DISABLE;  
  93.      
  94.     /* chip Disable */  
  95.       
  96.     return 0;  
  97. }  

    开发板的NAND Flash型号为k9f2g08u0a,它的容量是256MByte,NAND Flash的最小读取单位是以页为单位的,即2KByte(12位)每页,共128K页(17位),而地址线是8位的,因此当需要读取一页时,需分周期发送页地址,这款芯片规定前两个地址周期发送页内地址,后面的三周期发送页编号,它的流程如表1:

表1 NAND Flash地址

 

 

I/O 0

I/O 1

I/O 2

I/O 3

I/O 4

I/O 5

I/O 6

I/O 7

第一周期

A0

A1

A2

A3

A4

A5

A6

A7

第二周期

A8

A9

A10

A11

0

0

0

0

第三周期

A12

A13

A14

A15

A16

A17

A18

A19

第四周期

A20

A21

A22

A23

A24

A25

A26

A27

第五周期

A28

0

0

0

0

0

0

0

 

我们在读取uboot.bin时,直接按页读取,所以前两周期地址我们设成了全0,后面的3周期实际就是也编号。

修改board/fl2440/Makefile文件,使得nand_read.c能被编译到u-boot.bin中,修改28行为:

[cpp]  view plain copy
  1. COBJS   := fl2440.o nand_read.o flash.o  

我们还知道由于我们需要在前4K代码中完成代码的搬移,而搬移的代码集中在start.S和nand_read.c(实现读取nand-flash的功能)中,而U-boot的编译过程并不能保证nand_read.c能在前4K代码中,所以需要我们手动设置,修改文件arch/arm/cpu/arm920t/u-boot.lds文件40行为:

[cpp]  view plain copy
  1. .text :  
  2. {  
  3.     arch/arm/cpu/arm920t/start.o    (.text)  
  4.                board/fl2440/lowlevel_init.o (.text)  
  5.                board/fl2440/nand_read.o (.text)  
  6.     *(.text)  
  7. }  

注意,这里使用的nand_read.c代码进行从nand_flash启动,这里的代码跟U-boot进行Nand操作的驱动代码是不同的(相互独立),这里仅仅实现了“读取”,而没有实现“擦除”、“写入”等操作。
这样,编译器在编译时能保证start.S和nand_read.c编译出的二进制代码在前4K。

修改include/configs/fl2440.h中,添加相关的宏定义以支持NAND Flash的串口操作命令:

[cpp]  view plain copy
  1. #define CONFIG_CMD_NAND   /*****add by yanghao*****/  
  2. <p>#if defined(CONFIG_CMD_NAND)</p><p>#define CONFIG_NAND_S3C2410  
  3. #define CONFIG_SYS_MAX_NAND_DEVICE   1     /* Max number of NAND devices        */  
  4. #define NAND_MAX_CHIPS   1  
  5. #define CONFIG_SYS_NAND_BASE 0x4E000000</p>#endif  

 

然后将开发板设置成为从NAND Flash启动,将编译出来的u-boot.bin烧写入NAND Flash,上电这样就完成了从NAND Flash的启动。

 source http://blog.csdn.net/yanghao23/article/details/7696096