Nandfalsh移植
1.在cpu/s3c64xx/s3c6410/下新建nand.c
2.在nand.c上添加board_nand_init()实现nand_chip的初始化功能
3.添加初始化函数
4.在include/configs/smdk6410.h上定义相关宏
完成上述移植后,实际上启动后的uboot中的nand命令是通过include/nand.h实现的
------------------------------------------------------------------------------------------------------------------------------------分割线---------------------------------------------------------------------------------------------
在这前先定义nand的一些硬件地址
在S3C6410.C中
/*
?* Nand flash controller
?*/
#define ELFIN_NAND_BASE?? ??? ?0x70200000
#define NFCONF_OFFSET?????????? 0x00
#define NFCONT_OFFSET?????????? 0x04
#define NFCMMD_OFFSET?????????? 0x08
#define NFADDR_OFFSET?????????? 0x0c
#define NFDATA_OFFSET?? ??? ?0x10
#define NFMECCDATA0_OFFSET????? 0x14
#define NFMECCDATA1_OFFSET????? 0x18
#define NFSECCDATA0_OFFSET????? 0x1c
#define NFSBLK_OFFSET?????????? 0x20
#define NFEBLK_OFFSET?????????? 0x24
#define NFSTAT_OFFSET?????????? 0x28
#define NFESTAT0_OFFSET???????? 0x2c
#define NFESTAT1_OFFSET???????? 0x30
#define NFMECC0_OFFSET????????? 0x34
#define NFMECC1_OFFSET????????? 0x38
#define NFSECC_OFFSET?????????? 0x3c
#define NFMLCBITPT_OFFSET?????? 0x40
#define NF8ECCERR0_OFFSET?? ?0x44
#define NF8ECCERR1_OFFSET?? ?0x48
#define NF8ECCERR2_OFFSET?? ?0x4c
#define NFM8ECC0_OFFSET?? ??? ?0x50
#define NFM8ECC1_OFFSET?? ??? ?0x54
#define NFM8ECC2_OFFSET?? ??? ?0x58
#define NFM8ECC3_OFFSET?? ??? ?0x5c
#define NFMLC8BITPT0_OFFSET?? ?0x60
#define NFMLC8BITPT1_OFFSET?? ?0x64
#define NFCONF?? ??? ??? ?(ELFIN_NAND_BASE+NFCONF_OFFSET)
#define NFCONT?? ??? ??? ?(ELFIN_NAND_BASE+NFCONT_OFFSET)
#define NFCMMD?? ??? ??? ?(ELFIN_NAND_BASE+NFCMMD_OFFSET)
#define NFADDR????????? ??? ?(ELFIN_NAND_BASE+NFADDR_OFFSET)
#define NFDATA???????? ??? ?(ELFIN_NAND_BASE+NFDATA_OFFSET)
#define NFMECCDATA0??? ??? ?(ELFIN_NAND_BASE+NFMECCDATA0_OFFSET)
#define NFMECCDATA1??? ??? ?(ELFIN_NAND_BASE+NFMECCDATA1_OFFSET)
#define NFSECCDATA0???? ??? ?(ELFIN_NAND_BASE+NFSECCDATA0_OFFSET)
#define NFSBLK???????? ??? ?(ELFIN_NAND_BASE+NFSBLK_OFFSET)
#define NFEBLK????????? ??? ?(ELFIN_NAND_BASE+NFEBLK_OFFSET)
#define NFSTAT????????? ??? ?(ELFIN_NAND_BASE+NFSTAT_OFFSET)
#define NFESTAT0??????? ??? ?(ELFIN_NAND_BASE+NFESTAT0_OFFSET)
#define NFESTAT1??????? ??? ?(ELFIN_NAND_BASE+NFESTAT1_OFFSET)
#define NFMECC0???????? ??? ?(ELFIN_NAND_BASE+NFMECC0_OFFSET)
#define NFMECC1???????? ??? ?(ELFIN_NAND_BASE+NFMECC1_OFFSET)
#define NFSECC????????? ??? ?(ELFIN_NAND_BASE+NFSECC_OFFSET)
#define NFMLCBITPT????????? ??? ?(ELFIN_NAND_BASE+NFMLCBITPT_OFFSET)
#define NF8ECCERR0?? ??? ?(ELFIN_NAND_BASE+NF8ECCERR0_OFFSET)
#define NF8ECCERR1?? ??? ?(ELFIN_NAND_BASE+NF8ECCERR1_OFFSET)
#define NF8ECCERR2?? ??? ?(ELFIN_NAND_BASE+NF8ECCERR2_OFFSET)
#define NFM8ECC0?? ??? ?(ELFIN_NAND_BASE+NFM8ECC0_OFFSET)
#define NFM8ECC1?? ??? ?(ELFIN_NAND_BASE+NFM8ECC1_OFFSET)
#define NFM8ECC2?? ??? ?(ELFIN_NAND_BASE+NFM8ECC2_OFFSET)
#define NFM8ECC3?? ??? ?(ELFIN_NAND_BASE+NFM8ECC3_OFFSET)
#define NFMLC8BITPT0?? ??? ?(ELFIN_NAND_BASE+NFMLC8BITPT0_OFFSET)
#define NFMLC8BITPT1?? ??? ?(ELFIN_NAND_BASE+NFMLC8BITPT1_OFFSET)
#define NFCONF_REG?? ??? ?__REG(ELFIN_NAND_BASE+NFCONF_OFFSET)
#define NFCONT_REG?? ??? ?__REG(ELFIN_NAND_BASE+NFCONT_OFFSET)
#define NFCMD_REG?? ??? ?__REG(ELFIN_NAND_BASE+NFCMMD_OFFSET)
#define NFADDR_REG????????? ??? ?__REG(ELFIN_NAND_BASE+NFADDR_OFFSET)
#define NFDATA_REG???????? ??? ?__REG(ELFIN_NAND_BASE+NFDATA_OFFSET)
#define NFDATA8_REG???????? ??? ?__REGb(ELFIN_NAND_BASE+NFDATA_OFFSET)
#define NFMECCDATA0_REG??? ??? ?__REG(ELFIN_NAND_BASE+NFMECCDATA0_OFFSET)
#define NFMECCDATA1_REG??? ??? ?__REG(ELFIN_NAND_BASE+NFMECCDATA1_OFFSET)
#define NFSECCDATA0_REG???? ??? ?__REG(ELFIN_NAND_BASE+NFSECCDATA0_OFFSET)
#define NFSBLK_REG???????? ??? ?__REG(ELFIN_NAND_BASE+NFSBLK_OFFSET)
#define NFEBLK_REG????????? ??? ?__REG(ELFIN_NAND_BASE+NFEBLK_OFFSET)
#define NFSTAT_REG????????? ??? ?__REG(ELFIN_NAND_BASE+NFSTAT_OFFSET)
#define NFESTAT0_REG??????? ??? ?__REG(ELFIN_NAND_BASE+NFESTAT0_OFFSET)
#define NFESTAT1_REG??????? ??? ?__REG(ELFIN_NAND_BASE+NFESTAT1_OFFSET)
#define NFMECC0_REG???????? ??? ?__REG(ELFIN_NAND_BASE+NFMECC0_OFFSET)
#define NFMECC1_REG???????? ??? ?__REG(ELFIN_NAND_BASE+NFMECC1_OFFSET)
#define NFSECC_REG????????? ??? ?__REG(ELFIN_NAND_BASE+NFSECC_OFFSET)
#define NFMLCBITPT_REG??????? ??? ?__REG(ELFIN_NAND_BASE+NFMLCBITPT_OFFSET)
#define NFCONF_ECC_MLC?? ??? ?(1<<24)
#define NFCONF_ECC_1BIT?? ??? ?(0<<23)
#define NFCONF_ECC_4BIT?? ??? ?(2<<23)
#define NFCONF_ECC_8BIT?? ??? ?(1<<23)
#define NFCONT_ECC_ENC?? ??? ?(1<<18)
#define NFCONT_WP?? ??? ?(1<<16)
#define NFCONT_MECCLOCK?? ??? ?(1<<7)
#define NFCONT_SECCLOCK?? ??? ?(1<<6)
#define NFCONT_INITMECC?? ??? ?(1<<5)
#define NFCONT_INITSECC?? ??? ?(1<<4)
#define NFCONT_INITECC?? ??? ?(NFCONT_INITMECC | NFCONT_INITSECC)
#define NFCONT_CS_ALT?? ??? ?(1<<1)
#define NFCONT_CS?? ??? ?(1<<1)
#define NFSTAT_ECCENCDONE?? ?(1<<7)
#define NFSTAT_ECCDECDONE?? ?(1<<6)
#define NFSTAT_RnB?? ??? ?(1<<0)
#define NFESTAT0_ECCBUSY?? ?(1<<31)
在nand.h中对比芯片手册,添加修改必要的命令
Nand基本指令:
/*
*Standard NAND flash commands
*/
#defineNAND_CMD_READ0 0
#defineNAND_CMD_READ1 1
#defineNAND_CMD_RNDOUT 5
#defineNAND_CMD_PAGEPROG 0x10
#defineNAND_CMD_READOOB 0x50
#defineNAND_CMD_ERASE1 0x60
#defineNAND_CMD_STATUS 0x70
#defineNAND_CMD_STATUS_MULTI 0x71
#defineNAND_CMD_SEQIN 0x80
#defineNAND_CMD_RNDIN 0x85
#defineNAND_CMD_READID 0x90
#defineNAND_CMD_ERASE2 0xd0
#defineNAND_CMD_RESET 0xff
/*Extended commands for large page devices */
#defineNAND_CMD_READSTART 0x30
#defineNAND_CMD_RNDOUTSTART 0xE0
#defineNAND_CMD_CACHEDPROG 0x15
/*Extended commands for AG-AND device */
*Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
* there is no way to distinguish that from NAND_CMD_READ0
* until the remaining sequence of commands has been completed
* so add a high order bit and mask it off in the command.
#defineNAND_CMD_DEPLETE1 0x100
#defineNAND_CMD_DEPLETE2 0x38
#defineNAND_CMD_STATUS_ERROR 0x72
/*multi-bank error status (banks 0-3) */
#defineNAND_CMD_STATUS_ERROR0 0x73
#defineNAND_CMD_STATUS_ERROR1 0x74
#defineNAND_CMD_STATUS_ERROR2 0x75
#defineNAND_CMD_STATUS_ERROR3 0x76
#defineNAND_CMD_STATUS_RESET 0x7f
#defineNAND_CMD_STATUS_CLEAR 0xff

nand.c文件
voidboard_nand_init(struct nand_chip *nand)
s3c_nand_hwcontrol函数
staticvoid s3c_nand_hwcontrol(struct mtd_info *mtd,int dat,unsigned intctrl)
s3c_nand_device_ready函数
staticint s3c_nand_device_ready(struct mtd_info *mtdinfo)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
深入分析
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
U-BOOTNand命令支持
u-boot1.1.6nand_legacy驱动提供了u-boot对nand相关命令的一个轻量级的实现,但好象可扩展性不足。本文主要分析u-boot1.16/drivers/nand文档夹下的源码。
一.关键数据结构
1.structmtd_info
该结构在
include
\
linux
\
mtd
\
Mtd.h
中定义,字段比较多,有很多还是函数指针,他是
MTD
设备操作的通用接口,这个结构中有一个比较重要的成员
void*priv
,
priv
被声明成
void
指针,在下文的分析中会知道
priv
实际上指向了
nand_chip
结构。
2.structnand_chip
该结构在include\linux\mtd\Nand.h中定义,从名字上看就知道u-boot用他来描述NandFlash芯片的结构,比如他定义了页地址的偏移,页地址的位掩码等。structnand_chip不用我们手动的初始化,而是由另外一个结构,structnand_flash_dev在程式中动态的初始化。
3.structnand_flash_dev
该结构的定义有两处地方分别是
①include/linux/mtd/nand_legacy.h由nand_legacy模块使用
②include/linux/mtd/nand.h由u-boot通用nand架构使用
特别是在移植的时候要小心把两者混淆。我们先来看看2中该结构的定义
structnand_flash_dev {
char *name;
int id;
unsigned longpagesize;
unsigned long chipsize;
unsigned longerasesize;
unsigned long options;
};
name : Nand Flash名称
id: u-boot内部id编号
chipsize: 以MB为单位的芯片大小
erasesize: 擦除块的大小
options: 一些选项,比较重要的是Flash的数据位宽
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
nand.c中
structnand_info_t nand_info[ CFG_MAX_NAND_DEVICE ]
#defineCFG_MAX_NAND_DEVICE 1在smdk6410.h中定义板子的NandFlash芯片的数量
structnand_flash_dev nand_flash_ids[] = { …};
在drivers\nand\nand_ids.c中定义,可以找到适合自己的nandflash描述
{"NAND2GiB 3,3V 8-bit",0xD5,4096,2048,512*1024,LP_OPTIONS},
含义为Name.ID code,pagesize,chipsize in MegaByte,eraseblock size,options
二.nandflash初始化流程图

1.nand_init(nand.c)
nand_init在被board.c调用
#if(CONFIG_COMMANDS & CFG_CMD_NAND)
voidnand_init (void);
#endif
是u-bootNand的主函数
nand_init的主要功能是对CFG_MAX_NAND_DEVICE个Nand设备进行初始化(调用nand_init_chip),在nand/nand.c中
voidnand_init(void)
{
inti;
unsignedint size = 0;
for(i = 0; i < CFG_MAX_NAND_DEVICE; i++) {
nand_init_chip(&nand_info[i],&nand_chip[i],base_address[i]);
size+= nand_info[i].size;
if(nand_curr_device == -1)
nand_curr_device= i;
}
#ifdefFORLINX_DEBUG
printf("NandFlashSize is %lu MB ",size / (1024 * 1024));
#else
printf("%luMB ",SimSun">#endif
#ifdefined(CFG_NAND_FLASH_BBT)
printf("(FlashBased BBT Enabled)");
printf("n");
#ifdefCFG_NAND_SELECT_DEVICE
/*
* Select the chip in the board/cpu specific driver
*/
board_nand_select_device(nand_info[nand_curr_device].priv,nand_curr_device);
}
累加NandFlash的总大小。在nand_init结束时,能够配置是否执行board_nand_select_device,选择Nand芯片。
2.nand_init_chip(drivers\nand\nand.c)
staticvoid nand_init_chip(structmtd_info *mtd,struct nand_chip *nand,ulong base_addr )调用各个研发板提供的board_nand_init函数(board\\.c)让研发板获得初始化NandFlash芯片的机会。调用nand_scan。
staticvoid nand_init_chip(struct mtd_info *mtd,
ulong base_addr)
{
mtd->priv= nand;
nand->IO_ADDR_R= nand->IO_ADDR_W = (void __iomem *)base_addr;
board_nand_init(nand);
//printf("nand_init_chip!n");
if(nand_scan(mtd,1) == 0) {
if(!mtd->name)
mtd->name= (char *)default_nand_name;
}else
mtd->name= NULL;
}
3.nand_scan(nand_base.c)
intnand_scan(struct mtd_info *mtd,int maxchips)
intret;
ret= nand_scan_ident(mtd,maxchips);
if(!ret)
ret= nand_scan_tail(mtd);
returnret;
}
这是u-boot初始化nand设备的核心函数。他主要完成以下工作
1)初始化nand_chip的函数指针,这些函数一般在.c中定义。
…
structnand_chip *this = mtd->priv
....
if( this-> cmdfunc ==NULL )
this->cmdfunc = nand_command;
…
2)使用上面注册的函数指针,读取NandFlash的设备,并且在上文提到的nand_flash_ids[]中找是否有匹配项,若找到匹配的项,则初始化nand_chip和mtd_info,他们的初始化代码老长的一段,一般没什么问题。
三.Nand Flash操作
拿read操作来说,调用流程如下
