首页 > 代码库 > u-boot移植(九)---代码修改---NAND

u-boot移植(九)---代码修改---NAND

一、NAND原理

  技术分享

  NAND 无地址空间,地址和数据的发送都依赖于LDATA[0:7]这一串数据总线。

  技术分享技术分享

   不看随机页编程,看到从高位到低位的页,总共分为64个页面,每个页的组成是2K + 64  个byte,一个块的大小是(128K + 4K)byte,64页组成一块。

1.1 NAND Flash的编址

  nand flash的的页的大小是(2048 + 64)byte,64这个数据是不参与编址的。

  访问 nand flash:

    • 发出命令:读、写、擦除
    • 发出地址
    • 传输数据

   命令设置如下:

  技术分享

1.2 nand flash的访问

  技术分享

  可以看看上面的模式选择,然后对应引脚进行操作,就可以进行读写操作。命令和数据就通过这些引脚来进行操作。但是不必直接操作这些引脚,可以通过寄存器来进行操作。

  查看S3C2440的手册,可以看到如下的信息:

  技术分享

  写命令寄存器就相当于NAND Flash寄存器命令周期,写地址寄存器就相当于NAND Flash寄存器的地址周期......

   我们的NAND Flash是X8的,即是8位NAND Flash,对应2440上面的一些控制寄存器:

  NAND Flash命令寄存器:

  技术分享

  地址寄存器:

  技术分享

  数据寄存器:

  技术分享

  状态寄存器:

  技术分享

  还有一些其他寄存器是与读写有关的。

  操作这些寄存器,2440会自动驱动PIN脚给出信号。

二、u-boot中设置nand启动

2.1 建立init.c

  这是NAND启动的初始化文件,里面包含了nand启动的初始化函数。代码添加到 borad/samdung/jz2440/ 目录下:

  1 /* NAND FLASH控制器 */
  2 #define NFCONF (*((volatile unsigned long *)0x4E000000))
  3 #define NFCONT (*((volatile unsigned long *)0x4E000004))
  4 #define NFCMMD (*((volatile unsigned char *)0x4E000008))
  5 #define NFADDR (*((volatile unsigned char *)0x4E00000C))
  6 #define NFDATA (*((volatile unsigned char *)0x4E000010))
  7 #define NFSTAT (*((volatile unsigned char *)0x4E000020))
  8 
  9 /* GPIO */
 10 #define GPHCON              (*(volatile unsigned long *)0x56000070)
 11 #define GPHUP               (*(volatile unsigned long *)0x56000078)
 12 
 13 /* UART registers*/
 14 #define ULCON0              (*(volatile unsigned long *)0x50000000)
 15 #define UCON0               (*(volatile unsigned long *)0x50000004)
 16 #define UFCON0              (*(volatile unsigned long *)0x50000008)
 17 #define UMCON0              (*(volatile unsigned long *)0x5000000c)
 18 #define UTRSTAT0            (*(volatile unsigned long *)0x50000010)
 19 #define UTXH0               (*(volatile unsigned char *)0x50000020)
 20 #define URXH0               (*(volatile unsigned char *)0x50000024)
 21 #define UBRDIV0             (*(volatile unsigned long *)0x50000028)
 22 
 23 #define TXD0READY   (1<<2)
 24 
 25 
 26 void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len);
 27 
 28 /* 判定是否是nor启动 */
 29 static int isBootFromNorFlash(void)
 30 {
 31     volatile int *p = (volatile int *)0;
 32     int val;
 33 
 34     val = *p;
 35     *p = 0x12345678;
 36     if (*p == 0x12345678)
 37     {
 38         /* 写成功, 是nand启动 */
 39         *p = val;
 40         return 0;
 41     }
 42     else
 43     {
 44         /* NOR不能像内存一样写 */
 45         return 1;
 46     }
 47 }
 48 
 49 /* 拷贝代码到sdram */
 50 void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
 51 {    
 52     int i = 0;
 53     
 54     /* 如果是NOR启动 */
 55     if (isBootFromNorFlash())
 56     {
 57         while (i < len)
 58         {
 59             dest[i] = src[i];
 60             i++;
 61         }
 62     }
 63     else
 64     {
 65         //nand_init();
 66         nand_read_ll((unsigned int)src, dest, len);
 67     }
 68 }
 69 
 70 /* 清除BSS */
 71 void clear_bss(void)
 72 {
 73     extern int __bss_start, __bss_end;
 74     int *p = &__bss_start;
 75     
 76     for (; p < &__bss_end; p++)
 77         *p = 0;
 78 }
 79 
 80 /* nand初始化 */
 81 void nand_init_ll(void)
 82 {
 83 #define TACLS   0
 84 #define TWRPH0  1
 85 #define TWRPH1  0
 86     /* 设置时序 */
 87     NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
 88     /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
 89     NFCONT = (1<<4)|(1<<1)|(1<<0);    
 90 }
 91 
 92 static void nand_select(void)
 93 {
 94     NFCONT &= ~(1<<1);    
 95 }
 96 
 97 static void nand_deselect(void)
 98 {
 99     NFCONT |= (1<<1);    
100 }
101 
102 static void nand_cmd(unsigned char cmd)
103 {
104     volatile int i;
105     NFCMMD = cmd;
106     for (i = 0; i < 10; i++);
107 }
108 
109 static void nand_addr(unsigned int addr)
110 {
111     unsigned int col  = addr % 2048;
112     unsigned int page = addr / 2048;
113     volatile int i;
114 
115     NFADDR = col & 0xff;
116     for (i = 0; i < 10; i++);
117     NFADDR = (col >> 8) & 0xff;
118     for (i = 0; i < 10; i++);
119     
120     NFADDR  = page & 0xff;
121     for (i = 0; i < 10; i++);
122     NFADDR  = (page >> 8) & 0xff;
123     for (i = 0; i < 10; i++);
124     NFADDR  = (page >> 16) & 0xff;
125     for (i = 0; i < 10; i++);    
126 }
127 
128 static void nand_wait_ready(void)
129 {
130     while (!(NFSTAT & 1));
131 }
132 
133 static unsigned char nand_data(void)
134 {
135     return NFDATA;
136 }
137 
138 void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len)
139 {
140     int col = addr % 2048;
141     int i = 0;
142         
143     /* 1. 选中 */
144     nand_select();
145 
146     while (i < len)
147     {
148         /* 2. 发出读命令00h */
149         nand_cmd(0x00);
150 
151         /* 3. 发出地址(分5步发出) */
152         nand_addr(addr);
153 
154         /* 4. 发出读命令30h */
155         nand_cmd(0x30);
156 
157         /* 5. 判断状态 */
158         nand_wait_ready();
159 
160         /* 6. 读数据 */
161         for (; (col < 2048) && (i < len); col++)
162         {
163             buf[i] = nand_data();
164             i++;
165             addr++;
166         }
167         
168         col = 0;
169     }
170 
171     /* 7. 取消选中 */        
172     nand_deselect();
173 }

  修改 borad/samdung/jz2440/ 目录下的 makefile:

  技术分享

2.2 去掉代码重定位

  去掉 -pie 选项:

  技术分享

  注释掉第82行:

  技术分享

2.3 修改代码链接地址

  Jz2440.h (include\configs) 

  技术分享

2.4 修改链接脚本文件

  U-boot.lds (arch\arm\cpu) 链接脚本的修改,本版本u-boot将一个文件夹下面的c文件都链接成一个.o文件,名字为built-in.o,所以我们直接写上built-in.o即可。

  技术分享

  技术分享

  将这两个built-in.o放入链接脚本当中:

  技术分享

2.5 修改 board_init_f

  在crt0.S中设置nand 启动的代码:

  技术分享

  这一段代码就是 nand 重定位代码了。CONFIG_SYS_TEXT_BASE 是自己设置的,可以自行设置大小。

  接下来的代码就是跳转到 board_init_f_mem 和 board_init_f 中执行初始化。

   init_sequence_f 链表中要注释掉下面两行,并更改:

  技术分享

2.6 修改重定位代码

  首先在board_init_f(Board_f.c (common) )添加返回函数:

  

 1 unsigned int board_init_f(ulong boot_flags)
 2 {
 3 
 4     gd->flags = boot_flags;
 5     gd->have_console = 0;
 6 
 7     if (initcall_run_list(init_sequence_f))
 8         hang();
 9 #if 0
10 #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && 11         !defined(CONFIG_EFI_APP)
12     /* NOTREACHED - jump_to_copy() does not return */
13     hang();
14 #endif
15 #endif
16     return (unsigned int)(gd->new_gd);  //添加的返回值,返回id供 board_init_r调用
17 }

  board_init_f 函数原型记得在 include/common中也修改。

  修改crt0.S 代码如下:

ENTRY(_main)

/*
 * Set up initial C runtime environment and call board_init_f(0).
 * 初始化C运行环境并且调用 board_init_f(0) 函数
 */

 /*
  * 初始化栈地址
  */
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
    ldr    sp, =(CONFIG_SPL_STACK)
#else
    /* Generic-asm-offsets.h (include\generated)
     * #define GENERATED_GBL_DATA_SIZE 192
     * JZ2440.h(include\config)
     * #define PHYS_SDRAM_1        0x30000000
     * #define CONFIG_SYS_SDRAM_BASE    PHYS_SDRAM_1
     * #define CONFIG_SYS_INIT_SP_ADDR    (CONFIG_SYS_SDRAM_BASE + 0x1000 - GENERATED_GBL_DATA_SIZE)
     * 
     * CONFIG_SYS_INIT_SP_ADDR = 0x30000000 + 0x1000 - 192(0xc0) = 0x30000f40
     */
    ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)        /* 设置CFIG_SYS_INIT_SP_ADDR定义的地址,include/configs/jz2440.h中定义 */
#endif
#if defined(CONFIG_CPU_V7M)    /* v7M forbids using SP as BIC destination */
    mov    r3, sp
    bic    r3, r3, #7
    mov    sp, r3
#else
    /* sp 的8字节对齐 */
    bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
#endif
    /* 设置nand 启动 */
    bl nand_init_ll    /* 跳转到borad/samsung/jz2440/init.c 中执行 nand_init_ll 函数 */
    
    mov r0, #0
    ldr r1, =(CONFIG_SYS_TEXT_BASE)    /*CONFIG_SYS_TEXT_BASE=0x33f00000 程序的链接地址*/
    ldr r2, =0x100000                /* 程序大小 */    
    bl copy_code_to_sdram            /* 拷贝代码到SDRAM */
    
    bl clear_bss                    /* 清除bss */

    ldr pc, =call_board_init_f            /* 执行第一阶段初始化 */

    bl call_board_init_r            /* 执行第二阶段代码 */

    adr lr, here                 /*设置返回地址为下面的here,重定位到sdram后返回here运行*/
    ldr r0, [r9, #GD_RELOC_OFF]     /* r0 = gd->reloc_off 取重定位地址偏移值 */
    add lr, lr, r0                /*返回地址加偏移地址等于重定位后在sdram中的here地址*/

here:        /*返回后跳到sdram中运行    */    
    /*
      * now relocate vectors
      */
    bl    relocate_vectors

    /* Set up final (full) environment */
    bl    c_runtime_cpu_setup    /* we still call old routine here */

    
call_board_init_f:
    mov    r0, sp                    /* r0 = sp */
    bl    board_init_f_mem        /*跳转到 board_init_f_mem 执行*/
    mov    sp, r0                    

    mov    r0, #0
    bl    board_init_f            /* 调用单板的初始化函数,跳转到 borad_init_f 处执行 */

call_board_init_r:
    ldr    r1, =CONFIG_SYS_TEXT_BASE
    /* call board_init_r */
    bl board_init_r    /* this is auto-relocated! */
ENDPROC(_main)

  here的代码一定不能注释掉,注释掉后就启动不了

2.7 去掉-pie选项

  如下图:

  技术分享

  技术分享

 三、编译烧写

  make CROSS_COMPILE=arm-2440-linux-gnueabi-

  技术分享

  生成的 u-boot.bin 有470K 左右。

  然后通过jtag 工具直接烧写进nand 的  0地址中,拨码开关拨到 nand 启动,显示如下:

  技术分享

 

 

  

 

 

  

u-boot移植(九)---代码修改---NAND