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_MULTI 0x71
#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
1.在cpu/s3c64xx/s3c6410/下新建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
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的数据位宽
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
4.在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(drivers\nand\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 ", size / (1024 * 1024));
#endif
#ifdefined(CFG_NAND_FLASH_BBT)
printf("(FlashBased BBT Enabled)");
#endif
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);
#endif
}
累加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, struct nand_chip *nand,
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(drivers\nand\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的函数指针,这些函数一般在board\\.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操作来说,调用流程如下