NAND驱动分析--(一)
来源:互联网 发布:秒赞秒评大师软件 编辑:程序博客网 时间:2024/06/05 18:58
因为nand flash驱动是采用了MTD技术,所以首先对nand硬件驱动层进行分析(以ppc架构为例进行分析,nand flash采用了Micron公司的512MB、2K页大小、的flash芯片)。
ppc架构的cpu芯片并没有集成专用的nand flash控制器,而是使用elbc(增强型本地总线控制器)的nand控制模式来对nand flash芯片进行控制的。所以首先分析nand底层硬件驱动,fsl_elbc_nand.c文件。
drivers\mtd\nand\fsl_elbc_nand.c文件:
linux系统在装载底层硬件驱动时,会首先调用fsl_elbc_nand_init()函数。此函数的源码如下:
int __init fsl_elbc_nand_init(void)/*static int __devinit fsl_elbc_nand_probe(struct of_device *dev, const struct of_device_id *match)*/{ struct fsl_lbc_regs __iomem *lbc; struct fsl_elbc_mtd *priv; //struct resource res;#ifdef CONFIG_MTD_PARTITIONS static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; struct mtd_partition *parts;#endif int ret; int bank; //struct device_node *node = dev->node; printk("Init elbc nand\n"); if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) return -ENODEV; lbc = fsl_lbc_ctrl_dev->regs; /* find which chip select it is connected to */ for (bank = 0; bank < MAX_BANKS; bank++) if ((in_be32(&lbc->bank[bank].br) & BR_V) && (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM && (in_be32(&lbc->bank[bank].br) & in_be32(&lbc->bank[bank].or) & BR_BA) == convert_lbc_address(LBC_SRAM_ADD_BASE)) break; if (bank >= MAX_BANKS) { printk("addr not match any chip selects\n"); return -ENODEV; } //priv = kzalloc(sizeof(*priv), GFP_KERNEL); priv = kmalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; memset(priv,0,sizeof(*priv)); if (fsl_lbc_ctrl_dev->nand == NULL) { //elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL); elbc_fcm_ctrl = kmalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL); if (!elbc_fcm_ctrl) return -ENOMEM; memset(elbc_fcm_ctrl,0,sizeof(*elbc_fcm_ctrl)); elbc_fcm_ctrl->read_bytes = 0; elbc_fcm_ctrl->index = 0; elbc_fcm_ctrl->addr = NULL; spin_lock_init(&elbc_fcm_ctrl->controller.lock); init_waitqueue_head(&elbc_fcm_ctrl->controller.wq); fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl; } elbc_fcm_ctrl->chips[bank] = priv; priv->bank = bank; priv->ctrl = fsl_lbc_ctrl_dev; priv->vbase = ioremap(LBC_SRAM_ADD_BASE,LBC_SRAM_SIZE); if (!priv->vbase) { printk("elbc failed to map chip region\n"); ret = -ENOMEM; goto err; } priv->mtd.name = pname; if (!priv->mtd.name) { ret = -ENOMEM; goto err; } ret = fsl_elbc_chip_init(priv); if (ret) goto err; priv->fmr |= (12 << FMR_CWTO_SHIFT); if (nand_scan (&priv->mtd, 1)) { printk("flash scan failed\n"); goto err; } fsl_elbc_chip_init_tail(&priv->mtd); add_mtd_partitions(&priv->mtd, p1020_partition_info, 3);err: //fsl_elbc_chip_remove(priv); return ret;}
其中elbc寄存器结构体和描述elbc的mtd信息结构体如下所示:
struct fsl_lbc_regs __iomem *lbc; //elbc寄存器结构体 struct fsl_elbc_mtd *priv; //elbc的mtd信息结构体
继续往下分析,可以看到lbc = fsl_lbc_ctrl_dev->regs;由此可知,lbc的基地址是由fsl_lbc_ctrl_dev结构体中的regs成员赋予的,而fsl_lbc_ctrl_dev结构体的初始化代码如下所示:
static __init int fsl_lbc_init(void){ int ret; printk("init fsl lbc controller\n"); fsl_lbc_ctrl_dev = kmalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL); \\分配内存空间 if (!fsl_lbc_ctrl_dev) return -ENOMEM; memset(fsl_lbc_ctrl_dev,0,sizeof(*fsl_lbc_ctrl_dev)); spin_lock_init(&fsl_lbc_ctrl_dev->lock); init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait); fsl_lbc_ctrl_dev->regs = 0xffe05000; //给elbc的基地址赋值 fsl_lbc_ctrl_dev->regs = ioremap(fsl_lbc_ctrl_dev->regs, 0x1000); //映射elbc寄存器的基地址 if (!fsl_lbc_ctrl_dev->regs) { printk("failed to get memory region\n"); ret = -ENODEV; goto err; } fsl_lbc_ctrl_dev->irq = 3+64; //赋值中断号 ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev); //初始化elbc的中断相关等寄存器 if (ret < 0) goto err; ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0, "fsl-lbc", fsl_lbc_ctrl_dev); //注册elbc的中断函数 if (ret != 0) { printk("failed to install irq (%d)\n", fsl_lbc_ctrl_dev->irq); ret = fsl_lbc_ctrl_dev->irq; goto err; } return 0;err: return ret;}
有上述代码可知,在fsl_elbc_nand_init()函数中的lbc其实是elbc寄存器的基地址,如果想对elbc的寄存器进行操作,直接对lbc进行赋值即可。
接下来回到fsl_elbc_nand_init()函数当中,继续往下,会看到priv = kmalloc(sizeof(*priv), GFP_KERNEL);语句。此时将对priv结构体分配内存空间,并对priv的各个成员进行初始化操作。如以下代码所示:
priv = kmalloc(sizeof(*priv), GFP_KERNEL); //为priv结构体分配内存空间if (!priv) return -ENOMEM;memset(priv,0,sizeof(*priv));if (fsl_lbc_ctrl_dev->nand == NULL) //判断nand成员是否为空,如果是则执行如下代码。事实证明nand成员确实为空。{ /* 分配elbc_fcm_ctrl结构体,并对其进行初始化 */ elbc_fcm_ctrl = kmalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL); if (!elbc_fcm_ctrl) return -ENOMEM; memset(elbc_fcm_ctrl,0,sizeof(*elbc_fcm_ctrl)); elbc_fcm_ctrl->read_bytes = 0; elbc_fcm_ctrl->index = 0; elbc_fcm_ctrl->addr = NULL; spin_lock_init(&elbc_fcm_ctrl->controller.lock); init_waitqueue_head(&elbc_fcm_ctrl->controller.wq); fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl; //最后将初始化的elbc_fcm_ctrl结构体指针赋值给nand成员。}elbc_fcm_ctrl->chips[bank] = priv; //再将priv结构指针赋值给elbc_fcm_ctrl的chips成员。priv->bank = bank; //得到nand flash的片选信号数值编号。priv->ctrl = fsl_lbc_ctrl_dev; //最后再将控制器结构体fsl_lbc_ctrl_dev指针赋值给ctrl。
继续往下分析,可以看到调用了ret = fsl_elbc_chip_init(priv);函数。此函数用于初始化priv结构体中的nand_chip成员,而此成员中的一些函数就是代表了对nand flash芯片的一些基本操作,如:写命令、读数据和写地址等。而代码最后还将调用nand_scan (&priv->mtd, 1)函数,来扫描nand设备并对mtd结构进行新建和初始化。
而对fsl_elbc_chip_init和nand_scan 函数的分析,将放到下一章来进行分析。
- NAND驱动分析--(一)
- Linux NAND FLASH驱动分析(一)
- linux nand flash 驱动(一) --- 原理分析
- NAND驱动分析--(二)
- NAND驱动分析--(三)
- nand FLASH 驱动分析
- nand 驱动分析
- NAND FLASH 驱动分析
- nand flash驱动分析
- u-boot nand flash驱动架构分析一
- 内核读写nand flash驱动分析(含注释)
- NAND FLASH学习笔记之MTD下nand flash驱动(一)
- NAND FLASH学习笔记之MTD下nand flash驱动(一)
- NAND控制器驱动程序分析(一)
- S3C2440之NAND FLASH移植到S3C2410的驱动分析[一]
- s3c2410的nand flash的驱动分析
- s3c2410的nand flash的驱动分析
- s3c2410的nand flash的驱动分析
- 南宁市第二届网络与信息安全技术竞赛——web200
- android微信登录的app签名 和 项目正式签名替换默认签名
- UVA 10815
- 递归栈(hanoi问题)
- 算法练习---跳跃游戏二(动态规划)
- NAND驱动分析--(一)
- JavaScript的原型模式
- 软件测试基础介绍
- IntelliJ IDEA基本用法
- 李宏毅机器学习课程笔记2:Classification、Logistic Regression、Brief Introduction of Deep Learning
- maven入门之将Jar安装到本地仓库
- 最长的单词
- 阿里云OSS介绍之一 总体介绍与使用
- 树莓派7寸官方屏修改分辨率