zoukankan      html  css  js  c++  java
  • linux 设备驱动 nand驱动框架

    nand 设备驱动(一)架构

    使用mini2440 - nand

    1. nand硬件

    1.1 资源

    LDATD0~7数据线和地址线是复用的,都是8位

    既可以传输数据(命令或者数据), 也可以发送地址信号

    信号说明:

    CLE: 命令锁存, 高表示cmd

    ALE: 地址锁存, 高表示地址

    CE :片选,低有效

    R/B:状态: 低电平表示busy, 高电平表示idle, 

    RE:读使能, 

    WE:

    命令集:

    1.2 硬件操作

     读ID命令字90, 时序如下:

    2. kernel-nand驱动结构

    开发板上电后有输出:

    S3C24XX NAND Driver, (c) 2004 Simtec Electronics
    s3c2440-nand s3c2440-nand: Tacls=3, 30ns Twrph0=7 70ns, Twrph1=3 30ns
    NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
    Scanning device for bad blocks

    搜索“S3C24XX NAND Driver”
    s3c2410.c (driversmtd and)

    调用关系
    s3c2410_nand_init
        s3c2440_nand_driver
            s3c2440_nand_probe
                s3c24xx_nand_probe
                    s3c2410_nand_inithw
                    s3c2410_nand_init_chip
                    nand_scan
                    s3c2410_nand_add_partition

    在s3c2410_nand_init_chip

    s3c2410_nand_init_chip
        struct nand_chip *chip = &nmtd->chip;
        chip->write_buf    = s3c2410_nand_write_buf;
        chip->read_buf     = s3c2410_nand_read_buf;
        chip->select_chip  = s3c2410_nand_select_chip;
        chip->cmd_ctrl  = s3c2440_nand_hwcontrol;
        chip->dev_ready = s3c2440_nand_devready;
        chip->IO_ADDR_R = chip->IO_ADDR_W;
    
        nmtd->info       = info;
        nmtd->mtd.priv       = chip;
        nmtd->mtd.owner    = THIS_MODULE;

    再看nand_scan          // 在文件nand_base.c

    nand_scan
    nand_scan_ident
            nand_set_defaults(chip, busw);                    // 设置默认参数, 如果s3c2410_nand_init_chip设置了就用设置的函数
            nand_get_flash_type                               // Get the flash and manufacturer id
                /* Select the device */
                chip->select_chip(mtd, 0);
            
                /* Send the command for reading device ID */
                chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); // 发送0x90,即读ID
            
                /* Read manufacturer and device IDs */
                *maf_id = chip->read_byte(mtd);                 // 读厂商ID
                dev_id = chip->read_byte(mtd);                  // 读设备ID
                
                输出“NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)”
                printk(KERN_INFO "NAND device: Manufacturer ID:"
                   " 0x%02x, Chip ID: 0x%02x (%s %s)
    ", *maf_id,
                   dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
                   // nand_flash_ids 表示{NAND_MFR_SAMSUNG, "Samsung"},
               
            chip->select_chip(mtd, i); 
            chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);    // 发命令/数据

    最后s3c2410_nand_add_partition

    add_mtd_partitions
            mtd_table[i] = mtd;          // mtd_table是全局数组
            list_for_each(this, &mtd_notifiers) {
            mtd_notifiers是一个链表head, 在mtdcore.c (driversmtd)里面添加
                register_mtd_user      // mtdchar.c (driversmtd) 和mtd_blkdevs.c (driversmtd)调用,分别是字符设备和块设备

    3. nand驱动编写

    从上面分析看出,编写nand flash驱动主要有:
    3.1 定义nand_chip *chip
    3.2 设置
    3.3 注册

    搜索nand_scan可以看到很多例子
    参考:s3c2410.c 和at91_nand.c (driversmtd and)

     例程:

    /*
    *  kernel  : linux-2.6.22.6
    *  gcc     : arm-linux-gcc -3.4.5
    *
    *  Note(s) :  nand driver for mini2440
    *             reference  driver/mtd/nand/s3c2410.c and driver/mtd/nand/at91_nand.c
    */
    
    
    #include <linux/slab.h>
    #include <linux/module.h>
    #include <linux/platform_device.h>
    #include <linux/mtd/mtd.h>
    #include <linux/mtd/nand.h>
    #include <linux/mtd/partitions.h>
    
    #include <asm/io.h>
    #include <asm/sizes.h>
    
    #include <asm/hardware.h>
    #include <asm/arch/gpio.h>
    
    #include <linux/clk.h>
    
    
    static struct nand_chip *mini2440_nand_chip;
    static struct mtd_info    *mini2440_mtd;
    
    struct s3c_nand_regs {
        unsigned long nfconf  ;
        unsigned long nfcont  ;
        unsigned long nfcmd   ;
        unsigned long nfaddr  ;
        unsigned long nfdata  ;
        unsigned long nfeccd0 ;
        unsigned long nfeccd1 ;
        unsigned long nfeccd  ;
        unsigned long nfstat  ;
        unsigned long nfestat0;
        unsigned long nfestat1;
        unsigned long nfmecc0 ;
        unsigned long nfmecc1 ;
        unsigned long nfsecc  ;
        unsigned long nfsblk  ;
        unsigned long nfeblk  ;
    };
    
    static struct s3c_nand_regs *mini2440_nand_regs;
    
    #ifdef CONFIG_MTD_NAND_MINI2440_HWECC
        
    #endif
    
    
    static struct mtd_partition mini2440_partitions[] = {
        [0] = {
            .name   = "bootloader",
            .size   = 0x00040000,
            .offset    = 0,
        },
        [1] = {
            .name   = "params",
            .offset = MTDPART_OFS_APPEND,
            .size   = 0x00020000,
        },
        [2] = {
            .name   = "kernel",
            .offset = MTDPART_OFS_APPEND,
            .size   = 0x00200000,
        },
        [3] = {
            .name   = "root",
            .offset = MTDPART_OFS_APPEND,
            .size   = MTDPART_SIZ_FULL,
        }
    };
    
    
    static void    mini2440_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
    {
        struct nand_chip *this = mtd->priv;
        readsb(this->IO_ADDR_W, buf, len);
    }
    
    static void    mini2440_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
    {
        struct nand_chip *this = mtd->priv;
        readsb(this->IO_ADDR_R, buf, len);
    }
    
    static void    mini2440_nand_select_chip(struct mtd_info *mtd, int chip)
    {
        if(-1 == chip)
        {
            /* disselect */
            /* NFCONT[1]  = 1  desselect */
            mini2440_nand_regs->nfcont |= (1<<1);
        }
        else
        {
            /* select */
            mini2440_nand_regs->nfcont &= ~(1<<1);
        }
    }
    
    static void    mini2440_nand_hwcontrol(struct mtd_info *mtd, int dat,
                        unsigned int ctrl)
    {
        if (ctrl & NAND_CLE)
            mini2440_nand_regs->nfcmd = dat;
        else
            mini2440_nand_regs->nfaddr = dat;
    }
    
    static int mini2440_nand_devready(struct mtd_info *mtd)
    {
        return (mini2440_nand_regs->nfstat & (1 << 0));
    }
    
    
    static int mini2440_nand_init(void)
    {
        int ret = -EBUSY;
        
        struct clk    *clk;
        /* 分配nand_chip    */
        mini2440_nand_chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
        if(!mini2440_nand_chip)
            return ret;
    
        mini2440_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs));
    
        /* 设置nand_chip     */
        mini2440_nand_chip->write_buf    = mini2440_nand_write_buf;
        mini2440_nand_chip->read_buf     = mini2440_nand_read_buf;
        mini2440_nand_chip->select_chip  = mini2440_nand_select_chip;
        mini2440_nand_chip->chip_delay   = 50;
        //mini2440_nand_chip->priv         = nmtd;
        mini2440_nand_chip->options         = 0;
        mini2440_nand_chip->ecc.mode     = NAND_ECC_SOFT;
    
        mini2440_nand_chip->IO_ADDR_W = &mini2440_nand_regs->nfdata;
        mini2440_nand_chip->IO_ADDR_R = &mini2440_nand_regs->nfdata;
        mini2440_nand_chip->cmd_ctrl  = mini2440_nand_hwcontrol;
        mini2440_nand_chip->dev_ready = mini2440_nand_devready;
    
        mini2440_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
        if(!mini2440_mtd)
            goto err;
    
        mini2440_mtd->priv       = mini2440_nand_chip;
        mini2440_mtd->owner    = THIS_MODULE;
    
        /* 硬件相关操作       */
        clk = clk_get(NULL, "nand");
        clk_enable(clk);
    
    #define TACLS    0
    #define TWRPH0   1
    #define TWRPH1   0
        mini2440_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
    
        //s3c_nand_chip->dev_ready(s3c_mtd, -1);
        mini2440_nand_regs->nfcont = (1<<1) | (1<<0);
        
    
        nand_scan(mini2440_mtd, 1);
    
        ret = add_mtd_device(mini2440_mtd);
        if (!ret)
            goto out;
    
        /*  add_mtd_partitions    */
        add_mtd_partitions(mini2440_mtd, mini2440_partitions, ARRAY_SIZE(mini2440_partitions));
        
        return 0;
    
    out:
        nand_release(mini2440_mtd);
        kfree(mini2440_mtd);
        iounmap(mini2440_nand_regs);
    
    err:
        kfree(mini2440_nand_chip);
        return -EFAULT;
    }
    
    static void mini2440_nand_exit(void)
    {
        del_mtd_partitions(mini2440_mtd);
        nand_release(mini2440_mtd);
        kfree(mini2440_mtd);
        iounmap(mini2440_nand_regs);
        kfree(mini2440_nand_chip);
    }
    
    
    module_init(mini2440_nand_init);
    module_exit(mini2440_nand_exit);
    
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("Flinn Flinn682@foxmail.com");
    MODULE_DESCRIPTION("nand driver for mini2440");
  • 相关阅读:
    Login
    2Sum,3Sum,4Sum,kSum,3Sum Closest系列
    Word Search II
    Word Search
    Linux命令四
    linux命令三
    Linux命令二
    Linux命令一
    网络基础
    操作系统
  • 原文地址:https://www.cnblogs.com/hulig7/p/9928122.html
Copyright © 2011-2022 走看看