前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Nand Flash驱动程序分析

Nand Flash驱动程序分析

作者头像
DragonKingZhu
发布2022-05-08 16:13:42
5430
发布2022-05-08 16:13:42
举报
代码语言:javascript
复制
/*Nand Flash驱动分析*/

/*首先: 市面上的开发板很多,Nand Flash差不多都一样。先说说Nand Flash的特性*/


/* 上图是OK6410开发板的Nand Flash原理图,从上图可知:
1. 数据线和地址线明显是公用的。因为只看见了DATA0-DATA7没看见地址线。作为一个存储芯片当然要写数据,读数据。当然需要地址线。
2. DATA0-DATA7在好多地址被使用了,那怎么区分当前是那个芯片。那当然要CSN2和CSN3来控制当前选中那个芯片,也就是让那个芯片工作。
3. FWEN和FREN是写使能信号,和读使能信息。来控制读写的操作
4. 当FCLE为高电平时传输的是命令, FALE为高电平时传输的是地址,当FCLE和FALE都为低电平时传输的是数据。(可以从Nand Flash芯片手册上获取到)


既然了解这么多,就该知道Nand Flash一般的工作流程了:
1. 先发命令,
2. 再发地址(可能需要发送好几个周期),
3. 发出数据或者读取数据

*/


/*其次,我们来分析三星公司自带的Nand Flash驱动程序。路径: drivers/mtd/nand/s3c2410.c*/

//老套路了还是平台驱动程序,既然是平台驱动程序,就有平台设备的存在
static int __init s3c2410_nand_init(void)
{
	printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");

	return platform_driver_register(&s3c24xx_nand_driver);
}


//平台设备与驱动想匹配时,就会调用probe函数

/* s3c24xx_nand_probe  //注释写的是多么的清楚
 *
 * called by device layer when it finds a device matching	//先是当发现设备后调用设备层,接着代码检测是否能分配足够的资源
 * one our driver can handled. This code checks to see if //然后调用Nand 层去寻找设备。
 * it can allocate all necessary resources then calls the //注释中出现了Device 层和 Nand层的概念,以后会说到
 * nand layer to look for devices
*/
static int s3c24xx_nand_probe(struct platform_device *pdev)
{
	struct s3c2410_nand_info *info;
	
	//分配info结构
	info = kzalloc(sizeof(*info), GFP_KERNEL);
	platform_set_drvdata(pdev, info);
	
	//设置时钟,使能时钟
	info->clk = clk_get(&pdev->dev, "nand");
	s3c2410_nand_clk_set_state(info, CLOCK_ENABLE);
	
	//初始化硬件
	s3c2410_nand_inithw(info);
	
	//初始化所有可能的芯片
	s3c2410_nand_init_chip
	
	//nand 寻找设备
	nand_scan_ident();
	
	//如果没有找到,
	if (nmtd->scan_res == 0) {
		s3c2410_nand_update_chip(info, nmtd);
		nand_scan_tail(&nmtd->mtd);//寻找设备
		s3c2410_nand_add_partition(info, nmtd, sets);//增加分区
	}
}

//寻找Nand Flash设备
int nand_scan_ident(struct mtd_info *mtd, int maxchips,struct nand_flash_dev *table)
{
	/* Get buswidth to select the correct functions */
	busw = chip->options & NAND_BUSWIDTH_16;	//设置总线宽度
	/* Set the default functions */
	nand_set_defaults(chip, busw);		//设置一些默认的函数

	/* Read the flash type */
	type = nand_get_flash_type(mtd, chip, busw, //读取flash的类型
				&nand_maf_id, &nand_dev_id, table);

}

/*所谓设置默认函数,就是设置flash的读,写,发送命令,发送数据,等待等函数。*/
static void nand_set_defaults(struct nand_chip *chip, int busw)
{
	/* check for proper chip_delay setup, set 20us if not */
	if (!chip->chip_delay)	//如果没有设置延迟时间,那就设置
		chip->chip_delay = 20;

	/* check, if a user supplied command function given */
	if (chip->cmdfunc == NULL)  //如果没有设置发送命令的函数,那就需要我们自己设置
		chip->cmdfunc = nand_command;  

	/* check, if a user supplied wait function given */
	if (chip->waitfunc == NULL)  //如果没有设置等待函数,那就需要在驱动程序中设置
		chip->waitfunc = nand_wait;

	if (!chip->select_chip)
		chip->select_chip = nand_select_chip;  //片选函数设置
	if (!chip->read_byte)
		chip->read_byte = busw ? nand_read_byte16 : nand_read_byte; //读flash函数
	if (!chip->read_word)
		chip->read_word = nand_read_word;
	if (!chip->block_bad)
		chip->block_bad = nand_block_bad;
	if (!chip->block_markbad)
		chip->block_markbad = nand_default_block_markbad;
	if (!chip->write_buf)
		chip->write_buf = busw ? nand_write_buf16 : nand_write_buf; //写flash函数
	if (!chip->read_buf)
		chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
	if (!chip->verify_buf)
		chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
	if (!chip->scan_bbt)
		chip->scan_bbt = nand_default_bbt;
	}
}

/* 取得Flash和厂家id,寻找是否支持该设备
 * Get the flash and manufacturer id and lookup if the type is supported
 */
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
						  struct nand_chip *chip,
						  int busw,
						  int *maf_id, int *dev_id,
						  struct nand_flash_dev *type)
{
		/* Select the device */
	chip->select_chip(mtd, 0); //先选中芯片

	/*
	 * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
	 * after power-up
	 */
	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);	//reset芯片

	/* Send the command for reading device ID */
	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); //发送读取ID的命令90h,

	/* Read manufacturer and device IDs */
	*maf_id = chip->read_byte(mtd); //读取厂家ID
	*dev_id = chip->read_byte(mtd); //读取设备ID
	
}

s3c2410_nand_add_partition -> mtd_device_register ->add_mtd_partitions -> add_mtd_device->
{
	list_for_each_entry(not, &mtd_notifiers, list)//遍历mtd_notifiers中每个调用add函数
		not->add(mtd);	
}

//那mtd_notifiers在那里设置了?
void register_mtd_user (struct mtd_notifier *new)
{
	list_add(&new->list, &mtd_notifiers);//在这里设置了mtd_notifiers

	__module_get(THIS_MODULE);

	mtd_for_each_device(mtd)
		new->add(mtd);
}

//看看谁调用register_mtd_user函数

//一个文件在: drivers/mtd/mtdchar.c
register_mtd_user(&mtdchar_notifier);

//一个文件在: drivers/mtd/mtd_blkdevs.c
register_mtd_user(&blktrans_notifier);


//先看mtdchar_notifier中的add函数

static void mtd_notify_add(struct mtd_info *mtd)
{
}

//再看blktrans_notifier中的add函数
static void blktrans_notify_add(struct mtd_info *mtd)
{
	//遍历blktrans_majors链表,调用add_mtd函数
	list_for_each_entry(tr, &blktrans_majors, list)
		tr->add_mtd(tr, mtd);
}

//看blktrans_majors链表在那里设置?
int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
{
	list_add(&tr->list, &blktrans_majors); //此函数中有设置	
}

//init_mtdblock函数调用了register_mtd_blktrans函数
static int __init init_mtdblock(void)
{
	mutex_init(&mtdblks_lock);

	return register_mtd_blktrans(&mtdblock_tr);
}

//看mtdblock_tr结构中的add_mtd函数
static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
		
}
int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
{
	//穿件gendisk结构
	gd = alloc_disk(1 << tr->part_bits);
	
	//初始化gendisk
	new->disk = gd;
	gd->private_data = new;
	gd->major = tr->major;
	gd->first_minor = (new->devnum) << tr->part_bits;
	gd->fops = &mtd_blktrans_ops;
	
	set_capacity(gd, (new->size * tr->blksize) >> 9);

	//初始化请求队列
	new->rq = blk_init_queue(mtd_blktrans_request, &new->queue_lock);

	//注册gendisk
	add_disk(gd);
	
}

/*在这里可以发现,是不是块设备的基本操作等。 其实是内核帮我们已经做好了这些东西。
  这样做的好处是把Nand Flash相关的操作都抽象出来,放在nand层。 而把和硬件相关的,
  经常需要变化的留给设备层,而设备层就是由我们程序员编写,因为设备层的差别各异,
  很难抽象成统一的整体。
  
  所以我们编写块设备的话,只需要做设备层相关的操作,其余的操作内核已经帮我们做好了。
*/



/*上面的分析是对自带的程序分析: 那我们如何写驱动程序同时也能融合到内核为我们提供好的nand层*/

/*
	1. 分配一个nand_chip结构  
	2. 设置nand_chip结构
	   设置cmdfunc, waitfunc, select_chip等函数
	3. 硬件相关的代码
		 使能时钟, 设置时钟,选择芯片
	4. 使用nand_scan识别nand flash
	5. 添加分区(这样就会将nand flash驱动加到内核中)
*/
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-02-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档