1,主机环境:VMare下CentOS 5.5 ,1G内存。
2,集成开发环境:Elipse IDE
3,编译编译环境:arm-linux-gcc v4.4.3,arm-none-eabi-gcc v4.5.1。
4,开发板:mini2440,2M nor flash,128M nand flash。
5,u-boot版本:u-boot-2009.08
6,参考文章:
http://blogold.chinaunix.net/u3/101649/showart.php?id=2105215
http://blog.chinaunix.net/space.php?uid=23787856&do=blog&id=115382
http://blogimg.chinaunix.net/blog/upfile2/100811115954.pdf
目前u-boot中还没有对2440上Nand Flash的支持,也就是说要想u-boot从Nand Flash上启动得自己去实现了。在做u-boot移植的时候,多数人使用的是Nand flash启动或Nar Flash启动。这样u-boot就只能在Nand flash或Nor flash。那么我们如何让我们的u-boot在Nand flash或Nor flash都能使用。
3.1,Nand flash或Nor flash双启动原理
首先,看一下我们熟悉的u-boot启动的时候执行的一段程序,这段程序一般存放在Nand flash中或Nor flash中。我们所说的Nand flash启动或Nor flash启动主要是涉及到一段搬移代码。这段搬移代码的功能是u-boot自己把自己搬移到内存中执行。如下是Nor flash启动中的这段搬移代码(这里以s3c2410为例)
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
#endif
上面这段代码就是把u-boot搬移到内存。而不同的启动方式区别也就在这段代码上,如果我们这里是Nand flash启动的话我们也需要写相同功能的代码,不同的是对于Nand的操作和Nor的操作是完全不同的,选择Nor flash启动是将Nor flash映射到片选0上也就是0x0地址而选择Nand flash启动则是将CPU的片内RAM(4K)映射到0地址,通过Nand flash控制器操作Nand flash。我们这里讨论如何实现Nand 和 Nor双启动。下面我们看看这两种启动的映射关系。
# define BWSCON 0x48000000
ldr r0,=BWSCON
ldr r0,[r0]
and r0,r0,#6
cmp r0, #0
bne relocate
3.2,为u-boot增加对nand flash支持实际操作
【1】修改代码重定向部分,增加Nor flash 和Nand flash 双启动
修改cpu/arm920t/start.S文件,为使u-boot从Nand Flash启动,需要将下面注释掉的CPU和DRAM初始化部分还原。
用gedit打开cpu/arm920t/start.S,定位到199行附近,找到如下代码
//#ifndef CONFIG_SKIP_LOWLEVEL_INIT
//bl cpu_init_crit
//#endif
将注释掉的这段代码恢复,修改如下:
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
Tekkaman Ninja从2009.08 开始就在启动时增加了启动时检测自身是否已经在SDRAM中(通过OpenJTAG载入),以及芯片是Norboot还是Nandboot的机制,来决定代码重定向的方式,使得编译出的bin文件可以同时烧入Nand Flash和Nor flash,以及被OpenJTAG载入进行调试。至于这部分的原理,在Tekkaman Ninja的博客文章《在U-boot下实现自动识别启动Flash的原理(针对S3C24x0)》中有详细叙述。这部分代码修改后结果如下:
(1)判断当前代码位置,如果在内存,直接跳到stack_setup
//#ifndef CONFIG_SKIP_RELOCATE_UBOOT
//relocate: /* relocate U-Boot to RAM */
/***************** Check the code position begain*******************************/
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
/****************** Check the code position end ********************************/
(2)如果不是在代码当前位置不再内存中,就判断启动的Flash:Nand 或者Nor
/***************** Check the boot flash begain **********************************/
# define BWSCON 0x48000000
ldr r0,=BWSCON
ldr r0,[r0]
ands r0,r0,#6
cmp r0, #0
bne relocate
/* recovery */
ldr r0, =(0xdeadbeef)
ldr r1, =( (4<<28)|(3<<4)|(3<<2) )
str r0, [r1]
/***************** check the boot flash end ************************************/
(3)如果判断是在Nand Flash中启动的话,那么nand Flash搬移代码如下:
定义u-boot在nand flash中存放的长度为#define LENGTH_UBOOT 0x60000,可以方便修改u-boot因为裁剪和增添大小的改变而占的长度。
// copy U-Boot to RAM form Nand Flash
/***************** NAND BOOT start *************************************************/
#define LENGTH_UBOOT 0x60000
#define NAND_CTL_BASE 0x4E000000
#ifdef CONFIG_S3C2440
/* Offset */
#define oNFCONF 0x00
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFSTAT 0x20
@ reset NAND
mov r1, #NAND_CTL_BASE
ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]
ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control
str r2, [r1, #oNFCONT]
ldr r2, [r1, #oNFCONT]
ldr r2, =(0x6) @ RnB Clear
str r2, [r1, #oNFSTAT]
ldr r2, [r1, #oNFSTAT]
mov r2, #0xff @ RESET command
strb r2, [r1, #oNFCMD]
mov r3, #0 @ wait
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1
nand2:
ldr r2, [r1, #oNFSTAT] @ wait ready
tst r2, #0x4
beq nand2
ldr r2, [r1, #oNFCONT]
orr r2, r2, #0x2 @ Flash Memory Chip Disable
str r2, [r1, #oNFCONT]
@ get read to call C functions (for nand_read())
ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @ no previous frame, so fp=0
@ copy U-Boot to RAM
ldr r0, =TEXT_BASE
mov r1, #0x0
mov r2, #LENGTH_UBOOT
bl nand_read_ll
tst r0, #0x0
beq ok_nand_read
bad_nand_read:
loop2:
b loop2 @ infinite loop
ok_nand_read:
@ verify
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq stack_setup
bne go_next
notmatch:
loop3:
b loop3 @ infinite loop
#endif
#ifdef CONFIG_S3C2410
/* Offset */
#define oNFCONF 0x00
#define oNFCMD 0x04
#define oNFSTAT 0x10
@ reset NAND
mov r1, #NAND_CTL_BASE
ldr r2, =0xf830 @ initial value
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]
bic r2, r2, #0x800 @ enable chip
str r2, [r1, #oNFCONF]
mov r2, #0xff @ RESET command
strb r2, [r1, #oNFCMD]
mov r3, #0 @ wait
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1
nand2:
ldr r2, [r1, #oNFSTAT] @ wait ready
tst r2, #0x1
beq nand2
ldr r2, [r1, #oNFCONF]
orr r2, r2, #0x800 @ disable chip
str r2, [r1, #oNFCONF]
@ get read to call C functions (for nand_read())
ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @ no previous frame, so fp=0
@ copy U-Boot to RAM
ldr r0, =TEXT_BASE
mov r1, #0x0
mov r2, #LENGTH_UBOOT
bl nand_read_ll
tst r0, #0x0
beq ok_nand_read
bad_nand_read:
loop2:
b loop2 @ infinite loop
ok_nand_read:
@ verify
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq stack_setup
bne go_next
notmatch:
loop3:
b loop3 @ infinite loop
#endif
/***************** NAND BOOT end *************************************************/
(4)如果判断是在Nor Flash中启动的话,那么nor Flash搬移代码如下:
// copy U-Boot to RAM form Nor Flash
/***************** NOR BOOT start *************************************************/
relocate: /* relocate U-Boot to RAM */
/*********** CHECK_FOR_MAGIC_NUMBER***************/
ldr r1, =(0xdeadbeef)
cmp r0, r1
bne loop3
/*********** CHECK_FOR_MAGIC_NUMBER***************/
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
//#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
/***************** NOR BOOT end********************************************/
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo
... ...
【2】在上面添加的代码中有一个跳转:bl nand_read_ll ,它跳入是新增的C 语言文件board/samsung/mini2440/nand_read.c中的函数,这个文件原本是用vivi 的代码,后来经过openmoko 的修改,并支持不同的Nand Flash 芯片,我又这里多加了几个个芯片ID以支持所有mini2440 的Nand Flash。代码如下:
/*
* nand_read.c: Simple NAND read functions for booting from NAND
*
* This is used by cpu/arm920/start.S assembler code,
* and the board-specific linker script must make sure this
* file is linked within the first 4kB of NAND flash.
*
* Taken from GPLv2 licensed vivi bootloader,
* Copyright (C) 2002 MIZI Research, Inc.
*
* Author: Hwang, Chideok <[email protected]>
* Date : $Date: 2004/02/04 10:37:37 $
*
* u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.
* Author: Harald Welte <[email protected]>
*/
#include <common.h>
#include <linux/mtd/nand.h>
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGw(x) (*(volatile unsigned short *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000
#if defined(CONFIG_S3C2410)
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCMD __REGb(NF_BASE + 0x4)
#define NFADDR __REGb(NF_BASE + 0x8)
#define NFDATA __REGb(NF_BASE + 0xc)
#define NFSTAT __REGb(NF_BASE + 0x10)
#define NFSTAT_BUSY 1
#define nand_select() (NFCONF &= ~0x800)
#define nand_deselect() (NFCONF |= 0x800)
#define nand_clear_RnB() do {} while (0)
#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCONT __REGi(NF_BASE + 0x4)
#define NFCMD __REGb(NF_BASE + 0x8)
#define NFADDR __REGb(NF_BASE + 0xc)
#define NFDATA __REGb(NF_BASE + 0x10)
#define NFDATA16 __REGw(NF_BASE + 0x10)
#define NFSTAT __REGb(NF_BASE + 0x20)
#define NFSTAT_BUSY 1
#define nand_select() (NFCONT &= ~(1 << 1))
#define nand_deselect() (NFCONT |= (1 << 1))
#define nand_clear_RnB() (NFSTAT |= (1 << 2))
#endif
static inline void nand_wait(void)
{
int i;
while (!(NFSTAT & NFSTAT_BUSY))
for (i=0; i<10; i++);
}
struct boot_nand_t {
int page_size;
int block_size;
int bad_block_offset;
// unsigned long size;
};
#if 0
#if defined(CONFIG_S3C2410) || defined(CONFIG_MINI2440)
/* configuration for 2410 with 512byte sized flash */
#define NAND_PAGE_SIZE 512
#define BAD_BLOCK_OFFSET 5
#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
#define NAND_BLOCK_SIZE 0x4000
#else
/* configuration for 2440 with 2048byte sized flash */
#define NAND_5_ADDR_CYCLE
#define NAND_PAGE_SIZE 2048
#define BAD_BLOCK_OFFSET NAND_PAGE_SIZE
#define NAND_BLOCK_MASK (NAND_PAGE_SIZE - 1)
#define NAND_BLOCK_SIZE (NAND_PAGE_SIZE * 64)
#endif
/* compile time failure in case of an invalid configuration */
#if defined(CONFIG_S3C2410) && (NAND_PAGE_SIZE != 512)
#error "S3C2410 does not support nand page size != 512"
#endif
#endif
static int is_bad_block(struct boot_nand_t * nand, unsigned long i)
{
unsigned char data;
unsigned long page_num;
nand_clear_RnB();
if (nand->page_size == 512) {
NFCMD = NAND_CMD_READOOB; /* 0x50 */
NFADDR = nand->bad_block_offset & 0xf;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;
} else if (nand->page_size == 2048) {
page_num = i >> 11; /* addr / 2048 */
NFCMD = NAND_CMD_READ0;
NFADDR = nand->bad_block_offset & 0xff;
NFADDR = (nand->bad_block_offset >> 8) & 0xff;
NFADDR = page_num & 0xff;
NFADDR = (page_num >> 8) & 0xff;
NFADDR = (page_num >> 16) & 0xff;
NFCMD = NAND_CMD_READSTART;
} else {
return -1;
}
nand_wait();
data = (NFDATA & 0xff);
if (data != 0xff)
return 1;
return 0;
}
static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr)
{
unsigned short *ptr16 = (unsigned short *)buf;
unsigned int i, page_num;
nand_clear_RnB();
NFCMD = NAND_CMD_READ0;
if (nand->page_size == 512) {
/* Write Address */
NFADDR = addr & 0xff;
NFADDR = (addr >> 9) & 0xff;
NFADDR = (addr >> 17) & 0xff;
NFADDR = (addr >> 25) & 0xff;
} else if (nand->page_size == 2048) {
page_num = addr >> 11; /* addr / 2048 */
/* Write Address */
NFADDR = 0;
NFADDR = 0;
NFADDR = page_num & 0xff;
NFADDR = (page_num >> 8) & 0xff;
NFADDR = (page_num >> 16) & 0xff;
NFCMD = NAND_CMD_READSTART;
} else {
return -1;
}
nand_wait();
#if defined(CONFIG_S3C2410)
for (i = 0; i < nand->page_size; i++) {
*buf = (NFDATA & 0xff);
buf++;
}
#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442)
for (i = 0; i < (nand->page_size>>1); i++) {
*ptr16 = NFDATA16;
ptr16++;
}
#endif
return nand->page_size;
}
static unsigned short nand_read_id(void)
{
unsigned short res = 0;
NFCMD = NAND_CMD_READID;
NFADDR = 0;
res = NFDATA;
res = (res << 8) | NFDATA;
return res;
}
extern unsigned int dynpart_size[];
/* low level nand read function */
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
unsigned short nand_id;
struct boot_nand_t nand;
/* chip Enable */
nand_select();
nand_clear_RnB();
for (i = 0; i < 10; i++)
;
nand_id = nand_read_id();
if (0) { /* dirty little hack to detect if nand id is misread */
unsigned short * nid = (unsigned short *)0x31fffff0;
*nid = nand_id;
}
if (nand_id == 0xec76 /* Samsung K91208 */
||nand_id == 0xad76 ) { /*Hynix HY27US08121A*/
nand.page_size = 512;
nand.block_size = 16 * 1024;
nand.bad_block_offset = 5;
// nand.size = 0x4000000;
} else if (nand_id == 0xecf1 /* Samsung K9F1G08U0B */
||nand_id == 0xecda /* Samsung K9F2G08U0B */
||nand_id == 0xecd3 ) { /* Samsung K9K8G08 */
nand.page_size = 2048;
nand.block_size = 128 * 1024;
nand.bad_block_offset = nand.page_size;
// nand.size = 0x8000000;
} else {
return -1; // hang
}
if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1))))
return -1; /* invalid alignment */
for (i=start_addr; i < (start_addr + size);) {
#ifdef CONFIG_S3C2410_NAND_SKIP_BAD
//if (i & (nand.block_size-1)== 0) {//warning: suggest parentheses around comparison in operand of '&'
if ((i & (nand.block_size-1))== 0) {
if (is_bad_block(&nand, i) ||
is_bad_block(&nand, i + nand.page_size)) {
/* Bad block */
i += nand.block_size;
size += nand.block_size;
continue;
}
}
#endif
j = nand_read_page_ll(&nand, buf, i);
i += j;
buf += j;
}
/* chip Disable */
nand_deselect();
return 0;
}
然后保存为nand_read.c,还要记得路径是在board/samsung/mini2440/目录下。
注意:上面这段代码中对Nand进行寻址的部分,这跟具体的Nand Flash的寻址方式有关。根据我们开发板上的Nand Flash(K9F1G08U0C)数据手册得知,片内寻址是采用27位地址形式。从第0位开始分四次通过I/O0-I/O7进行传送,并进行片内寻址。具体含义和结构图如下(相关概念参考Nand数据手册):
0-11位:Y-Buffers偏移地址
12-27位:X-Buffers偏移地址
【3】在board/samsung/mini2440/Makefile中添加nand_read.c的编译选项,使他编译到u-boot中,修改后代码如下:
include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).a
COBJS := nand_read.o mini2440.o flash.o
SOBJS := lowlevel_init.o
【4】在mini2440.h头文件中加入Nand要用到的宏和寄存器的定义。
用gedit打开include/configs/mini2440.h头文件,定位到文件末尾处加入下列代码:
/*-----------------------------------------------------------------------
* NAND flash settings
*/
#define CONFIG_S3C2410_NAND_SKIP_BAD 1
【5】在cpu/arm920t/u-boot.lds中添加下面两行代码,主要目的是防止编译器把我们自己添加的用于nandboot的子函数放到4K之后,否则是无法启动的,修改后代码如下:
.text :
{
cpu/arm920t/start.o (.text)
board/samsung/mini2440/lowlevel_init.o (.text)
board/samsung/mini2440/nand_read.o (.text)
*(.text)
}
3.3,重新编译
这里发生一个错误,错误原因是有一个变量没有定义,这个错误发生在【1】修改代码重定向部分,增加Nor flash 和Nand flash 双启动,错误提示信息如下:
Error: Internal_relocation (type 182) not fixed up (OFFSET_IMM)
编译 start.S 文件时出错。错误位置
340 @ get read to call C functions (for nand_read())
341 ldr sp, DW_STACK_START @ setup stack pointer
342 mov fp, #0 @ no previous frame, so fp=0
反复排查问题,原来宏DW_STACK_START 原作者在文章中没有贴出定义,加上以下代码在cpu/arm920t/start.S的459行附件
ldrpc, _start_armboot
_start_armboot: .word start_armboot
#define STACK_BASE 0x33f00000
#define STACK_SIZE 0x10000
.align 2
DW_STACK_START: .wordSTACK_BASE+STACK_SIZE-4
重新编译,成功,编译成功后生成u-boot.bin文件。下载时先将mini2440开发板调到Nor启动档,利用supervivi的a命令将u-boot.bin下载到开发板的Nand Flash中,再把开发板调到Nand启动档,打开电源就从Nand Flash启动了,启动结果如下:
... ...
Enter your selection: ?
U-Boot 2009.08 ( 5鏈?06 2011 - 14:17:44)
DRAM: 64 MB
Flash: 2 MB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
[u-boot@MINI2440]#nand info
Unknown command nand' - try 'help'
[u-boot@MINI2440]#
从上面的运行结果看,显然现在的Nand还不能做任何事情,而且也没有显示有关Nand的任何信息,所以只能说明上面的这些步骤只是完成了Nand移植的Stage1部分。下面我们来添加我们开发板上的Nand Flash(K9F1G08U0B)的Stage2部分的有关操作支持。
3.4,在U-boot 启动的第一阶段,初始化了Nand Flash 控制器。但到第二阶段start_armboot函数还是会再次初始化Nand Flash 控制器。因为第二阶段和第一阶段的代码基本是独立的,第一阶段的代码基本只起到代码重定位的作用,到了第二阶段才是真正U-boot 的开始,以前的初始化过程还会重做一遍,比如始化Nand Flash 控制器、CPU 频率等。因为 S3C2440 和S3C2410 之间的很大差别就是:S3C2410 的Nand Flash 控制器只支持512B+16B 的Nand Flash,而S3C2440 还支持2KB+64B 的大容量Nand Flash。所以在Nand Flash 控制器上寄存器和控制流程上的差别很明显,底层驱动代码的修改也是必须的。具体的差别还是需要对比芯片数据手册的,下面我们结合代码来分析一下u-boot在第二阶段的执行流程:
<1>.lib_arm/board.c文件中的start_armboot函数调用了drivers/mtd/nand/nand.c文件中的nand_init函数,如下:
#if defined(CONFIG_CMD_NAND) //可以看到CONFIG_CMD_NAND宏决定了Nand的初始化
puts ("NAND: ");
nand_init();
#endif
<2>.nand_init调用了同文件下的nand_init_chip函数;
<3>.nand_init_chip函数调用drivers/mtd/nand/s3c2410_nand.c文件下的board_nand_init函数,然后再调用drivers/mtd/nand/nand_base.c函数中的nand_scan函数;
<4>.nand_scan函数调用了同文件下的nand_scan_ident函数等。
【1】Nand Flash 相关代码的修改
打开/drivers/mtd/nand/s3c2410_nand.c,定位到37行,修改如下:
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000
#if defined(CONFIG_S3C2410)
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCMD __REGb(NF_BASE + 0x4)
... ...
#define S3C2410_ADDR_NALE 4
#define S3C2410_ADDR_NCLE 8
#endif
#if defined(CONFIG_S3C2440)
#define S3C2410_ADDR_NALE 0x08
#define S3C2410_ADDR_NCLE 0x0c
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCONT __REGb(NF_BASE + 0x4)
#define NFCMD __REGb(NF_BASE + 0x8)
#define NFADDR __REGb(NF_BASE + 0xc)
#define NFDATA __REGb(NF_BASE + 0x10)
#define NFMECCD0 __REGb(NF_BASE + 0x14)
#define NFMECCD1 __REGb(NF_BASE + 0x18)
#define NFSECCD __REGb(NF_BASE + 0x1c)
#define NFSTAT __REGb(NF_BASE + 0x20)
#define NFESTAT0 __REGb(NF_BASE + 0x24)
#define NFESTAT1 __REGb(NF_BASE + 0x28)
#define NFMECC0 __REGb(NF_BASE + 0x2c)
#define NFMECC1 __REGb(NF_BASE + 0x30)
#define NFSECC __REGb(NF_BASE + 0x34)
#define NFSBLK __REGb(NF_BASE + 0x38)
#define NFEBLK __REGb(NF_BASE + 0x3c)
#define NFECC0 __REGb(NF_BASE + 0x2c)
#define NFECC1 __REGb(NF_BASE + 0x2d)
#define NFECC2 __REGb(NF_BASE + 0x2e)
#define S3C2410_NFCONT_EN (1<<0)
#define S3C2410_NFCONT_INITECC (1<<4)
#define S3C2410_NFCONT_nFCE (1<<1)
#define S3C2410_NFCONT_MAINECCLOCK (1<<5)
#define S3C2410_NFCONF_TACLS(x) ((x)<<12)
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<8)
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<4)
#endif
ulong IO_ADDR_W = NF_BASE;
static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
//struct nand_chip *chip = mtd->priv;
DEBUGN("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
if (ctrl & NAND_CTRL_CHANGE) {
//ulong IO_ADDR_W = NF_BASE;//应注释掉这个局部变量否则找不到ID "No NAND device found!!!"
IO_ADDR_W = NF_BASE;
if (!(ctrl & NAND_CLE))
IO_ADDR_W |= S3C2410_ADDR_NCLE;
if (!(ctrl & NAND_ALE))
IO_ADDR_W |= S3C2410_ADDR_NALE;
//chip->IO_ADDR_W = (void *)IO_ADDR_W;
#if defined(CONFIG_S3C2410)
if (ctrl & NAND_NCE)
NFCONF &= ~S3C2410_NFCONF_nFCE;
else
NFCONF |= S3C2410_NFCONF_nFCE;
#endif
#if defined(CONFIG_S3C2440)
if (ctrl & NAND_NCE)
NFCONT &= ~S3C2410_NFCONT_nFCE;
else
NFCONT |= S3C2410_NFCONT_nFCE;
#endif
}
if (cmd != NAND_CMD_NONE)
//writeb(cmd, chip->IO_ADDR_W);
writeb(cmd, (void *)IO_ADDR_W);
}
... ...
#ifdef CONFIG_S3C2410_NAND_HWECC
void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
DEBUGN("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
#if defined(CONFIG_S3C2410)
NFCONF |= S3C2410_NFCONF_INITECC;
#endif
#if defined(CONFIG_S3C2440)
NFCONT |= S3C2410_NFCONT_INITECC;
#endif
}
... ...
#endif
int board_nand_init(struct nand_chip *nand)
{
u_int32_t cfg;
u_int8_t tacls, twrph0, twrph1;
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
DEBUGN("board_nand_init()\n");
clk_power->CLKCON |= (1 << 4);
/* initialize hardware */
#if defined(CONFIG_S3C2410)
twrph0 = 3; twrph1 = 0; tacls = 0;
cfg = S3C2410_NFCONF_EN;
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
NFCONF = cfg;
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e00000c;
#endif
#if defined(CONFIG_S3C2440)
twrph0 = 4; twrph1 = 2; tacls = 0;
cfg = 0;
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
NFCONF = cfg;
NFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0);
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;
#endif
/* read_buf and write_buf are default */
/* read_byte and write_byte are default */
【2】在mini2440.h里添加nand_flash相关宏定义
打开include/configs/mini2440.h,定位到98行附近,加入下列代码:
/*
* Command line configuration.
*/
#include <config_cmd_default.h>
#define CONFIG_CMD_CACHE
#define CONFIG_CMD_DATE
#define CONFIG_CMD_ELF
#define CONFIG_CMD_NAND
#define CONFIG_CMD_JFFS2 /* JFFS2 Support*/
... ...
在文件末尾处加入下列代码:
/*-----------------------------------------------------------------------
* NAND flash settings
*/
#if defined(CONFIG_CMD_NAND)
#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_NAND_BASE 0x4E000000
#define CONFIG_SYS_MAX_NAND_DEVICE 1 /* Max number of NAND devices */
#define SECTORSIZE 512
#define SECTORSIZE_2K 2048
#define NAND_SECTOR_SIZE SECTORSIZE
#define NAND_SECTOR_SIZE_2K SECTORSIZE_2K
#define NAND_BLOCK_MASK 511
#define NAND_BLOCK_MASK_2K 2047
#define NAND_MAX_CHIPS 1
#define CONFIG_MTD_NAND_VERIFY_WRITE
#define CONFIG_SYS_64BIT_VSPRINTF /* needed for nand_util.c */
#endif /* CONFIG_CMD_NAND */
#define CONFIG_S3C2410_NAND_SKIP_BAD 1
3.5,重新编译,按上面3.3中方法下载,运行结果如下:
Enter your selection: ?
U-Boot 2009.08 ( 5鏈?06 2011 - 19:52:47)
DRAM: 64 MB
Flash: 2 MB
NAND: 128 MiB
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
[u-boot@MINI2440]# nand info
Device 0: NAND 128MiB 3,3V 8-bit, sector size 128 KiB
[u-boot@MINI2440]# saveenv
Saving Environment to Flash...
Un-Protected 16 sectors
Erasing Flash...Erasing sector 64 ...
从上面输出信息可以看到保存环境变量并没有成功,而且它是将把环境变量保存到Flash即Nor flash中,显然这不正确,我们是要保存到Nand中。原来,u-boot在默认的情况下把环境变量都是保存到Nor Flash中的,所以我们要修改代码,让它保存到Nand中,如下:
打开include/configs/mini2440.h,定位到193行附近,注释掉下列代码:
/* timeout values are in ticks */
#define CONFIG_SYS_FLASH_ERASE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Erase */
#define CONFIG_SYS_FLASH_WRITE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Write */
//#define CONFIG_ENV_IS_IN_FLASH 1
//#define CONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */
然后加入下列代码:
/*-----------------------------------------------------------------------
* NAND flash settings
*/
#define CONFIG_ENV_IS_IN_NAND 1
#define CONFIG_ENV_OFFSET 0x40000 //将环境变量保存到nand中的0x40000位置必,须在块的起始位置
#define CONFIG_ENV_SIZE 0x20000 /*必须为块大小的整数倍 , 否则会提示下面的信息,将擦除整个块*/
#if defined(CONFIG_CMD_NAND)
Warning: Erase size 0x00010000 smaller than one erase block 0x00020000
Erasing 0x00020000 instead
NAND 128MiB 3,3V 8-bit: MTD Erase failure: -22
Writing to Nand... FAILED!
然后保存,重新编译、拨到nor 档下载,在拨到nand 档上电运行:
Enter your selection: ?
U-Boot 2009.08 ( 5鏈?06 2011 - 22:30:25)
DRAM: 64 MB
Flash: 2 MB
NAND: 128 MiB
*** Warning - bad CRC or NAND, using default environment
In: serial
Out: serial
Err: serial
[u-boot@MINI2440]# saveenv
Saving Environment to NAND...
Erasing Nand...
Erasing at 0x4000000000002 -- 0% complete.
Writing to Nand... done
[u-boot@MINI2440]#
可以看到环境变量保存成功,将开发板重新上电后不会再有bad CRC告警,nand flash 移植成功。
接下来将进入u-boot的第四阶段,为u-boot-2009.08增加网卡DM9000驱动支持。
有时间要研究代码呀,一定要,待续。。。。。