Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2968925
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: Android平台

2014-09-20 14:34:24

原文地址:http://blog.chinaunix.net/uid-26009923-id-4140652.html

一. nand devices分析
1.1 platform_devices的添加
在arch/arm/plat-samsun/dev-nand.c中
  1. static struct resource s3c_nand_resource[] = {
  2.     [0] = {
  3.         .start = S3C_PA_NAND,
  4.         .end = S3C_PA_NAND + SZ_1M,
  5.         .flags = IORESOURCE_MEM,
  6.     }
  7. };
  8. struct platform_device s3c_device_nand = {
  9.     .name         = "s3c2410-nand",
  10.     .id         = -1,
  11.     .num_resources     = ARRAY_SIZE(s3c_nand_resource),
  12.     .resource     = s3c_nand_resource,
  13. };
  14. EXPORT_SYMBOL(s3c_device_nand);
别看这儿是s3c2410-nand后来又设置为s3c6410-nand
arch/arm/mach-s3c64xx/s3c6410.c中
  1. void __init s3c6410_map_io(void)
  2. {
  3.     s3c_device_nand.name = "s3c6410-nand";
  4. }
1.1 分区信息的添加
在arch/arm/mach-s3c64xx/mach-smdk6410.c中
  1. struct mtd_partition ok6410_nand_part[] = {
  2.     {
  3.         .name        = "Bootloader",
  4.         .offset        = 0,
  5.         .size        = (* SZ_1M),
  6.         .mask_flags    = MTD_CAP_NANDFLASH,
  7.     },
  8.     {
  9.         .name        = "Kernel",
  10.         .offset        = (* SZ_1M),
  11.         .size        = (5*SZ_1M) ,
  12.         .mask_flags    = MTD_CAP_NANDFLASH,
  13.     },

  14.     {
  15.         .name        = "User",
  16.         .offset        = (* SZ_1M),
  17.         .size        = (200*SZ_1M) ,
  18.     },
  19.     {
  20.         .name        = "File System",
  21.         .offset        = MTDPART_OFS_APPEND,
  22.         .size        = MTDPART_SIZ_FULL,
  23.     }
  24. };

  25. static struct s3c2410_nand_set ok6410_nand_sets[] = {
  26.     [0] = {
  27.         .name = "nand",
  28.         .nr_chips = 1,
  29.         .nr_partitions = ARRAY_SIZE(ok6410_nand_part),
  30.         .partitions = ok6410_nand_part,
  31.     },
  32. };

  33. static struct s3c2410_platform_nand ok6410_nand_info = {
  34.     .tacls = 25,
  35.     .twrph0 = 55,
  36.     .twrph1 = 40,
  37.     .nr_sets = ARRAY_SIZE(ok6410_nand_sets),
  38.     .sets = ok6410_nand_sets,
  39. };
然后在smdk6410_machine_init中添加
    s3c_nand_set_platdata(&ok6410_nand_info);
  1. void __init s3c_nand_set_platdata(struct s3c2410_platform_nand *nand)
  2. {
  3.     s3c_device_nand.dev.platform_data = nand;
  4. }
二. nand driver分析
在drivers/mtd/nand/s3c_nand.c中
module_init(s3c_nand_init);
--> s3c_nand_init
  1. static int __init s3c_nand_init(void)
  2. {
  3.     printk("S3C NAND Driver, (c) 2008 Samsung Electronics\n");
  4.     return platform_driver_register(&s3c6410_nand_driver);
  5. }
匹配name
  1. static struct platform_driver s3c6410_nand_driver = {
  2.     .probe        = s3c6410_nand_probe,
  3.     .remove        = s3c_nand_remove,
  4.     .suspend    = s3c_nand_suspend,
  5.     .resume        = s3c_nand_resume,
  6.     .driver        = {
  7.         .name    = "s3c6410-nand",
  8.         .owner    = THIS_MODULE,
  9.     },
  10. };
进入probe函数
  1. static int s3c6410_nand_probe(struct platform_device *dev)
  2. {
  3.     return s3c_nand_probe(dev, TYPE_S3C6410);
  4. }
再次进入调用
  1. static int s3c_nand_probe(struct platform_device *pdev, enum s3c_cpu_type cpu_type)
  2. {
  3.     struct s3c2410_platform_nand *plat = pdev->dev.platform_data;
  4.     struct s3c2410_nand_set *sets;
  5.     struct nand_chip *nand;
  6.     struct resource *res;
  7.     
  8.     struct nand_flash_dev *type = NULL;
  9.     //打开nand flash 时钟
  10.     s3c_nand.clk = clk_get(&pdev->dev, "nand");
  11.     clk_enable(s3c_nand.clk);
  12.     //ioremap  Nand flash控制寄存器
  13.     res = pdev->resource;
  14.     size = res->end - res->start + 1;
  15.     s3c_nand.area = request_mem_region(res->start, size, pdev->name);
  16.     s3c_nand.cpu_type = cpu_type;
  17.     s3c_nand.device = &pdev->dev;
  18.     s3c_nand.regs = ioremap(res->start, size);
  19.     s3c_nand.platform = plat;

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

  22.     s3c_nand.mtd_count = nr_sets;

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

  28.     s3c_mtd->priv = nand;

  29.     for (= 0; i < sets->nr_chips; i++) {                 //sets->nr_chips=1
  30.         nand->IO_ADDR_R      = (char *)(s3c_nand.regs + S3C_NFDATA);
  31.         nand->IO_ADDR_W      = (char *)(s3c_nand.regs + S3C_NFDATA);
  32.         nand->cmd_ctrl       = s3c_nand_hwcontrol;
  33.         nand->dev_ready      = s3c_nand_device_ready;
  34.         nand->scan_bbt       = s3c_nand_scan_bbt;
  35.         nand->options        = 0;
  36.         nand->ecc.mode       = NAND_ECC_HW;
  37.         nand->ecc.hwctl      = s3c_nand_enable_hwecc;
  38.         nand->ecc.calculate  = s3c_nand_calculate_ecc;
  39.         nand->ecc.correct    = s3c_nand_correct_data;
  40.         //发起读取设备ID流程
  41.         s3c_nand_hwcontrol(0, NAND_CMD_READID, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
  42.         s3c_nand_hwcontrol(0, 0x00, NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);
  43.         s3c_nand_hwcontrol(0, 0x00, NAND_NCE | NAND_ALE);
  44.         s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
  45.         s3c_nand_device_ready(0);
  46.             //第1次读取的是device code=0xD5
  47.         tmp = readb(nand->IO_ADDR_R);  
  48.         dev_id = tmp = readb(nand->IO_ADDR_R);  
  49.             //查表获取 nand flash的硬件信息
  50.           // name                     id    pagesize chipsize    erasesize       option            
              // {"NAND 2GiB 3,3V 8-bit", 0xD5, 4096,    2048,       512*1024,   LP_OPTIONS},
  51.         for (= 0; nand_flash_ids[j].name != NULL; j++) {
  52.             if (tmp == nand_flash_ids[j].id) {
  53.                 type = &nand_flash_ids[j];
  54.                 break;
  55.             }
  56.         }

  57.         nand->cellinfo = readb(nand->IO_ADDR_R); 
  58.         tmp = readb(nand->IO_ADDR_R);
  59.         if (!type->pagesize) {
  60.             if (((nand->cellinfo >> 2) & 0x3) == 0) {                
  61.             } else {
  62.                 nand_type = S3C_NAND_TYPE_MLC_4BIT;
  63.                 nand->options |= NAND_NO_SUBPAGE_WRITE;   
  64.                 nand->ecc.read_page = s3c_nand_read_page_4bit;
  65.                 nand->ecc.write_page = s3c_nand_write_page_4bit;
  66.                 nand->ecc.size = 512;
  67.                 nand->ecc.bytes = 8;   
  68.                 nand->ecc.layout = &s3c_nand_oob_mlc_64;
  69.                 if(dev_id == 0xd5)
  70.                 {
  71.                     printk("dev_id == 0xd5 select s3c_nand_oob_mlc_128\n");
  72.                     nand_type = S3C_NAND_TYPE_MLC_8BIT;
  73.                     nand->ecc.read_page = s3c_nand_read_page_8bit;
  74.                     nand->ecc.write_page = s3c_nand_write_page_8bit;
  75.                     nand->ecc.size = 512;
  76.                     nand->ecc.bytes = 13;   
  77.                     nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;
  78.                 }
  79.             }
  80.         } 
  81.         nand_scan(s3c_mtd, 1);
  82.         add_mtd_partitions(s3c_mtd, sets->partitions, sets->nr_partitions);
  83.     }
  84.     return 0;
  85. }

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

  1. int add_mtd_partitions(struct mtd_info *masterconst struct mtd_partition *parts, int nbparts)
  2. {
  3.     struct mtd_part *slave;
  4.     uint64_t cur_offset = 0;
  5.     for (= 0; i < nbparts; i++) {
  6.         slave = add_one_partition(master, parts + i, i, cur_offset);
  7.         cur_offset = slave->offset + slave->mtd.size;
  8.     }

  9.     return 0;
  10. }
  11. EXPORT_SYMBOL(add_mtd_partitions);

阅读(949) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~