打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
linux nandflash

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
转自:https://blog.csdn.net/chenliang0224/article/details/79372559
————————————————
版权声明:本文为CSDN博主「JDSH0224」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/chenliang0224/article/details/79372559

1. 前言:

1.1 先分析下nandflash的布局、操作结构


由图可以看出一片Nand flash为一个设备(device),其数据存储分层为:

a.  1个设备(device)=1024个块(Blocks),块也是Nand flash擦除操作的最小单位。

b.  1个块(block) = 64页(Pages),页是Nand flash写入的最小单位,对于每一个页,由数据块区域和空闲区域。数据区,也容易理解,就是存储一些数据,而对于空闲区,一般也叫做OOB(out of Band),这个区域,是基于Nand flash的硬件特性设计的,Nand flash在数据读写的时候很容易错误,所以为了保证数据的正确性,必须要有对应的检测和纠错的机制,此机制就被叫做ECC,所以设计了该多余的区域,用来放置数据的校验值。

c.  1个页(page) = 数据块大小(2K)+OOB块大小(64Bytes)

那么通过上面我们就可以计算出怎么访问一个物理地址:块大小*块号+页大小*页号+页内陆址。

从硬件的图来看,对于K9F1G08X0C这款芯片,其容量为132MB,那么就应该需要28条地址先,而现在只有8条地址线,对于Nand flash就导入了地址周期的概念,对于该款flash,所以需要4个周期:2个列地址(Column)周期和2个行地址(ROW)周期。从下面的功能框图来看,对于列地址A0--A11,就是页内陆址,地址范围就是0--4094,与页内陆址(2K+64)吻合,其实对于页内陆址,其实只需要A0-A10,而对于多出来的A11,是用来表示页内的oob区域。那么对于A12-A27就是用来表示属于哪一个块和块里面的哪一个页号。

1.2 要对nandflash操作,比如读取一页数据、写入一页数据,都要发送对应的命令,而且要符合硬件的规定,如图:


从上图可以看出,在Read读取数据时需两个周期Cycle,即分两次发送对应的命令,第一次是0x00,第二次是0x30,而且两次中间要发送对应的地址行地址(页)+列地址(页内陆址),这个要特别注意,在下面的源码读取数据时会分析到。

由于篇幅原因,关于nandflash中oob、bbt、ecc,详见:点击打开链接

2. nandflash相关结构体

a. struct nuc970_nand_info

  1. struct nuc970_nand_info {
  2. struct nand_hw_control controller; //nandflash驱动控制器操作结构体
  3. struct mtd_info mtd; //nandflash分区操作结构体
  4. struct nand_chip chip; //芯片操作结构体
  5. struct mtd_partition *parts; //nandflash分区数组信息
  6. int nr_parts; //nandflash分区数组个数
  7. struct platform_device *pdev; //指向dev.c中的设备
  8. struct clk *clk; //nandflash控制器时钟
  9. struct clk *fmi_clk; //fmi控制器时钟
  10. void __iomem *reg; //寄存器
  11. int eBCHAlgo; //BCH ECC算法
  12. int m_i32SMRASize; //见datasheet FMI__NANDRACTL 表示oob的字节数
  13. int m_ePageSize; //页大小
  14. unsigned char * pnand_vaddr; //nandflash虚拟地址
  15. unsigned char * pnand_phyaddr; //nandflash物理地址
  16. int m_i32MyShowTime; //???相当于信号量
  17. spinlock_t lock;
  18. };

b. struct nand_hw_control

  1. struct nand_hw_control {
  2. spinlock_t lock;
  3. struct nand_chip *active; //芯片操作结构体
  4. wait_queue_head_t wq;
  5. };

c. struct nand_chip

  1. struct nand_chip {
  2. void __iomem *IO_ADDR_R;
  3. void __iomem *IO_ADDR_W;
  4. uint8_t (*read_byte)(struct mtd_info *mtd); //读一个byte
  5. u16 (*read_word)(struct mtd_info *mtd); //读一个word
  6. void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); //写一个缓冲区数据
  7. void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); //读一个缓冲区数据
  8. void (*select_chip)(struct mtd_info *mtd, int chip); //片选
  9. int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); //坏块
  10. int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); //坏块标记
  11. void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); //命令控制
  12. int (*init_size)(struct mtd_info *mtd, struct nand_chip *this,
  13. u8 *id_data); //???
  14. int (*dev_ready)(struct mtd_info *mtd); //设备忙状态?
  15. void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,
  16. int page_addr); //命令功能
  17. int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); //???
  18. void (*erase_cmd)(struct mtd_info *mtd, int page); //擦除命令
  19. int (*scan_bbt)(struct mtd_info *mtd); //bbt:bad blockta(即坏块表),扫描坏块表
  20. int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
  21. int status, int page);
  22. int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
  23. uint32_t offset, int data_len, const uint8_t *buf,
  24. int oob_required, int page, int cached, int raw);
  25. int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip,
  26. int feature_addr, uint8_t *subfeature_para);
  27. int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
  28. int feature_addr, uint8_t *subfeature_para);
  29. int chip_delay; //芯片时序特性
  30. unsigned int options;
  31. unsigned int bbt_options; //坏块表选项
  32. int page_shift;
  33. int phys_erase_shift;
  34. int bbt_erase_shift;
  35. int chip_shift;
  36. int numchips;
  37. uint64_t chipsize;
  38. int pagemask;
  39. int pagebuf;
  40. unsigned int pagebuf_bitflips;
  41. int subpagesize;
  42. uint8_t cellinfo;
  43. int badblockpos;
  44. int badblockbits;
  45. int onfi_version; //ONFI版本
  46. struct nand_onfi_paramsonfi_params;
  47. flstate_t state;
  48. uint8_t *oob_poi;
  49. struct nand_hw_control *controller;
  50. struct nand_ecclayout *ecclayout;
  51. struct nand_ecc_ctrl ecc;
  52. struct nand_buffers *buffers;
  53. struct nand_hw_control hwcontrol;
  54. uint8_t *bbt;
  55. struct nand_bbt_descr *bbt_td; //坏块表
  56. struct nand_bbt_descr *bbt_md;
  57. struct nand_bbt_descr *badblock_pattern;
  58. void *priv;
  59. };

d. struct mtd_partition

  1. struct mtd_partition {
  2. char *name; /* identifier string */
  3. uint64_t size; /* partition size */
  4. uint64_t offset; /* offset within the master MTD space */
  5. uint32_t mask_flags; /* master MTD flags to mask out for this partition */
  6. struct nand_ecclayout *ecclayout;/* out of band layout for this partition (NAND only) */
  7. };

e. struct nand_ecclayout

  1. struct nand_ecclayout {
  2. __u32 eccbytes; //表示使用几个ecc字节
  3. __u32 eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE]; //表示ecc占用的位置,因为现在一版大页面4kbyte也就128个,所以数组为128,以后有更大页面的,这里也要改了。
  4. __u32 oobavail; //有几个oob可用,这个跟下面的成员有点像,一般用下面的
  5. struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE]; //定义oob有效个数,从哪开始等
  6. };

d. struct nand_oobfree

  1. struct nand_oobfree {
  2. __u32 offset;
  3. __u32 length;
  4. };

e. struct mtd_info

  1. struct mtd_info {
  2. u_char type; //flash类型,如MTD_NORFLASH,MTD_NANDFLASH
  3. uint32_t flags; //MTD属性标志,MTD_WRITEABLE,MTD_NO_ERASE等
  4. uint64_t size; //mtd设备的大小
  5. /* "Major" erase size for the device. Naïve users may take this
  6. * to be the only erase size available, or may use the more detailed
  7. * information below if they desire
  8. */
  9. uint32_t erasesize; //MTD设备的擦除单元大小,对于NandFlash来说就是Block的大小
  10. /* Minimal writable flash unit size. In case of NOR flash it is 1 (even
  11. * though individual bits can be cleared), in case of NAND flash it is
  12. * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
  13. * it is of ECC block size, etc. It is illegal to have writesize = 0.
  14. * Any driver registering a struct mtd_info must ensure a writesize of
  15. * 1 or larger.
  16. */
  17. uint32_t writesize; //写大小, 对于norFlash是字节,对nandFlash为一页
  18. /*
  19. * Size of the write buffer used by the MTD. MTD devices having a write
  20. * buffer can write multiple writesize chunks at a time. E.g. while
  21. * writing 4 * writesize bytes to a device with 2 * writesize bytes
  22. * buffer the MTD driver can (but doesn't have to) do 2 writesize
  23. * operations, but not 4. Currently, all NANDs have writebufsize
  24. * equivalent to writesize (NAND page size). Some NOR flashes do have
  25. * writebufsize greater than writesize.
  26. */
  27. uint32_t writebufsize; //
  28. uint32_t oobsize; // Amount of OOB data per block (e.g. 16) OOB字节数
  29. uint32_t oobavail; // Available OOB bytes per block 可用的OOB字节数
  30. /*
  31. * If erasesize is a power of 2 then the shift is stored in
  32. * erasesize_shift otherwise erasesize_shift is zero. Ditto writesize.
  33. */
  34. unsigned int erasesize_shift;
  35. unsigned int writesize_shift;
  36. /* Masks based on erasesize_shift and writesize_shift */
  37. unsigned int erasesize_mask;
  38. unsigned int writesize_mask;
  39. /*
  40. * read ops return -EUCLEAN if max number of bitflips corrected on any
  41. * one region comprising an ecc step equals or exceeds this value.
  42. * Settable by driver, else defaults to ecc_strength. User can override
  43. * in sysfs. N.B. The meaning of the -EUCLEAN return code has changed;
  44. * see Documentation/ABI/testing/sysfs-class-mtd for more detail.
  45. */
  46. unsigned int bitflip_threshold;
  47. // Kernel-only stuff starts here.
  48. const char *name;
  49. int index;
  50. /* ECC layout structure pointer - read only! */
  51. struct nand_ecclayout *ecclayout;
  52. /* max number of correctible bit errors per ecc step */
  53. unsigned int ecc_strength;
  54. /* Data for variable erase regions. If numeraseregions is zero,
  55. * it means that the whole device has erasesize as given above.
  56. */
  57. int numeraseregions;
  58. struct mtd_erase_region_info *eraseregions; //可变擦除区域
  59. /*
  60. * Do not call via these pointers, use corresponding mtd_*()
  61. * wrappers instead.
  62. */
  63. //擦除函数
  64. int (*_erase) (struct mtd_info *mtd, struct erase_info *instr);
  65. int (*_point) (struct mtd_info *mtd, loff_t from, size_t len,
  66. size_t *retlen, void **virt, resource_size_t *phys);
  67. int (*_unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
  68. unsigned long (*_get_unmapped_area) (struct mtd_info *mtd,
  69. unsigned long len,
  70. unsigned long offset,
  71. unsigned long flags);
  72. // 读写flash函数
  73. int (*_read) (struct mtd_info *mtd, loff_t from, size_t len,
  74. size_t *retlen, u_char *buf);
  75. int (*_write) (struct mtd_info *mtd, loff_t to, size_t len,
  76. size_t *retlen, const u_char *buf);
  77. int (*_panic_write) (struct mtd_info *mtd, loff_t to, size_t len,
  78. size_t *retlen, const u_char *buf);
  79. //带oob读写Flash函数
  80. int (*_read_oob) (struct mtd_info *mtd, loff_t from,
  81. struct mtd_oob_ops *ops);
  82. int (*_write_oob) (struct mtd_info *mtd, loff_t to,
  83. struct mtd_oob_ops *ops);
  84. int (*_get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
  85. size_t len);
  86. int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from,
  87. size_t len, size_t *retlen, u_char *buf);
  88. int (*_get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
  89. size_t len);
  90. int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from,
  91. size_t len, size_t *retlen, u_char *buf);
  92. int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to,
  93. size_t len, size_t *retlen, u_char *buf);
  94. int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
  95. size_t len);
  96. int (*_writev) (struct mtd_info *mtd, const struct kvec *vecs,
  97. unsigned long count, loff_t to, size_t *retlen);
  98. void (*_sync) (struct mtd_info *mtd);
  99. int (*_lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
  100. int (*_unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
  101. int (*_is_locked) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
  102. int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs);
  103. int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs);
  104. int (*_suspend) (struct mtd_info *mtd);
  105. void (*_resume) (struct mtd_info *mtd);
  106. /*
  107. * If the driver is something smart, like UBI, it may need to maintain
  108. * its own reference counting. The below functions are only for driver.
  109. */
  110. int (*_get_device) (struct mtd_info *mtd);
  111. void (*_put_device) (struct mtd_info *mtd);
  112. /* Backing device capabilities for this device
  113. * - provides mmap capabilities
  114. */
  115. struct backing_dev_info *backing_dev_info;
  116. struct notifier_block reboot_notifier; /* default mode before reboot */
  117. /* ECC status information */
  118. struct mtd_ecc_stats ecc_stats;
  119. /* Subpage shift (NAND) */
  120. int subpage_sft;
  121. void *priv; //指向chip, struct nand_chip *chip
  122. struct module *owner;
  123. struct device dev;
  124. int usecount;
  125. };

3. struct platform_device 

  1. static u64 nuc970_device_fmi_dmamask = 0xffffffffUL;
  2. struct platform_device nuc970_device_fmi = {
  3. .name = "nuc970-fmi",
  4. .id = -1,
  5. .num_resources = ARRAY_SIZE(nuc970_fmi_resource),
  6. .resource = nuc970_fmi_resource,
  7. .dev = {
  8. .dma_mask = &nuc970_device_fmi_dmamask,
  9. .coherent_dma_mask = 0xffffffffUL
  10. }
  11. };
  12. static struct resource nuc970_fmi_resource[] = {
  13. [0] = {
  14. .start = NUC970_PA_FMI,
  15. .end = NUC970_PA_FMI + NUC970_SZ_FMI - 1,
  16. .flags = IORESOURCE_MEM,
  17. },
  18. [1] = {
  19. .start = IRQ_FMI,
  20. .end = IRQ_FMI,
  21. .flags = IORESOURCE_IRQ,
  22. }
  23. };
  24. static u64 nuc970_device_fmi_dmamask = 0xffffffffUL;
platform_add_devices(&nuc970_device_fmi, 1);

fmi设备注册。

4. static struct platform_driver

  1. static struct platform_driver nuc970_nand_driver = {
  2. .driver = {
  3. .name = "nuc970-fmi",
  4. .owner = THIS_MODULE,
  5. },
  6. .probe = nuc970_nand_probe,
  7. .remove = nuc970_nand_remove,
  8. };

设备和驱动通过名称“nuc970-fmi”匹配,调用.probe=nuc970_nand_probe;

5. probe(...)

在分析nuc970_nand_probe(...)函数之前,先看下驱动的几个API

nandflash硬件ECC初始化:

  1. static void nuc970_nand_hwecc_init (struct mtd_info *mtd)
  2. {
  3. struct nuc970_nand_info *nand = container_of(mtd, struct nuc970_nand_info, mtd);
  4. writel ( readl(REG_SMCSR)|0x1, REG_SMCSR); // reset SM controller
  5. // Redundant area size
  6. writel( nand->m_i32SMRASize , REG_SMREACTL );
  7. // Protect redundant 3 bytes
  8. // because we need to implement write_oob function to partial data to oob available area.
  9. // Please note we skip 4 bytes
  10. writel( readl(REG_SMCSR) | 0x100, REG_SMCSR);
  11. // To read/write the ECC parity codes automatically from/to NAND Flash after data area field written.
  12. writel( readl(REG_SMCSR) | 0x10, REG_SMCSR);
  13. if ( nand->eBCHAlgo >= 0 ) {
  14. // Set BCH algorithm 设置ECC算法
  15. writel( (readl(REG_SMCSR) & (~0x007C0000)) | g_i32BCHAlgoIdx[nand->eBCHAlgo], REG_SMCSR);
  16. // Enable H/W ECC, ECC parity check enable bit during read page
  17. //使能ECC算法 | 使能读取页数据后,使用字段ecc检查
  18. writel( readl(REG_SMCSR) | 0x00800080, REG_SMCSR);
  19. } else {
  20. // Disable H/W ECC / ECC parity check enable bit during read page
  21. //禁止ECC | 读取数据后,禁止使用字段
  22. writel( readl(REG_SMCSR) & (~0x00800000) &(~0x80), REG_SMCSR);
  23. }
  24. }

硬件ECC禁止:

  1. static void nuc970_nand_hwecc_fini (struct mtd_info *mtd)
  2. {
  3. struct nand_chip *chip = mtd->priv;
  4. if ( chip->ecc.mode == NAND_ECC_HW_OOB_FIRST )
  5. writel(readl(REG_SMCSR)&(~0x00800000), REG_SMCSR); // ECC disable
  6. }

NandFlash初始化,包括nandflash选择使能,通讯时序设置,片选CS0,写保护寄存器开启,软复位nandflash:

  1. static void nuc970_nand_initialize ( void )
  2. {
  3. ENTER() ;
  4. // Enable SM_EN 该寄存器还包括eMMC,这里使能nandflash功能
  5. writel( NAND_EN, REG_NAND_FMICSR );
  6. // Timing control
  7. // writel(0x3050b, REG_SMTCR);
  8. // tCLS= (2+1)TAHB,
  9. // tCLH= (2*2+2)TAHB,
  10. // tALS= (2*1+1)TAHB,
  11. // tALH= (2*2+2)TAHB,
  12. writel(0x20305, REG_SMTCR); //时序控制
  13. // Enable SM_CS0 片选CS0
  14. writel((readl(REG_SMCSR)&(~0x06000000))|0x04000000, REG_SMCSR);
  15. //nandflash 写保护寄存器, 1表示没有写保护,数据是可写的
  16. writel(0x1, REG_NFECR); /* un-lock write protect */
  17. // NAND Reset 软复位
  18. writel(readl(REG_SMCSR) | 0x1, REG_SMCSR); // software reset
  19. LEAVE();
  20. }

页大小决定了ecc空间,具体如下:

  1. static const int g_i32ParityNum[ePageSize_CNT][eBCH_CNT] = {
  2. { 8, 15, 23, 29, -1 }, // For 512
  3. { 32, 60, 92, 116, 90 }, // For 2K
  4. { 64, 120, 184, 232, 180 }, // For 4K
  5. { 128, 240, 368, 464, 360 }, // For 8K
  6. };

硬件ecc选择bch算法:

  1. static int nuc970_hwecc_choice_bch_algorithm ( E_PAGESIZE ePagesize, int oob_size, int oob_available )
  2. {
  3. int i;
  4. /* Rule: select a BCH algorithm as the oob_size/2 large than parity number */
  5. for ( i=eBCH_T24; i>=0; i-- )
  6. if ( g_i32ParityNum[ePagesize][i] > 0 )
  7. //oob_size-oob_available-DEF_RESERVER_OOB_SIZE_FOR_MARKER=存储ecc校验空间,
  8. //如果g_i32ParityNum[ePagesize][i]值小于该空间表示可以存储ecc的校验值,即
  9. //可选择该硬件bch算法.
  10. if ( g_i32ParityNum[ePagesize][i] <= (oob_size-oob_available-DEF_RESERVER_OOB_SIZE_FOR_MARKER) ) // use half ecc size
  11. break;
  12. return i;
  13. }

nuc970选择ECC算法:

  1. static void nuc970_choice_bch_algo ( struct mtd_info *mtd, int page )
  2. {
  3. int i;
  4. struct nuc970_nand_info *nand = container_of(mtd, struct nuc970_nand_info, mtd);
  5. struct mtd_partition *part;
  6. struct nand_ecclayout *part_ecclayout;
  7. int BCHAlgoIdx=0;
  8. int SMRASize=0;
  9. u32 page_addr = page * mtd->writesize; //页地址*1页的大小
  10. for ( i=0; i<nand->nr_parts; i++ )
  11. {
  12. part = &nand->parts[i];
  13. part_ecclayout = part->ecclayout;
  14. if ( part_ecclayout && part_ecclayout != mtd->ecclayout ) { //ecclayout是否匹配?
  15. if ( part->offset <= page_addr && page_addr < part->offset+part->size ) //判定page_addr地址是否在当前分区范围内?
  16. {
  17. struct nuc970_nand_ecclayout * pSNUC970NandEccLayout=(struct nuc970_nand_ecclayout *)part_ecclayout;
  18. BCHAlgoIdx = pSNUC970NandEccLayout->m_BCHAlgoidx;
  19. SMRASize = pSNUC970NandEccLayout->m_SMRASize;
  20. break;
  21. }
  22. }
  23. }
  24. if ( i == nand->nr_parts ) //相等表示未找到对应的分区
  25. {
  26. //chp BCHAlgoIdx = nuc970_hwecc_choice_bch_algorithm ( nand->m_ePageSize, mtd->oobsize, mtd->oobavail );
  27. BCHAlgoIdx = nuc970_nand_SYSTEM_oob.m_BCHAlgoidx;
  28. SMRASize = mtd->oobsize;
  29. }
  30. if ( BCHAlgoIdx != nand->eBCHAlgo ) //bch算法进行了更新?
  31. {
  32. if ( BCHAlgoIdx >= 0 )
  33. printk("(0x%08X)BCH change to %s: %dB\n", page_addr, g_pcBCHAlgoIdx[BCHAlgoIdx], g_i32ParityNum[nand->m_ePageSize][BCHAlgoIdx] );
  34. else
  35. printk("(0x%08X)BCH change to No-ECC\n", page_addr );
  36. }
  37. nand->eBCHAlgo = BCHAlgoIdx;
  38. if ( SMRASize != nand->m_i32SMRASize )
  39. printk("(0x%08X)SMRA size change to %dB\n", page_addr, SMRASize );
  40. nand->m_i32SMRASize = SMRASize;
  41. }

nandflash ecc数据纠正:

  1. void fmiSM_CorrectData_BCH(u8 ucFieidIndex, u8 ucErrorCnt, u8* pDAddr)
  2. {
  3. u32 uaData[24], uaAddr[24];
  4. u32 uaErrorData[4];
  5. u8 ii, jj;
  6. u32 uPageSize;
  7. u32 field_len, padding_len, parity_len;
  8. u32 total_field_num;
  9. u8 *smra_index;
  10. ENTER();
  11. //--- assign some parameters for different BCH and page size
  12. switch (readl(REG_SMCSR) & 0x007C0000) //获取nandflash寄存器中BCH算法
  13. {
  14. case BCH_T24:
  15. field_len = 1024;
  16. padding_len = BCH_PADDING_LEN_1024;
  17. parity_len = BCH_PARITY_LEN_T24;
  18. break;
  19. case BCH_T15:
  20. field_len = 512;
  21. padding_len = BCH_PADDING_LEN_512;
  22. parity_len = BCH_PARITY_LEN_T15;
  23. break;
  24. case BCH_T12:
  25. field_len = 512;
  26. padding_len = BCH_PADDING_LEN_512;
  27. parity_len = BCH_PARITY_LEN_T12;
  28. break;
  29. case BCH_T8:
  30. field_len = 512;
  31. padding_len = BCH_PADDING_LEN_512;
  32. parity_len = BCH_PARITY_LEN_T8;
  33. break;
  34. case BCH_T4:
  35. field_len = 512;
  36. padding_len = BCH_PADDING_LEN_512;
  37. parity_len = BCH_PARITY_LEN_T4;
  38. break;
  39. default:
  40. printk("NAND ERROR: %s(): invalid SMCR_BCH_TSEL = 0x%08X\n", __FUNCTION__, (u32)(readl(REG_SMCSR) & 0x7C0000));
  41. LEAVE();
  42. return;
  43. }
  44. uPageSize = readl(REG_SMCSR) & 0x00030000; //获取nandflash中页大小
  45. switch (uPageSize)
  46. {
  47. case 0x30000: total_field_num = 8192 / field_len; break;
  48. case 0x20000: total_field_num = 4096 / field_len; break;
  49. case 0x10000: total_field_num = 2048 / field_len; break;
  50. case 0x00000: total_field_num = 512 / field_len; break;
  51. default:
  52. printk("NAND ERROR: %s(): invalid SMCR_PSIZE = 0x%08X\n", __FUNCTION__, uPageSize);
  53. LEAVE();
  54. return;
  55. }
  56. //--- got valid BCH_ECC_DATAx and parse them to uaData[]
  57. // got the valid register number of BCH_ECC_DATAx since one register include 4 error bytes
  58. jj = ucErrorCnt/4;
  59. jj ++;
  60. if (jj > 6)
  61. jj = 6; // there are 6 BCH_ECC_DATAx registers to support BCH T24
  62. for(ii=0; ii<jj; ii++)
  63. {
  64. uaErrorData[ii] = readl(REG_BCH_ECC_DATA0 + ii*4); //读取ECC数据
  65. }
  66. for(ii=0; ii<jj; ii++)
  67. {
  68. uaData[ii*4+0] = uaErrorData[ii] & 0xff;
  69. uaData[ii*4+1] = (uaErrorData[ii]>>8) & 0xff;
  70. uaData[ii*4+2] = (uaErrorData[ii]>>16) & 0xff;
  71. uaData[ii*4+3] = (uaErrorData[ii]>>24) & 0xff;
  72. }
  73. //--- got valid REG_BCH_ECC_ADDRx and parse them to uaAddr[]
  74. // got the valid register number of REG_BCH_ECC_ADDRx since one register include 2 error addresses
  75. jj = ucErrorCnt/2;
  76. jj ++;
  77. if (jj > 12)
  78. jj = 12; // there are 12 REG_BCH_ECC_ADDRx registers to support BCH T24
  79. for(ii=0; ii<jj; ii++)
  80. {
  81. uaAddr[ii*2+0] = readl(REG_BCH_ECC_ADDR0 + ii*4) & 0x07ff; // 11 bits for error address nandflash ecc错误字节地址
  82. uaAddr[ii*2+1] = (readl(REG_BCH_ECC_ADDR0 + ii*4)>>16) & 0x07ff;
  83. }
  84. //--- pointer to begin address of field that with data error
  85. pDAddr += (ucFieidIndex-1) * field_len;
  86. //--- correct each error bytes
  87. for(ii=0; ii<ucErrorCnt; ii++)
  88. {
  89. // for wrong data in field
  90. if (uaAddr[ii] < field_len)
  91. {
  92. #ifdef NUC970_NAND_DEBUG
  93. printk("BCH error corrected for data: address 0x%08X, data [0x%02X] --> ",
  94. (unsigned int)(pDAddr+uaAddr[ii]), (unsigned int)(*(pDAddr+uaAddr[ii])));
  95. #endif
  96. *(pDAddr+uaAddr[ii]) ^= uaData[ii]; //异或,计算ECC,即读取数据的ECC和nandflash中的ecc进行异或比较
  97. #ifdef NUC970_NAND_DEBUG
  98. printk("[0x%02X]\n", *(pDAddr+uaAddr[ii]));
  99. #endif
  100. }
  101. // for wrong first-3-bytes in redundancy area
  102. else if (uaAddr[ii] < (field_len+3))
  103. {
  104. uaAddr[ii] -= field_len;
  105. uaAddr[ii] += (parity_len*(ucFieidIndex-1)); // field offset
  106. #ifdef NUC970_NAND_DEBUG
  107. printk("BCH error corrected for 3 bytes: address 0x%08X, data [0x%02X] --> ",
  108. (unsigned int)((u8 *)REG_SMRA0 + uaAddr[ii]), (unsigned int)(*((u8 *)REG_SMRA0 + uaAddr[ii])));
  109. #endif
  110. *((u8 *)REG_SMRA0 + uaAddr[ii]) ^= uaData[ii];
  111. #ifdef NUC970_NAND_DEBUG
  112. printk("[0x%02X]\n", *((u8 *)REG_SMRA0+uaAddr[ii]));
  113. #endif
  114. }
  115. //以下代码为纠错代码,老衲没有看明白.......!!!!!
  116. // for wrong parity code in redundancy area
  117. else
  118. {
  119. // BCH_ERR_ADDRx = [data in field] + [3 bytes] + [xx] + [parity code]
  120. // |<-- padding bytes -->|
  121. // The BCH_ERR_ADDRx for last parity code always = field size + padding size.
  122. // So, the first parity code = field size + padding size - parity code length.
  123. // For example, for BCH T12, the first parity code = 512 + 32 - 23 = 521.
  124. // That is, error byte address offset within field is
  125. uaAddr[ii] = uaAddr[ii] - (field_len + padding_len - parity_len);
  126. // smra_index point to the first parity code of first field in register SMRA0~n
  127. smra_index = (u8 *)
  128. (REG_SMRA0 + (readl(REG_SMREACTL) & 0x1ff) - // bottom of all parity code -
  129. (parity_len * total_field_num) // byte count of all parity code
  130. );
  131. // final address = first parity code of first field +
  132. // offset of fields +
  133. // offset within field
  134. #ifdef NUC970_NAND_DEBUG
  135. printk("BCH error corrected for parity: address 0x%08X, data [0x%02X] --> ",
  136. (unsigned int)(smra_index + (parity_len * (ucFieidIndex-1)) + uaAddr[ii]),
  137. (unsigned int)(*(smra_index + (parity_len * (ucFieidIndex-1)) + uaAddr[ii])));
  138. #endif
  139. *((u8 *)smra_index + (parity_len * (ucFieidIndex-1)) + uaAddr[ii]) ^= uaData[ii];
  140. #ifdef NUC970_NAND_DEBUG
  141. printk("[0x%02X]\n",
  142. *((u8 *)smra_index + (parity_len * (ucFieidIndex-1)) + uaAddr[ii]));
  143. #endif
  144. }
  145. } // end of for (ii<ucErrorCnt)
  146. LEAVE();
  147. }
  148. int fmiSMCorrectData (struct mtd_info *mtd, unsigned long uDAddr )
  149. {
  150. int uStatus, ii, jj, i32FieldNum=0;
  151. volatile int uErrorCnt = 0;
  152. ENTER();
  153. if ( readl ( REG_SMISR ) & 0x4 ) //只读,表明ECC校验值是否出错
  154. {
  155. if ( ( readl(REG_SMCSR) & 0x7C0000) == BCH_T24 ) //BCH_T24的页为1024字节,其他的为512字节
  156. i32FieldNum = mtd->writesize / 1024; // Block=1024 for BCH
  157. else
  158. i32FieldNum = mtd->writesize / 512;
  159. //每一页的大小,我使用的是每页=2K,而计算ecc是每512字节计算一个oob,所以这里有四个
  160. if ( i32FieldNum < 4 ) //每一页会计算ECC校
  161. i32FieldNum = 1;
  162. else
  163. i32FieldNum /= 4;
  164. for ( jj=0; jj<i32FieldNum; jj++ )
  165. {
  166. //REG_SMECC_ST0+jj*4: 该寄存器每8个bit表示一个ECC状态,Bit0~1是否有ECC错误,Bit2~7 表示ECC错误的个数是多少?
  167. uStatus = readl ( REG_SMECC_ST0+jj*4 );
  168. if ( !uStatus )
  169. continue;
  170. for ( ii=1; ii<5; ii++ )
  171. {
  172. if ( !(uStatus & 0x03) ) { // No error Bit0~1
  173. uStatus >>= 8;
  174. continue;
  175. } else if ( (uStatus & 0x03)==0x01 ) { // Correctable error 错误,数据纠正
  176. uErrorCnt = (uStatus >> 2) & 0x1F;
  177. #ifdef NUC970_NAND_DEBUG
  178. printk("Field (%d, %d) have %d error!!\n", jj, ii, uErrorCnt);
  179. #endif
  180. fmiSM_CorrectData_BCH(jj*4+ii, uErrorCnt, (char*)uDAddr);
  181. break;
  182. } else // uncorrectable error or ECC error
  183. {
  184. #ifdef NUC970_NAND_DEBUG
  185. printk("SM uncorrectable error is encountered, 0x%4x !!\n", uStatus);
  186. #endif
  187. LEAVE();
  188. return -1;
  189. }
  190. uStatus >>= 8;
  191. }
  192. } //jj
  193. }
  194. LEAVE();
  195. return uErrorCnt;
  196. }

使能硬件ECC:

  1. void nuc970_nand_enable_hwecc(struct mtd_info *mtd, int mode)
  2. {
  3. ENTER();
  4. #ifdef NUC970_NAND_DEBUG
  5. {
  6. char * ptr=REG_SMRA0;
  7. int i=0;
  8. if( mode == NAND_ECC_READ )
  9. printk("[R]=\n");
  10. else
  11. printk("[W]=\n");
  12. for(i=0; i<mtd->oobsize; i++)
  13. {
  14. printk("%X ", *(ptr+i) );
  15. if ( i % 32 == 31)
  16. printk("\n");
  17. }
  18. printk("\n");
  19. }
  20. #endif
  21. LEAVE();
  22. }

DMA使能、禁止:

  1. static void nuc970_nand_dmac_init( void )
  2. {
  3. // DMAC enable
  4. writel( readl(REG_NAND_DMACCSR) | 0x3, REG_NAND_DMACCSR);
  5. writel( readl(REG_NAND_DMACCSR) & (~0x2), REG_NAND_DMACCSR);
  6. // Clear DMA finished flag
  7. writel( readl(REG_SMISR) | 0x1, REG_SMISR);
  8. // Disable Interrupt
  9. writel(readl(REG_SMIER) & ~(0x1), REG_SMIER);
  10. }
  11. /*
  12. * nuc970_nand_dmac_fini - Finalize dma controller
  13. */
  14. static void nuc970_nand_dmac_fini(void)
  15. {
  16. // Clear DMA finished flag
  17. writel(readl(REG_SMISR) | 0x1, REG_SMISR);
  18. }

读nandflash字节:

  1. static unsigned char nuc970_nand_read_byte(struct mtd_info *mtd)
  2. {
  3. unsigned char ret;
  4. struct nuc970_nand_info *nand;
  5. ENTER() ;
  6. if ( nuc970_wait_sem(mtd) < 0 )
  7. return -1;
  8. nand = container_of(mtd, struct nuc970_nand_info, mtd);
  9. ret = (unsigned char)read_data_reg(nand);
  10. nuc970_release_sem(mtd);
  11. LEAVE();
  12. return ret;
  13. }

批量读nandflash字节:

  1. static void nuc970_nand_read_buf(struct mtd_info *mtd, unsigned char *buf, int len)
  2. {
  3. int i;
  4. struct nuc970_nand_info *nand;
  5. nand = container_of(mtd, struct nuc970_nand_info, mtd);
  6. ENTER() ;
  7. if ( nuc970_wait_sem(mtd) < 0 )
  8. return;
  9. for (i = 0; i < len; i++)
  10. buf[i] = (unsigned char)read_data_reg(nand);
  11. nuc970_release_sem(mtd);
  12. LEAVE();
  13. }

批量写nandflash字节:

  1. static void nuc970_nand_write_buf(struct mtd_info *mtd, const unsigned char *buf, int len)
  2. {
  3. int i;
  4. struct nuc970_nand_info *nand;
  5. nand = container_of(mtd, struct nuc970_nand_info, mtd);
  6. ENTER() ;
  7. if ( nuc970_wait_sem(mtd) < 0 )
  8. return;
  9. for (i = 0; i < len; i++)
  10. write_data_reg(nand, buf[i]);
  11. nuc970_release_sem(mtd);
  12. LEAVE();
  13. }

DMA对nandflash的读、写操作:

  1. static inline int _nuc970_nand_dma_transfer(struct mtd_info *mtd, const u_char *addr, unsigned int len, int is_write)
  2. {
  3. struct nuc970_nand_info *nand = container_of(mtd, struct nuc970_nand_info, mtd);
  4. dma_addr_t dma_addr = (dma_addr_t)nand->pnand_phyaddr;
  5. ENTER() ;
  6. // For save, wait DMAC to ready
  7. while ( readl(REG_NAND_DMACCSR) & 0x200 );
  8. // Reinitial dmac
  9. nuc970_nand_dmac_init();
  10. // Fill dma_addr
  11. writel((unsigned long)dma_addr, REG_NAND_DMACSAR);
  12. // Enable target abort interrupt generation during DMA transfer.
  13. writel( 0x1, REG_NAND_DMACIER);
  14. // Clear Ready/Busy 0 Rising edge detect flag
  15. writel(0x400, REG_SMISR);
  16. // Set which BCH algorithm
  17. if ( nand->eBCHAlgo >= 0 ) {
  18. // Set BCH algorithm
  19. writel( (readl(REG_SMCSR) & (~0x7C0000)) | g_i32BCHAlgoIdx[nand->eBCHAlgo], REG_SMCSR);
  20. // Enable H/W ECC, ECC parity check enable bit during read page
  21. writel( readl(REG_SMCSR) | 0x00800000 | 0x80, REG_SMCSR);
  22. } else {
  23. // Disable H/W ECC / ECC parity check enable bit during read page
  24. writel( readl(REG_SMCSR) & (~0x00800080), REG_SMCSR);
  25. }
  26. writel( nand->m_i32SMRASize , REG_SMREACTL );
  27. writel( readl(REG_SMIER) & (~0x4), REG_SMIER );
  28. writel ( 0x4, REG_SMISR );
  29. // Enable SM_CS0
  30. writel((readl(REG_SMCSR)&(~0x06000000))|0x04000000, REG_SMCSR);
  31. /* setup and start DMA using dma_addr */
  32. if ( is_write ) {
  33. register char * ptr=REG_SMRA0; //register 是提示编译器将这个变量不放在栈内,放在寄存器中进行操作
  34. // To mark this page as dirty.
  35. if ( ptr[3] == 0xFF )
  36. ptr[3] = 0;
  37. if ( ptr[2] == 0xFF )
  38. ptr[2] = 0;
  39. if ( addr )
  40. memcpy( (void*)nand->pnand_vaddr, (void*)addr, len);
  41. writel ( readl(REG_SMCSR) | 0x4, REG_SMCSR ); //DMA写使能
  42. while ( !(readl(REG_SMISR) & 0x1) ); //DMA读、写数据完成中断标识
  43. } else {
  44. // Blocking for reading
  45. // Enable DMA Read
  46. writel ( readl(REG_SMCSR) | 0x2, REG_SMCSR); //DMA读使能
  47. if ( readl(REG_SMCSR) & 0x80 ) {
  48. do {
  49. int stat=0;
  50. if ( (stat=fmiSMCorrectData ( mtd, (unsigned long)nand->pnand_vaddr)) < 0 ) //重要,待分析!!!
  51. {
  52. mtd->ecc_stats.failed++;
  53. writel ( 0x4, REG_SMISR ); //清除ECC校验出错中断标识
  54. writel ( 0x3, REG_NAND_DMACCSR); // reset DMAC
  55. writel ( readl(REG_SMCSR)|0x1, REG_SMCSR); // reset SM controller
  56. break;
  57. }
  58. else if ( stat > 0 ) {
  59. //mtd->ecc_stats.corrected += stat; //Occure: MLC UBIFS mount error
  60. writel ( 0x4, REG_SMISR );
  61. }
  62. } while ( !(readl(REG_SMISR) & 0x1) || (readl(REG_SMISR) & 0x4) );
  63. } else
  64. while ( !(readl(REG_SMISR) & 0x1) );
  65. if ( addr )
  66. memcpy( (void*)addr, (void*)nand->pnand_vaddr, len );
  67. }
  68. nuc970_nand_dmac_fini();
  69. LEAVE();
  70. return 0;
  71. }
从DMA中nandflash批量读:
  1. static void nuc970_read_buf_dma(struct mtd_info *mtd, u_char *buf, int len)
  2. {
  3. ENTER();
  4. if ( nuc970_wait_sem(mtd) < 0 )
  5. return;
  6. if ( len == mtd->writesize ) /* start transfer in DMA mode */
  7. _nuc970_nand_dma_transfer ( mtd, buf, len, 0x0);
  8. else {
  9. nuc970_nand_read_buf(mtd, buf, len);
  10. #ifdef NUC970_NAND_DEBUG
  11. {
  12. int i;
  13. printk("R OOB %d\n", len );
  14. for ( i=0; i<len; i++ )
  15. {
  16. printk("%02X ", buf[i] );
  17. if ( i%32 == 31 ) printk("\n");
  18. }
  19. printk("\n");
  20. }
  21. #endif
  22. }
  23. nuc970_release_sem(mtd);
  24. LEAVE();
  25. }
向DMA中nandflash批量写:
  1. static void nuc970_write_buf_dma(struct mtd_info *mtd, const u_char *buf, int len)
  2. {
  3. ENTER();
  4. if ( nuc970_wait_sem(mtd) < 0 )
  5. return;
  6. if ( len == mtd->writesize ) /* start transfer in DMA mode */
  7. _nuc970_nand_dma_transfer(mtd, (u_char *)buf, len, 0x1);
  8. else
  9. {
  10. #ifdef NUC970_NAND_DEBUG
  11. int i;
  12. printk("W OOB %d\n", len);
  13. for ( i=0; i<len; i++ )
  14. {
  15. printk("%02X ", buf[i] );
  16. if ( i%32 == 31 ) printk("\n");
  17. }
  18. #endif
  19. nuc970_nand_write_buf(mtd, buf, len);
  20. }
  21. nuc970_release_sem(mtd);
  22. LEAVE();
  23. }

校验nandflash是否busy状态:

  1. static int nuc970_check_rb(struct nuc970_nand_info *nand)
  2. {
  3. unsigned int val;
  4. ENTER();
  5. spin_lock(&nand->lock);
  6. val = readl(REG_SMISR) & READYBUSY;
  7. spin_unlock(&nand->lock);
  8. LEAVE();
  9. return val;
  10. }
  11. static int nuc970_nand_devready(struct mtd_info *mtd)
  12. {
  13. struct nuc970_nand_info *nand;
  14. int ready;
  15. ENTER() ;
  16. if ( nuc970_wait_sem(mtd) < 0 )
  17. return -1;
  18. nand = container_of(mtd, struct nuc970_nand_info, mtd);
  19. ready = (nuc970_check_rb(nand)) ? 1 : 0;
  20. nuc970_release_sem(mtd);
  21. LEAVE();
  22. return ready;
  23. }

命令操作接口,对应ONFI中的标准,这里特别强调下命令操作的步骤,例如读数据操作,内容如下:第一次是0x00h,第二次是0x30h,而两次命令中间,需要发送对应的你所要读取的页的地址,在发送地址截至,接下来调用读数据接口接收数据:

  1. static void nuc970_nand_command_lp(struct mtd_info *mtd, unsigned int command, int column, int page_addr)
  2. {
  3. register struct nand_chip *chip = mtd->priv;
  4. struct nuc970_nand_info *nand;
  5. ENTER() ;
  6. if ( nuc970_wait_sem(mtd) < 0 ) //获取mtd分区是否加锁?
  7. {
  8. LEAVE();
  9. return;
  10. }
  11. nand = container_of(mtd, struct nuc970_nand_info, mtd);
  12. //页地址有效 && 对应有效的命令 = 选择有效的bch算法
  13. if ( page_addr != -1 && ( command == NAND_CMD_SEQIN || command == NAND_CMD_READ0 || command == NAND_CMD_READOOB ) )
  14. nuc970_choice_bch_algo ( mtd, page_addr );
  15. if (command == NAND_CMD_READOOB) { //如何理解if语句内部???解析如下
  16. column += mtd->writesize; //oob位于每一页的后面,这里的column表示列地址(nuc970_nand_read_oob_hwecc(...)函数在
  17. //读取oob时,column=0),要读取出对应的oob开始地址为“页+cloumn”
  18. command = NAND_CMD_READ0;
  19. }
  20. //以下部分要理解,需看懂时序,详解《linux_nand_driver.pdf》第20页时序图
  21. write_cmd_reg(nand, command & 0xff); //启动写命令到nandflash控制器
  22. if (column != -1 || page_addr != -1) {
  23. if (column != -1) {
  24. write_addr_reg(nand, (column&0xFF) ); //列地址,即页内陆址 低8bit
  25. if ( page_addr != -1 )
  26. write_addr_reg(nand, (column >> 8) ); //列地址,即页内陆址 高8bit
  27. else
  28. write_addr_reg(nand, (column >> 8) | ENDADDR); //ENDADDR, FMI_NANDADDR的第31bit,表明本次的地址结束
  29. }
  30. if (page_addr != -1) {
  31. write_addr_reg(nand, (page_addr&0xFF) ); //页地址,具体可以定位到哪一页
  32. if ( chip->chipsize > (128 << 20) ) {
  33. write_addr_reg(nand, (page_addr >> 8)&0xFF );
  34. write_addr_reg(nand, ((page_addr >> 16)&0xFF)|ENDADDR );
  35. } else {
  36. write_addr_reg(nand, ((page_addr >> 8)&0xFF)|ENDADDR );
  37. }
  38. }
  39. }
  40. switch (command) {
  41. case NAND_CMD_ERASE1: //case语句成立,就表示当前命令执行完,直接释放锁,退出即可!
  42. case NAND_CMD_ERASE2:
  43. case NAND_CMD_CACHEDPROG:
  44. case NAND_CMD_PAGEPROG:
  45. case NAND_CMD_SEQIN:
  46. case NAND_CMD_RNDIN:
  47. case NAND_CMD_STATUS:
  48. LEAVE();
  49. nuc970_release_sem(mtd);
  50. return;
  51. case NAND_CMD_RESET: //待分析工作原理???
  52. if (chip->dev_ready)
  53. break;
  54. if ( chip->chip_delay )
  55. udelay(chip->chip_delay);
  56. write_cmd_reg(nand, NAND_CMD_STATUS);
  57. write_cmd_reg(nand, command);
  58. while (!nuc970_check_rb(nand)) ;
  59. LEAVE();
  60. nuc970_release_sem(mtd);
  61. return;
  62. case NAND_CMD_RNDOUT: //待分析工作原理???
  63. write_cmd_reg(nand, NAND_CMD_RNDOUTSTART); //启动随机读取,外面调用该nuc970_nand_command_lp(...)函数,待该函数返回会有相应的接口读取数据
  64. nuc970_release_sem(mtd);
  65. LEAVE();
  66. return;
  67. case NAND_CMD_READ0: //read0命令
  68. write_cmd_reg(nand, NAND_CMD_READSTART); //见《linux_nand_driver.pdf》第18页,内容如下:“第一次是0x00h,第二次是0x30h,而两次命令中间,需要发送对应的你所要
  69. //读取的页的地址...”,外面调用该nuc970_nand_command_lp(...)函数,待该函数返回会有相应的接口读取数据
  70. break;
  71. default:
  72. if (!chip->dev_ready) {
  73. if ( chip->chip_delay )
  74. udelay(chip->chip_delay);
  75. LEAVE();
  76. nuc970_release_sem(mtd);
  77. return;
  78. }
  79. }
  80. while (!nuc970_check_rb(nand)) ;
  81. nuc970_release_sem(mtd);
  82. LEAVE();
  83. }

nandflash硬件ECC写操作:

  1. static void nuc970_nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required)
  2. {
  3. uint8_t *ecc_calc = chip->buffers->ecccalc;
  4. uint32_t hweccbytes=chip->ecc.layout->eccbytes;
  5. register char * ptr=REG_SMRA0;
  6. ENTER();
  7. if ( nuc970_wait_sem(mtd) < 0 )
  8. {
  9. LEAVE();
  10. return ;
  11. }
  12. memset ( (void*)ptr, 0xFF, mtd->oobsize );
  13. memcpy ( (void*)ptr, (void*)chip->oob_poi, mtd->oobsize - chip->ecc.total );
  14. _nuc970_nand_dma_transfer( mtd, buf, mtd->writesize , 0x1);
  15. // Copy parity code in SMRA to calc
  16. memcpy ( (void*)ecc_calc, (void*)( REG_SMRA0 + ( mtd->oobsize - chip->ecc.total ) ), chip->ecc.total );
  17. // Copy parity code in calc to oob_poi
  18. memcpy ( (void*)(chip->oob_poi+hweccbytes), (void*)ecc_calc, chip->ecc.total);
  19. nuc970_release_sem(mtd);
  20. LEAVE();
  21. }

硬件ecc,先读取oob,确定ecc是否出错,纠错正常才读取数据:

  1. static int nuc970_nand_read_page_hwecc_oob_first(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
  2. {
  3. int eccsize = chip->ecc.size;
  4. uint8_t *p = buf;
  5. char * ptr=REG_SMRA0;
  6. ENTER();
  7. if ( nuc970_wait_sem(mtd) < 0 )
  8. {
  9. LEAVE();
  10. return -1;
  11. }
  12. //printk("smcsr 0x%x\n", readl(REG_SMCSR));
  13. //nuc970_choice_bch_algo ( mtd, page );
  14. /* At first, read the OOB area */
  15. nuc970_nand_command_lp(mtd, NAND_CMD_READOOB, 0, page);
  16. nuc970_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
  17. // Second, copy OOB data to SMRA for page read
  18. memcpy ( (void*)ptr, (void*)chip->oob_poi, mtd->oobsize );
  19. // Third, read data from nand
  20. nuc970_nand_command_lp(mtd, NAND_CMD_READ0, 0, page);
  21. _nuc970_nand_dma_transfer(mtd, p, eccsize, 0x0);
  22. // Fouth, restore OOB data from SMRA
  23. memcpy ( (void*)chip->oob_poi, (void*)ptr, mtd->oobsize );
  24. nuc970_release_sem(mtd);
  25. LEAVE();
  26. return 0;
  27. }

oob(out-of-band)参数配置:

  1. static void nuc970_layout_oob_table ( struct nand_ecclayout* pNandOOBTbl, int oobsize , int eccbytes )
  2. {
  3. //ecc使用字节数
  4. pNandOOBTbl->eccbytes = eccbytes;
  5. //oob中多余的字节数 = oob总空间 - DEF_RESERVER_OOB_SIZE_FOR_MARKER - ecc占用的字节数
  6. pNandOOBTbl->oobavail = oobsize - DEF_RESERVER_OOB_SIZE_FOR_MARKER - eccbytes ;
  7. //下面我的理解是,坏块标记,至于如何使用,待分析????
  8. pNandOOBTbl->oobfree[0].offset = DEF_RESERVER_OOB_SIZE_FOR_MARKER; // Bad block marker size
  9. pNandOOBTbl->oobfree[0].length = oobsize - eccbytes - pNandOOBTbl->oobfree[0].offset ;
  10. }

硬件ecc读取oob,这里多说一句,oob读取流程[命令 + 地址(列地址+行地址) + 等待nandflash忙 + 开始数据读取]
a. 发送读取命令NAND_CMD_READOOB,读取oob,实际上在ONFI协议中并没有NAND_CMD_READOOB命令,在函数nuc970_nand_command_lp(...)内部进行了转换为读命令NAND_CMD_READ0,oob的偏移位置为“每一页的尾部”,所以该函数的形参中column=0;  
b. 读取数据, nuc970_nand_read_buf(...):

  1. static int nuc970_nand_read_oob_hwecc(struct mtd_info *mtd, struct nand_chip *chip, int page)
  2. {
  3. char * ptr=REG_SMRA0;
  4. ENTER();
  5. if ( nuc970_wait_sem(mtd) < 0 )
  6. {
  7. LEAVE();
  8. return -1;
  9. }
  10. nuc970_nand_command_lp(mtd, NAND_CMD_READOOB, 0, page);
  11. // nuc970_choice_bch_algo ( mtd, page );
  12. nuc970_nand_read_buf(mtd, &chip->oob_poi[0], mtd->oobsize);
  13. // Second, copy OOB data to SMRA for page read
  14. memcpy ( (void*)ptr, (void*)chip->oob_poi, mtd->oobsize );
  15. // Third, read data from nand
  16. nuc970_nand_command_lp(mtd, NAND_CMD_READ0, 0, page);
  17. _nuc970_nand_dma_transfer(mtd, NULL, mtd->writesize, 0x0);
  18. // Fouth, recovery OOB data for SMRA
  19. memcpy ( (void*)chip->oob_poi, (void*)ptr, mtd->oobsize );
  20. nuc970_release_sem(mtd);
  21. return 0;
  22. }

按顺序写数据到nandflash:

  1. static int nuc970_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offset, int data_len,
  2. const uint8_t *buf, int oob_required, int page, int cached, int raw)
  3. {
  4. int status;
  5. if ( nuc970_wait_sem(mtd) < 0 )
  6. {
  7. LEAVE();
  8. return -1;
  9. }
  10. nuc970_nand_command_lp(mtd, NAND_CMD_SEQIN, 0x00, page);
  11. if (unlikely(raw))
  12. chip->ecc.write_page_raw(mtd, chip, buf, 0);
  13. else
  14. {
  15. if ( page >= 0 && page < (1<<(chip->phys_erase_shift+2)) / mtd->writesize ) // four blocks
  16. {
  17. // Special pattern
  18. char * ptr=REG_SMRA0;
  19. memset ( (void*)ptr, 0xFF, mtd->oobsize );
  20. ptr[3] = 0x00;
  21. ptr[2] = 0x00;
  22. ptr[1] = 0xFF;
  23. _nuc970_nand_dma_transfer( mtd, buf, mtd->writesize , 0x1 );
  24. }
  25. else
  26. {
  27. nuc970_nand_write_page_hwecc ( mtd, chip, buf, oob_required );
  28. }
  29. }
  30. /*
  31. * Cached progamming disabled for now, Not sure if its worth the
  32. * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
  33. */
  34. cached = 0;
  35. if (!cached || !(chip->options & NAND_CACHEPRG)) {
  36. nuc970_nand_command_lp(mtd, NAND_CMD_PAGEPROG, -1, -1);
  37. status = chip->waitfunc(mtd, chip);
  38. /*
  39. * See if operation failed and additional status checks are
  40. * available
  41. */
  42. if ((status & NAND_STATUS_FAIL) && (chip->errstat))
  43. status = chip->errstat(mtd, chip, FL_WRITING, status, page);
  44. if (status & NAND_STATUS_FAIL)
  45. {
  46. nuc970_release_sem(mtd);
  47. return -EIO;
  48. }
  49. }
  50. else {
  51. nuc970_nand_command_lp(mtd, NAND_CMD_CACHEDPROG, -1, -1);
  52. status = chip->waitfunc(mtd, chip);
  53. }
  54. #if 0 // for verify
  55. /* Send command to read back the data */
  56. nuc970_nand_command_lp(mtd, NAND_CMD_READ0, 0, page);
  57. if (nuc970_verify_buf(mtd, buf, mtd->writesize))
  58. {
  59. nuc970_release_sem(mtd);
  60. return -EIO;
  61. }
  62. #endif
  63. nuc970_release_sem(mtd);
  64. return 0;
  65. }
对底层硬件操作的函数调用分析完了,接下来正真开始驱动注册:
  1. static int nuc970_nand_probe(struct platform_device *pdev)
  2. {
  3. struct nand_chip *chip;
  4. struct nuc970_nand_info *nuc970_nand;
  5. struct mtd_info *mtd;
  6. struct pinctrl *p;
  7. int retval=0;
  8. E_PAGESIZE ePageSize;
  9. ENTER() ;
  10. nuc970_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc970_nand_info), GFP_KERNEL);
  11. if (!nuc970_nand)
  12. return -ENOMEM;
  13. //分配虚拟地址
  14. nuc970_nand->pnand_vaddr = (unsigned char *) dma_alloc_writecombine(NULL, 512*16, (dma_addr_t *)&nuc970_nand->pnand_phyaddr, GFP_KERNEL);
  15. if(nuc970_nand->pnand_vaddr == NULL){
  16. printk(KERN_ERR "nuc970_nand: failed to allocate ram for nand data.\n");
  17. return -ENOMEM;
  18. }
  19. platform_set_drvdata(pdev, nuc970_nand); //将nuc970_nand绑定为pdev的私有数据!
  20. spin_lock_init(&nuc970_nand->controller.lock);
  21. init_waitqueue_head(&nuc970_nand->controller.wq);
  22. nuc970_nand->pdev = pdev;
  23. //这里有个疑问是mtd包含chip???我猜mtd应该是对应上层(如nandflash_erase命令就是和MTD相关),chip是对底层硬件操作
  24. mtd = &nuc970_nand->mtd; //分区操作结构体
  25. chip = &(nuc970_nand->chip); //芯片操作结构体
  26. nuc970_nand->mtd.priv = chip; //将chip绑定到mtd的私有成员
  27. nuc970_nand->mtd.owner = THIS_MODULE;
  28. spin_lock_init(&nuc970_nand->lock);
  29. /*
  30. * Get Clock
  31. */
  32. nuc970_nand->fmi_clk = clk_get(NULL, "fmi_hclk");
  33. if (IS_ERR(nuc970_nand->fmi_clk)) {
  34. printk("no fmi_clk?\n");
  35. retval = -ENXIO;
  36. goto fail1;
  37. }
  38. nuc970_nand->clk = clk_get(NULL, "nand_hclk");
  39. if (IS_ERR(nuc970_nand->clk)) {
  40. printk("no nand_clk?\n");
  41. goto fail2;
  42. }
  43. clk_prepare(nuc970_nand->fmi_clk);
  44. clk_enable(nuc970_nand->fmi_clk);
  45. clk_prepare(nuc970_nand->clk);
  46. clk_enable(nuc970_nand->clk);
  47. nuc970_nand->chip.controller = &nuc970_nand->controller;
  48. //绑定chip的接口操作函数,即chip对应底层硬件的操作方式
  49. chip->cmdfunc = nuc970_nand_command_lp; //nandflash命令操作
  50. chip->read_byte = nuc970_nand_read_byte; //读字节
  51. chip->select_chip = nuc970_nand_select_chip; //chip片选
  52. chip->read_buf = nuc970_read_buf_dma; //从DMA中读取nandflash数据
  53. chip->write_buf = nuc970_write_buf_dma; //通过DMA写数据到nandflash
  54. // Check NAND device NBUSY0 pin
  55. chip->dev_ready = nuc970_nand_devready; //读nandflash控制器是否busy
  56. /* set up nand options */
  57. chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
  58. //chip->options |= NAND_SKIP_BBTSCAN;
  59. nuc970_nand->reg = 0x00;
  60. // Read OOB data first, then HW read page
  61. chip->write_page = nuc970_nand_write_page; //页写操作
  62. chip->ecc.mode = NAND_ECC_HW_OOB_FIRST; //???
  63. chip->ecc.hwctl = nuc970_nand_enable_hwecc; //使能硬件ECC
  64. chip->ecc.calculate = nuc970_nand_calculate_ecc; //计算ECC
  65. chip->ecc.correct = nuc970_nand_correct_data; //纠正数据
  66. chip->ecc.write_page= nuc970_nand_write_page_hwecc; //硬件ECC页写操作
  67. chip->ecc.read_page = nuc970_nand_read_page_hwecc_oob_first; //读页数据前先读取oob(out of bound)
  68. chip->ecc.read_oob = nuc970_nand_read_oob_hwecc; //读取数据
  69. chip->ecc.layout = &nuc970_nand_oob;
  70. //配置gpio管脚为nandflash功能
  71. #if defined (CONFIG_NUC970_NAND_PC)
  72. p = devm_pinctrl_get_select(&pdev->dev, "nand-PC");
  73. #elif defined (CONFIG_NUC970_NAND_PI)
  74. p = devm_pinctrl_get_select(&pdev->dev, "nand-PI");
  75. #endif
  76. if (IS_ERR(p))
  77. {
  78. dev_err(&pdev->dev, "unable to reserve pin\n");
  79. retval = PTR_ERR(p);
  80. }
  81. nuc970_nand_initialize( );
  82. nuc970_nand->m_i32MyShowTime = 0;
  83. /* first scan to find the device and get the page size */
  84. if (nand_scan_ident(&(nuc970_nand->mtd), 1, NULL)) {
  85. retval = -ENXIO;
  86. goto fail3;
  87. }
  88. //Set PSize bits of SMCSR register to select NAND card page size
  89. switch (mtd->writesize) { //每一页的大小,我使用的是2K,而计算ecc是每512字节计算一个oob,所以这里有四个
  90. case 2048:
  91. writel( (readl(REG_SMCSR)&(~0x30000)) + 0x10000, REG_SMCSR);
  92. ePageSize = ePageSize_2048;
  93. break;
  94. case 4096:
  95. writel( (readl(REG_SMCSR)&(~0x30000)) + 0x20000, REG_SMCSR);
  96. ePageSize = ePageSize_4096;
  97. break;
  98. case 8192:
  99. writel( (readl(REG_SMCSR)&(~0x30000)) + 0x30000, REG_SMCSR);
  100. ePageSize = ePageSize_8192;
  101. break;
  102. /* Not support now. */
  103. case 512:
  104. //writel( (readl(REG_SMCSR)&(~0x30000)) + 0, REG_SMCSR);
  105. //ePageSize = ePageSize_512;
  106. //break;
  107. default:
  108. printk("NUC970 NAND CONTROLLER IS NOT SUPPORT THE PAGE SIZE. (%d, %d)\n", mtd->writesize, mtd->oobsize );
  109. goto fail3;
  110. }
  111. nuc970_nand->m_ePageSize = ePageSize;
  112. {
  113. // System area
  114. int i32eBCHAlgo = 0;
  115. switch(ePageSize) {
  116. case 0:
  117. case 1: i32eBCHAlgo = eBCH_T4; break;
  118. case 2: i32eBCHAlgo = eBCH_T8; break;
  119. case 3: i32eBCHAlgo = eBCH_T12; break;
  120. default:
  121. break;
  122. }
  123. nuc970_nand_SYSTEM_oob.m_BCHAlgoidx = i32eBCHAlgo;
  124. nuc970_nand_SYSTEM_oob.m_SMRASize = g_SYSAREA_NAND_EXTRA_SIZE[ePageSize];
  125. nuc970_layout_oob_table ( (struct nand_ecclayout*)&nuc970_nand_SYSTEM_oob, nuc970_nand_SYSTEM_oob.m_SMRASize, g_i32ParityNum[ePageSize][i32eBCHAlgo] );
  126. printk("SYSTEM: USE %s HWECC algorithm(SMRA size: %d, Parity number:%d bytes)\n",
  127. g_pcBCHAlgoIdx[i32eBCHAlgo],nuc970_nand_SYSTEM_oob.m_SMRASize,g_i32ParityNum[ePageSize][i32eBCHAlgo] );
  128. //chp i32eBCHAlgo = nuc970_hwecc_choice_bch_algorithm ( ePageSize, mtd->oobsize, 0 );
  129. i32eBCHAlgo = nuc970_nand_SYSTEM_oob.m_BCHAlgoidx;
  130. nuc970_nand_EXECUTE_oob.m_BCHAlgoidx = i32eBCHAlgo;
  131. if ( ePageSize==3 && mtd->oobsize >= g_SYSAREA_NAND_EXTRA_SIZE[ePageSize] ) // 8K, oob >= 376Byte
  132. {
  133. nuc970_nand_EXECUTE_oob.m_SMRASize = g_SYSAREA_NAND_EXTRA_SIZE[ePageSize];
  134. mtd->oobsize = nuc970_nand_EXECUTE_oob.m_SMRASize;
  135. }
  136. else if ( ePageSize==1 && mtd->oobsize >= g_SYSAREA_NAND_EXTRA_SIZE[ePageSize] ) // 2K, oob >= 64Byte
  137. {
  138. nuc970_nand_EXECUTE_oob.m_SMRASize = g_SYSAREA_NAND_EXTRA_SIZE[ePageSize];
  139. mtd->oobsize = nuc970_nand_EXECUTE_oob.m_SMRASize;
  140. }
  141. else
  142. nuc970_nand_EXECUTE_oob.m_SMRASize = mtd->oobsize;
  143. if ( i32eBCHAlgo >= 0 ) {
  144. nuc970_layout_oob_table ( (struct nand_ecclayout*)&nuc970_nand_EXECUTE_oob, nuc970_nand_EXECUTE_oob.m_SMRASize, g_i32ParityNum[ePageSize][i32eBCHAlgo] );
  145. printk("EXECUTE: USE %s HWECC algorithm(SMRA size: %d, Parity number:%d bytes)\n",
  146. g_pcBCHAlgoIdx[i32eBCHAlgo], nuc970_nand_EXECUTE_oob.m_SMRASize, g_i32ParityNum[ePageSize][i32eBCHAlgo] );
  147. }
  148. }
  149. #ifndef CONFIG_MTD_CMDLINE_PARTS
  150. nuc970_nand->parts = (struct mtd_partition*)partitions;
  151. nuc970_nand->nr_parts = ARRAY_SIZE(partitions);
  152. #endif
  153. nuc970_nand->m_i32SMRASize = mtd->oobsize;
  154. //chp nuc970_nand->eBCHAlgo = nuc970_hwecc_choice_bch_algorithm ( ePageSize, mtd->oobsize, 0 );
  155. nuc970_nand->eBCHAlgo = nuc970_nand_SYSTEM_oob.m_BCHAlgoidx;
  156. if ( nuc970_nand->eBCHAlgo < 0 ) {
  157. nuc970_layout_oob_table ( &nuc970_nand_oob, mtd->oobsize, 0 );
  158. chip->ecc.bytes = 0;
  159. chip->ecc.size = mtd->writesize;
  160. printk("Choice BCH algorithm: No match.\n");
  161. } else {
  162. nuc970_layout_oob_table ( &nuc970_nand_oob, mtd->oobsize, g_i32ParityNum[ePageSize][nuc970_nand->eBCHAlgo] );
  163. chip->ecc.bytes = nuc970_nand_oob.eccbytes;
  164. chip->ecc.size = mtd->writesize;
  165. printk("USE %s HWECC algorithm(Parity number:%d bytes)\n", g_pcBCHAlgoIdx[nuc970_nand->eBCHAlgo], g_i32ParityNum[ePageSize][nuc970_nand->eBCHAlgo] );
  166. }
  167. /* set BCH Tn */
  168. switch (nuc970_nand->eBCHAlgo)
  169. {
  170. case eBCH_T4:
  171. chip->ecc.strength = 4;
  172. break;
  173. case eBCH_T8:
  174. chip->ecc.strength = 8;
  175. break;
  176. case eBCH_T12:
  177. chip->ecc.strength = 12;
  178. break;
  179. case eBCH_T15:
  180. chip->ecc.strength = 15;
  181. break;
  182. case eBCH_T24:
  183. chip->ecc.strength = 24;
  184. break;
  185. default:
  186. ;
  187. }
  188. /* add mtd-id. The string should same as uboot definition */
  189. mtd->name = "nand0";
  190. /* second phase scan */
  191. if ( nand_scan_tail( &(nuc970_nand->mtd) ) ) {
  192. retval = -ENXIO;
  193. goto fail3;
  194. }
  195. if ( nuc970_nand->eBCHAlgo >= 0 )
  196. nuc970_nand_hwecc_init (&(nuc970_nand->mtd));
  197. else
  198. nuc970_nand_hwecc_fini (&(nuc970_nand->mtd));
  199. dump_chip_info( chip );
  200. /* First look for RedBoot table or partitions on the command
  201. * line, these take precedence over device tree information */
  202. mtd_device_parse_register(&(nuc970_nand->mtd), NULL, NULL, nuc970_nand->parts, nuc970_nand->nr_parts);
  203. LEAVE();
  204. dump_regs(__LINE__);
  205. printk("fmi-sm: registered successfully! mtdid=%s\n", mtd->name);
  206. return retval;
  207. fail3:
  208. fail2:
  209. fail1: kfree(nuc970_nand);
  210. return retval;
  211. }

probe(...)探测函数内部已基本有注释,现在主要分析几个重要的的函数,如下,

nandflash扫描识别,包括厂商ID,芯片ID,是否符合ONFI标准....

  1. if (nand_scan_ident(&(nuc970_nand->mtd), 1, NULL)) {
  2. retval = -ENXIO;
  3. goto fail3;
  4. }
  1. int nand_scan_ident(struct mtd_info *mtd, int maxchips,
  2. struct nand_flash_dev *table)
  3. {
  4. int i, busw, nand_maf_id, nand_dev_id;
  5. struct nand_chip *chip = mtd->priv;
  6. struct nand_flash_dev *type;
  7. /* Get buswidth to select the correct functions */
  8. busw = chip->options & NAND_BUSWIDTH_16;
  9. /* Set the default functions */
  10. nand_set_defaults(chip, busw); //设置默认函数接口,包括坏块扫描函数
  11. /* Read the flash type */
  12. //读取flash的类型,包括厂商ID,设备ID
  13. type = nand_get_flash_type(mtd, chip, busw,
  14. &nand_maf_id, &nand_dev_id, table);
  15. if (IS_ERR(type)) {
  16. if (!(chip->options & NAND_SCAN_SILENT_NODEV))
  17. pr_warn("No NAND device found\n");
  18. chip->select_chip(mtd, -1);
  19. return PTR_ERR(type);
  20. }
  21. chip->select_chip(mtd, -1);
  22. /* Check for a chip array */
  23. for (i = 1; i < maxchips; i++) {
  24. //片选使能
  25. chip->select_chip(mtd, i);
  26. //复位nandflash
  27. /* See comment in nand_get_flash_type for reset */
  28. chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
  29. //发送读ID命令
  30. /* Send the command for reading device ID */
  31. chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
  32. //读取厂商ID和设备ID
  33. /* Read manufacturer and device IDs */
  34. if (nand_maf_id != chip->read_byte(mtd) ||
  35. nand_dev_id != chip->read_byte(mtd)) {
  36. chip->select_chip(mtd, -1); //片选禁止
  37. break;
  38. }
  39. chip->select_chip(mtd, -1);
  40. }
  41. if (i > 1)
  42. pr_info("%d NAND chips detected\n", i);
  43. //保存当前片选的nandflash
  44. /* Store the number of chips and calc total size for mtd */
  45. chip->numchips = i;
  46. mtd->size = i * chip->chipsize;
  47. return 0;
  48. }

nandflash默认接口设置,函数形参 @busw决定了外围总线宽度是8位还是16位,我这里是8位,默认设置的函数我们在probe()探测函数内部绑定,这里主要分析坏块扫描接口绑定:

  1. static void nand_set_defaults(struct nand_chip *chip, int busw)
  2. {
  3. /* check for proper chip_delay setup, set 20us if not */
  4. if (!chip->chip_delay)
  5. chip->chip_delay = 20;
  6. /* check, if a user supplied command function given */
  7. if (chip->cmdfunc == NULL)
  8. chip->cmdfunc = nand_command;
  9. /* check, if a user supplied wait function given */
  10. if (chip->waitfunc == NULL)
  11. chip->waitfunc = nand_wait;
  12. if (!chip->select_chip)
  13. chip->select_chip = nand_select_chip;
  14. /* If called twice, pointers that depend on busw may need to be reset */
  15. if (!chip->read_byte || chip->read_byte == nand_read_byte)
  16. chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
  17. if (!chip->read_word)
  18. chip->read_word = nand_read_word;
  19. if (!chip->block_bad)
  20. chip->block_bad = nand_block_bad;
  21. if (!chip->block_markbad)
  22. chip->block_markbad = nand_default_block_markbad;
  23. if (!chip->write_buf || chip->write_buf == nand_write_buf)
  24. chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
  25. if (!chip->read_buf || chip->read_buf == nand_read_buf)
  26. chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
  27. if (!chip->scan_bbt)
  28. chip->scan_bbt = nand_default_bbt; //绑定坏块扫描函数
  29. if (!chip->controller) {
  30. chip->controller = &chip->hwcontrol;
  31. spin_lock_init(&chip->controller->lock);
  32. init_waitqueue_head(&chip->controller->wq);
  33. }
  34. }

先看下坏块表的结构体:

  1. struct nand_bbt_descr {
  2. int options; //选项,具体见赋值
  3. int pages[NAND_MAX_CHIPS]; //nandflash芯片个数,我们这里为1块
  4. int offs; //坏块标记存放在oob区域,offs是相对oob的偏移位置
  5. int veroffs;
  6. uint8_t version[NAND_MAX_CHIPS];
  7. int len; //坏块标记占用的字节数
  8. int maxblocks;
  9. int reserved_block_code;
  10. uint8_t *pattern; //如果坏块标记的是0xff,则说明这个block是好的
  11. };

nandflash默认坏块表:

  1. int nand_default_bbt(struct mtd_info *mtd)
  2. {
  3. struct nand_chip *this = mtd->priv;
  4. /* Is a flash based bad block table requested? */
  5. if (this->bbt_options & NAND_BBT_USE_FLASH) {
  6. /* Use the default pattern descriptors */
  7. if (!this->bbt_td) {
  8. if (this->bbt_options & NAND_BBT_NO_OOB) {
  9. this->bbt_td = &bbt_main_no_oob_descr;
  10. this->bbt_md = &bbt_mirror_no_oob_descr;
  11. } else {
  12. this->bbt_td = &bbt_main_descr;
  13. this->bbt_md = &bbt_mirror_descr;
  14. }
  15. }
  16. } else {
  17. this->bbt_td = NULL;
  18. this->bbt_md = NULL;
  19. }
  20. if (!this->badblock_pattern)
  21. nand_create_badblock_pattern(this); //建立一个bad block坏块表模式
  22. return nand_scan_bbt(mtd, this->badblock_pattern); //扫描坏块表
  23. }

建立一个坏块表模版:

  1. static int nand_create_badblock_pattern(struct nand_chip *this)
  2. {
  3. struct nand_bbt_descr *bd;
  4. if (this->badblock_pattern) {
  5. pr_warn("Bad block pattern already allocated; not replacing\n");
  6. return -EINVAL;
  7. }
  8. bd = kzalloc(sizeof(*bd), GFP_KERNEL);
  9. if (!bd)
  10. return -ENOMEM;
  11. bd->options = this->bbt_options & BADBLOCK_SCAN_MASK; //坏块扫描
  12. bd->offs = this->badblockpos; //坏块标记存放在每个page的oob里面
  13. bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; //根据总线的宽度决定坏块标记在oob的字节数
  14. bd->pattern = scan_ff_pattern; //如果坏块标记的是0xff,则说明这个block是好的
  15. bd->options |= NAND_BBT_DYNAMICSTRUCT; //表明bbt是动态结构体
  16. this->badblock_pattern = bd;
  17. return 0;
  18. }

扫描坏块,以下函数说明已经很详细了,就是如果flash已经存在bbt了,就读取到内存中,如果没有,就扫描全部flash芯片建立bbt;那最初的bbt从何而来?2种来源,一种是bootloader启动的时候,创建了bbt并保存到flash中;另外就是kernel第一次启动的时候如果没有找到合法的bbt就扫描flash并建立bbt

  1. int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
  2. {
  3. struct nand_chip *this = mtd->priv;
  4. int len, res = 0;
  5. uint8_t *buf;
  6. struct nand_bbt_descr *td = this->bbt_td;
  7. struct nand_bbt_descr *md = this->bbt_md;
  8. len = mtd->size >> (this->bbt_erase_shift + 2);
  9. /*
  10. * Allocate memory (2bit per block) and clear the memory bad block
  11. * table.
  12. */
  13. this->bbt = kzalloc(len, GFP_KERNEL);
  14. if (!this->bbt)
  15. return -ENOMEM;
  16. /*
  17. * If no primary table decriptor is given, scan the device to build a
  18. * memory based bad block table.
  19. */
  20. if (!td) {
  21. if ((res = nand_memory_bbt(mtd, bd))) {
  22. pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
  23. kfree(this->bbt);
  24. this->bbt = NULL;
  25. }
  26. return res;
  27. }
  28. verify_bbt_descr(mtd, td);
  29. verify_bbt_descr(mtd, md);
  30. /* Allocate a temporary buffer for one eraseblock incl. oob */
  31. len = (1 << this->bbt_erase_shift);
  32. len += (len >> this->page_shift) * mtd->oobsize;
  33. buf = vmalloc(len);
  34. if (!buf) {
  35. kfree(this->bbt);
  36. this->bbt = NULL;
  37. return -ENOMEM;
  38. }
  39. /* Is the bbt at a given page? */
  40. if (td->options & NAND_BBT_ABSPAGE) { //
  41. read_abs_bbts(mtd, buf, td, md);
  42. } else {
  43. /* Search the bad block table using a pattern in oob */
  44. search_read_bbts(mtd, buf, td, md);
  45. }
  46. res = check_create(mtd, buf, bd);
  47. /* Prevent the bbt regions from erasing / writing */
  48. mark_bbt_region(mtd, td);
  49. if (md)
  50. mark_bbt_region(mtd, md);
  51. vfree(buf);
  52. return res;
  53. }

搜索坏块表:

  1. static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
  2. struct nand_bbt_descr *td,
  3. struct nand_bbt_descr *md)
  4. {
  5. /* Search the primary table */
  6. search_bbt(mtd, buf, td); //扫描主要的表
  7. /* Search the mirror table */
  8. if (md)
  9. search_bbt(mtd, buf, md); //扫描镜像表
  10. }
  1. static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
  2. {
  3. struct nand_chip *this = mtd->priv;
  4. int i, chips;
  5. int bits, startblock, block, dir;
  6. int scanlen = mtd->writesize + mtd->oobsize; //数据区+oob区
  7. int bbtblocks;
  8. int blocktopage = this->bbt_erase_shift - this->page_shift;
  9. /* Search direction top -> down? */
  10. if (td->options & NAND_BBT_LASTBLOCK) {
  11. startblock = (mtd->size >> this->bbt_erase_shift) - 1;
  12. dir = -1;
  13. } else {
  14. startblock = 0;
  15. dir = 1;
  16. }
  17. /* Do we have a bbt per chip? */
  18. if (td->options & NAND_BBT_PERCHIP) {
  19. chips = this->numchips;
  20. bbtblocks = this->chipsize >> this->bbt_erase_shift;
  21. startblock &= bbtblocks - 1;
  22. } else {
  23. chips = 1;
  24. bbtblocks = mtd->size >> this->bbt_erase_shift;
  25. }
  26. /* Number of bits for each erase block in the bbt */
  27. bits = td->options & NAND_BBT_NRBITS_MSK;
  28. for (i = 0; i < chips; i++) {
  29. /* Reset version information */
  30. td->version[i] = 0;
  31. td->pages[i] = -1;
  32. /* Scan the maximum number of blocks */
  33. for (block = 0; block < td->maxblocks; block++) { //遍历chip的全部blocks
  34. int actblock = startblock + dir * block; //计算哪个block
  35. loff_t offs = (loff_t)actblock << this->bbt_erase_shift; //计算block在nandflash中的的偏移
  36. /* Read first page */
  37. scan_read(mtd, buf, offs, mtd->writesize, td);
  38. if (!check_pattern(buf, scanlen, mtd->writesize, td)) { //校验坏块
  39. td->pages[i] = actblock << blocktopage; //计算实际有坏块的页
  40. if (td->options & NAND_BBT_VERSION) {
  41. offs = bbt_get_ver_offs(mtd, td);
  42. td->version[i] = buf[offs];
  43. }
  44. break;
  45. }
  46. }
  47. startblock += this->chipsize >> this->bbt_erase_shift;
  48. }
  49. /* Check, if we found a bbt for each requested chip */
  50. for (i = 0; i < chips; i++) {
  51. if (td->pages[i] == -1)
  52. pr_warn("Bad block table not found for chip %d\n", i);
  53. else
  54. pr_info("Bad block table found at page %d, version "
  55. "0x%02X\n", td->pages[i], td->version[i]);
  56. }
  57. return 0;
  58. }

如果出现坏块,内核在启动时会打印如下的信息:

  1. Bad block table found at page 65472, version 0x01
  2. Bad block table found at page 65408, version 0x01

关于nandflash坏块表,后续专门写一篇文章,待续......

再重新回到nand_scan_ident(...)函数中的nand_get_flash_type(...)获取厂商ID、设备ID:

  1. static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
  2. struct nand_chip *chip,
  3. int busw,
  4. int *maf_id, int *dev_id,
  5. struct nand_flash_dev *type)
  6. {
  7. int i, maf_idx;
  8. u8 id_data[8];
  9. /* Select the device */
  10. chip->select_chip(mtd, 0);
  11. /*
  12. * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
  13. * after power-up.
  14. */
  15. chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
  16. /* Send the command for reading device ID */
  17. chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
  18. /* Read manufacturer and device IDs */
  19. *maf_id = chip->read_byte(mtd);
  20. *dev_id = chip->read_byte(mtd);
  21. /*
  22. * Try again to make sure, as some systems the bus-hold or other
  23. * interface concerns can cause random data which looks like a
  24. * possibly credible NAND flash to appear. If the two results do
  25. * not match, ignore the device completely.
  26. */
  27. chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
  28. /* Read entire ID string */
  29. for (i = 0; i < 8; i++)
  30. id_data[i] = chip->read_byte(mtd);
  31. if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
  32. pr_info("%s: second ID read did not match "
  33. "%02x,%02x against %02x,%02x\n", __func__,
  34. *maf_id, *dev_id, id_data[0], id_data[1]);
  35. return ERR_PTR(-ENODEV);
  36. }
  37. if (!type)
  38. type = nand_flash_ids;
  39. for (; type->name != NULL; type++) {
  40. if (is_full_id_nand(type)) {
  41. if (find_full_id_nand(mtd, chip, type, id_data, &busw))
  42. goto ident_done;
  43. } else if (*dev_id == type->dev_id) {
  44. break;
  45. }
  46. }
  47. chip->onfi_version = 0;
  48. if (!type->name || !type->pagesize) {
  49. //探测是否是ONFI标准,如果是就读取chip的大小、页擦除大小、页尺寸....
  50. /* Check is chip is ONFI compliant */
  51. if (nand_flash_detect_onfi(mtd, chip, &busw))
  52. goto ident_done;
  53. }
  54. if (!type->name)
  55. return ERR_PTR(-ENODEV);
  56. if (!mtd->name)
  57. mtd->name = type->name;
  58. chip->chipsize = (uint64_t)type->chipsize << 20;
  59. if (!type->pagesize && chip->init_size) {
  60. /* Set the pagesize, oobsize, erasesize by the driver */
  61. busw = chip->init_size(mtd, chip, id_data);
  62. } else if (!type->pagesize) {
  63. /* Decode parameters from extended ID */
  64. nand_decode_ext_id(mtd, chip, id_data, &busw);
  65. } else {
  66. nand_decode_id(mtd, chip, type, id_data, &busw);
  67. }
  68. /* Get chip options */
  69. chip->options |= type->options;
  70. /*
  71. * Check if chip is not a Samsung device. Do not clear the
  72. * options for chips which do not have an extended id.
  73. */
  74. if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
  75. chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
  76. ident_done:
  77. /* Try to identify manufacturer */
  78. for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
  79. if (nand_manuf_ids[maf_idx].id == *maf_id)
  80. break;
  81. }
  82. if (chip->options & NAND_BUSWIDTH_AUTO) {
  83. WARN_ON(chip->options & NAND_BUSWIDTH_16);
  84. chip->options |= busw;
  85. nand_set_defaults(chip, busw);
  86. } else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
  87. /*
  88. * Check, if buswidth is correct. Hardware drivers should set
  89. * chip correct!
  90. */
  91. pr_info("NAND device: Manufacturer ID:"
  92. " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
  93. *dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
  94. pr_warn("NAND bus width %d instead %d bit\n",
  95. (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
  96. busw ? 16 : 8);
  97. return ERR_PTR(-EINVAL);
  98. }
  99. nand_decode_bbm_options(mtd, chip, id_data);
  100. /* Calculate the address shift from the page size */
  101. chip->page_shift = ffs(mtd->writesize) - 1;
  102. /* Convert chipsize to number of pages per chip -1 */
  103. chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;
  104. chip->bbt_erase_shift = chip->phys_erase_shift =
  105. ffs(mtd->erasesize) - 1;
  106. if (chip->chipsize & 0xffffffff)
  107. chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
  108. else {
  109. chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32));
  110. chip->chip_shift += 32 - 1;
  111. }
  112. chip->badblockbits = 8;
  113. chip->erase_cmd = single_erase_cmd;
  114. /* Do not replace user supplied command function! */
  115. if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
  116. chip->cmdfunc = nand_command_lp;
  117. pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s),"
  118. " %dMiB, page size: %d, OOB size: %d\n",
  119. *maf_id, *dev_id, nand_manuf_ids[maf_idx].name,
  120. chip->onfi_version ? chip->onfi_params.model : type->name,
  121. (int)(chip->chipsize >> 20), mtd->writesize, mtd->oobsize);
  122. return type;
  123. }

输出的调试信息为:

NAND device: Manufacturer ID: 0x01, Chip ID: 0xf1 (AMD/Spansion S34ML01G2), 128MiB, page size: 2048, OOB size: 64S

nuc970_probe(...)-->nand_scan_tail(...),该函数主要完成一些未初始化的函数,并扫描整个chip的坏块:

  1. int nand_scan_tail(struct mtd_info *mtd)
  2. {
  3. int i;
  4. struct nand_chip *chip = mtd->priv;
  5. /* New bad blocks should be marked in OOB, flash-based BBT, or both */
  6. BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
  7. !(chip->bbt_options & NAND_BBT_USE_FLASH));
  8. if (!(chip->options & NAND_OWN_BUFFERS))
  9. chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
  10. if (!chip->buffers)
  11. return -ENOMEM;
  12. /* Set the internal oob buffer location, just after the page data */
  13. chip->oob_poi = chip->buffers->databuf + mtd->writesize;
  14. /*
  15. * If no default placement scheme is given, select an appropriate one.
  16. */
  17. if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {
  18. switch (mtd->oobsize) { //oob中的布局
  19. case 8:
  20. chip->ecc.layout = &nand_oob_8;
  21. break;
  22. case 16:
  23. chip->ecc.layout = &nand_oob_16;
  24. break;
  25. case 64:
  26. chip->ecc.layout = &nand_oob_64;
  27. break;
  28. case 128:
  29. chip->ecc.layout = &nand_oob_128;
  30. break;
  31. default:
  32. pr_warn("No oob scheme defined for oobsize %d\n",
  33. mtd->oobsize);
  34. BUG();
  35. }
  36. }
  37. if (!chip->write_page)
  38. chip->write_page = nand_write_page;
  39. /* set for ONFI nand */
  40. if (!chip->onfi_set_features)
  41. chip->onfi_set_features = nand_onfi_set_features;
  42. if (!chip->onfi_get_features)
  43. chip->onfi_get_features = nand_onfi_get_features;
  44. /*
  45. * Check ECC mode, default to software if 3byte/512byte hardware ECC is
  46. * selected and we have 256 byte pagesize fallback to software ECC
  47. */
  48. switch (chip->ecc.mode) {
  49. case NAND_ECC_HW_OOB_FIRST:
  50. /* Similar to NAND_ECC_HW, but a separate read_page handle */
  51. if (!chip->ecc.calculate || !chip->ecc.correct ||
  52. !chip->ecc.hwctl) {
  53. pr_warn("No ECC functions supplied; "
  54. "hardware ECC not possible\n");
  55. BUG();
  56. }
  57. if (!chip->ecc.read_page)
  58. chip->ecc.read_page = nand_read_page_hwecc_oob_first;
  59. case NAND_ECC_HW:
  60. /* Use standard hwecc read page function? */
  61. if (!chip->ecc.read_page)
  62. chip->ecc.read_page = nand_read_page_hwecc;
  63. if (!chip->ecc.write_page)
  64. chip->ecc.write_page = nand_write_page_hwecc;
  65. if (!chip->ecc.read_page_raw)
  66. chip->ecc.read_page_raw = nand_read_page_raw;
  67. if (!chip->ecc.write_page_raw)
  68. chip->ecc.write_page_raw = nand_write_page_raw;
  69. if (!chip->ecc.read_oob)
  70. chip->ecc.read_oob = nand_read_oob_std;
  71. if (!chip->ecc.write_oob)
  72. chip->ecc.write_oob = nand_write_oob_std;
  73. if (!chip->ecc.read_subpage)
  74. chip->ecc.read_subpage = nand_read_subpage;
  75. if (!chip->ecc.write_subpage)
  76. chip->ecc.write_subpage = nand_write_subpage_hwecc;
  77. case NAND_ECC_HW_SYNDROME:
  78. if ((!chip->ecc.calculate || !chip->ecc.correct ||
  79. !chip->ecc.hwctl) &&
  80. (!chip->ecc.read_page ||
  81. chip->ecc.read_page == nand_read_page_hwecc ||
  82. !chip->ecc.write_page ||
  83. chip->ecc.write_page == nand_write_page_hwecc)) {
  84. pr_warn("No ECC functions supplied; "
  85. "hardware ECC not possible\n");
  86. BUG();
  87. }
  88. /* Use standard syndrome read/write page function? */
  89. if (!chip->ecc.read_page)
  90. chip->ecc.read_page = nand_read_page_syndrome;
  91. if (!chip->ecc.write_page)
  92. chip->ecc.write_page = nand_write_page_syndrome;
  93. if (!chip->ecc.read_page_raw)
  94. chip->ecc.read_page_raw = nand_read_page_raw_syndrome;
  95. if (!chip->ecc.write_page_raw)
  96. chip->ecc.write_page_raw = nand_write_page_raw_syndrome;
  97. if (!chip->ecc.read_oob)
  98. chip->ecc.read_oob = nand_read_oob_syndrome;
  99. if (!chip->ecc.write_oob)
  100. chip->ecc.write_oob = nand_write_oob_syndrome;
  101. if (mtd->writesize >= chip->ecc.size) {
  102. if (!chip->ecc.strength) {
  103. pr_warn("Driver must set ecc.strength when using hardware ECC\n");
  104. BUG();
  105. }
  106. break;
  107. }
  108. pr_warn("%d byte HW ECC not possible on "
  109. "%d byte page size, fallback to SW ECC\n",
  110. chip->ecc.size, mtd->writesize);
  111. chip->ecc.mode = NAND_ECC_SOFT;
  112. case NAND_ECC_SOFT:
  113. chip->ecc.calculate = nand_calculate_ecc;
  114. chip->ecc.correct = nand_correct_data;
  115. chip->ecc.read_page = nand_read_page_swecc;
  116. chip->ecc.read_subpage = nand_read_subpage;
  117. chip->ecc.write_page = nand_write_page_swecc;
  118. chip->ecc.read_page_raw = nand_read_page_raw;
  119. chip->ecc.write_page_raw = nand_write_page_raw;
  120. chip->ecc.read_oob = nand_read_oob_std;
  121. chip->ecc.write_oob = nand_write_oob_std;
  122. if (!chip->ecc.size)
  123. chip->ecc.size = 256;
  124. chip->ecc.bytes = 3;
  125. chip->ecc.strength = 1;
  126. break;
  127. case NAND_ECC_SOFT_BCH:
  128. if (!mtd_nand_has_bch()) {
  129. pr_warn("CONFIG_MTD_ECC_BCH not enabled\n");
  130. BUG();
  131. }
  132. chip->ecc.calculate = nand_bch_calculate_ecc;
  133. chip->ecc.correct = nand_bch_correct_data;
  134. chip->ecc.read_page = nand_read_page_swecc;
  135. chip->ecc.read_subpage = nand_read_subpage;
  136. chip->ecc.write_page = nand_write_page_swecc;
  137. chip->ecc.read_page_raw = nand_read_page_raw;
  138. chip->ecc.write_page_raw = nand_write_page_raw;
  139. chip->ecc.read_oob = nand_read_oob_std;
  140. chip->ecc.write_oob = nand_write_oob_std;
  141. /*
  142. * Board driver should supply ecc.size and ecc.bytes values to
  143. * select how many bits are correctable; see nand_bch_init()
  144. * for details. Otherwise, default to 4 bits for large page
  145. * devices.
  146. */
  147. if (!chip->ecc.size && (mtd->oobsize >= 64)) {
  148. chip->ecc.size = 512;
  149. chip->ecc.bytes = 7;
  150. }
  151. chip->ecc.priv = nand_bch_init(mtd,
  152. chip->ecc.size,
  153. chip->ecc.bytes,
  154. &chip->ecc.layout);
  155. if (!chip->ecc.priv) {
  156. pr_warn("BCH ECC initialization failed!\n");
  157. BUG();
  158. }
  159. chip->ecc.strength =
  160. chip->ecc.bytes * 8 / fls(8 * chip->ecc.size);
  161. break;
  162. case NAND_ECC_NONE:
  163. pr_warn("NAND_ECC_NONE selected by board driver. "
  164. "This is not recommended!\n");
  165. chip->ecc.read_page = nand_read_page_raw;
  166. chip->ecc.write_page = nand_write_page_raw;
  167. chip->ecc.read_oob = nand_read_oob_std;
  168. chip->ecc.read_page_raw = nand_read_page_raw;
  169. chip->ecc.write_page_raw = nand_write_page_raw;
  170. chip->ecc.write_oob = nand_write_oob_std;
  171. chip->ecc.size = mtd->writesize;
  172. chip->ecc.bytes = 0;
  173. chip->ecc.strength = 0;
  174. break;
  175. default:
  176. pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode);
  177. BUG();
  178. }
  179. /* For many systems, the standard OOB write also works for raw */
  180. if (!chip->ecc.read_oob_raw)
  181. chip->ecc.read_oob_raw = chip->ecc.read_oob;
  182. if (!chip->ecc.write_oob_raw)
  183. chip->ecc.write_oob_raw = chip->ecc.write_oob;
  184. /*
  185. * The number of bytes available for a client to place data into
  186. * the out of band area.
  187. */
  188. chip->ecc.layout->oobavail = 0;
  189. for (i = 0; chip->ecc.layout->oobfree[i].length
  190. && i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)
  191. chip->ecc.layout->oobavail +=
  192. chip->ecc.layout->oobfree[i].length;
  193. mtd->oobavail = chip->ecc.layout->oobavail;
  194. /*
  195. * Set the number of read / write steps for one page depending on ECC
  196. * mode.
  197. */
  198. chip->ecc.steps = mtd->writesize / chip->ecc.size;
  199. if (chip->ecc.steps * chip->ecc.size != mtd->writesize) {
  200. pr_warn("Invalid ECC parameters\n");
  201. BUG();
  202. }
  203. chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
  204. /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
  205. if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
  206. !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
  207. switch (chip->ecc.steps) {
  208. case 2:
  209. mtd->subpage_sft = 1;
  210. break;
  211. case 4:
  212. case 8:
  213. case 16:
  214. mtd->subpage_sft = 2;
  215. break;
  216. }
  217. }
  218. chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
  219. /* Initialize state */
  220. chip->state = FL_READY;
  221. /* Invalidate the pagebuffer reference */
  222. chip->pagebuf = -1;
  223. /* Large page NAND with SOFT_ECC should support subpage reads */
  224. if ((chip->ecc.mode == NAND_ECC_SOFT) && (chip->page_shift > 9))
  225. chip->options |= NAND_SUBPAGE_READ;
  226. /* Fill in remaining MTD driver data */
  227. mtd->type = MTD_NANDFLASH;
  228. mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
  229. MTD_CAP_NANDFLASH;
  230. mtd->_erase = nand_erase;
  231. mtd->_point = NULL;
  232. mtd->_unpoint = NULL;
  233. mtd->_read = nand_read;
  234. mtd->_write = nand_write;
  235. mtd->_panic_write = panic_nand_write;
  236. mtd->_read_oob = nand_read_oob;
  237. mtd->_write_oob = nand_write_oob;
  238. mtd->_sync = nand_sync;
  239. mtd->_lock = NULL;
  240. mtd->_unlock = NULL;
  241. mtd->_suspend = nand_suspend;
  242. mtd->_resume = nand_resume;
  243. mtd->_block_isbad = nand_block_isbad;
  244. mtd->_block_markbad = nand_block_markbad;
  245. mtd->writebufsize = mtd->writesize;
  246. /* propagate ecc info to mtd_info */
  247. mtd->ecclayout = chip->ecc.layout;
  248. mtd->ecc_strength = chip->ecc.strength;
  249. /*
  250. * Initialize bitflip_threshold to its default prior scan_bbt() call.
  251. * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
  252. * properly set.
  253. */
  254. if (!mtd->bitflip_threshold)
  255. mtd->bitflip_threshold = mtd->ecc_strength;
  256. /* Check, if we should skip the bad block table scan */
  257. if (chip->options & NAND_SKIP_BBTSCAN)
  258. return 0;
  259. /* Build bad block table */
  260. return chip->scan_bbt(mtd);
  261. }
  262. EXPORT_SYMBOL(nand_scan_tail);
最后调用“chip->scan_bbt(mtd)”扫描坏块、并且建立坏块表,函数内部上面已经分析过,这里不在赘述!

6. 分区表创建

nandflash分区结构体定义:

  1. static struct mtd_partition partitions[] = {
  2. {
  3. .name = "u-boot",
  4. .offset = 0,
  5. .size = 2 * 1024 * 1024,
  6. .ecclayout = (struct nand_ecclayout*)&nuc970_nand_SYSTEM_oob
  7. },
  8. {
  9. .name = "Kernel",
  10. .size = 20 * 1024 * 1024,
  11. .offset = MTDPART_OFS_APPEND,
  12. .ecclayout = (struct nand_ecclayout*)&nuc970_nand_EXECUTE_oob
  13. },
  14. {
  15. .name = "user",
  16. .offset = MTDPART_OFS_APPEND,
  17. .size = MTDPART_SIZ_FULL
  18. }
  19. };

分区结构注册:

mtd_device_parse_register(&(nuc970_nand->mtd), NULL, NULL, nuc970_nand->parts, nuc970_nand->nr_parts);
  1. int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
  2. struct mtd_part_parser_data *parser_data,
  3. const struct mtd_partition *parts,
  4. int nr_parts)
  5. {
  6. int err;
  7. struct mtd_partition *real_parts;
  8. err = parse_mtd_partitions(mtd, types, &real_parts, parser_data);
  9. if (err <= 0 && nr_parts && parts) {
  10. //复制parts分区到内存
  11. real_parts = kmemdup(parts, sizeof(*parts) * nr_parts,
  12. GFP_KERNEL);
  13. if (!real_parts)
  14. err = -ENOMEM;
  15. else
  16. err = nr_parts; //分区个数
  17. }
  18. if (err > 0) { //err > 0条件成立
  19. err = add_mtd_partitions(mtd, real_parts, err); //增加MTD分区
  20. kfree(real_parts);
  21. } else if (err == 0) {
  22. err = add_mtd_device(mtd); //增加MTD设备,见下面
  23. if (err == 1)
  24. err = -ENODEV;
  25. }
  26. return err;
  27. }
  1. int add_mtd_partitions(struct mtd_info *master,
  2. const struct mtd_partition *parts,
  3. int nbparts)
  4. {
  5. struct mtd_part *slave;
  6. uint64_t cur_offset = 0;
  7. int i;
  8. printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
  9. for (i = 0; i < nbparts; i++) {
  10. slave = allocate_partition(master, parts + i, i, cur_offset); //分配一个分区,见下面
  11. if (IS_ERR(slave))
  12. return PTR_ERR(slave);
  13. mutex_lock(&mtd_partitions_mutex);
  14. list_add(&slave->list, &mtd_partitions); //将分区添加到mtd_partitions全局链表中
  15. mutex_unlock(&mtd_partitions_mutex);
  16. add_mtd_device(&slave->mtd); //将mtd添加到设备对象中,见下面
  17. cur_offset = slave->offset + slave->mtd.size;
  18. }
  19. return 0;
  20. }

动态分配一个分区allocate_partitions(...),包括函数的对mtd操作的函数初始化:

  1. static struct mtd_part *allocate_partition(struct mtd_info *master,
  2. const struct mtd_partition *part, int partno,
  3. uint64_t cur_offset)
  4. {
  5. struct mtd_part *slave;
  6. char *name;
  7. /* allocate the partition structure */
  8. slave = kzalloc(sizeof(*slave), GFP_KERNEL);
  9. name = kstrdup(part->name, GFP_KERNEL); //分区名称
  10. if (!name || !slave) {
  11. printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n",
  12. master->name);
  13. kfree(name);
  14. kfree(slave);
  15. return ERR_PTR(-ENOMEM);
  16. }
  17. /* set up the MTD object for this partition */
  18. slave->mtd.type = master->type; //flash类型,如MTD_NORFLASH
  19. slave->mtd.flags = master->flags & ~part->mask_flags;
  20. slave->mtd.size = part->size; //分区大小
  21. slave->mtd.writesize = master->writesize; //分区最小写单元,NOR-FLASH为1个字节,NAND-FLASH为一页
  22. slave->mtd.writebufsize = master->writebufsize;
  23. slave->mtd.oobsize = master->oobsize; //OOB大小,包括ECC检验
  24. slave->mtd.oobavail = master->oobavail;
  25. slave->mtd.subpage_sft = master->subpage_sft;
  26. slave->mtd.name = name; //分区名称,如内核“kernel”,文件系统“rootfs”
  27. slave->mtd.owner = master->owner;
  28. slave->mtd.backing_dev_info = master->backing_dev_info;
  29. /* NOTE: we don't arrange MTDs as a tree; it'd be error-prone
  30. * to have the same data be in two different partitions.
  31. */
  32. slave->mtd.dev.parent = master->dev.parent;
  33. slave->mtd._read = part_read; //分区读
  34. slave->mtd._write = part_write; //分区写
  35. if (master->_panic_write)
  36. slave->mtd._panic_write = part_panic_write; //内核恐慌(崩溃)时写操作
  37. if (master->_point && master->_unpoint) {
  38. slave->mtd._point = part_point;
  39. slave->mtd._unpoint = part_unpoint;
  40. }
  41. if (master->_get_unmapped_area)
  42. slave->mtd._get_unmapped_area = part_get_unmapped_area;
  43. if (master->_read_oob)
  44. slave->mtd._read_oob = part_read_oob; //读oob ecc校验
  45. if (master->_write_oob)
  46. slave->mtd._write_oob = part_write_oob;
  47. if (master->_read_user_prot_reg)
  48. slave->mtd._read_user_prot_reg = part_read_user_prot_reg;
  49. if (master->_read_fact_prot_reg)
  50. slave->mtd._read_fact_prot_reg = part_read_fact_prot_reg;
  51. if (master->_write_user_prot_reg)
  52. slave->mtd._write_user_prot_reg = part_write_user_prot_reg;
  53. if (master->_lock_user_prot_reg)
  54. slave->mtd._lock_user_prot_reg = part_lock_user_prot_reg;
  55. if (master->_get_user_prot_info)
  56. slave->mtd._get_user_prot_info = part_get_user_prot_info;
  57. if (master->_get_fact_prot_info)
  58. slave->mtd._get_fact_prot_info = part_get_fact_prot_info;
  59. if (master->_sync)
  60. slave->mtd._sync = part_sync;
  61. if (!partno && !master->dev.class && master->_suspend &&
  62. master->_resume) {
  63. slave->mtd._suspend = part_suspend;
  64. slave->mtd._resume = part_resume;
  65. }
  66. if (master->_writev)
  67. slave->mtd._writev = part_writev;
  68. if (master->_lock)
  69. slave->mtd._lock = part_lock;
  70. if (master->_unlock)
  71. slave->mtd._unlock = part_unlock;
  72. if (master->_is_locked)
  73. slave->mtd._is_locked = part_is_locked;
  74. if (master->_block_isbad)
  75. slave->mtd._block_isbad = part_block_isbad;
  76. if (master->_block_markbad)
  77. slave->mtd._block_markbad = part_block_markbad;
  78. slave->mtd._erase = part_erase; //分区擦除
  79. slave->master = master;
  80. slave->offset = part->offset;
  81. if (slave->offset == MTDPART_OFS_APPEND)
  82. slave->offset = cur_offset;
  83. if (slave->offset == MTDPART_OFS_NXTBLK) {
  84. slave->offset = cur_offset;
  85. if (mtd_mod_by_eb(cur_offset, master) != 0) {
  86. /* Round up to next erasesize */
  87. slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
  88. printk(KERN_NOTICE "Moving partition %d: "
  89. "0x%012llx -> 0x%012llx\n", partno,
  90. (unsigned long long)cur_offset, (unsigned long long)slave->offset);
  91. }
  92. }
  93. if (slave->offset == MTDPART_OFS_RETAIN) {
  94. slave->offset = cur_offset;
  95. if (master->size - slave->offset >= slave->mtd.size) {
  96. slave->mtd.size = master->size - slave->offset
  97. - slave->mtd.size;
  98. } else {
  99. printk(KERN_ERR "mtd partition \"%s\" doesn't have enough space: %#llx < %#llx, disabled\n",
  100. part->name, master->size - slave->offset,
  101. slave->mtd.size);
  102. /* register to preserve ordering */
  103. goto out_register;
  104. }
  105. }
  106. if (slave->mtd.size == MTDPART_SIZ_FULL)
  107. slave->mtd.size = master->size - slave->offset;
  108.         //注意这里内核会打印分区的地址范围
  109. printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset,
  110. (unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name);
  111. /* let's do some sanity checks */
  112. if (slave->offset >= master->size) {
  113. /* let's register it anyway to preserve ordering */
  114. slave->offset = 0;
  115. slave->mtd.size = 0;
  116. printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n",
  117. part->name);
  118. goto out_register;
  119. }
  120. if (slave->offset + slave->mtd.size > master->size) {
  121. slave->mtd.size = master->size - slave->offset;
  122. printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n",
  123. part->name, master->name, (unsigned long long)slave->mtd.size);
  124. }
  125. if (master->numeraseregions > 1) {
  126. /* Deal with variable erase size stuff */
  127. int i, max = master->numeraseregions;
  128. u64 end = slave->offset + slave->mtd.size;
  129. struct mtd_erase_region_info *regions = master->eraseregions;
  130. /* Find the first erase regions which is part of this
  131. * partition. */
  132. for (i = 0; i < max && regions[i].offset <= slave->offset; i++)
  133. ;
  134. /* The loop searched for the region _behind_ the first one */
  135. if (i > 0)
  136. i--;
  137. /* Pick biggest erasesize */
  138. for (; i < max && regions[i].offset < end; i++) {
  139. if (slave->mtd.erasesize < regions[i].erasesize) {
  140. slave->mtd.erasesize = regions[i].erasesize;
  141. }
  142. }
  143. BUG_ON(slave->mtd.erasesize == 0);
  144. } else {
  145. /* Single erase size */
  146. slave->mtd.erasesize = master->erasesize;
  147. }
  148. if ((slave->mtd.flags & MTD_WRITEABLE) &&
  149. mtd_mod_by_eb(slave->offset, &slave->mtd)) {
  150. /* Doesn't start on a boundary of major erase size */
  151. /* FIXME: Let it be writable if it is on a boundary of
  152. * _minor_ erase size though */
  153. slave->mtd.flags &= ~MTD_WRITEABLE;
  154. printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
  155. part->name);
  156. }
  157. if ((slave->mtd.flags & MTD_WRITEABLE) &&
  158. mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
  159. slave->mtd.flags &= ~MTD_WRITEABLE;
  160. printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
  161. part->name);
  162. }
  163. slave->mtd.ecclayout = master->ecclayout;
  164. slave->mtd.ecc_strength = master->ecc_strength;
  165. slave->mtd.bitflip_threshold = master->bitflip_threshold;
  166. if (master->_block_isbad) {
  167. uint64_t offs = 0;
  168. while (offs < slave->mtd.size) {
  169. if (mtd_block_isbad(master, offs + slave->offset))
  170. slave->mtd.ecc_stats.badblocks++;
  171. offs += slave->mtd.erasesize;
  172. }
  173. }
  174. out_register:
  175. return slave;
  176. }

上面函数执行完后,会输出如下报文:

  1. Creating 3 MTD partitions on "nand0":
  2. 0x000000000000-0x000000200000 : "u-boot"
  3. 0x000000200000-0x000000700000 : "kernel"
  4. 0x000000700000-0x000008000000 : "rootfs"

增加mtd设备:

  1. int add_mtd_device(struct mtd_info *mtd)
  2. {
  3. struct mtd_notifier *not;
  4. int i, error;
  5. if (!mtd->backing_dev_info) {
  6. switch (mtd->type) {
  7. case MTD_RAM:
  8. mtd->backing_dev_info = &mtd_bdi_rw_mappable;
  9. break;
  10. case MTD_ROM:
  11. mtd->backing_dev_info = &mtd_bdi_ro_mappable;
  12. break;
  13. default:
  14. mtd->backing_dev_info = &mtd_bdi_unmappable;
  15. break;
  16. }
  17. }
  18. BUG_ON(mtd->writesize == 0);
  19. mutex_lock(&mtd_table_mutex);
  20. i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
  21. if (i < 0)
  22. goto fail_locked;
  23. mtd->index = i;
  24. mtd->usecount = 0;
  25. /* default value if not set by driver */
  26. if (mtd->bitflip_threshold == 0)
  27. mtd->bitflip_threshold = mtd->ecc_strength;
  28. if (is_power_of_2(mtd->erasesize))
  29. mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
  30. else
  31. mtd->erasesize_shift = 0;
  32. if (is_power_of_2(mtd->writesize))
  33. mtd->writesize_shift = ffs(mtd->writesize) - 1;
  34. else
  35. mtd->writesize_shift = 0;
  36. mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
  37. mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
  38. /* Some chips always power up locked. Unlock them now */
  39. if ((mtd->flags & MTD_WRITEABLE) && (mtd->flags & MTD_POWERUP_LOCK)) {
  40. error = mtd_unlock(mtd, 0, mtd->size);
  41. if (error && error != -EOPNOTSUPP)
  42. printk(KERN_WARNING
  43. "%s: unlock failed, writes may not work\n",
  44. mtd->name);
  45. }
  46. /* Caller should have set dev.parent to match the
  47. * physical device.
  48. */
  49. mtd->dev.type = &mtd_devtype;
  50. mtd->dev.class = &mtd_class;
  51. mtd->dev.devt = MTD_DEVT(i);
  52. dev_set_name(&mtd->dev, "mtd%d", i);
  53. dev_set_drvdata(&mtd->dev, mtd);
  54. if (device_register(&mtd->dev) != 0)
  55. goto fail_added;
  56. if (MTD_DEVT(i))
  57. device_create(&mtd_class, mtd->dev.parent,
  58. MTD_DEVT(i) + 1,
  59. NULL, "mtd%dro", i);
  60. pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name);
  61. /* No need to get a refcount on the module containing
  62. the notifier, since we hold the mtd_table_mutex */
  63. list_for_each_entry(not, &mtd_notifiers, list)
  64. not->add(mtd);
  65. mutex_unlock(&mtd_table_mutex);
  66. /* We _know_ we aren't being removed, because
  67. our caller is still holding us here. So none
  68. of this try_ nonsense, and no bitching about it
  69. either. :) */
  70. __module_get(THIS_MODULE);
  71. return 0;
  72. fail_added:
  73. idr_remove(&mtd_idr, i);
  74. fail_locked:
  75. mutex_unlock(&mtd_table_mutex);
  76. return 1;
  77. }

7. 未完成的问题:

1. nandflash bbt表的扫描分析;

2. 文件系统对nandflash访问的层次问题;

可以参考这篇文章:点击打开链接

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Linux内核中NAND Flash坏块管理
uboot移植与源码分析总结(6)-Nand驱动
Nand :oob,bbt,ecc
转 powerpc平台,norflash及nandflash驱动及设备注册全过程
nand flash 的oob 及坏块管理
linux内核中对nand的坏块管理
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服