NAND驱动分析--(一)

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值