因为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 函数的分析,将放到下一章来进行分析。