十七、u-boot 调试-- NAND FLASH 启动

17.1 启动原理

引导启动时,NAND Flash 存储器的开始 4K 字节将被加载到 Steppingstone 中并且执行加载到 Steppingstone 的引导代码。
通常引导代码会复制 NAND Flash 的内容到 SDRAM 中。通过使用硬件 ECC,有效地检查 NAND Flash 数据。
在复制完成的基础上,将在 SDRAM 中执行主程序。

17.2 编写代码

编写的 s3c2440 启动代码放在 board/samsung/jz2440 下,这是开发板特有的。

17.2.1 添加 nand 启动的 API 代码

在 samsung/board/jz2440 文件夹添加代码:

boot_from_nand.h

 1 #ifndef __BOOT_FROM_NAND_H
 2 #define __BOOT_FROM_NAND_H
 3 
 4 #define BOOT_TYPY_NAND      0
 5 #define BOOT_TYPY_NOR       1
 6 
 7 /* NAND FLASH控制器 */
 8 #define NFCONF (*((volatile unsigned long *)0x4E000000))        ///< nandflash 配置寄存器
 9 #define NFCONT (*((volatile unsigned long *)0x4E000004))        ///< nandflash 控制寄存器
10 #define NFCMMD (*((volatile unsigned char *)0x4E000008))        ///< nandflash 命令集寄存器
11 #define NFADDR (*((volatile unsigned char *)0x4E00000C))        ///< nandflash 地址集寄存器
12 #define NFDATA (*((volatile unsigned char *)0x4E000010))        ///< nandflash 数据寄存器
13 #define NFSTAT (*((volatile unsigned char *)0x4E000020))        ///< nandflash 运行状态寄存器
14 
15 #define TACLS   0
16 #define TWRPH0  1
17 #define TWRPH1  0
18 
19 /** bss 段首尾地址 */
20 extern char __bss_start[0];
21 extern char __bss_end[0];
22 
23 /** 重定位拷贝的起始和结束地址 */
24 extern char __image_copy_start[0];
25 extern char __image_copy_end[0];
26 
27 #endif

boot_from_nand.c

  1 #include "boot_from_nand.h"
  2 
  3 /** 片选信号操作 */
  4 static void nand_select(void)
  5 {
  6     /** 
  7      * NFCONT 寄存器的第 1 位控制片选信号 nFCE 
  8      * 此位为 0 使能片选, 为 1 禁止片选
  9      */
 10     NFCONT &= ~(1 << 1);
 11 }
 12 
 13 /** nand 发送命令 */
 14 static void nand_write_cmd(unsigned char cmd)
 15 {
 16     volatile int i;
 17     NFCMMD = cmd;
 18     for (i = 0; i < 10; i++);
 19 }
 20 
 21 /** nand 发送地址 */
 22 static void nand_write_addr(unsigned int addr)
 23 {
 24     unsigned int col  = addr % 2048;
 25     unsigned int page = addr / 2048;
 26     volatile int i;
 27 
 28     NFADDR = col & 0xff;
 29     for (i = 0; i < 10; i++);
 30     NFADDR = (col >> 8) & 0xff;
 31     for (i = 0; i < 10; i++);
 32 
 33     NFADDR  = page & 0xff;
 34     for (i = 0; i < 10; i++);
 35     NFADDR  = (page >> 8) & 0xff;
 36     for (i = 0; i < 10; i++);
 37     NFADDR  = (page >> 16) & 0xff;
 38     for (i = 0; i < 10; i++);
 39 }
 40 
 41 /** 等待 nand 处于空闲状态 */
 42 static void nand_wait_idle(void)
 43 {
 44     while (!(NFSTAT & 1));
 45 }
 46 
 47 /** 读取 nand 中的数据 */
 48 static unsigned char nand_read_data(void)
 49 {
 50     return NFDATA;
 51 }
 52 
 53 /** 取消片选 */
 54 static void nand_deselect(void)
 55 {
 56     NFCONT |= (1 << 1);
 57 }
 58 
 59 void boot_nand_read(unsigned int addr, unsigned char *buf, unsigned int len)
 60 {
 61     int col = addr % 2048;
 62     int i = 0;
 63 
 64     /* 1. 选中 */
 65     nand_select();
 66 
 67     while (i < len)
 68     {
 69         /* 2. 发出读命令00h */
 70         nand_write_cmd(0x00);
 71 
 72         /* 3. 发出地址(分5步发出) */
 73         nand_write_addr(addr);
 74 
 75         /* 4. 发出读命令30h */
 76         nand_write_cmd(0x30);
 77 
 78         /* 5. 判断状态 */
 79         nand_wait_idle();
 80 
 81         /* 6. 读数据 */
 82         for (; (col < 2048) && (i < len); col++)
 83         {
 84             buf[i] = nand_read_data();
 85             i++;
 86             addr++;
 87         }
 88 
 89         col = 0;
 90     }
 91 
 92     /* 7. 取消选中 */
 93     nand_deselect();
 94 }
 95 
 96 /* 清除 BSS */
 97 void boot_clear_bss(void)
 98 {
 99     int *pBssStart = __bss_start;
100     int *pBssEnd = __bss_end;
101 
102     for (; pBssStart < pBssEnd; pBssStart++)
103         *pBssStart = 0;
104 }
105 
106 /* 判定是否是nor启动 */
107 static int boot_type_check(void)
108 {
109     volatile int *p = (volatile int *)0;
110     int val;
111 
112     val = *p;
113     *p = 0x12345678;
114     if (*p == 0x12345678)
115     {
116         /* 写成功, 是nand启动 */
117         *p = val;
118         return BOOT_TYPY_NAND;
119     }
120     else
121     {
122         /* NOR不能像内存一样写 */
123         return BOOT_TYPY_NOR;
124     }
125 }
126 
127 
128 /* 拷贝代码到sdram */
129 void boot_copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
130 {
131     char *pCodeStart = __image_copy_start;
132     char *pCodeEnd   = __image_copy_end;
133     char *pSrc = (char *)0;
134     int i = 0;
135 
136     /* 如果是NOR启动 */
137     if (boot_type_check())
138     {
139         while (pCodeStart < pCodeEnd)
140         {
141             *pCodeStart = *pSrc;
142             pCodeStart++;
143             pSrc++;
144         }
145     }
146     else
147     {
148         boot_nand_read(0, (unsigned char *)pCodeStart, (unsigned int)(pCodeEnd - pCodeStart));
149     }
150 }
151 
152 static void nand_reset(void)
153 {
154     nand_select(); // 片选
155     nand_write_cmd(0xff); // 发送复位命令
156     nand_wait_idle();   // 等待空闲
157     nand_deselect();
158 }
159 
160 /** nand flash 初始化 */
161 void boot_nand_init(void)
162 {
163     /** 设置时序 */
164     NFCONF = (TACLS << 12) | (TWRPH0 << 8) |(TWRPH1 << 4);
165     /** 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
166     NFCONT = (1 << 4) | (1 << 1) |(1 << 0);
167 
168     /** 复位 */
169     nand_reset();
170 }

修改 Makefile:

 这里使用 extra-y 防止 jz2440 目录编译成一个 built-in.o,boot_from_nand.o 需要独立出来,需要添加到链接脚本中。

同样的 lowlevel_init 在重定位完成之前被调用,用于初始化SDRAM,但是该函数在 bin 文件中会被链接到了 4KB 之外,因此也需要单独编译,并在 链接脚本中添加

 17.2.2 重定位

前面已经说了 nand 中的前 4K 代码必须要拷贝到 芯片内部的 DRAM 中,所以必须要保证前 4K 代码必须包含重定位的代码,那么就需要对重定位进行修改,一个是保证 4K 代码包含启动代码,另一个是保证可以从 nand  启动。

代码的重定位要放在 SDRAM 初始化之后,nandflash 中的代码必须要拷贝到 SDRAM 中才能运行。

那么代码的修改就要从 cpu_init_crit(ubootarcharmcpuarm920tstart.S) 之后开始。

修改后,跳转到 _main 中去执行,里面做一些重定位判断,可以不影响操作,但是清除 BSS 那需要屏蔽掉:

 前面已经做过了 BSS 段的处理,所以这里不需要再做了。

17.2.3 修改链接脚本

/arch/arm/cpu/u-boot.lds

 17.2.4 配置重定位地址

为了不像从Nor flash启动时那样,针对不同的变量需要修改其在RAM中对应的地址,在从NAND flash启动时,我们在编译时直接加上在RAM中的偏移地址,使其编译之后的地址固定为将来在RAM中运行的地址。将链接地址确定为 0x33f00000,为u-boot镜像及其上面的内容保留1MB的空间

ubootincludeconfigsjz2440.h

 

 反汇编 u-boot,查看起始地址是否改变:arm-linux-objdump -D u-boot > u-boot.dis

可以看到起始地址已经改变

 17.2.5 去点 -pie 选项

uboot/arch/arm/config.mk

 17.2.6 去掉重定位方式的检查

检查用于ARM架构的u-boot的重定位方式,重定位必须是“相对的”,指的是动态链接的重定位方式。

将操作注释掉

 

17.2.6 设置重定位后的起始地址

u-boot 完成重定位后,要从 SRAM 中的 0x33f00000 处启动,因此要改 ubootarcharmlib elocate.S 的 relocate_vectors 向量地址:

 同时 board_init_f 中的 reserve_boot 函数的栈地址也需要改:

17.3 测试

17.3.1 nortflash 烧写测试

 17.3.2 nandflash 烧写测试

原文地址:https://www.cnblogs.com/kele-dad/p/12896258.html