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