nandflash驱动分析 针对K9GAG08U0D uboot1.1.6(下)

来源:互联网 发布:美空网怎么约 知乎 编辑:程序博客网 时间:2024/06/03 21:01

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-bootnand相关命令的一个轻量级的实现,但好象可扩展性不足。本文主要分析u-boot1.16/drivers/nand文档夹下的源码。
.关键数据结构
1.structmtd_info

该结构在includelinuxmtdMtd.h中定义,字段比较多,有很多还是函数指针,他是MTD设备操作的通用接口,这个结构中有一个比较重要的成员void*privpriv被声明成void指针,在下文的分析中会知道priv实际上指向了nand_chip结构。

2.structnand_chip

该结构在includelinuxmtdNand.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 1smdk6410.h中定义板子的NandFlash芯片的数量


structnand_flash_dev nand_flash_ids[] = { …};
driversnandnand_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_initdriversnandnand.c

nand_init在被board.c调用

#if(CONFIG_COMMANDS & CFG_CMD_NAND)

voidnand_init (void);

#endif

u-bootNand的主函数

nand_init的主要功能是对CFG_MAX_NAND_DEVICENand设备进行初始化(调用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
driversnandnand.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
driversnandnand_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_chipmtd_info,他们的初始化代码老长的一段,一般没什么问题。

.Nand Flash操作

read操作来说,调用流程如下