linux nand 驱动,Linux NAND FLASH驱动分析(一)

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

之前分析了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  调用平台总线驱动的match(drv->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_controlcontroller;

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;

intsel_bit;

intmtd_count;

unsigned longsave_sel;

unsigned longclk_rate;

enum s3c_cpu_typecpu_type;

#ifdef CONFIG_CPU_FREQ

struct notifier_blockfreq_transition;

#endif

};

struct nand_hw_control {

spinlock_t lock;

struct nand_chip *active;

wait_queue_head_t  wq;

};

struct s3c2410_nand_mtd {

struct mtd_infomtd;

struct nand_chipchip;

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;  可选的标志

intnr_chips;  有多少片NAND FLASH

intnr_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 structs3c2410_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,

},

};

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值