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,
},
};
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;
}
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;
}
}
EXPORT_SYMBOL(add_mtd_partitions);
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);
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories