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

一. 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);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值