linux驱动之NandFlash驱动



写块驱动程序的框架:

  1. 分配 gendisk 结构体,使用alloc_disk
  2. 设置:队列,属性
  3. 注册

Nandflash芯片操作:

1、NandFlash和S3c2440怎么硬件怎么连接?

DATA0 ~DATA7上既传输数据,又传输地址,也传输命令

当ALE为高电平时传输的是地址

当CLE为高电平时传输的是数据

当ALE和CLE都为地电平时传输的是数据

2、数据线既接到NAND FLASH也接到 NOR FLASH,还接到SDRAM,DM9000等等。怎么避免干扰?

这些设备在访问之前,必须选中,没有选中的芯片不会工作。

3、假设,烧写 NAND FLASH把命令、地址、数据发给它之后,NANDFLASH肯定不可能瞬间完成烧写的。怎么判断烧写完成?

通过状态因叫RnB来判断,它为高电平,表示ready,它为低电平表示busy。

4、怎么操作 NandFlash?

根据NandFlash的datasheet,思路为:

发出命令   ---   发出地址   ----  发出数据/读数据


 NANDFLASHS3C2440
发命令选中芯片
CLE设为高电平
在DATA0~DATA8上输出命令值
发出一个写脉冲
NFCMMD=命令
发地址选中芯片
ALE设为高电平
在DATA0~DATA8上输出地址
发出一个写脉冲
NFADDR=地址
发数据选中芯片
ALE,CLE设为高电平
在DATA0~DATA8上输出数据
发出一个写脉冲
NFDATA=数据
读数据选中芯片
ALE,CLE设为高电平
读DATA0~DATA8的数据
val = NFDATA


裸奔:

读ID的方法(参照datasheet的时序)

选中NFCONT的bit1 设为00x4E000004
发出命令0X90NFCMMD = 0x900x4E000008
发出地址0X00NFADDR = 0x000x4E00000C
读数据得到0XECval = NFDATA0x4E000010
都数据得到device_codeval = NFDATA0x4E000010

============================================================================================================

驱动思路:

1、分配nandchip结构体

2、设置这个结构体

3、硬件的相关操作

4、使用 nand_scan

5、add_mtd_partitions


1、分配一个nandchip结构体:

static struct nand_chip *s3c_nand;
s3c_nand = kzalloc(sizeof(struct nand_chip),GFP_KERNEL);

2、设置这个nand_chip结构体

关于怎么设置,可以通过察看nandscan这个方法使用了什么来反推需要怎么配置这个nand_chip结构体的


	s3c_nand->select_chip = s3c2440_select_chip;
	s3c_nand->cmd_ctrl    = s3c2440_cmd_ctrl;
	s3c_nand->IO_ADDR_R   = &s3c_nand_regs->nfdata;
	s3c_nand->IO_ADDR_W   = &s3c_nand_regs->nfdata;
	s3c_nand->dev_ready   =s3c2440_dev_ready;
	s3c_nand->ecc.mode    = NAND_ECC_SOFT;//ECC校验
对于 s3c2440_select_chip等操作函数内核是可以自动分配一个默认的函数的,但是这个默认你的函数是不能真正工作的。因此需要我们自己去定义。

s3c2440_select_chip、s3c2440_cmd_ctrl、s3c2440_dev_ready 涉及了硬件的相关操作,因此要配置下硬件。

这里的ecc.mode 是使用ecc校验功能。这是nand_flash的没一页的OOB区都会保存这位校验的ECC用于检验是否有位翻转。

3、硬件的相关操作:

首次还是要映射相关的寄存器,在这个驱动函数中,寄存器的定义:

struct s3c_nand_regs
{
	 unsigned long nfconf  ;
	 unsigned long nfcont  ;
	 unsigned long nfcmd   ;
	 unsigned long nfaddr  ;
	 unsigned long nfdata  ;
	 unsigned long nfeccd0 ;
	 unsigned long nfeccd1 ;
	 unsigned long nfeccd  ;
	 unsigned long nfstat  ;
	 unsigned long nfestat0;
	 unsigned long nfestat1;
	 unsigned long nfmecc0 ;
	 unsigned long nfmecc1 ;
	 unsigned long nfsecc  ;
	 unsigned long nfsblk  ;
	 unsigned long nfeblk  ;
};

然后ioremap一下:

s3c_nand_regs = ioremap(0x4E000000,sizeof(struct s3c_nand_regs));

接下来完成s3c2440_select_chip、s3c2440_cmd_ctrl、s3c2440_dev_ready这三个函数.这三个函数的定义根据datasheet可作如下的定义:

s3c2440_select_chip

static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr)
{
	if(chipnr == -1)
	{
		/*取消选中
		 * NFCONT【1】=1*/
		s3c_nand_regs->nfcont |= (1<<1) ;
	}
	else
	{
		/*选中
		 * NFCONT【1】=0*/
		s3c_nand_regs->nfcont &= ~(1<<1);
	}
}
s3c2440_cmd_ctrl
static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int data,unsigned int ctrl)
{
	if (ctrl & NAND_CLE)
	{
		/*发命令
		 * NFCMMD = dat*/
		s3c_nand_regs->nfcmd = data;
	}
	else
	{
		/*发数据
		 * NFADDR = dat*/
		s3c_nand_regs->nfaddr = data;
	}
}
s3c2440_dev_ready
static int	s3c2440_dev_ready(struct mtd_info *mtd)
{
	/*NFSTAT[0]
	 * */
	return s3c_nand_regs->nfstat & (1<<0);
}

在硬件配置中,要注意一点就是时钟的配置,每个模块的时钟默认都是关闭的,因此如果我们要使用nandflash的主控制器,那么就要开启其clk:

	struct clk *clk;

        clk = clk_get(NULL,"nand");
	clk_enable(clk);   //clkcon的bit4

说到时钟,我们没有理由不去考虑时序问题,在s3c2440里面的的nandflash控制器的相关寄存器有这个配置:nfconf

     *HCLOK = 100MHz   10ns
     * TACLS:发出cle/ale之后多长时间才发出 nWE信号,从NAND手册可知cle/ale与nWE可以同时发出,所以TACLS值可以为0
     * TWRPH0 nWE信号的脉冲宽度  从手册上: HCLK *(TWRPH0 + 1) >=12ns,所以 TWRPH0 >= 1
     * TWRPH1 nWE变为高电平后,CLE/ALE多长时间才能变为低电平,nand手册可知 它要>=5ns  所以TWRPH1>=0

所以配置为:

#define  TACLS    0
#define  TWRPH0   1
#define  TWRPH1   0
	s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);

4、接下来使用nand_scan来识别这个nandflash。

这个函数的原型: int nand_scan (struct mtd_info *mtd, int max_chips);

因此我们还要定义一个mtd结构体,并且简单的设置它

static struct mtd_info *mtd;

    mtd = kzalloc(sizeof(struct mtd_info),GFP_KERNEL);
    mtd->owner = THIS_MODULE;
    mtd->priv = s3c_nand;

max_chips 最多片数,我们只有1片,所以选1.


5、添加分区:

add_mtd_partitions(mtd,s3c_nand_parts,3);

函数原型为:

int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
在这个函数需要mtd_partition,来创建每个分区。分区如下:

static struct mtd_partition s3c_nand_parts[] = {
[0] = {
	.name	= "wangqi_Board_uboot",
	.offset	= 0x00000000,
	.size	= 0x00040000,
},
[1] = {
	.name	= "wangqi_Board_kernel",
	.offset	= 0x00200000,
	.size	= 0x00200000,
},
[2] = {
	.name	= "wangqi_Board_yaffs2",
	.offset	= 0x00400000,
	.size	= 0x0FB80000,
}
};

这样一个完整的nandflash驱动就做好了。


========================================================================================================

测试:

make menuconfig 在源码驱动中去掉nandflash的驱动程序。

    -> Device Drivers                                                                                                                                   
  │       -> Memory Technology Device (MTD) support (MTD [=y])                                                                                             
  │         -> NAND Device Support (MTD_NAND [=y])  


文件系统需要挂载nfs网络文件系统。挂载方法:点击打开链接

insmod


 ls -l /dev/mtd*


crw-rw----    1 root     root       90,   0 Jan  1 00:00 /dev/mtd0
crw-rw----    1 root     root       90,   1 Jan  1 00:00 /dev/mtd0ro
crw-rw----    1 root     root       90,   2 Jan  1 00:00 /dev/mtd1
crw-rw----    1 root     root       90,   3 Jan  1 00:00 /dev/mtd1ro
crw-rw----    1 root     root       90,   4 Jan  1 00:00 /dev/mtd2
crw-rw----    1 root     root       90,   5 Jan  1 00:00 /dev/mtd2ro
brw-rw----    1 root     root       31,   0 Jan  1 00:00 /dev/mtdblock0
brw-rw----    1 root     root       31,   1 Jan  1 00:00 /dev/mtdblock1
brw-rw----    1 root     root       31,   2 Jan  1 00:00 /dev/mtdblock2


完整源码:点击打开链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值