uboot2009 nandflash移植

(参考文章)增加nand flash功能

(uboot分区参考):uboot环境变量与内核MTD分区关系

移植环境

  • 主机环境:VMare下RHLE6 ,1G内存。
  • 编译编译环境:arm-linux-gcc v4.3.2
  • 开发板:FL2440,4M nor flash,256M nand flash。
  • u-boot版本:u-boot-2009.08

首先注意一个问题:

先请大家看《第五章 存储器控制器中》的Figure 5-1. S3C2440A Memory Map after Reset(也就是那个映射图),从理论上来讲,对于0x40000000以后的内存,只有在Nor boot的时候才存在;而在nandboot 的时候他被映射到了0x00000000,在0x40000000以后不存在内存。如果我们在启动的时候,将一些特定的数据写入0x40000000~0x40001000之间,那么按照数据手册上的说法,如果回读的结果和写入的一致说明是nor boot,否则就是nand boot! 这种办法理论上是通的,但是实际上,那个图是错的!!通过我的实验,正真的映射图如下:

从上图我们可以看出,无论是Nor boot还是nand boot ,这4K的内部SRAM都被映射到了0x40000000,而在nand boot的时候,这块内存同时还被映射到了0x00000000。那么一开始提出的办法就不可行了,而且在nand boot 的时候,写入0x40000000~0x40001000还会破坏自身的程序。

  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双启动。下面我们看看这两种启动的映射关系。

同时我们可以看到: 总线宽度和等待控制寄存器:

在系统重启时会扫描BWSCON的状态,而BWSCON的其他位的初始状态都是0,只有DW0(BWSCON[2:1])的值由OM[1:0]来决定,通过上面的2个图我们可以发现,我们可以通过判断BWSCON的第2位、第3位   {DW0(BWSCON[2:1])}的值,判断是Nor flash启动还是Nand Flash启动。

可以启动代码之前添加如下代码,来判断是Nor flash启动还是Nand Flash启动。

 # define BWSCON   0x48000000 
        ldr r0,=BWSCON
        ldr r0,[r0]
        and r0,r0,#6
        cmp  r0, #0  
        bne  relocate

 ///////////////////////////////////////////////////
     //nand_boot
  //Nand
搬移代码
////////////////////////////////////////////////////

  relocate
       //nor_boot
      //Nor
搬移代码
////////////////////////////////////////////////////

有了上面这段代码,就可以实现双启动了,只要再适当的添加对应的功能我们的uboot就完成了

  1. 为u-boot增加对nand flash支持实际操作

2.1 修改代码重定向部分,增加Nor flash 和Nand flash 双启动

修改cpu/arm920t/start.S文件,为使u-bootNand Flash启动,需要将下面注释掉的CPUDRAM初始化部分还原。

vim打开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

  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 -------------*/

  1. 如果不是在代码当前位置不再内存中,就判断启动的FlashNand 或者Nor

/*------------ Check the boot flash begain --------------*/

# define BWSCON 0x48000000

ldr r0,=BWSCON

ldr r0,[r0]

ands r0,r0,#6

cmp r0, #0

bne relocate

/*-----------check the boot flash end-------------------*/

  1. 如果判断是在Nand Flash中启动的话,那么nand  Flash搬移代码如下:

定义u-bootnand 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 ---------------*/

  1. 如果判断是在Nor  Flash中启动的话,那么nor  Flash搬移代码如下:

// copy U-Boot to RAM form Nor Flash

/*---------------NOR BOOT start------------------*/

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

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

 

  1. 在上面添加的代码中有一个跳转:bl nand_read_ll ,它跳入是新增的C 语言文件board/fl2440/nand_read.c中的函数,这个文件原本是用vivi 的代码,后来经过openmoko 的修改,并支持不同的Nand Flash 芯片,我又这里多加了几个个芯片ID以支持所有fl2440 的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 <hwang@mizi.com>

* Date : $Date: 2004/02/04 10:37:37 $

*

* u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc.

* Author: Harald Welte <laforge@openmoko.org>

*/

#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_FL2440)

/* 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 /fl2440/目录下。

注意:上面这段代码中对Nand进行寻址的部分,这跟具体的Nand Flash的寻址方式有关。

 

根据我们开发板上的Nand Flash(K9F2G08x0a)数据手册得知,片内寻址是采用28位地址形式。从第0位开始分五次通过I/O0I/O7进行传送,并进行片内寻址。具体含义和结构图如下(相关概念参考Nand数据手册)

0-11位:Y-Buffers偏移地址

12-28位:X-Buffers偏移地址

2.3. 在board/fl2440/Makefile中添加nand_read.c的编译选项,使他编译到u-boot中,修改后代码如下:
include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).a
COBJS :=  nand_read.o fl2440.o flash.o
SOBJS := lowlevel_init.o

2.4. 在fl2440.h头文件中加入Nand要用到的宏和寄存器的定义。

用vim打开include/configs/fl2440.h头文件,定位到文件末尾处加入下列代码:

/*-----------------------------------------------------------------------

* NAND flash settings

*/

#define CONFIG_S3C2410_NAND_SKIP_BAD 1

 

2.5. 在cpu/arm920t/u-boot.lds中添加下面两行代码,主要目的是防止编译器把我们自己添加的用于nandboot的子函数放到4K之后,否则是无法启动的,修改后代码如下:
 
.text :
 {

cpu/arm920t/start.o (.text)
     board/samsung/fl2440/lowlevel_init.o (.text)

board/samsung/fl2440/nand_read.o (.text)

*(.text)
 }

现在的Nand还不能做任何事情,而且也没有显示有关Nand的任何信息,所以只能说明上面的这些步骤只是完成了Nand移植的Stage1部分。下面我们来添加我们开发板上的Nand Flash(K9F2G08x0A)的Stage2部分的有关操作支持。

  1. Uboot第二间断nandflash移植

在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 */

 

  1. 在fl2440.h里添加nand_flash相关宏定义


    打开include/configs/fl2440.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

u-boot在默认的情况下把环境变量都是保存到Nor Flash中的,所以我们要修改代码,让它保存到Nand中,如下:

打开include/configs/fl2440.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!

posted on 2012-11-23 13:51  WithYouTh  阅读(398)  评论(0编辑  收藏  举报