一. 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);
阅读(1849) | 评论(0) | 转发(0) |