Chinaunix首页 | 论坛 | 博客
  • 博客访问: 812467
  • 博文数量: 321
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 936
  • 用 户 组: 普通用户
  • 注册时间: 2013-02-23 11:25
文章分类

全部博文(321)

文章存档

2017年(1)

2016年(10)

2015年(61)

2014年(187)

2013年(62)

分类: 嵌入式

2015-07-12 00:07:23

原文地址:2. nand初始化 作者:changyongID

1. nand_init();    drivers/mtd/nand/nand.c

先来看个nand_init的简要过程图


nand初始化关键的两个函数 board_nand_init 和 nand_scan

board_nand_init 是与板级相关的,uboot中cpu/arm920t/s3c24x0/nand.c中,移植的时候要重点
查看

     7    clk_power->CLKCON |= (1 << 4);

     8    /* initialize hardware */
     9    twrph0 = 3; twrph1 = 0; tacls = 0;

    10    cfg = S3C2410_NFCONF_EN;
    11    cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
    12    cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
    13    cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);

    14    NFCONF = cfg;

    15    /* initialize nand_chip data structure */
    16    nand->IO_ADDR_R = nand->IO_ADDR_W = 0x4e00000c;

    17    /* read_buf and write_buf are default */
    18    /* read_byte and write_byte are default */

    19    /* hwcontrol always must be implemented */
    20    nand->hwcontrol = s3c2410_hwcontrol;

    21    nand->dev_ready = s3c2410_dev_ready;
 

     9    twrph0 = 3; twrph1 = 0; tacls = 0;

    10    cfg = S3C2410_NFCONF_EN;
    11    cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
    12    cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
    13    cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);

    14    NFCONF = cfg;

    28    nand->eccmode = NAND_ECC_SOFT;
  
    33    nand->options = 0;


第7行 置CLKCON第5位,给nand控制器供电,上电默认是供电的

9~14 行,配置NFCONF ,移植时,这几个值要仔细对照数据手册算一下

16行 nand的读写I/O都设为NFDATA
     NAND读时,用的肯定是NFDATA
     写nand时,可能写数据、命令或地址,所以写I/O可能会为 NFDATA NFCMD NFADDR
     这个在相应的操作中会被s3c2410_hwcontrol修改

19~23 填充nand_chip结构 


nand_scan drivers/mtd/nand/nand_base.c

6        busw = this->options & NAND_BUSWIDTH_16;

上面的结果为0,这里nand为k9f1208,bus_width为8


   7        /* check for proper chip_delay setup, set 20us if not */
     8        if (!this->chip_delay)
     9            this->chip_delay = 20;

    10        /* check, if a user supplied command function given */
    11        if (this->cmdfunc == NULL)
    12            this->cmdfunc = nand_command;

    13        /* check, if a user supplied wait function given */
    14        if (this->waitfunc == NULL)
    15            this->waitfunc = nand_wait;

    16        if (!this->select_chip)
    17            this->select_chip = nand_select_chip;
    18        if (!this->write_byte)
    19            this->write_byte = busw ? nand_write_byte16 : nand_write_byte;
    20        if (!this->read_byte)
    21            this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
    22        if (!this->write_word)
    23            this->write_word = nand_write_word;
    24        if (!this->read_word)
    25            this->read_word = nand_read_word;
    26        if (!this->block_bad)
    27            this->block_bad = nand_block_bad;
    28        if (!this->block_markbad)
    29            this->block_markbad = nand_default_block_markbad;
    30        if (!this->write_buf)
    31            this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
    32        if (!this->read_buf)
    33            this->read_buf = busw ? nand_read_buf16 : nand_read_buf;
    34        if (!this->verify_buf)
    35            this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
    36        if (!this->scan_bbt)
    37            this->scan_bbt = nand_default_bbt;


7~ 37行 判断nand_chip的成员函数是否已经初始化过,若未初始化,则给其赋相应值


   38        /* Select the device */
    39        this->select_chip(mtd, 0);

    40        /* Send the command for reading device ID */
    41        this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);

    42        /* Read manufacturer and device IDs */
    43        nand_maf_id = this->read_byte(mtd);
    44        nand_dev_id = this->read_byte(mtd);

38~44 使能nand => 发送读id命令和地址0x00 => 读nand芯片的id
       nand_maf_id => 厂商代码 samsung为 0xec
       nand_dev_id  => 设备代码 k9f1208为 0x76


        /* Print and store flash device information */
    46        for (i = 0; nand_flash_ids[i].name != NULL; i++) {

    47            if (nand_dev_id != nand_flash_ids[i].id)
    48                continue;

通过nand)dev_id在nand_flash_ids[]数组中找到芯片对应项,该项上含有芯片的一些信息,如对于此块
nand,读出nand_dev_id为0x76后,则在nand_flash_ids[]中匹配到下面这一项

 {"NAND 64MiB 3,3V 8-bit",    0x76, 512, 64, 0x4000, 0},

  由此可知,页面大小为512bytes, 芯片容量为64M, 擦写页面大小为16k 等 





   49 if (!mtd->name)  mtd->name = nand_flash_ids[i].name;
    50 this->chipsize = nand_flash_ids[i].chipsize << 20;

49 行 mtd_name就指向字符串 "NAND 64MiB 3,3V 8-bit"
50 行  芯片大小为 64M 即 0x4000000

70 /* Old devices have this data hardcoded in the
    71 * device id table */

    72 mtd->erasesize = nand_flash_ids[i].erasesize;
    73 mtd->oobblock = nand_flash_ids[i].pagesize;
    74 mtd->oobsize = mtd->oobblock / 32;
    75 busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;

72 => 擦除页面16k
73 => 页大小512 bytes
74 => out of blank 大小 16 bytes
75 => busw = 0


90 /* Calculate the address shift from the page size */
    91 this->page_shift = ffs(mtd->oobblock) - 1;
    92 this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
    93 this->chip_shift = ffs(this->chipsize) - 1;


#define ffs(x) generic_ffs(x)
/* Return the position of the first bit set in I, or 0 if none are set.
   The least-significant bit is position 1, the most-significant 32.  */
找出第一个为1的位,最低位为1
即 0x1000 0000 0000 0000 0000 0000 0000 0000 返回32
   0x0001 返回1
所以这里 ffs(mtd->oobblock) = 10 , this->page_shift = 9
  this->bbt_erase_shift = this->phys_erase_shift = 13
  this->chip_shift = 26




    94 /* Set the bad block position */
    95 this->badblockpos = mtd->oobblock > 512 ?
    96 NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;

判断是大页还是小页,来确定坏块标记位置 this->badblockpos大页为0, 小页为5



   97 /* Get chip options, preserve non chip based options */
    98 this->options &= ~NAND_CHIPOPTIONS_MSK;
    99 this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
   100 /* Set this as a default. Board drivers can override it, if neccecary */
   101 this->options |= NAND_NO_AUTOINCR;

暂时还看不懂上面几句



   105 if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
   106      this->options &= ~NAND_SAMSUNG_LP_OPTIONS;

   107 /* Check for AND chips with 4 page planes */
   108 if (this->options & NAND_4PAGE_ARRAY)
   109     this->erase_cmd = multi_erase_cmd;
   110 else
   111     this->erase_cmd = single_erase_cmd;

   112 /* Do not replace user supplied command function ! */
   113 if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
   114     this->cmdfunc = nand_command_lp;



   115 /* Try to identify manufacturer */
   116 for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
   117     if (nand_manuf_ids[j].id == nand_maf_id)
   118         break;
   119 }



   122        if (!nand_flash_ids[i].name) {
   123    #ifndef CFG_NAND_QUIET_TEST
   124            printk (KERN_WARNING "No NAND device found!!!\n");
   125    #endif
   126            this->select_chip(mtd, -1);
   127            return 1;
   128        }

上面的i到这里一直没变,仍然停在id相等的那一项上,判断那一项是否为空?因为id不匹配的话,
nand_flash_ids最后一项即为NULL


   129        for (i=1; i < maxchips; i++) {
   130            this->select_chip(mtd, i);

   131            /* Send the command for reading device ID */
   132            this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);

   133            /* Read manufacturer and device IDs */
   134            if (nand_maf_id != this->read_byte(mtd) ||
   135             nand_dev_id != this->read_byte(mtd))
   136                break;
   137        }

这里,如果有多块nand芯片,则去读它们的ID
nand_scan的调用为 nand_scan(mtd, 1)  , 即maxchips == 1
所以130 ~ 136 会跳过去



   140        /* Allocate buffers, if neccecary */
   141        if (!this->oob_buf) {
   142            size_t len;
   143            len = mtd->oobsize << (this->phys_erase_shift - this->page_shift);
   144            this->oob_buf = kmalloc (len, GFP_KERNEL);
   145            if (!this->oob_buf) {
   146                printk (KERN_ERR "nand_scan(): Cannot allocate oob_buf\n");
   147                return -ENOMEM;
   148            }
   149            this->options |= NAND_OOBBUF_ALLOC;
   150        }

   151        if (!this->data_buf) {
   152            size_t len;
   153            len = mtd->oobblock + mtd->oobsize;
   154            this->data_buf = kmalloc (len, GFP_KERNEL);
   155            if (!this->data_buf) {
   156                if (this->options & NAND_OOBBUF_ALLOC)
   157                    kfree (this->oob_buf);
   158                printk (KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
   159                return -ENOMEM;
   160            }
   161            this->options |= NAND_DATABUF_ALLOC;
   162        }

141 this->oobbuf还未初始化,进入
143 len = 16 << (13 - 9) = 256 为this->oobbuf分配256bytes的空间

153 len = 512 + 16 = 528


   164        this->numchips = i;   //芯片数
   165        mtd->size = i * this->chipsize; //总大小
  167      this->pagemask = (this->chipsize >> this->page_shift) - 1; // 页数 - 1
   168        /* Preset the internal oob buffer */
   169        memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift)); // 清this->oob_buf
   172        if (!this->autooob) {
     175            switch (mtd->oobsize) {
   176            case 8:
   177                this->autooob = &nand_oob_8;
   178                break;
   179            case 16:
   180                this->autooob = &nand_oob_16;
   181                break;
   182            case 64:
   183                this->autooob = &nand_oob_64;
   184                break;
   185            case 128:
   186                this->autooob = &nand_oob_128;
   187                break;
   188            default:
   189                printk (KERN_WARNING "No oob scheme defined for oobsize %d\n",
   190                    mtd->oobsize);
   191            }
   192        }


   195        mtd->oobavail = 0;
   196        for (i=0; this->autooob->oobfree[i][1]; i++)
   197            mtd->oobavail += this->autooob->oobfree[i][1];






203        this->eccsize = 256;    /* set default eccsize */
204        this->eccbytes = 3;




   233        case NAND_ECC_SOFT:
   234            this->calculate_ecc = nand_calculate_ecc;
   235            this->correct_data = nand_correct_data;
   236            break




   268        case NAND_ECC_SOFT:
   269            this->eccsteps = mtd->oobblock / 256;
   270            break;

上面填充ECC相关成员



   275        /* De-select the device */
   276        this->select_chip(mtd, -1);

   277        /* Invalidate the pagebuffer reference */
   278        this->pagebuf = -1;

   279        /* Fill in remaining MTD driver data */
   280        mtd->type = MTD_NANDFLASH;
   281        mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
   282        mtd->ecctype = MTD_ECC_SW;
   283        mtd->erase = nand_erase;
   284        mtd->point = NULL;
   285        mtd->unpoint = NULL;
   286        mtd->read = nand_read;
   287        mtd->write = nand_write;
   288        mtd->read_ecc = nand_read_ecc;
   289        mtd->write_ecc = nand_write_ecc;
   290        mtd->read_oob = nand_read_oob;
   291        mtd->write_oob = nand_write_oob;

   292        mtd->sync = nand_sync;

   293        mtd->block_isbad = nand_block_isbad;
   294        mtd->block_markbad = nand_block_markbad;

   295        /* and make the autooob the default one */
   296        memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));

   297        /* Build bad block table */
   298        return this->scan_bbt (mtd);


276 行 禁止nand芯片

280 ~ 294 填充mtd结构

298 建立坏块列表, 返回

mtd结构和nand_chip结构是整个nand操作的关键,这两个结构体都非常复杂,重要的是不知道其中的成员(函数)
是用来干什么的,都有什么作用,在什么地方用到。

总之,从nand_scan退出之后,nand_chip和mtd结构里就记录了该块nand芯片的所有信息及对其作各种操作的函数。


最后来看一下这块k9f1208经过board_nand_init()和nand_scan()之后的情况,
下面 蓝色粗体 表示从board_nand_init中初始化
     红色粗体表示从 nand_scan 中初始化
    黑色粗体表示初始化之后仍会改变的值
    普通字体表示暂未使用的成员
 1    struct nand_chip {

     2        void  __iomem    *IO_ADDR_R;  => 0x4e00000c 即NFDATA 在board_nand_init()中初始化
     3        void  __iomem    *IO_ADDR_W;  => 会在hwcontrol函数中变化,为NFDATA、NFCMD、NFADDR之一

     4        u_char        (*read_byte)(struct mtd_info *mtd); => 读一个字节,在nand_scan()中初始化
     5        void        (*write_byte)(struct mtd_info *mtd, u_char byte); => 写一个字节,在nand_scan()中初始化
     6        u16        (*read_word)(struct mtd_info *mtd); => 读一个字,在nand_scan()中初始化
     7        void        (*write_word)(struct mtd_info *mtd, u16 word);=> 写一个字,在nand_scan()中初始化

     8        void        (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); => 写长度为len的buf 在nand_scan()中初始化
     9        void        (*read_buf)(struct mtd_info *mtd, u_char *buf, int len); => 读长度为len的buf 在nand_scan()中初始化
    10        int        (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); => 在nand_scan()中初始化
    11        void        (*select_chip)(struct mtd_info *mtd, int chip); =>使能/禁止nand芯片,chip=-1 禁止, chip=0 使能 在nand_scan()中初始化
    12        int        (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); =>  在nand_scan()中初始化
    13        int        (*block_markbad)(struct mtd_info *mtd, loff_t ofs); =>  在nand_scan()中初始化
    14        void        (*hwcontrol)(struct mtd_info *mtd, int cmd); => s3c2410_hwcontrol 在board_nand_init()中初始化
    15        int        (*dev_ready)(struct mtd_info *mtd); => s3c2410_dev_ready 等待nand状态变为空闲,在board_nand_init()中初始化
    16        void        (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); => 写命令及地址 在nand_scan()中初始化
    17        int        (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); => nand_wait  在nand_scan()中初始化
    18        int        (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); => nand_calculate_ecc   在nand_scan()中初始化
    19        int        (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); => nand_ccorrect_data   在nand_scan()中初始化
    20        void        (*enable_hwecc)(struct mtd_info *mtd, int mode);
    21        void        (*erase_cmd)(struct mtd_info *mtd, int page); => single_erase_cmd  在nand_scan()中初始化
    22        int        (*scan_bbt)(struct mtd_info *mtd); =>  在nand_scan()中初始化
    23        int        eccmode; => NAND_ECC_SOFT  在board_nand_init()中初始化
    24        int        eccsize; => 256  在nand_scan()中初始化
    25        int        eccbytes;=> 3   在nand_scan()中初始化
    26        int        eccsteps; => mtd->oobblock / 256 = 2
    27        int        chip_delay; => 20  在nand_scan()中初始化
    28        int        page_shift; => 页面偏移 9, 2^9 = 512  在nand_scan()中初始化
    29        int        phys_erase_shift; => 14 , 2^14 = 16k 一个block的大小  在nand_scan()中初始化
    30        int        bbt_erase_shift; => 14 , 2^14 = 16k 一个block的大小  在nand_scan()中初始化
    31        int        chip_shift; => 26, 2^26 = 64M 芯片大小  在nand_scan()中初始化
    32        u_char        *data_buf; => 分配528bytes空间   在nand_scan()中初始化
    33        u_char        *oob_buf; => 分配512bytes空间   在nand_scan()中初始化
    34        int        oobdirty;
    35        u_char        *data_poi;
    36        unsigned int    options; => 在board_nand_init()中初始为0, 在nand_scan()中被改写
    37        int        badblockpos; =>坏块标记的位置  在nand_scan()中初始化
    38        int        numchips; => 芯片数 1  在nand_scan()中初始化
    39        unsigned long    chipsize; => 芯片大小64M  在nand_scan()中初始化
    40        int        pagemask; => 页数-1  在nand_scan()中初始化
    41        int        pagebuf; => -1   在nand_scan()中初始化
    42        struct nand_oobinfo    *autooob; => &nand_oob_16 , nand_oob_16是个结构体,记录芯片oob区的相关信息
    43        uint8_t        *bbt;
    44        struct nand_bbt_descr    *bbt_td;
    45        struct nand_bbt_descr    *bbt_md;
    46        struct nand_bbt_descr    *badblock_pattern;
    47        struct nand_hw_control    *controller;
    48        void        *priv;
    49    };
阅读(1133) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~