首页 > 其他 > 详细

Linux NAND FLASH驱动分析(一)

时间:2014-03-12 08:46:21      阅读:478      评论:0      收藏:0      [点我收藏+]

  最近一直在忙着工作上的事情,好久都没有更新博客了,发现最近思想是比较混乱的。学任何东西都坚持不下去,既然选择驱动开发这条路就要坚持下去。

  之前分析了Linux块设备驱动,是以内存块来模拟的虚拟块设备。现在重点来分析Linux NAND FLASH驱动,移植过uboot的朋友都知道,在uboot中NAND FLASH驱动正是从Linux内核中移植过去的,Linux内核中对FLASH的驱动都是以MTD来实现的,现在就来揭秘MTD驱动的神秘面纱。

  在Linux内核启动阶段,总能看到这样的打印信息(“S3C24XX NAND Driver, (c) 2004 Simtec Electronics”),没错,这就是NAND FLASH驱动中打印出来,我们就顺藤摸瓜的分析下去。

  注:Linux内核版本为2.6.36.4

  在drivers/mtd/nand/s3c2410.c中的s3c2410_nand_init函数即为驱动的入口。

s3c2410_nand_init

  --> platform_driver_register(&s3c24xx_nand_driver)

主要工作就是注册了一个平台驱动。以下为该平台驱动的实例:

static struct platform_driver s3c24xx_nand_driver = {
  .probe=  s3c24xx_nand_probe,
  .remove=  s3c24xx_nand_remove,
  .suspend=  s3c24xx_nand_suspend,
  .resume=  s3c24xx_nand_resume,
  .id_table= s3c24xx_driver_ids,
  .driver= {
    .name= "s3c24xx-nand",
    .owner= THIS_MODULE,
  },
};

platform_driver_register

  --> driver_register

     --> bus_add_driver

        --> driver_attach

          --> __driver_attach

             --> driver_match_device  调用平台总线驱动的matchdrv->bus->match ? drv->bus->match(dev, drv) : 1;

                 --> platform_match

                    --> platform_match_id  将用platform_driver.id_table的name与平台设备的name进行匹配

             --> driver_probe_device

--> really_probe

   --> 最终调用平台驱动的probe方法:s3c24xx_nand_probe

下面就从这个函数开始分析:

s3c24xx_nand_probe

  1.分配一个s3c2410_nand_info结构空间

 info =kzalloc(sizeof(*info), GFP_KERNEL); 

  2.将该结构设置为平台设备的私有数据

  platform_set_drvdata(pdev, info);

  3.获取时钟,使能时钟

  clk_get(&pdev->dev, "nand");

  clk_enable(info->clk);

  4.设置分配的s3c2410_nand_info结构

  info->area = request_mem_region(res->start, size, pdev->name);

 info->device     = &pdev->dev;
  info->platform   = plat;// 平台数据
  info->regs       = ioremap(res->start, size);  // 对NAND FLASH控制器对应的I/O内存进行映射

 info->cpu_type   = cpu_type;

  5.初始化NAND FLASH控制器

  s3c2410_nand_inithw(info);


涉及的数据结构:

struct s3c2410_nand_info {
    struct nand_hw_control  controller;
    struct s3c2410_nand_mtd  *mtds;
    struct s3c2410_platform_nand  *platform;

    struct device *device;
    struct resource *area;
    struct clk *clk;
    void __iomem *regs;
    void __iomem *sel_reg;
    int sel_bit;
    int mtd_count;
    unsigned long save_sel;
    unsigned long clk_rate;
    enum s3c_cpu_type cpu_type;
#ifdef CONFIG_CPU_FREQ
    struct notifier_block freq_transition;
#endif
};


struct nand_hw_control {
    spinlock_t  lock;
    struct nand_chip  *active;
    wait_queue_head_t  wq;
};


struct s3c2410_nand_mtd {
    struct mtd_info  mtd;
    struct nand_chip  chip;
    struct s3c2410_nand_set  *set;
    struct s3c2410_nand_info *info;
    int  scan_res;
};


描述NAND FLASH的平台信息

struct s3c2410_platform_nand {
  /* 控制器的时序信息,所有的都是以纳秒为单位 */
  inttacls;  从CLE/ALE到nWE/nOE 信号的有效时间 
  inttwrph0;  nWE/nOE的有效时间
  inttwrph1;  从nWE/nOE失效到CLE/ALE释放的时间 
  unsigned intignore_unset_ecc:1;
  intnr_sets;  支持多少种配置
  struct s3c2410_nand_set *sets;  配置集合
  void(*select_chip)(struct s3c2410_nand_set *, int chip);  选择芯片的函数指针
};


用于描述S3C2410平台的NAND FLASH 配置

struct s3c2410_nand_set {
  unsigned intdisable_ecc:1; 是否禁止ECC校验
  unsigned intflash_bbt:1;  是否使用FLASH来存储坏块表
  unsigned intoptions;  可选的标志
  int nr_chips;   有多少片NAND FLASH
  int nr_partitions; 有多个分区
  char *name; 名字
  int *nr_map;
  struct mtd_partition*partitions;  MTD分区表指针
  struct nand_ecclayout*ecc_layout;  ECC布局图指针
};


用来描述一个MTD分区

struct mtd_partition {
  char *name; 分区的名字 
  uint64_t size;  分区的大小 
  uint64_t offset;  在整个MTD设备中的偏移地址
  uint32_t mask_flags;  主MTD设备掩码对于该分区不起左右的掩码位 
  struct nand_ecclayout *ecclayout;  ECC布局 
};


用于描述ECC布局

struct nand_ecclayout {
  __u32 eccbytes;  用于ECC校验的数据字节数
  __u32 eccpos[64];   ECC数据的存放位置
  __u32 oobavail;   OOB区可用大小
  struct nand_oobfree oobfree[8];    用来描述一个OOB空闲区
};


用来描述OOB空闲区

struct nand_oobfree {
  __u32 offset;     空闲区的偏移地址
  __u32 length;    空闲取的长度
};

在/arch/arm/plat-s3c24xx/common-smdk.c中有s3c2410_platform_nand的实例:smdk_nand_info

static struct s3c2410_platform_nandsmdk_nand_info = {
  .tacls = 20,
  .twrph0 = 60,
  .twrph1 = 20,
  .nr_sets = ARRAY_SIZE(smdk_nand_sets),  // = 1支持一种配置
  .sets =smdk_nand_sets,
};


static struct s3c2410_nand_setsmdk_nand_sets[] = {
  [0] = {
    .name = "NAND",
    .nr_chips = 1, 只有一块NAND FLASH
    .nr_partitions= ARRAY_SIZE(smdk_default_nand_part),  该NAND FLASH上分区数
    .partitions=smdk_default_nand_part,  NAND FLASH上的分区表
  },
};


static struct mtd_partitionsmdk_default_nand_part[] = {
  [0] = {
    .name = "Boot Agent",
    .size = SZ_16K,
    .offset = 0,
  },
  [1] = {
    .name = "S3C2410 flash partition 1",
    .offset = 0,
    .size = SZ_2M,
  },
  [2] = {
    .name = "S3C2410 flash partition 2",
    .offset = SZ_4M,
    .size = SZ_4M,
  },
[3] = {
    .name = "S3C2410 flash partition 3",
    .offset = SZ_8M,
    .size = SZ_2M,
  },
};





Linux NAND FLASH驱动分析(一),布布扣,bubuko.com

Linux NAND FLASH驱动分析(一)

原文:http://blog.csdn.net/lpjybn/article/details/21046353

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!