【linux学习笔记】Nandflash驱动程序实现

nandflash裸机原理分析

在这里插入图片描述常见的flash芯片如nand和nor。后者比较“高级”,有数据线和地址线,一般支持内存一样的数据读取,写数据时需要按照datasheet发送命令代码,数据较前者稳定,可擦除次数少,编程速度较前者满;前者则是“皮实耐操”的典型代表,无数据线、地址线,数据、命令、地址都从IO口输入、输出,因此想要读写nand,必须要通过IO口,拉高/拉低一系列引脚,如ALE(address latch enable)、CLE(command latch enable),读使能RE、写使能WE,R/B(ready/busy output)负责表明一组操作会否完成。但是以上复杂操作只是针对如之前使用的DSP、单片机等,无nandflash控制器的芯片,对于ARM来讲,这些操作都由nandflash控制器完成。
在这里插入图片描述

nand块驱动设备框架

在这里插入图片描述如上图所示,MTD设备通常可分为四层,从上到下依次是:
设备节点、MTD设备层、MTD原始设备层、硬件驱动层。

  • Flash硬件驱动层:Flash硬件驱动层负责对Flash硬件的读、写和擦除操作。MTD设备的Nand Flash芯片的驱动则drivers/mtd/nand/子目录下,Nor Flash芯片驱动位于drivers/mtd/chips/子目录下。

  • MTD原始设备层:用于描述MTD原始设备的数据结构是mtd_info,它定义了大量的关于MTD的数据和操作函数。其中mtdcore.c: MTD原始设备接口相关实现,mtdpart.c : MTD分区接口相关实现。

  • MTD设备层:基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90)。其中mtdchar.c : MTD字符设备接口相关实现,mtdblock.c : MTD块设备接口相关实现。块设备模拟:MTD提供一个称谓mtdblock的块驱动程序,它在闪存上模拟一块硬盘,你可以将任何文件系统(如:ext2)放在模拟的闪存磁盘上,mtdblock隐藏了复杂的闪存访问过程(比如写之前先删除相关扇区的内容),被mtdblock创建的设备节点命名为/dev/mtdblock/X,其中X是分区号。字符设备模拟:mtdchar是底层闪存设备呈现出线性特点,与文件系统的块设备特性不同,mtdchar建立的设备节点命名为/dev/mtd/X,其中X为分区号,例如,写入引导程序: dd if=bootloader.bin of=/dev/mtd/0 ;一个原始mtdchar分区的使用示例是POST错误日志,另外一个嵌入式系统使用字符闪存分区的例子是保存类似于PC的CMOS、EEPROM信息。

  • 设备节点:通过mknod在/dev子目录下建立MTD块设备节点(主设备号为31)和MTD字符设备节点(主设备号为90)。通过访问此设备节点即可访问MTD字符设备和块设备

作为一个初学者,学到现在发现,所谓的内核驱动程序开发,其实许多工作并不要你去做,都是写内核的那些大牛做好的,比如这里nandflash的基本协议也就是MTD原始设备层。需要我们这些菜鸟做的就是根据nand特性修改底层代码,其实还是单片机开发。

参看at91_nand.c,可以发现这是一个典型的drive-bus-device模型。这部分属于nand底层驱动程序部分。init函数将包含设备信息的结构体注册到bus上:
platform_driver_register(&at91_nand_driver);
如果在bus上存在一个与该驱动相匹配的device结构体,则调用probe函数。再此主要涉及两个重要结构体。

Linux内核使用mtd_info结构体表示MTD原始设备,这其中定义了大量关于MTD的数据和操作函数;

struct mtd_info {
     
    u_char type;         /* MTD类型,包括MTD_NORFLASH,MTD_NANDFLASH等(可参考mtd-abi.h) */  
    uint32_t flags;      /* MTD属性标志,MTD_WRITEABLE,MTD_NO_ERASE等(可参考mtd-abi.h) */  
    uint64_t size;       /* mtd设备的大小 */  
    uint32_t erasesize;  /* MTD设备的擦除单元大小,对于NandFlash来说就是Block的大小 */  
    uint32_t writesize;  /* 写大小, 对于norFlash是字节,对nandFlash为一页 */  
    uint32_t oobsize;    /* OOB字节数 */  
    uint32_t oobavail;   /* 可用的OOB字节数 */  
    unsigned int erasesize_shift;   /* 默认为0,不重要 */  
    unsigned int writesize_shift;   /* 默认为0,不重要 */  
    unsigned int erasesize_mask;    /* 默认为1,不重要 */  
    unsigned int writesize_mask;    /* 默认为1,不重要 */  
    const char *name;               /* 名字,   不重要*/  
    int index;                      /* 索引号,不重要 */  
    int numeraseregions;            /* 通常为1 */  
    struct mtd_erase_region_info *eraseregions; /* 可变擦除区域 */  
      
    void *priv;     /* 设备私有数据指针,对于NandFlash来说指nand_chip结构体 */  
    struct module *owner;   /* 一般设置为THIS_MODULE */  
      
    /* 擦除函数 */  
    int (*erase) (struct mtd_info *mtd, struct erase_info *instr);  
  
    /* 读写flash函数 */  
    int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
    int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);  
  
    /* 带oob读写Flash函数 */  
    int (*read_oob) (struct mtd_info *mtd, loff_t from,  
             struct mtd_oob_ops *ops);  
    int (*write_oob) (struct mtd_info *mtd, loff_t to,  
             struct mtd_oob_ops *ops);  
  
    int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  
    int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
    int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  
    int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
    int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
    int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);  
  
    int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);  
    int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);  
    /* Sync */  
    void (*sync) (struct mtd_info *mtd);  
  
    /* Chip-supported device locking */  
    int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);  
    int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);  
  
    /* 电源管理函数 */  
    int (*suspend) (struct mtd_info *mtd);  
    void (*resume) (struct mtd_info *mtd);  
  
    
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值