Chinaunix首页 | 论坛 | 博客
  • 博客访问: 32148
  • 博文数量: 12
  • 博客积分: 445
  • 博客等级: 下士
  • 技术积分: 150
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-06 16:49
文章分类

全部博文(12)

文章存档

2012年(12)

我的朋友

分类: 嵌入式

2012-10-10 22:39:15

6、是u-boot支持从NandFlash启动


    先看S2C2440A的datasheet第五章 Memory Controller中的那个映射图,也就是那个Figure 5-1  S3C2440A Memory Map after Reset,从理论上来讲,对于0x40000000以后的内存,只有在Nor boot的时候才存在;而在 Nand boot的时候它被映射到了0x00000000,在0x40000000以后不存在内存。如果我们在启动的时候,将一些特定的数据写入0x40000000 - 0x40001000之间,那么按照手册上的说法,如果回读的结果和写入的一致说明是Nor boot,否则就是Nand boot。
    
    这种方法理论上是可以的,但是实际上,那个图是错的!真正的映射图如下:


    从上图可以看出,无论是Nor启动还是Nand启动,这4K的内部SRAM都被映射到了0x40000000,而在Nand boot的时候,这块内存同时被映射到了0x00000000,那么一开始提出的办法就不可行了,而且在Nand boot的时候,写入0x40000000 - 0x40001000还会破坏自身的程序。
    可以这样解决,在启动的时候,用程序将0x4000000 - 0x40001000中的某些位置清零,如果回读0x00000000 - 0x00001000中的相应位置为零,说明是Nand boot,如果是原来的数据(一定要选非零的位置)就是Nor boot。判断完如果是Nand boot,还要恢复被改动的数据,再进入自拷贝阶段。
    只要检测的位置合理,这个方法是可行的。现在的关键是选什么位置的数据最好呢?可以选在start.S文件开头,全局中断向量之后的:
                  
               .balignl 16,0xdeadbeef

     选这个数据作为检测位置的理由如下:
(1)他是非零数,而且数据是确定的:0xdeadbeef;
(2)他的位置是固定的:
0x0000003c0x4000003c);
(3)他在检测程序之前,不会影响程序的向下运行;
(4)他不属于程序,他是一个程序中的魔数(Magic Number),用魔数来检测也比较合理

     检测步骤如下:
     在启动的时候,将0x4000003c位置开始的四个字节清零,然后读取0x0000003c位置开始的四个字节。如果回读的结果为零,说明是Nand boot,否则就是Nor boot(为了保险还可以判断是否为0xdeadbeef,不是的话就说明有未知错误,死循环!)。但是最后有一点很重要:如果是Nand boot,必须要复原清零的数据。原因是:在nand boot过后,会核对内部SRAM中的4K程序,和从Nand中拷贝到SDRAM的前4K程序是否一致,如果不一致会进入死循环。 

    现在就动手修改u-boot源码,使其支持Nor 和 Nand双启动,主要是是修改start.S这个文件,代码如下:


  1. #ifndef CONFIG_SKIP_RELOCATE_UBOOT

  2. adr r0, _start /* r0 <- current position of code */
  3. ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
  4. cmp r0, r1 /* don't reloc during debug */
  5. beq stack_setup
  6. ldr r1, =((4<<28)|(3<<4)|(3<<2)) /* address of Internal SRAM 0x4000003C*/
  7. mov r0, #0 /* r0 = 0 */
  8. str r0, [r1]
  9. mov r1, #0x3c /* address of men 0x0000003C*/
  10. ldr r0, [r1]
  11. cmp r0, #0
  12. bne relocate
  13. /* recovery */
  14. ldr r0, =(0xdeadbeef)
  15. ldr r1, =( (4<<28)|(3<<4)|(3<<2) )
  16. str r0, [r1]
  17. #define LENGTH_UBOOT 0x60000
  18. #define NAND_CTL_BASE 0x4E000000
  19. #define oNFCONF 0x00
  20. #define oNFCONT 0x04
  21. #define oNFCMD 0x08
  22. #define oNFSTAT 0x20
  23. @ reset NAND
  24. mov r1, #NAND_CTL_BASE
  25. ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
  26. str r2, [r1, #oNFCONF]
  27. ldr r2, [r1, #oNFCONF]
  28. ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control
  29. str r2, [r1, #oNFCONT]
  30. ldr r2, [r1, #oNFCONT]
  31. ldr r2, =(0x6) @ RnB Clear
  32. str r2, [r1, #oNFSTAT]
  33. ldr r2, [r1, #oNFSTAT]
  34. mov r2, #0xff @ RESET command
  35. strb r2, [r1, #oNFCMD]
  36. mov r3, #0 @ wait
  37. nand1:
  38. add r3, r3, #0x1
  39. cmp r3, #0xa
  40. blt nand1
  41. nand2:
  42. ldr r2, [r1, #oNFSTAT] @ wait ready
  43. tst r2, #0x4
  44. beq nand2
  45. ldr r2, [r1, #oNFCONT]
  46. orr r2, r2, #0x2 @ Flash Memory Chip Disable
  47. str r2, [r1, #oNFCONT]
  48. @ get read to call C functions (for nand_read())
  49. ldr sp, DW_STACK_START @ setup stack pointer
  50. mov fp, #0 @ no previous frame, so fp=0
  51. @ copy U-Boot to RAM
  52. ldr r0, =TEXT_BASE
  53. mov r1, #0x0
  54. mov r2, #LENGTH_UBOOT
  55. bl nand_read_ll
  56. tst r0, #0x0
  57. beq ok_nand_read
  58. bad_nand_read:
  59. loop2:
  60. b loop2 @ infinite loop
  61. ok_nand_read:
  62. @ verify
  63. mov r0, #0
  64. ldr r1, =TEXT_BASE
  65. mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
  66. go_next:
  67. ldr r3, [r0], #4
  68. ldr r4, [r1], #4
  69. teq r3, r4
  70. bne notmatch
  71. subs r2, r2, #4
  72. beq stack_setup
  73. bne go_next
  74. notmatch:
  75. loop3:
  76. b loop3 @ infinite loop
  77. relocate: /* relocate U-Boot to RAM */
  78. ldr r1, =(0xdeadbeef)
  79. cmp r0, r1
  80. bne loop3
  81. adr r0, _start /* r0 <- current position of code */
  82. ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
  83. //cmp r0, r1 /* don't reloc during debug */
  84. //beq stack_setup
  85. ldr r2, _armboot_start
  86. ldr r3, _bss_start
  87. sub r2, r3, r2 /* r2 <- size of armboot */
  88. add r2, r0, r2 /* r2 <- source end address */
  89. copy_loop:
  90. ldmia r0!, {r3-r10} /* copy from source address [r0] */
  91. stmia r1!, {r3-r10} /* copy to target address [r1] */
  92. cmp r0, r2 /* until source end addreee [r2] */
  93. ble copy_loop
  94. #endif /* CONFIG_SKIP_RELOCATE_UBOOT */

  95. /* Set up the stack */
  96. stack_setup:
  97. ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
  98. sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */
  99. sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */
  100. #ifdef CONFIG_USE_IRQ
  101. sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
  102. #endif
  103. sub sp, r0, #12 /* leave 3 words for abort-stack */
  104. clear_bss:
  105. ldr r0, _bss_start /* find start of bss segment */
  106. ldr r1, _bss_end /* stop here */
  107. mov r2, #0x00000000 /* clear */
  108. clbss_l:str r2, [r0] /* clear loop... */
  109. add r0, r0, #4
  110. cmp r0, r1
  111. ble clbss_l
  112. ldr pc, _start_armboot
  113. _start_armboot: .word start_armboot
  114. #define STACK_BASE 0x33f00000
  115. #define STACK_SIZE 0x10000
  116. .align 2
  117. DW_STACK_START: .word STACK_BASE+STACK_SIZE-4


   另外,还需在board/samsung/smdk2440/目录下新建一个nand_read.c文件,用来实现上面汇编中要调用的nand_read_ll函数,代码如下:


  1. #include
  2. #include


  3. #define __REGb(x)    (*(volatile unsigned char *)(x))
  4. #define __REGw(x)    (*(volatile unsigned short *)(x))
  5. #define __REGi(x)    (*(volatile unsigned int *)(x))
  6. #define NF_BASE        0x4e000000

  7. #define NFCONF        __REGi(NF_BASE + 0x0)
  8. #define NFCONT        __REGi(NF_BASE + 0x4)
  9. #define NFCMD        __REGb(NF_BASE + 0x8)
  10. #define NFADDR        __REGb(NF_BASE + 0xc)
  11. #define NFDATA        __REGb(NF_BASE + 0x10)
  12. #define NFDATA16    __REGw(NF_BASE + 0x10)
  13. #define NFSTAT        __REGb(NF_BASE + 0x20)
  14. #define NFSTAT_BUSY    1
  15. #define nand_select()    (NFCONT &= ~(1 << 1))
  16. #define nand_deselect()    (NFCONT |= (1 << 1))
  17. #define nand_clear_RnB()    (NFSTAT |= (1 << 2))

  18. static inline void nand_wait(void)
  19. {
  20.     int i;

  21.     while (!(NFSTAT & NFSTAT_BUSY))
  22.         for (i=0; i<10; i++);
  23. }

  24. struct boot_nand_t {
  25.     int page_size;
  26.     int block_size;
  27.     int bad_block_offset;
  28. };

  29. static int is_bad_block(struct boot_nand_t * nand, unsigned long i)
  30. {
  31.     unsigned char data;
  32.     unsigned long page_num;

  33.     nand_clear_RnB();
  34.     if (nand->page_size == 512) {
  35.         NFCMD = NAND_CMD_READOOB; /* 0x50 */
  36.         NFADDR = nand->bad_block_offset & 0xf;
  37.         NFADDR = (i >> 9) & 0xff;
  38.         NFADDR = (i >> 17) & 0xff;
  39.         NFADDR = (i >> 25) & 0xff;
  40.     } else if (nand->page_size == 2048) {
  41.         page_num = i >> 11; /* 2048 */
  42.         NFCMD = NAND_CMD_READ0;
  43.         NFADDR = nand->bad_block_offset & 0xff;
  44.         NFADDR = (nand->bad_block_offset >> 8) & 0xff;
  45.         NFADDR = page_num & 0xff;
  46.         NFADDR = (page_num >> 8) & 0xff;
  47.         NFADDR = (page_num >> 16) & 0xff;
  48.         NFCMD = NAND_CMD_READSTART;
  49.     } else {
  50.         return -1;
  51.     }
  52.     
  53.     nand_wait();
  54.     
  55.     data = (NFDATA & 0xff);
  56.     if (data != 0xff)
  57.         return 1;

  58.     return 0;
  59. }

  60. static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr)
  61. {
  62.     unsigned short *ptr16 = (unsigned short *)buf;
  63.     unsigned int i, page_num;

  64.     nand_clear_RnB();

  65.     NFCMD = NAND_CMD_READ0;

  66.     if (nand->page_size == 512) {
  67.         NFADDR = addr & 0xff;
  68.         NFADDR = (addr >> 9) & 0xff;
  69.         NFADDR = (addr >> 17) & 0xff;
  70.         NFADDR = (addr >> 25) & 0xff;
  71.     } else if (nand->page_size == 2048) {
  72.         page_num = addr >> 11; /* 2048 */
  73.         NFADDR = 0;
  74.         NFADDR = 0;
  75.         NFADDR = page_num & 0xff;
  76.         NFADDR = (page_num >> 8) & 0xff;
  77.         NFADDR = (page_num >> 16) & 0xff;
  78.         NFCMD = NAND_CMD_READSTART;
  79.     } else {
  80.         return -1;
  81.     }
  82.     
  83.     nand_wait();

  84.     for (i = 0; i < (nand->page_size>>1); i++) {
  85.         *ptr16 = NFDATA16;
  86.         ptr16++;
  87.     }

  88.     return nand->page_size;
  89. }


  90. static unsigned short nand_read_id()
  91. {
  92.     unsigned short res = 0;
  93.     NFCMD = NAND_CMD_READID;
  94.     NFADDR = 0;
  95.     res = NFDATA;
  96.     res = (res << 8) | NFDATA;
  97.     return res;
  98. }

  99. int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
  100. {
  101.     int i, j;
  102.     unsigned short nand_id;
  103.     struct boot_nand_t nand;

  104.     /* chip Enable */
  105.     nand_select();
  106.     nand_clear_RnB();
  107.     
  108.     for (i = 0; i < 10; i++)
  109.         ;
  110.     nand_id = nand_read_id();
  111.     

  112.     if (nand_id == 0xec76 ||        /* Samsung K91208 */
  113.            nand_id == 0xad76 ) {    /*Hynix HY27US08121A*/
  114.         nand.page_size = 512;
  115.         nand.block_size = 16 * 1024;
  116.         nand.bad_block_offset = 5;
  117.     } else if (nand_id == 0xecf1 ||     /* Samsung K9F1G08U0B */
  118.          nand_id == 0xecda ||     /* Samsung K9F2G08U0B */
  119.          nand_id == 0xecd3 )    { /* Samsung K9K8G08 */
  120.         nand.page_size = 2048;
  121.         nand.block_size = 128 * 1024;
  122.         nand.bad_block_offset = nand.page_size;
  123.     } else {
  124.         return -1;
  125.     }
  126.     if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1))))
  127.         return -1;     /* invalid alignment */

  128.     for (i=start_addr; i < (start_addr + size);) {
  129. #ifdef CONFIG_S3C2410_NAND_SKIP_BAD
  130.         if (i & (nand.block_size-1)== 0) {
  131.             if (is_bad_block(&nand, i) ||
  132.              is_bad_block(&nand, i + nand.page_size)) {
  133.                 /* Bad block */
  134.                 i += nand.block_size;
  135.                 size += nand.block_size;
  136.                 continue;
  137.             }
  138.         }
  139. #endif
  140.         j = nand_read_page_ll(&nand, buf, i);
  141.         i += j;
  142.         buf += j;
  143.     }

  144.     /* chip Disable */
  145.     nand_deselect();

  146.     return 0;
  147. }

    然后,在board/samsung/smdk2440/Makefile中添加nand_read.c的编译选项,使他编译到u-boot中,如下:

COBJS    := smdk2440.o flash.o nand_read.o

    还有一个重要的地方要修改,在cpu/arm920t/u-boot.lds中,这个u-boot启动连接脚本文件决定了u-boot运行的入口地址,以及各个段的存储位置,这也是链接定位的作用。添加下面两行代码的主要目的是防止编译器把我们自己添加的用于nand boot的子函数放到4K之后,否则是无法启动的。如下:

.text :
{
    cpu/arm920t/start.o    (.text)
    board/samsung/smdk2440/lowlevel_init.(.text)
    board/samsung/smdk2440/nand_read.(.text)

    *(.text)
}

    

    最后编译u-boot,生成u-boot.bin文件。然后将u-boot.bin下载到开发板的Nand Flash中,把开发板调到Nand启动档,打开电源就从Nand Flash启动了,启动结果图如下:


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