您的位置:首页 > 移动开发 > Android开发

android2.3.4----8. nand flash驱动分析

2016-06-13 16:04 323 查看
一. nand devices分析

1.1 platform_devices的添加

在arch/arm/plat-samsun/dev-nand.c中

static struct resource s3c_nand_resource[] = {

[0] = {

.start = S3C_PA_NAND,

.end = S3C_PA_NAND + SZ_1M,

.flags = IORESOURCE_MEM,

}

};

struct platform_device s3c_device_nand = {

.name = “s3c2410-nand”,

.id = -1,

.num_resources = ARRAY_SIZE(s3c_nand_resource),

.resource = s3c_nand_resource,

};

EXPORT_SYMBOL(s3c_device_nand);

别看这儿是s3c2410-nand后来又设置为s3c6410-nand

arch/arm/mach-s3c64xx/s3c6410.c中

void __init s3c6410_map_io(void)

{

s3c_device_nand.name = “s3c6410-nand”;

}

1.1 分区信息的添加

在arch/arm/mach-s3c64xx/mach-smdk6410.c中

struct mtd_partition ok6410_nand_part[] = {

{

.name = “Bootloader”,

.offset = 0,

.size = (1 * SZ_1M),

.mask_flags = MTD_CAP_NANDFLASH,

},

{

.name = “Kernel”,

.offset = (1 * SZ_1M),

.size = (5*SZ_1M) ,

.mask_flags = MTD_CAP_NANDFLASH,

},

{
.name        = "User",
.offset        = (6 * SZ_1M),
.size        = (200*SZ_1M) ,
},
{
.name        = "File System",
.offset        = MTDPART_OFS_APPEND,
.size        = MTDPART_SIZ_FULL,
}


};

static struct s3c2410_nand_set ok6410_nand_sets[] = {

[0] = {

.name = “nand”,

.nr_chips = 1,

.nr_partitions = ARRAY_SIZE(ok6410_nand_part),

.partitions = ok6410_nand_part,

},

};

static struct s3c2410_platform_nand ok6410_nand_info = {

.tacls = 25,

.twrph0 = 55,

.twrph1 = 40,

.nr_sets = ARRAY_SIZE(ok6410_nand_sets),

.sets = ok6410_nand_sets,

};

然后在smdk6410_machine_init中添加

s3c_nand_set_platdata(&ok6410_nand_info);

void __init s3c_nand_set_platdata(struct s3c2410_platform_nand *nand)

{

s3c_device_nand.dev.platform_data = nand;

}

二. nand driver分析

在drivers/mtd/nand/s3c_nand.c中

module_init(s3c_nand_init);

–> s3c_nand_init

static int __init s3c_nand_init(void)

{

printk(“S3C NAND Driver, (c) 2008 Samsung Electronics\n”);

return platform_driver_register(&s3c6410_nand_driver);

}

匹配name

static struct platform_driver s3c6410_nand_driver = {

.probe = s3c6410_nand_probe,

.remove = s3c_nand_remove,

.suspend = s3c_nand_suspend,

.resume = s3c_nand_resume,

.driver = {

.name = “s3c6410-nand”,

.owner = THIS_MODULE,

},

};

进入probe函数

static int s3c6410_nand_probe(struct platform_device *dev)

{

return s3c_nand_probe(dev, TYPE_S3C6410);

}

再次进入调用

static int s3c_nand_probe(struct platform_device *pdev, enum s3c_cpu_type cpu_type)

{

struct s3c2410_platform_nand *plat = pdev->dev.platform_data;

struct s3c2410_nand_set *sets;

struct nand_chip *nand;

struct resource *res;

struct nand_flash_dev *type = NULL;
//打开nand flash 时钟
s3c_nand.clk = clk_get(&pdev->dev, "nand");
clk_enable(s3c_nand.clk);
//ioremap  Nand flash控制寄存器
res = pdev->resource;
size = res->end - res->start + 1;
s3c_nand.area = request_mem_region(res->start, size, pdev->name);
s3c_nand.cpu_type = cpu_type;
s3c_nand.device = &pdev->dev;
s3c_nand.regs = ioremap(res->start, size);
s3c_nand.platform = plat;

sets = (plat != NULL) ? plat->sets : NULL;      //sets.partitions就是分区信息
nr_sets = (plat != NULL) ? plat->nr_sets : 1;   //nr_sets=1

s3c_nand.mtd_count = nr_sets;

//分配内存大小为: mtd_info + nand_chip,并初始化
s3c_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
nand = (struct nand_chip *) (&s3c_mtd[1]);  //所以nand_chip的起始地址是&mtd_info[1]
memset((char *) s3c_mtd, 0, sizeof(struct mtd_info));
memset((char *) nand, 0, sizeof(struct nand_chip));

s3c_mtd->priv = nand;

for (i = 0; i < sets->nr_chips; i++) {                 //sets->nr_chips=1
nand->IO_ADDR_R      = (char *)(s3c_nand.regs + S3C_NFDATA);
nand->IO_ADDR_W      = (char *)(s3c_nand.regs + S3C_NFDATA);
nand->cmd_ctrl       = s3c_nand_hwcontrol;
nand->dev_ready      = s3c_nand_device_ready;
nand->scan_bbt       = s3c_nand_scan_bbt;
nand->options        = 0;
nand->ecc.mode       = NAND_ECC_HW;
nand->ecc.hwctl      = s3c_nand_enable_hwecc;
nand->ecc.calculate  = s3c_nand_calculate_ecc;
nand->ecc.correct    = s3c_nand_correct_data;
//发起读取设备ID流程
s3c_nand_hwcontrol(0, NAND_CMD_READID, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
s3c_nand_hwcontrol(0, 0x00, NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);
s3c_nand_hwcontrol(0, 0x00, NAND_NCE | NAND_ALE);
s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
s3c_nand_device_ready(0);
//第1次读取的是device code=0xD5
tmp = readb(nand->IO_ADDR_R);
dev_id = tmp = readb(nand->IO_ADDR_R);
//查表获取 nand flash的硬件信息
// name                     id    pagesize chipsize    erasesize       option
// {"NAND 2GiB 3,3V 8-bit", 0xD5, 4096,    2048,       512*1024,   LP_OPTIONS},
for (j = 0; nand_flash_ids[j].name != NULL; j++) {
if (tmp == nand_flash_ids[j].id) {
type = &nand_flash_ids[j];
break;
}
}

nand->cellinfo = readb(nand->IO_ADDR_R);
tmp = readb(nand->IO_ADDR_R);
if (!type->pagesize) {
if (((nand->cellinfo >> 2) & 0x3) == 0) {
} else {
nand_type = S3C_NAND_TYPE_MLC_4BIT;
nand->options |= NAND_NO_SUBPAGE_WRITE;
nand->ecc.read_page = s3c_nand_read_page_4bit;
nand->ecc.write_page = s3c_nand_write_page_4bit;
nand->ecc.size = 512;
nand->ecc.bytes = 8;
nand->ecc.layout = &s3c_nand_oob_mlc_64;
if(dev_id == 0xd5)
{
printk("dev_id == 0xd5 select s3c_nand_oob_mlc_128\n");
nand_type = S3C_NAND_TYPE_MLC_8BIT;
nand->ecc.read_page = s3c_nand_read_page_8bit;
nand->ecc.write_page = s3c_nand_write_page_8bit;
nand->ecc.size = 512;
nand->ecc.bytes = 13;
nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;
}
}
}
nand_scan(s3c_mtd, 1);
add_mtd_partitions(s3c_mtd, sets->partitions, sets->nr_partitions);
}
return 0;


}

nand_scan

–>nand_scan_ident

–> nand_set_defaults 设置chip的指针

–> nand_get_flash_type 获取flash的类型

nand_scan

–> nand_scan_tail 设置chip->ecc的指针 及 mtd的一些指针

–> chip->scan_bbt 最后调用scan_bbt,不过这儿直接返回0

int add_mtd_partitions(struct mtd_info *master, const struct mtd_partition *parts, int nbparts)

{

struct mtd_part *slave;

uint64_t cur_offset = 0;

for (i = 0; i < nbparts; i++) {

slave = add_one_partition(master, parts + i, i, cur_offset);

cur_offset = slave->offset + slave->mtd.size;

}

return 0;


}

EXPORT_SYMBOL(add_mtd_partitions);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android