Chinaunix首页 | 论坛 | 博客
  • 博客访问: 148888
  • 博文数量: 40
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 908
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-03 11:03
个人简介

学习linux

文章分类
文章存档

2014年(7)

2013年(33)

我的朋友

分类: 嵌入式

2013-09-11 23:49:55

1. Linux的MTD系统:
    在linux的用户空间中访问flash时要经过三层,
   一是上层设备层,核心导出字符设备和块设备;字符设备定义在mtdchar.c(major为90),实现了file_operations,都是调用下层的函数。
   块设备定义了mtdblk_dev,每个块设备对应一个分区,即mtd_part(major为31)。
   二是中间层原始设备层,用mtd_part表示分区,对应上层的每个次设备号,mtd_info表示一个芯片设备描述,上层的读写函数会
    通过核心调用这个结构的相关函数。可以用add_mtd_partitions向核心添加几个新的分区(用mtd_part表示),这需要描述分区
    信息的结构mtd_partition(在板文件定义)和整个芯片属性和方法的结构mtd_info(这里面包含了读写和控制函数,会调用下层的函数)。
   三是底层芯片级驱动,主要是nand_chip结构体,mtd_info的priv指针指向nand_chip,所以中间层的函数通过这个指针调用nand_chip中的
   函数。这个结构体包含了关于nand flash的地址信息,读写方法,ECC模式,硬件控制等一系列底层机制。我们只需要定义nand_chip的
    这些成员,因为内核的nand_base.c实现了很多通用代码。

    我们要做的就是第三步,先实现nand_chip的有关成员,这与硬件有关,再用nand_scan(mtd_info *mtd ),这会探测芯片,
    探测芯片即调用nand_chip中的函数并用nand_chip的成员初始化mtd_info,这是整个芯片的中间层描述,再调用add_mtd_partitions,
    即用板文件的分区表mtd_partition数组和前面准备的mtd_info向核心添加整个芯片的所有分区,即是新建几个mtd_part,每个表示一个
    分区,这里面包含mtd_info,其中大多成员直接指向整个芯片的mtd_info,因为分区的操作与芯片的操作是一样的。


2. 实现ok6410的nand flash驱动:
    首先在板文件定义struct mtd_partition ok6410_nand_part[],即分区信息,struct s3c2410_nand_set ok6410_nand_sets[]
     即所有芯片信息,这里就只有一个芯片;struct s3c2410_platform_nand ok6410_nand_info,包含前面信息和芯片属性的
     platform_data;最后用s3c_nand_set_platdata(&ok6410_nand_info);形成platform_device,注册到platform总线。
     总线会由name找到(match)驱动,即在s3c-nand.c,执行驱动的probe。下面是这个函数:
    主要流程为:
    a. 得到clk并打开时钟
    b. 申请I/O内存并映射到内核虚拟地址
    c. 申请nand_chip和mtd_info的内存,根据电路板情况初始化nand_chip的成员
    d. 将mtd_info的priv指向nand_chip(下面调用的函数都是nand_chip中的)
    e. nand_scan探测nand_flash,这时会读取芯片ID,并用nand_chip初始化mtd_info
    f. 调用mtd_add_partitions,用板文件的分区表mtd_partition和上面芯片的mtd_info,新建分区,即几个mtd_part
    g. 以后MTD上层访问某个分区,都可以由mtd_part的mtd_info找到nand_flash,并调用其中的函数

点击(此处)折叠或打开

  1. /* s3c_nand_probe
  2.  *
  3.  * called by device layer when it finds a device matching
  4.  * one our driver can handled. This code checks to see if
  5.  * it can allocate all necessary resources then calls the
  6.  * nand layer to look for devices
  7.  */
  8. static int s3c_nand_probe(struct platform_device *pdev, enum s3c_cpu_type cpu_type)
  9. {    
  10.     struct s3c2410_platform_nand *plat = pdev->dev.platform_data;
  11.     struct s3c2410_nand_set *sets;
  12.     struct nand_chip *nand;
  13.     struct resource *res;
  14.     int err = 0;
  15.     int ret = 0;
  16.     int nr_sets;
  17.     int i, j, size;

  18. #if defined(CONFIG_MTD_NAND_S3C_HWECC)
  19.     struct nand_flash_dev *type = NULL;
  20.     u_char tmp;
  21.     u_char dev_id;
  22. #endif

  23.     /* get the clock source and enable it */

  24.     s3c_nand.clk = clk_get(&pdev->dev, "nand");
  25.     if (IS_ERR(s3c_nand.clk)) {
  26.         dev_err(&pdev->dev, "failed to get clock");
  27.         err = -ENOENT;
  28.         goto exit_error;
  29.     }

  30.     clk_enable(s3c_nand.clk);

  31.     /* allocate and map the resource */

  32.     /* currently we assume we have the one resource */
  33.     res = pdev->resource;
  34.     size = res->end - res->start + 1;

  35.     s3c_nand.area = request_mem_region(res->start, size, pdev->name);

  36.     if (s3c_nand.area == NULL) {
  37.         dev_err(&pdev->dev, "cannot reserve register region\n");
  38.         err = -ENOENT;
  39.         goto exit_error;
  40.     }

  41.     s3c_nand.cpu_type = cpu_type;
  42.     s3c_nand.device = &pdev->dev;
  43.     s3c_nand.regs = ioremap(res->start, size);
  44.     s3c_nand.platform = plat;

  45.     if (s3c_nand.regs == NULL) {
  46.         dev_err(&pdev->dev, "cannot reserve register region\n");
  47.         err = -EIO;
  48.         goto exit_error;
  49.     }
  50.     sets = (plat != NULL) ? plat->sets : NULL;
  51.     nr_sets = (plat != NULL) ? plat->nr_sets : 1;

  52.     s3c_nand.mtd_count = nr_sets;

  53.     /* allocate memory for MTD device structure and private data */
  54.     s3c_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);

  55.     if (!s3c_mtd) {
  56.         printk("Unable to allocate NAND MTD dev structure.\n");
  57.         return -ENOMEM;
  58.     }

  59.     /* Get pointer to private data */
  60.     nand = (struct nand_chip *) (&s3c_mtd[1]);

  61.     /* Initialize structures */
  62.     memset((char *) s3c_mtd, 0, sizeof(struct mtd_info));
  63.     memset((char *) nand, 0, sizeof(struct nand_chip));

  64.     /* Link the private data with the MTD structure */
  65.     s3c_mtd->priv = nand;



  66.     for (i = 0; i < sets->nr_chips; i++)
  67.     {
  68.         nand->IO_ADDR_R        = (char *)(s3c_nand.regs + S3C_NFDATA);
  69.         nand->IO_ADDR_W        = (char *)(s3c_nand.regs + S3C_NFDATA);
  70.         nand->cmd_ctrl        = s3c_nand_hwcontrol;
  71.         nand->dev_ready        = s3c_nand_device_ready;
  72.         nand->scan_bbt        = s3c_nand_scan_bbt;
  73.         nand->options        = 0;

  74. #if defined(CONFIG_MTD_NAND_S3C_CACHEDPROG)
  75.         nand->options        |= NAND_CACHEPRG;
  76. #endif

  77. #if defined(CONFIG_MTD_NAND_S3C_HWECC)
  78.         nand->ecc.mode        = NAND_ECC_HW;
  79.         nand->ecc.hwctl        = s3c_nand_enable_hwecc;
  80.         nand->ecc.calculate    = s3c_nand_calculate_ecc;
  81.         nand->ecc.correct    = s3c_nand_correct_data;


  82.         // K9GAG08U0E must add below codes
  83.         {
  84.             s3c_nand_hwcontrol(0, NAND_CMD_RESET, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
  85.             s3c_nand_device_wait_ready(0);

  86.         }

  87.         s3c_nand_hwcontrol(0, NAND_CMD_READID, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
  88.         s3c_nand_hwcontrol(0, 0x00, NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);
  89.         s3c_nand_hwcontrol(0, 0x00, NAND_NCE | NAND_ALE);
  90.         s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
  91.         //s3c_nand_device_ready(0);

  92.         s3c_nand_device_wait_ready(0);

  93.          u32 manuf=tmp = readb(nand->IO_ADDR_R); /* Maf. ID */
  94.        

  95.         dev_id = tmp = readb(nand->IO_ADDR_R); /* Device ID */

  96.         printk("forlinx nandflash dev_id=%x\n",dev_id);

  97.         for (j = 0; nand_flash_ids[j].name != NULL; j++) {
  98.             if (tmp == nand_flash_ids[j].id) {
  99.                 type = &nand_flash_ids[j];
  100.                 break;
  101.             }
  102.         }

  103.         if (!type) {
  104.             printk("Unknown NAND Device.\n");
  105.             goto exit_error;
  106.         }

  107.         nand->cellinfo = readb(nand->IO_ADDR_R);    /* the 3rd byte */
  108.         tmp = readb(nand->IO_ADDR_R);            /* the 4th byte */
  109.         if (!type->pagesize)
  110.         {
  111.             if (((nand->cellinfo >> 2) & 0x3) == 0)
  112.             {

  113.                 nand_type = S3C_NAND_TYPE_SLC;
  114.                 nand->ecc.size = 512;
  115.                 nand->ecc.bytes    = 4;

  116.                 if ((1024 << (tmp & 0x3)) > 512)
  117.                 {
  118.                     nand->ecc.read_page = s3c_nand_read_page_1bit;
  119.                     nand->ecc.write_page = s3c_nand_write_page_1bit;
  120.                     nand->ecc.read_oob = s3c_nand_read_oob_1bit;
  121.                     nand->ecc.write_oob = s3c_nand_write_oob_1bit;
  122.                     nand->ecc.layout = &s3c_nand_oob_64;

  123.                     printk("forlinx********Nandflash:Type=SLC ChipName:samsung-K9F2G08U0B or hynix-HY27UF082G2B****** \n");


  124.                 } else
  125.                 {
  126.                     nand->ecc.layout = &s3c_nand_oob_16;
  127.                 }

  128.             } else
  129.             {
  130.                 // int childType=tmp & 0x03; //Page size
  131.                 int childType = nand->cellinfo;

  132.                 if(dev_id == 0xd5)
  133.                 {

  134.                     nand_type = S3C_NAND_TYPE_MLC_8BIT;
  135.                     nand->ecc.read_page = s3c_nand_read_page_8bit;
  136.                     nand->ecc.write_page = s3c_nand_write_page_8bit;
  137.                     nand->ecc.size = 512;
  138.                     nand->ecc.bytes = 13;

  139.                     if(childType==0x94)
  140.                     {
  141.                         //K9GAG08U0D size=2GB type=MLC Page=4K
  142.                         nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;
  143.                         printk("forlinx****Nandflash:ChipType= MLC ChipName=samsung-K9GAG08U0D************ \n");
  144.                     }
  145.                     else if(childType==0x14)
  146.                     {
  147.                         //K9GAG08U0M size=2GB type=MLC Page=4K
  148.                         nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;
  149.                         printk("forlinx****Nandflash:ChipType= MLC ChipName=samsung-K9GAG08U0M************ \n");
  150.                     }
  151.                     else if(childType==0x84)
  152.                     {
  153.                         //K9GAG08U0E size=2GB type=MLC Page=8K
  154.                         nand->ecc.layout = &s3c_nand_oob_mlc_232_8bit;
  155.                         printk("forlinx****Nandflash:ChipType= MLC ChipName=samsung-K9GAG08U0E************ \n");

  156.                     }


  157.                 }else if(dev_id == 0xd7)
  158.                 {
  159.                     nand_type = S3C_NAND_TYPE_MLC_8BIT;
  160.                     nand->ecc.read_page = s3c_nand_read_page_8bit;
  161.                     nand->ecc.write_page = s3c_nand_write_page_8bit;
  162.                     nand->ecc.size = 512;
  163.                     nand->ecc.bytes = 13;
  164.                     nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;
  165.                     printk("forlinx****Nandflash:ChipType= MLC ChipName=samsung-K9LBG08U0D************ \n");


  166.                 }
  167.                 else if(dev_id == 0xd3)
  168.                 {
  169.                     nand_type = S3C_NAND_TYPE_MLC_4BIT;
  170.                     nand->options |= NAND_NO_SUBPAGE_WRITE;    /* NOP = 1 if MLC */
  171.                     nand->ecc.read_page = s3c_nand_read_page_4bit;
  172.                     nand->ecc.write_page = s3c_nand_write_page_4bit;
  173.                     nand->ecc.size = 512;
  174.                     nand->ecc.bytes = 8;    /* really 7 bytes */
  175.                     nand->ecc.layout = &s3c_nand_oob_mlc_64;

  176.                     printk("forlinx****Nandflash:ChipType=MLC ChipName=samsung-K9G8G08U0A************** \n");

  177.                 }

  178.             }

  179.         } else if(dev_id == 0xd7)
  180.         {
  181.             nand_type = S3C_NAND_TYPE_MLC_8BIT;
  182.             nand->ecc.read_page = s3c_nand_read_page_8bit;
  183.             nand->ecc.write_page = s3c_nand_write_page_8bit;
  184.             nand->ecc.size = 512;
  185.             nand->ecc.bytes = 13;
  186.             nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;
  187.             printk("forlinx****Nandflash:ChipType= MLC ChipName=samsung-K9LBG08U0D************ \n");

  188.         }
  189.         else if(manuf==0x2c && dev_id ==0x48)
  190.         {
  191.             //MT29F16G08ABACAWP size=2GB type=SLC Page=4K
  192.             nand_type = S3C_NAND_TYPE_MLC_8BIT;
  193.             nand->ecc.read_page = s3c_nand_read_page_8bit;
  194.             nand->ecc.write_page = s3c_nand_write_page_8bit;
  195.             nand->ecc.size = 512;
  196.             nand->ecc.bytes = 13;
  197.             nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;

  198.             printk("forlinx******Nandflash:ChipType= SLC ChipName=MT29F16G08ABACAWP\n");

  199.         } else if(manuf==0x2c && dev_id ==0x38)
  200.         {
  201.                 //MT29F16G08ABACAWP size=1GB type=SLC Page=4K
  202.                 nand_type = S3C_NAND_TYPE_MLC_8BIT;
  203.                 nand->ecc.read_page = s3c_nand_read_page_8bit;
  204.                 nand->ecc.write_page = s3c_nand_write_page_8bit;
  205.                 nand->ecc.size = 512;
  206.                 nand->ecc.bytes = 13;
  207.                 nand->ecc.layout = &s3c_nand_oob_mlc_128_8bit;

  208.                 printk("forlinx******Nandflash:ChipType= SLC ChipName=MT29F8G08ABABAWP\n");

  209.         }else
  210.         {
  211.             nand_type = S3C_NAND_TYPE_SLC;
  212.             nand->ecc.size = 512;
  213.             nand->cellinfo = 0;
  214.             nand->ecc.bytes = 4;
  215.             nand->ecc.layout = &s3c_nand_oob_16;
  216.             printk("forlinx *****Nandflash:ChipType= Unknow\n");

  217.         }

  218.         printk("S3C NAND Driver is using hardware ECC.\n");
  219. #else
  220.         nand->ecc.mode = NAND_ECC_SOFT;
  221.         printk("S3C NAND Driver is using software ECC.\n");
  222. #endif
  223.         if (nand_scan(s3c_mtd, 1)) {
  224.             ret = -ENXIO;
  225.             goto exit_error;
  226.         }

  227.         /* Register the partitions */
  228.         add_mtd_partitions(s3c_mtd, sets->partitions, sets->nr_partitions);
  229.     }

  230.     pr_debug("initialized ok\n");
  231.     return 0;

  232. exit_error:
  233.     kfree(s3c_mtd);


  234.     return ret;
  235. }







阅读(2448) | 评论(0) | 转发(0) |
0

上一篇:算法效率分析

下一篇:ok6410的DM9000驱动

给主人留下些什么吧!~~