加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Nandflash 驱动移植

发布时间:2020-12-15 17:39:24 所属栏目:百科 来源:网络整理
导读:前段时间,研究了一下4G的Nandflash驱动。手头上只有飞凌6410BSP自带的Nandflash驱动,该驱动不支持K9GAG08U0D(2G)和K9LBG08U0D(4G)的Nandflash。所以就要先把这个Nandflash驱动搞成支持K9GAG08U0D(2G)的。 接下来要弄的就是支持K9LBG08U0D(4G)的Nan

前段时间,研究了一下4G的Nandflash驱动。手头上只有飞凌6410BSP自带的Nandflash驱动,该驱动不支持K9GAG08U0D(2G)和K9LBG08U0D(4G)的Nandflash。所以就要先把这个Nandflash驱动搞成支持K9GAG08U0D(2G)的。

接下来要弄的就是支持K9LBG08U0D(4G)的Nandflash。由于TE6410板子用的是K9GAG08U0D(2G)的Nandflash,所以先移植到支持这个Nandflash的,再进一步修改成支持K9LBG08U0D的。


移植之前,先让我们来对比下K9GAG08U0D(2G)和K9LBG08U0D(4G)两个Nandflash:

K9GAG08U0D(2G):

? Organization
? ?- Memory Cell Array : (2G + 109M) x 8bit
? ?- Data Register ? ? ? ?: (4K + 218) x 8bit ?
?? Automatic Program and Erase
? ?- Page Program : (4K + 218)Byte
? ?- Block Erase ? ? : (512K + 27.25K)Byte
?? Page Read Operation
? ?- Page Size : (4K + 218)Byte
? ?- Random Read : 60 μ s(Max.)
? ?- Serial ?Access : 30ns(Min.)
?? Memory Cell : 2bit / Memory Cell



K9LBG08U0D(4G):

Organization
? ?- Memory Cell Array : (2G + 109M) x 8bit(文档这里是写的2G,也不知道是不是三星那个写文档的人搞错了,明明是4G,怎么写的是2G)
? ?- Data Register ? ? ? ?: (4K + 218) x 8bit ?
?? Automatic Program and Erase
? ?- Page Program : (4K + 218)Byte
? ?- Block Erase ? ? : (512K + 27.25K)Byte
?? Page Read Operation
? ?- Page Size : (4K + 218)Byte
? ?- Random Read : 60 μ s(Max.)
? ?- Serial ?Access : 30ns(Min.)
? ? *K9MDG08U5D: 50ns(Min.)
?? Memory Cell : 2bit / Memory Cell



两个Nandflash都是4K 页 218备用区的,这样就更好办了。而且这两个都可以直接使用8bit的ECC,刚好6410最大就能支持到8bit的ECC校验。


咱们再来看一下这个8BIT 的ECC校验流程:



现在暂时到这里,下一篇将介绍6410中的NFCON控制寄存器部分。

这里将会介绍一下S3C6410CPU中的NFCON,Nandflash控制寄存器


8.1 OVERVIEW?
?Recently NOR flash memory price has increased and pr ice for SDRAM and a NAND flash memory is moderatly?placed. ? ?
?The 6410 is equipped with an internal SRAM buffer called ‘Steppingstone’.?
?Generally,the boot code will copy NAND flash content to SDRAM. Using hardware ?ECC,the NAND flash data?
?validity will be checked. After the NAND flash content ?is copied to SDRAM,main program will be executed on?SDRAM.?
?To use NAND Flash,'XSELNAND' pin must be connected to High Level.?
??
?8.2 FEATURES?
?NAND flash controller features include:?
? ??
?1. ?NAND Flash memory I/F: Support 512Bytes and 2KB Page ?.?
?2. ?Software mode: User can directly access NAND flash memory. ?for example this feature can be used in?read/erase/program NAND flash memory.?
?3. ?Interface: 8-bit NAND flash memory interface bus.?
?4. ?Hardware ECC generation,detection and indication (Software correction).?

硬件产生ECC,软件矫正
?5. ?Support both SLC and MLC NAND flash memory : 1-bit ECC,4-bit and 8-bit ECC for NAND flash.?
? ? ? ?(Recommend: 1bit ECC for SLC,4bit and 8bit ECC for MLC NAND Flash)?

同时支持SLC和MLC的Nandflash:1bit ECC用于SLC Nandflash, 4bit和8bit ECC用于MLC Nandflash
?6. ?SFR I/F: Support Byte/half word/word access to Data and ECC Data register,and Word access to other??registers?
?7. ?SteppingStone I/F: Support Byte/half word/word access.?
?8. ?The Steppingstone 8-KB internal SRAM ?buffer can be used for another purpose ?.?


其他的这里就不废话了,大家看回文档吧。

其中要注意的地方:

Both 4bit and 8bit ECC modules can be used for only 512 bytes ECC parity code generation. ?

4bit和8bit的ECC模块同时能够用于产生每读写512字节数据对应的ECC校验值。


?4 bit and 8bit ECC modules generate the parity codes for each 512 byte. However,1 bit ECC modules generate?
?parity code per byte lane separately.?


?4bit ECC modules generate max 7byte parity codes and 8 ?bit ECC modules generate 13byte parity codes at each?
?512/24 bytes.?

在每读写512或24字节的数据时,4bit的ECC模块产生最多7个字节的ECC校验码,而8bit的ECC模块产生最多13字节的校验码


下面直接来看8bit ECC的编解码:

8.8.5 8-BIT ECC PROGRAMMING GUIDE (ENCODING)?
? 1. ?To use 8-bit ECC in software mode,set the Ms gLength to 0(512-byte message length) and set the ECCType?
?to “01”(enable 8-bit ECC). ECC module generates ECC parit y code for 512-byte write data. In order to start?
?the ECC module,you have to write ‘1’ on the Init MECC (NFCONT[5]) bit after cleaning the MainECCLock?
?(NFCONT[7]) bit to ‘0’ (Unlock). MainECCLock (NFCONT[7]) bit controls whether ECC Parity code is?
?generated or not.?
?Note. In 8bit ECC,MainECCLock should be cleared before initiating InitMECC.?
?2. ?Whenever data is written,the 8bit ECC module generates ECC parity code internally.?
?3. ?After you finish writing 512-byte ?data (not include spare area data),the parity codes are automatically updated?
?to NF8MECC0,NFMECC1,NF8MECC2,NF8MECC3 regi ster. You have to check encoding done at NFSTAT?
?register. And set the MainECCLock bit to ‘1’(lock). ? If you use 512-byte page size NAND flash memory,you?
?can program these values directly to spare area. ?However,if you use NAND flash memory more than 512-
?byte page,you can’t program immediately. In this case,you have to copy these par ity codes to other memory?
?like DRAM. After writing all main data,you c an write the copied ECC values to spare area.?
?The parity codes have self-correctable information include parity code itself.?
?4. ?To generate spare area ECC parity code,set the MsgLength to 1(24-byte message length),and set the?
?ECCType to “01”(enable 8bit ECC). 8bit ECC module generates the ECC parity code for 24-byte data. In?
?order to initiating the module,you have to write ‘1 ’ on the InitMECC (NFCONT[5]) bit after clearing the
MainECCLock (NFCONT[7]) bit to ‘0’(Unlock). ?
?MainECCLock (NFCONT[7]) bit controls whether ECC Parity code is generated or not.?

?Note. In 8bit ECC,MainECCLock should be cleared before initiating InitMECC.?
?5. ?Whenever data is written,the 8bit ECC module generates ECC parity code internally.?
?6. ?When you finish writing 24-byte meta or extra data,the parity codes are automatically updated to?
?NF8MECC0,NF8MECC3 register. you have to check encoding done at NFSTAT?
?register. And set the MainECCLock bit to ‘1’(lock) . ?You can program these parity codes to spare area. The?
?parity codes have self-correctable information include parity code itself.?

部分译文:(仅供参考)

8bit ECC编码:
1、要用8bit的ECC,需要设置MsgLength 为0(512-byte message length) 和设置ECCTypet为 “01”(enable 8bit ECC)。8bit ECC模块会在读取512字节主数据之后产生对应的ECC校验码。要8bit的ECC模块开始工作,你必须在设置InitMECC (NFCONT[5])为1之前把MainECCLock (NFCONT[7]) 清0进行解锁。
MainECCLock (NFCONT[7]) 位控制着是否要产生对应的ECC校验码。
注意:在8bit ECC中,MainECCLock必须先清0,然后在对InitMECC置1
2、数据一旦写完,MLC的ECC模块就会产生对应的ECC校验码。
3、当你完成了512字节的主数据的写操作(不包括备用区数据),对应的ECC校验码将会自动的更新到NFM8ECC0,NFM8ECC1,NFM8ECC2,NFM8ECC3寄存器中。你必须在NFSTAT寄存器中检测编码是否完成 (在这里应该是NFSTAT[7],不知道为什么文档中的NFSTAT寄存器中的7bit为保留位,而三星的MLC bsp中却有用到这个位,这个情况大家可以推敲下)。同时,设置MainECCLock 为1加锁。如果你用的是512字节页大小的Nandflash存储,你可以直接把这些产生的ECC校验码写到备用区中。如果你使用的Nandflash存储超过了512字节的页大小,你不能够直接把产生的ECC校验码写到备用区中。在这种情况,你必须把每写512字节主数据产生的ECC校验码拷贝到其他存储器中,如DRAM。当写完所有的主数据(即一页大小的主数据),你可以把拷贝到其他存储器的ECC校验码写到备用区中。这个校验码带有自身矫正的信息和校验码值。
剩下的ECC读写基本雷同,这里就不翻译了。


8.8.6 8-BIT ECC PROGRAMMING GUIDE (DECODING)?
?1. ?To use 8bit ECC in software mode,set the MsgLength to 0(512-byte message length) and set the ECCType
?to “01”(enable 8bit ECC). 8bit ECC module generates E CC parity code for 512-byte read data. In order to?
?initiating 8bit ECC module,you have to write ‘1’ on the InitMECC (NFCONT[5]) bit after clearing the?
?MainECCLock (NFCONT[7]) bit to ‘0’(Unlock). ?
?MainECCLock (NFCONT[7]) bit controls whether ECC Parity code is generated or not.?
?Note. In 8bit ECC,MainECCLock should be cleared before InitMECC?
?2. ?Whenever data is read,the MLC ECC m odule generates ECC parity code internally.?
?3. ?After you complete reading 512-byte data (not including spare area data),you must set the MainECCLock?
?(NFCONT[7]) bit to ‘1’(Lock) after reading parity ?codes. 8bit ECC module needs parity codes to detect?
?whether error bits exists or not. So you have to read the ECC parity code of 512-byte main data right after?
?reading the 512-byte data. Once the ECC parity code is ?read,8bit ECC engine starts searching any error?
?internally. 8bit ECC error searching engine needs mini mum 372 cycles to find any error. And set the?
?MainECCLock bit to ‘1’(lock). ECCDecDone(NFSTAT[6]) can be used to check whether ECC decoding is?
?completed or not. ?
?4. ?When ECCDecDone (NFSTAT[6]) is set (‘1’),NF8ECCERR0 indicates whether error bit exists or not. If any?
?error exists,you can fix it by referencing NF8ECCERR0/1/2 and NFMLC8BITPT0/1 register.?
?5. ?If you have more main data to read,continue doing from step 1.?
?6. ?For meta data error check,set the MsgLength to 1(24-byte message length) and set the ECCType to?
?“01”(enable 8bit ECC). ECC module generates the ECC parity ?code for 24-byte data. In order to initiating the
?8bit ECC module,you have to write ‘1’ on the InitMECC (NFCONT[5]) bit after clearing the MainECCLock?
?(NFCONT[7]) bit to ‘0’(Unlock). ?
?MainECCLock (NFCONT[7]) bit controls whether ECC Parity code is generated or not.?
?Note. In 8bit ECC,MainECCLock should be cleared before InitMECC?
?7. ?Whenever data is read,the 8bit ECC module generates ECC parity code internally.?

8. ?After you complete reading 24-byte,you must set the MainECCLock (NFCONT[7]) bit to ‘1’(Lock) after read?
?ing the parity code for 24-byte data. MLC ECC module needs parity codes to detect w hether error bits exists?
?or not. So you have to read ECC parity codes right after reading 24-byte data. Once ECC parity code is read,?
?8bit ECC engine starts searching any error internally. 8bit ECC error searching engine needs minimum 372?
?cycles to find any error. And set the MainECCLock ?bit to ‘1’(lock). ECCDecDone(NFSTAT[6]) can be used to?
?check whether ECC decoding is completed or not. ? ?
?9. ?When ECCDecDone (NFSTAT[6]) is set (‘1’),NF8ECCERR0 indicates whether error bit exist or not. If any?

error exists,you can fix it by referencing NF8ECCERR0/1/2 and NF8MLCBITPT register.?

部分译文:(仅供参考)

8bit ECC译码:
1、要用8bit的ECC,需要设置MsgLength 为0(512-byte message length) 和设置ECCTypet为 “01”(enable 8bit ECC)。8bit ECC模块会在读取512字节主数据之后产生对应的ECC校验码。要8bit的ECC模块开始工作,你必须在设置InitMECC (NFCONT[5])为1之前把MainECCLock (NFCONT[7]) 清0进行解锁。
MainECCLock (NFCONT[7]) 位控制着是否要产生对应的ECC校验码。
注意:在8bit ECC中,MainECCLock必须先清0,然后在对InitMECC置1
2、数据一旦被读取,MLC的ECC模块就会产生对应的ECC校验码。
3、在完成读取512字节的主数据后(不包括备用区数据),读取对应的主数据区的校验码,然后必须设置MainECCLock(NFCONT[7])位为1,锁住ECC的产生。8bit 的ECC模块需要这个校验码来确定是否有错误位的存在。所以你必须在读取完512字节的主数据之后,把对应的主数据区的ECC校验码读取出来。一旦主数据区对应的ECC校验码被读,8bit的ECC引擎就会开始查找错误。8bit的ECC错误查找引擎需要最少372个周期去查找存在的错误。同时设置MainECCLock位为1,加锁。ECCDecDone(NFSTAT[6]) 可以用于检测ECC译码是否完成。
4、当ECCDecDone (NFSTAT[6])设置为1,NF8ECCERR0会指出是否有错误位的存在。如果有错误存在,你可以用NF8ECCERR0/1/2和NFMLC8BITPT0/1去修正相应的错误。
5、如果你有更多的主数据要读取,则从第一步开始重复操作。

PS: 原文中有些寄存器是写错的,大家在看的时候要注意。

吐槽一下,三星这个文档实在是简陋的可以,而且错误的地方还很多,想不BS一下都不成。


在这里有个地方要注意的是:

在写数据到Nandflash的时候,每写512字节就会产生一次ECC,我们这里用的是4K页,大于512字节,所以必须把产生的ECC校验值保存起来,等到一页(4k)写完,再把这些ECC写入到备用区中。

而在读取数据的时候,却是每读取512字节的主数据,就会产生一次ECC,这时就要进行ECC校验、矫正了。和写的时候不大一样,需要注意这一点。


寄存器部分:


红色框住是主要使用的寄存器和8bit ECC所用到的寄存器。









主要用到的寄存器就到这了,下一篇将开始代码部分。

在飞凌提供的BSP中,Nandflash采用的是FMD+PDD的结构,PDD主要是应对上层的接口,这里我们不需要修改,直接修改FMD就好。(至于在网上看到很多人说这个结构理论上不支持MLC的Nandflash,这个暂且不说).

FMD部分的驱动源码在?C:WINCE600PLATFORMSMDK6410srccommonnandflashFMD 这个目录下边。

FMD的目录结构:

nand.s

cfnand.h

fmd_LB.h(实际并没用到)

fmd_SB.h(实际并没用到)

nand.h

fmd.cpp

sources

makefile



先看sources文件:

[cpp]? view plain copy
  1. !if?0??
  2. ?Copyright?(c)?Microsoft?Corporation.??All?rights?reserved.??
  3. ?!endif??
  4. ?!if?0??
  5. ?Use?of?this?sample?source?code?is?subject?to?the?terms?of?the?Microsoft??
  6. ?license?agreement?under?which?you?licensed?this?sample?source?code.?If??
  7. ?you?did?not?accept?the?terms?of?the?license?agreement,?you?are?not??
  8. ?authorized?to?use?this?sample?source?code.?For?the?terms?of?the?license,??
  9. ?please?see?the?license?agreement?between?you?and?Microsoft?or,?if?applicable,??
  10. ?see?the?LICENSE.RTF?on?your?install?media?or?the?root?of?your?tools?installation.??
  11. ?THE?SAMPLE?SOURCE?CODE?IS?PROVIDED?"AS?IS",?WITH?NO?WARRANTIES.??
  12. ?!endif??
  13. ?!IF?0??
  14. ???
  15. ???
  16. ?Module?Name:??
  17. ?????sources.??
  18. ?Abstract:??
  19. ?????This?file?specifies?the?target?component?being?built?and?the?list?of??
  20. ?????sources?files?needed?to?build?that?component.??Also?specifies?optional??
  21. ?????compiler?switches?and?libraries?that?are?unique?for?the?component?being??
  22. ?????built.??
  23. ?!ENDIF??
  24. ?TARGETNAME=nandflash_lib11??
  25. ?TARGETTYPE=LIBRARY??
  26. ?RELEASETYPE=PLATFORM??
  27. ?SYNCHRONIZE_BLOCK=1??
  28. ?WINCEOEM=1??
  29. ?WINCECPU=1??
  30. ?NOMIPS16CODE=1??
  31. ?ADEFINES=-pd?"_TGTCPU?SETS?"$(_TGTCPU)""?$(ADEFINES)??
  32. ?LDEFINES=-subsystem:native?/DEBUG?/DEBUGTYPE:CV?/FIXED:NO??
  33. ?INCLUDES=$(INCLUDES)??
  34. ?SOURCES=??
  35. ?????????fmd.cpp??
  36. ?ARM_SOURCES=??
  37. ?????????nand.s??
  38. ???

这个代码是飞凌提供的,且看这一句? TARGETNAME=nandflash_lib11 ,经查实,FMD+PDD使用的是FMD产生的nandflash_lib.lib库文件,而不是nandflash_lib11.lib文件,这也说明飞凌在这方面留了一手,并没有直接提供可用的源码,而是给了一个lib库给我们。

在这里,我们需要把 ??TARGETNAME=nandflash_lib11 ? ?修改为 ??TARGETNAME=nandflash_lib


cfnand.h文件:

copy
    /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++?
  1. ?THIS?CODE?AND?INFORMATION?IS?PROVIDED?"AS?IS"?WITHOUT?WARRANTY?OF?
  2. ?ANY?KIND,?EITHER?EXPRESSED?OR?IMPLIED,?INCLUDING?BUT?NOT?LIMITED?TO?
  3. ?THE?IMPLIED?WARRANTIES?OF?MERCHANTABILITY?AND/OR?FITNESS?FOR?A?
  4. ?PARTICULAR?PURPOSE.?
  5. ?Copyright?(c)?2001??Microsoft?Corporation?
  6. ??
  7. ?Module?Name:????S3C6410.H?
  8. ?Abstract:????????FLASH?Media?Driver?Interface?Samsung?S3C6410?CPU?with?NAND?Flash?
  9. ?????????????????controller.?
  10. ??
  11. ?Environment:????As?noted,?this?media?driver?works?on?behalf?of?the?FAL?to?directly?
  12. ?????????????????access?the?underlying?FLASH?hardware.??Consquently,?this?module?
  13. ?????????????????needs?to?be?linked?with?FLASHFAL.LIB?to?produce?the?device?driver?
  14. ?????????????????named?FLASHDRV.DLL.?
  15. ?-----------------------------------------------------------------------------*/??
  16. ?#ifndef?_S3C6410_CFNAND_H??
  17. ?#define?_S3C6410_CFNAND_H??
  18. ?#include?"FMD_LB.h"??
  19. ?#include?"FMD_SB.h"??
  20. ?#include?"nand.h"??
  21. ?#define?BW_X08????(0)??
  22. ?#define?BW_X16????(1)??
  23. ?#define?BW_X32????(2)??
  24. ?#define?MAX_SECTORS_PER_PAGE????(8)??
  25. ?/*****************************************************************************/??
  26. ?/*?S3C6410?Nand?Flash?Internal?Data?Structure?Definition????????????????????????????????????*/??
  27. ?typedef?struct??
  28. ?{??
  29. ?????UINT16?nMID;????????????/*?Manufacturer?ID???????????????*/??
  30. ?????UINT16?nDID;????????????????/*?Device?ID?????????????????????*/??
  31. ?????UINT16?nNumOfBlks;????????/*?Number?of?Blocks??????????????*/??
  32. ?????UINT16?nPgsPerBlk;????????/*?Number?of?Pages?per?block?????*/??
  33. ?????UINT16?nSctsPerPg;????????/*?Number?of?Sectors?per?page????*/??
  34. ?????UINT16?nNumOfPlanes;????/*?Number?of?Planes??????????????*/??
  35. ?????UINT16?nBlksInRsv;????????/*?The?Number?of?Blocks?in?Reservior?for?Bad?Blocks???*/??
  36. ?????UINT8?nBadPos;????????????/*?BadBlock?Information?Poisition*/??
  37. ?????UINT8?nLsnPos;????????????/*?LSN?Position??????????????????*/??
  38. ?????UINT8?nECCPos;????????????/*?ECC?Policy?:?HW_ECC,?SW_ECC???*/??
  39. ?????UINT16?nBWidth;????????????/*?Nand?Organization?X8?or?X16???*/??
  40. ?????UINT16?nTrTime;????????????/*?Typical?Read?Op?Time??????????*/??
  41. ?????UINT16?nTwTime;????????????/*?Typical?Write?Op?Time?????????*/??
  42. ?????UINT16?nTeTime;????????????/*?Typical?Erase?Op?Time?????????*/??
  43. ?????UINT16?nTfTime;????????????/*?Typical?Transfer?Op?Time??????*/??
  44. ?}?FlashDevSpec;??
  45. ?static?FlashDevSpec?astNandSpec[]?=?{??
  46. ?????/*************************************************************************/??
  47. ?????/*?nMID,?nDID,???????????????????????????????????????????????????????????*/??
  48. /*????????????nNumOfBlks?????????????????????????????????????????????????*/??
  49. /*??????????????????nPgsPerBlk???????????????????????????????????????????*/??
  50. /*??????????????????????nSctsPerPg???????????????????????????????????????*/??
  51. /*?????????????????????????nNumOfPlanes??????????????????????????????????*/??
  52. /*????????????????????????????nBlksInRsv?????????????????????????????????*/??
  53. /*????????????????????????????????nBadPos????????????????????????????????*/??
  54. /*???????????????????????????????????nLsnPos?????????????????????????????*/??
  55. /*??????????????????????????????????????nECCPos??????????????????????????*/??
  56. /*?????????????????????????????????????????nBWidth???????????????????????*/??
  57. /*????????????????????????????????????????????????nTrTime????????????????*/??
  58. /*????????????????????????????????????????????????????nTwTime????????????*/??
  59. /*?????????????????????????????????????????????????????????nTeTime???????*/??
  60. /*????????????????????????????????????????????????????????????????nTfTime*/??
  61. /*************************************************************************/??
  62. /*?8Gbit?DDP?NAND?Flash?*/??
  63. //{?0xEC,?0xD3,?8192,?64,?4,?2,?0,?8,?BW_X08,?50,?350,?2000,?50},??
  64. ????{?0xEC,?4096,?128,??
  65. ????/*?16Gbit?DDP?NAND?Flash?*/??
  66. //?8192??gjl???
  67. /*?4Gbit?DDP?NAND?Flash?*/??
  68. ?????{?0xEC,?0xAC,?80,248); line-height:20px; margin:0px!important; padding:0px 3px 0px 10px!important"> ?????{?0xEC,?0xDC,??
  69. ??
  70. /*?2Gbit?NAND?Flash?*/??
  71. /*?2Gbit?DDP?NAND?Flash?*/??
  72. /*1Gbit?NAND?Flash?*/??
  73. /*?1Gbit?NAND?Flash?*/??
  74. /*?512Mbit?NAND?Flash?*/??
  75. /*?512Mbit?XP?Card?*/??
  76. ?????{?0x98,108); list-style:decimal-leading-zero outside; color:inherit; line-height:20px; margin:0px!important; padding:0px 3px 0px 10px!important"> ?????{?0x98,?0x56,?0x46,0); background-color:inherit">/*?256Mbit?NAND?Flash?*/??
  77. /*?128Mbit?NAND?Flash?*/??
  78. ?????{?0x00,?0x00,????0,??0,??????0,???0,??0}??
  79. ?};??
  80. ?#endif?_S3C6410_CFNAND_H??
  81. ???

且看

copy
    /*?16Gbit?DDP?NAND?Flash?*/??
  1. ?0xEC,?50}??
这里就是使用的2G(16/8 bit=2byte) Nandflash?K9GAG08U0D的一些参数配置,其中 0xEC,0xD5表示的是Nandflash的ID号,总共有4096个block,每个block有128个page,每个page有8个sector

要支持4G(K9LBG08U0D) 的话,则加上下面的配置:

copy
    /*?32Gbit?DDP?NAND?Flash?*/??
  1. ????{?0xEC,?0xD7,??


在看nand.h文件之前,我们先来看一下fmd.cpp中引用的#include "s3c6410_nand.h"头文件:(该文件在C:WINCE600PLATFORMCOMMONSRCSOCS3C6410_SEC_V1OALINCs3c6410_nand.h)

copy
    //??
  1. //?Copyright?(c)?Microsoft?Corporation.??All?rights?reserved.??
  2. //??
  3. //?Use?of?this?source?code?is?subject?to?the?terms?of?the?Microsoft?end-user??
  4. //?license?agreement?(EULA)?under?which?you?licensed?this?SOFTWARE?PRODUCT.??
  5. //?If?you?did?not?accept?the?terms?of?the?EULA,?you?are?not?authorized?to?use??
  6. //?this?source?code.?For?a?copy?of?the?EULA,?please?see?the?LICENSE.RTF?on?your??
  7. //?install?media.??
  8. //------------------------------------------------------------------------------??
  9. //??Header:?s3c6410_nand.h??
  10. //??Defines?the?NAND?controller?CPU?register?layout?and?definitions.??
  11. ?#ifndef?__S3C6410_NAND_H??
  12. ?#define?__S3C6410_NAND_H??
  13. ?#if?__cplusplus??
  14. ?????extern?"C"??
  15. ?????{??
  16. ?#endif??
  17. //------------------------------------------------------------------------------??
  18. //??Type:?S3C6410_NAND_REG??
  19. //??NAND?Flash?controller?register?layout.?This?register?bank?is?located??
  20. //??by?the?constant?CPU_BASE_REG_XX_NAND?in?the?configuration?file??
  21. //??cpu_base_reg_cfg.h.??
  22. struct??
  23. ?{??
  24. ?????UINT32????NFCONF;????????//0x00????//?configuration?reg??
  25. ?????UINT32????NFCONT;????????//0x04??
  26. ?????UINT8????NFCMD;????????????//0x08????//?command?set?reg??
  27. ?????UINT8????d0[3];??
  28. ?????UINT8????NFADDR;????????//0x0C????//?address?set?reg??
  29. ?????UINT8????d1[3];??
  30. ?????UINT8????NFDATA;????????//0x10????//?data?reg??
  31. ?????UINT8????d2[3];??
  32. UINT32????NFMECCD0;????????//0x14??
  33. UINT32????NFMECCD1;????????//0x18??
  34. UINT32????NFSECCD;????????//0x1C??
  35. UINT32????NFSBLK;????????????//0x20??
  36. UINT32????NFEBLK;????????????//0x24??//?error?correction?code?2??
  37. UINT32????NFSTAT;????????????//0x28??//?operation?status?reg??
  38. UINT32????NFECCERR0;????????//0x2C??
  39. UINT32????NFECCERR1;????????//0x30??
  40. UINT32????NFMECC0;????????//0x34??//?error?correction?code?0??
  41. UINT32????NFMECC1;????????//0x38??//?error?correction?code?1??
  42. UINT32????NFSECC;????????????//0x3C??
  43. UINT32????NFMLCBITPT;????//0x40??
  44. ?}?S3C6410_NAND_REG,?*PS3C6410_NAND_REG;??
  45. ?#if?__cplusplus??
  46. ?????}??
  47. ???

注意到了麽?这个跟文档中的寄存器少了8bit ECC寄存器部分。


晕菜了吧,飞凌的这个2G 256M的BSP的Nandflash源码既然是这个样子,为什么还在那里号称8bit的ECC,还说开放源码。

靠别人都行的话,母猪都会上树啦!咱还是自己搞吧!

在上面UINT32 ? ?NFMLCBITPT; ? ?//0x40?的后面添加以下代码:

copy
    UINT32????NF8ECCERR0;???//0x44--?8位ECC错误状态0寄存器??
  1. ?UINT32????NF8ECCERR1;??//0x48--?8位ECC错误状态1寄存器??
  2. ?UINT32????NF8ECCERR2;??//0x4c--?8位ECC错误状态2寄存器??
  3. UINT32????NFM8ECC0;????????//0x50--?生成8位ECC状态0寄存器??
  4. UINT32????NFM8ECC1;????????//0x54--?生成8位ECC状态1寄存器??
  5. UINT32????NFM8ECC2;????????//0x58--?生成8位ECC状态2寄存器??
  6. UINT32????NFM8ECC3;????????//0x5c--?生成8位ECC状态3寄存器??
  7. UINT32????NFMLC8BITPT0;????????//0x60--?8位ECC错误位模式寄存器0??
  8. UINT32????NFMLC8BITPT1;????????//0x64--?8位ECC错误位模式寄存器1??


nand.h文件:

copy
    //?Use?of?this?sample?source?code?is?subject?to?the?terms?of?the?Microsoft??
  1. //?license?agreement?under?which?you?licensed?this?sample?source?code.?If??
  2. //?you?did?not?accept?the?terms?of?the?license?agreement,?you?are?not??
  3. //?authorized?to?use?this?sample?source?code.?For?the?terms?of?the?license,0); background-color:inherit">//?please?see?the?license?agreement?between?you?and?Microsoft?or,?if?applicable,0); background-color:inherit">//?see?the?LICENSE.RTF?on?your?install?media?or?the?root?of?your?tools?installation.??
  4. //?THE?SAMPLE?SOURCE?CODE?IS?PROVIDED?"AS?IS",?WITH?NO?WARRANTIES.??
  5. ?#ifndef?__NAND_H__??
  6. ?#define?__NAND_H__??
  7. //-----------------------------------------------------------------------------??
  8. ?????UINT16?nNumOfBlks;??
  9. ?????UINT16?nPagesPerBlk;??
  10. ?????UINT16?nSctsPerPage;??
  11. ?}?NANDDeviceInfo;??
  12. ?NANDDeviceInfo?stDeviceInfo;??
  13. ?#ifdef?__cplusplus??
  14. extern?"C"??{??
  15. ?NANDDeviceInfo?GetNandInfo(void);??
  16. ?}??
  17. ?#define?NUM_OF_BLOCKS????????(stDeviceInfo.nNumOfBlks)??
  18. ?#define?PAGES_PER_BLOCK????(stDeviceInfo.nPagesPerBlk)??
  19. ?#define?SECTORS_PER_PAGE????(stDeviceInfo.nSctsPerPage)??
  20. ?#undef?SECTOR_SIZE??
  21. ?#define?SECTOR_SIZE????????????(512)??
  22. ?#define?NAND_SECTOR_SIZE????(SECTOR_SIZE*SECTORS_PER_PAGE)??
  23. ?#define?NAND_PAGE_SIZE??????(SECTOR_SIZE*SECTORS_PER_PAGE)??//<?Physical?Page?Size??
  24. ?#define?IS_LB????????????????((SECTORS_PER_PAGE?==?4)||(SECTORS_PER_PAGE?==?8))??
  25. ?#define?USE_NFCE????????????(0)??
  26. ?#define?USE_GPIO????????????(0)??
  27. ?#define?TACLS????????????????(NAND_TACLS)??
  28. ?#define?TWRPH0????????????????(NAND_TWRPH0)??
  29. ?#define?TWRPH1????????????????(NAND_TWRPH1)??
  30. ?#define?ECCType?????????????????(23)??
  31. ?#define?CMD_READID????????????(0x90)????//??ReadID??
  32. ?#define?CMD_READ????????????(0x00)????//??Read??
  33. ?#define?CMD_READ2????????????(0x50)????//??Read2??
  34. ?#define?CMD_READ3????????????(0x30)????//??Read3??
  35. ?#define?CMD_RESET????????????(0xff)????//??Reset??
  36. ?#define?CMD_ERASE????????????(0x60)????//??Erase?phase?1??
  37. ?#define?CMD_ERASE2????????????(0xd0)????//??Erase?phase?2??
  38. ?#define?CMD_WRITE????????????(0x80)????//??Write?phase?1??
  39. ?#define?CMD_WRITE2????????????(0x10)????//??Write?phase?2??
  40. ?#define?CMD_STATUS????????????(0x70)????//??STATUS??
  41. ?#define?CMD_RDI????????????????(0x85)????//??Random?Data?Input??
  42. ?#define?CMD_RDO????????????????(0x05)????//??Random?Data?Output??
  43. ?#define?CMD_RDO2????????????(0xE0)????//??Random?Data?Output??
  44. ?#define?BADBLOCKMARK????????(0x00)??
  45. //??Status?bit?pattern??
  46. ?#define?STATUS_READY????????(0x40)????//??Ready??
  47. ?#define?STATUS_ERROR????????(0x01)????//??Error??
  48. ?#define?STATUS_ILLACC????????(0x20)????//?Illigar?Access??
  49. ?#define?NF_ECCERR0_ALL_FF????0x40000000??
  50. ?#define?NF_ECCERR0_ECC_READY????0x20000000??
  51. ?#define?NF_CMD(cmd)????????????????{g_pNFConReg->NFCMD???=??(unsigned?char)(cmd);}??
  52. ?#define?NF_ADDR(addr)????????????{g_pNFConReg->NFADDR??=??(unsigned?char)(addr);}??
  53. ?#define?NF_nFCE_L()????????????????{g_pNFConReg->NFCONT?&=?~(1<<1);}??
  54. ?#define?NF_nFCE_H()????????????????{g_pNFConReg->NFCONT?|=??(1<<1);}??
  55. ?#define?NF_ECC_DIRECTION_IN()?????????{g_pNFConReg->NFCONT?&=?~(1<<18);}??
  56. ?#define?NF_ECC_DIRECTION_OUT()????????{g_pNFConReg->NFCONT?|=?(1<<18);}??
  57. ?#define?NF_ECC_8BIT_STOP()????????????{g_pNFConReg->NFCONT?|=?(1<<12);}?//stop?the?last?encode?or?decode?of?8bit?mode.??
  58. ?#define?NF_RSTECC()?????????????????{g_pNFConReg->NFCONT?|=??((1<<5)?|?(1<<4));}??
  59. ?#define?NF_MSGLENGTH_512()?????{g_pNFConReg->NFCONF?&=?~(1<<25);}??
  60. ?#define?NF_MSGLENGTH_24()??????{g_pNFConReg->NFCONF?|=?(1<<25);}??
  61. ?#define?NF_ECCTYPE_CLR?????????(g_pNFConReg->NFCONF?&=?~(3<<23))??
  62. ?#define?NF_ECCTYPE_1BIT()??????{NF_ECCTYPE_CLR;}??
  63. ?#define?NF_ECCTYPE_4BIT()??????{NF_ECCTYPE_CLR?|=?(1<<24);}??
  64. ?#define?NF_ECCTYPE_8BIT()??????{NF_ECCTYPE_CLR?|=?(1<<23);}??
  65. ?#define?NF_MECC_UnLock()????????{g_pNFConReg->NFCONT?&=?~(1<<7);}??
  66. ?#define?NF_MECC_Lock()????????????{g_pNFConReg->NFCONT?|=?(1<<7);}??
  67. ?#define?NF_SECC_UnLock()????????{g_pNFConReg->NFCONT?&=?~(1<<6);}??
  68. ?#define?NF_SECC_Lock()????????????{g_pNFConReg->NFCONT?|=?(1<<6);}??
  69. ?#define?NF_CLEAR_RB()????????????{g_pNFConReg->NFSTAT?|=??(1<<4);}????????????????//?Have?write?'1'?to?clear?this?bit.??
  70. ?#define?NF_DETECT_RB()????????????{while((g_pNFConReg->NFSTAT&0x11)!=0x11);}????????//?RnB_Transdetect?&?RnB??
  71. ?#define?NF_WAITRB()????????????????{while?(!(g_pNFConReg->NFSTAT?&?(1<<0)))?;?}??
  72. ?#define?NF_RDDATA_BYTE()????????(g_pNFConReg->NFDATA)??
  73. ?#define?NF_RDDATA_WORD()????????(*(UINT32?*)0xb0200010)??
  74. ?#define?NF_WRDATA_BYTE(data)????{g_pNFConReg->NFDATA??=??(UINT8)(data);}??
  75. ?#define?NF_WRDATA_WORD(data)????{*(UINT32?*)0xb0200010??=??(UINT32)(data);}??
  76. ?#define?NF_RDMECC0()????????????(g_pNFConReg->NFMECC0)??
  77. ?#define?NF_RDMECC1()????????????(g_pNFConReg->NFMECC1)??
  78. ?#define?NF_RDSECC()????????????????(g_pNFConReg->NFSECC)??
  79. ?#define?NF_RDM8ECC0()????????????(g_pNFConReg->NFM8ECC0)??
  80. ?#define?NF_RDM8ECC1()????????????(g_pNFConReg->NFM8ECC1)??
  81. ?#define?NF_RDM8ECC2()????????????(g_pNFConReg->NFM8ECC2)??
  82. ?#define?NF_RDM8ECC3()????????????(g_pNFConReg->NFM8ECC3)??
  83. ?#define?NF_RDMECCD0()????????????(g_pNFConReg->NFMECCD0)??
  84. ?#define?NF_RDMECCD1()????????????(g_pNFConReg->NFMECCD1)??
  85. ?#define?NF_RDSECCD()????????????(g_pNFConReg->NFSECCD)??
  86. ?#define?NF_ECC_ERR0????????????????(g_pNFConReg->NFECCERR0)??
  87. ?#define?NF_ECC_ERR1????????????????(g_pNFConReg->NFECCERR1)??
  88. ?#define?NF_ECC8BIT_NUM??????????????????((g_pNFConReg->NF8ECCERR0?&?(0xf<<25))>>25)??
  89. ?#define?NF_ECC8LOCATION_BYTE1???????????(g_pNFConReg->NF8ECCERR0?&?(0x3ff))??
  90. ?#define?NF_ECC8LOCATION_BYTE2???????????((g_pNFConReg->NF8ECCERR0?&?(0x3ff<<15))>>15)??
  91. ?#define?NF_ECC8LOCATION_BYTE3???????????(g_pNFConReg->NF8ECCERR1?&?(0x3ff))??
  92. ?#define?NF_ECC8LOCATION_BYTE4???????????((g_pNFConReg->NF8ECCERR1?&?(0x3ff<<11))>>11)??
  93. ?#define?NF_ECC8LOCATION_BYTE5???????????((g_pNFConReg->NF8ECCERR1?&?(0x3ff<<22))>>22)??
  94. ?#define?NF_ECC8LOCATION_BYTE6???????????(g_pNFConReg->NF8ECCERR2?&?(0x3ff))??
  95. ?#define?NF_ECC8LOCATION_BYTE7???????????((g_pNFConReg->NF8ECCERR2?&?(0x3ff<<11))>>11)??
  96. ?#define?NF_ECC8LOCATION_BYTE8???????????((g_pNFConReg->NF8ECCERR2?&?(0x3ff<<22))>>22)??
  97. ?#define?NF_ECC8LOCATION_BIT(n)??????????(n?<=?4)?((g_pNFConReg->NFMLC8BITPT0?&?(0xff<<((n-1)*8)))>>((n-1)*8)):((g_pNFConReg->NFMLC8BITPT1?&?(0xff<<((n-5)*8)))>>((n-5)*8))??
  98. ?#define?NF_ECC4BIT_NUM??????????????????((g_pNFConReg->NFECCERR0?&?(0x7<<26))>>26)??
  99. ?#define?NF_ECC4LOCATION_BYTE(n)?????????((n?<=?2)?((g_pNFConReg->NFECCERR0?&?(0x3ff<<((n-1)*16)))>>((n-1)*16)):((g_pNFConReg->NFECCERR1?&?(0x3ff<<((n-3)*16)))>>((n-3)*16)))??
  100. ?#define?NF_ECC4LOCATION_BIT(n)??????????((g_pNFConReg->NFMLCBITPT?&?(0xff<<((n-1)*8)))>>((n-1)*8))??
  101. ?#define?NF_WRMECCD0(data)????????{g_pNFConReg->NFMECCD0?=?(data);}??
  102. ?#define?NF_WRMECCD1(data)????????{g_pNFConReg->NFMECCD1?=?(data);}??
  103. ?#define?NF_WRSECCD(data)????????{g_pNFConReg->NFSECCD?=?(data);}??
  104. ?#define?NF_RDSTAT????????????????(g_pNFConReg->NFSTAT)??
  105. enum??
  106. ?????ECC_CORRECT_MAIN?=?0,????//?correct?Main?ECC??
  107. ?????ECC_CORRECT_SPARE1?=?1,?????//?correct?Spare?for?Sector?Info?using?Main?ECC?Result?Area??
  108. ?????ECC_CORRECT_SPARE2?=?2,0); background-color:inherit">//?correct?Spare?for?MECC?using?Main?ECC?Result?Area??
  109. ?????ECC_CORRECT_SPARE?=?3???????//?correct?Spare?using?Spare?ECC?Result?Area??
  110. ?}?ECC_CORRECT_TYPE;??
  111. ?#endif????//?__NAND_H_.??
  112. ???

nand.h文件里有8bit ECC的相关定义,不要高兴的太早,这里面是有错滴,不知道是不是飞凌那边故意搞错的,还是本来就不是6410的。

且看定义:

#define NF_ECC_8BIT_STOP() ? ? ? ? ? ?{g_pNFConReg->NFCONT |= (1<<12);} //stop the last encode or decode of 8bit mode.

?
对比文档看一下这个NFCONT[12]是干什么的



NFCONT[11]这个才是8bitStop,但为什么源码中要定义NFCONT[12]为NF_ECC_8BIT_STOP,这个容易让人产生误解。咱还是改一下吧!

#define NF_ECC_8BIT_STOP() ? ? ? ? ? ?{g_pNFConReg->NFCONT |= (1<<11);}


相关引用的暂时到这里,下一篇将会开始源码分析

接着上一篇,这一篇介绍cpp部分


fmd.cpp,这里将逐个函数进行分析讲解:


[cpp]? view plain copy
    ?#include?<fmd.h>??
  1. ?#include?<nkintr.h>??
  2. ?#include?<oal.h>??
  3. //?BSP?Configuration?Files??
  4. ?#include?"bsp_cfg.h"??
  5. ?#include?"bsp_base_reg_cfg.h"??
  6. //?Base?Definitions??
  7. ?#include?"s3c6410_base_regs.h"??
  8. ?#include?"s3c6410_nand.h"??
  9. ?#include?"s3c6410_syscon.h"??
  10. //#include?<ethdbg.h>??
  11. ?#include?"Cfnand.h"??
  12. //#include?<kitl.h>??
  13. //#define?SYNC_OP??
  14. ?#define?CHECK_SPAREECC????(0)??//?1?gjl???
  15. ?#define?NAND_DEBUG????????(0)??
  16. ?#define?NAND_BASE????????(0xB0200000)????//?PA:0x70200000??
  17. ?#define?SYSCON_BASE????????(0xB2A0F000)????//?PA:0x7E00F000??
  18. ?#ifdef????SYNC_OP??
  19. ?CRITICAL_SECTION????g_csNandFlash;??
  20. ?#ifdef?__cplusplus????//?gjl??
  21. extern?"C"?{??
  22. ??int?iSighForSlcMlc;???//?gjl???
  23. static?volatile?S3C6410_NAND_REG?*g_pNFConReg?=?NULL;??
  24. volatile?S3C6410_SYSCON_REG?*g_pSysConReg?=?NULL;??
  25. ?#define?DEBUG_WRITE_READ_EQUAL?0??
  26. ?#if?DEBUG_WRITE_READ_EQUAL??
  27. DWORD?g_MECCBuf[8];??
  28. DWORD?g_MECCBuf_R[8];??
  29. DWORD?g_SECCBuf[2];??
  30. DWORD?g_SECCBuf_R[2];??
  31. void?RdPage512(unsigned?char?*bufPt);??
  32. ?????void?RdPage512Unalign(unsigned?char?*bufPt);??
  33. void?WrPage512(unsigned?void?WrPage512Unalign(unsigned?void?WrPageInfo(PBYTE?pBuff);??
  34. void?RdPageInfo(PBYTE?pBuff);??
  35. ?}??
  36. ?NANDDeviceInfo?GetNandInfo(void)?{?return?stDeviceInfo;?}??

引用头文件这部分不需要更改


1、读取Flash的ID:

copy
    /*?
  1. ????@func???DWORD?|?ReadFlashID?|?Reads?the?flash?manufacturer?and?device?codes.?
  2. ????@rdesc??Manufacturer?and?device?codes.?
  3. ????@comm?
  4. ????@xref?
  5. */??
  6. static?DWORD?ReadFlashID(void)??
  7. {??
  8. ????BYTE?Mfg,?Dev,?Nouse,?Infoma,?Planesize;??
  9. ????int?i;??
  10. ??
  11. ????NF_nFCE_L();????????????????//?Deselect?the?flash?chip.??
  12. ????NF_CMD(CMD_READID);????????//?Send?flash?ID?read?command.??
  13. ??
  14. ????NF_ADDR(0);??
  15. ????for?(i=0;?i<10;?i++)??
  16. ????{??
  17. ????????Mfg????=?NF_RDDATA_BYTE();??
  18. ????????if?(Mfg?==?0xEC?||?Mfg?==?0x98)?break;??
  19. ????}??
  20. ????Dev????=?NF_RDDATA_BYTE();??
  21. ????Nouse????=?NF_RDDATA_BYTE();??
  22. ????Infoma???=?NF_RDDATA_BYTE();??
  23. ????Planesize?=?NF_RDDATA_BYTE();??
  24. ????//RETAILMSG(1,?(TEXT("[FMD:ERR]?FMD_Init()?:?page?info?=?0x%08x,0x%08x,0x%08xn"),Infoma,Planesize));??
  25. //According?to?the?read?ID?from?flash,?Nouse=0x14,Infoma=0xa5,planesize=0x64,the?page?size?is?2K,?block?size?is?256KB??
  26. //there?are?4096?blocks,?plane?num=2,?plane?size=4Gbit??
  27. //So?we?should?change?the?cfnand.h?nandflash?information.??
  28. ????NF_nFCE_H();??
  29. return?((DWORD)(Mfg<<8)+Dev);??
  30. }??
这个也不需要修改,具体请参照手册


2、flash初始化:

copy
    ????@func???PVOID?|?FMD_Init?|?Initializes?the?Smart?Media?NAND?flash?controller.?
  1. ????@rdesc??Pointer?to?S3C2410?NAND?controller?registers.?
  2. PVOID?FMD_Init(LPCTSTR?lpActiveReg,?PPCI_REG_INFO?pRegIn,?PPCI_REG_INFO?pRegOut)??
  3. {??
  4. ????volatile?DWORD?nNandID;??
  5. ????UINT8?nMID,?nDID;??
  6. UINT32?nCnt;??
  7. BOOL?bNandExt?=?FALSE;??
  8. ????RETAILMSG(1,?(TEXT("[FMD]?++FMD_Init()?*######rn")));??
  9. ??????
  10. if?(pRegIn?&&?pRegIn->MemBase.Num?&&?pRegIn->MemBase.Reg[0])??
  11. ????????g_pNFConReg?=?(S3C6410_NAND_REG?*)(pRegIn->MemBase.Reg[0]);??
  12. ????}??
  13. else??
  14. ????????g_pNFConReg?=?(S3C6410_NAND_REG?*)NAND_BASE;??
  15. ????g_pSysConReg?=?(S3C6410_SYSCON_REG?*)SYSCON_BASE;??
  16. #ifdef????SYNC_OP??
  17. ????InitializeCriticalSection(&g_csNandFlash);??
  18. ????EnterCriticalSection(&g_csNandFlash);??
  19. #endif??
  20. //?Configure?BUS?Width?and?Chip?Select?for?NAND?Flash??
  21. ????g_pSysConReg->MEM_SYS_CFG?&=?~(1<<12);????//?NAND?Flash?BUS?Width?->?8?bit??
  22. ????g_pSysConReg->MEM_SYS_CFG?&=?~(0x1<<1);????//?Xm0CS2?->?NFCON?CS0??
  23. //?Set?up?initial?flash?controller?configuration.??
  24. ????g_pNFConReg->NFCONF?=?(TACLS<<12)?|?(TWRPH0<<8)?|?(TWRPH1<<4);??
  25. ????NF_ECCTYPE_4BIT();??
  26. ????g_pNFConReg->NFCONT?=?(0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0);??
  27. ????g_pNFConReg->NFSTAT?=?(1<<4);??
  28. ????nNandID?=?ReadFlashID();??
  29. ????LeaveCriticalSection(&g_csNandFlash);??
  30. ????nMID?=?(UINT8)(nNandID?>>?8);??
  31. ????nDID?=?(UINT8)(nNandID?&?0xff);??
  32. "[FMD:INF]?FMD_Init()?:?Read?ID?=?0x%08xn"),?nNandID));??
  33. for?(nCnt?=?0;?astNandSpec[nCnt].nMID?!=?0;?nCnt++)??
  34. ????????if?(nDID?==?astNandSpec[nCnt].nDID)??
  35. ????????{??
  36. ????????????bNandExt?=?TRUE;??
  37. ???????????? ????????}??
  38. if?(!bNandExt)??
  39. ????{??
  40. ????????RETAILMSG(1,?(TEXT("[FMD:ERR]?FMD_Init()?:?Unknown?ID?=?0x%08xn"),?nNandID));??
  41. return?NULL;??
  42. ????NUM_OF_BLOCKS?=?astNandSpec[nCnt].nNumOfBlks;??
  43. ????PAGES_PER_BLOCK?=?astNandSpec[nCnt].nPgsPerBlk;??
  44. ????SECTORS_PER_PAGE?=?astNandSpec[nCnt].nSctsPerPg;??
  45. ????RETAILMSG(1,?(TEXT("[FMD]?FMD_Init()?:?NUM_OF_BLOCKS?=?%dn"),?NUM_OF_BLOCKS));??
  46. "[FMD]?FMD_Init()?:?PAGES_PER_BLOCK?=?%dn"),?PAGES_PER_BLOCK));??
  47. "[FMD]?FMD_Init()?:?SECTORS_PER_PAGE?=?%dn"),?SECTORS_PER_PAGE));??
  48. //?gjl??
  49. if(iSighForSlcMlc?==?1)??
  50. ????????????NUM_OF_BLOCKS?=?8192;??
  51. ????????????PAGES_PER_BLOCK?=?8;??
  52. ????????????SECTORS_PER_PAGE?=?4;??
  53. ????????????NUM_OF_BLOCKS?=?astNandSpec[nCnt].nNumOfBlks;??
  54. ????????????PAGES_PER_BLOCK?=?astNandSpec[nCnt].nPgsPerBlk;??
  55. ????????????SECTORS_PER_PAGE?=?astNandSpec[nCnt].nSctsPerPg;??
  56. "[FMD]?--FMD_Init()n")));??
  57. return((PVOID)g_pNFConReg);??
  58. }??

上面这个代码是原BSP中的,这个初始化函数里面,有些东西需要修改一下

// Set up initial flash controller configuration.
g_pNFConReg->NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);

这个我们对照手册看一下


NFCONF[0]必须写0,NFCONF[2]必须写1,所以最后修改为:

copy
    g_pNFConReg->NFCONF?=?(TACLS<<12)?|?(TWRPH0<<8)?|?(TWRPH1<<4)?|?(1<<2)?|?(0<<0);??

这一句接下来,原代码中使用的是NF_ECCTYPE_4BIT(); ?4bit的ECC,这里我们将使用8bit的ECC,修改为

copy
    NF_ECCTYPE_8BIT();??????//?use?8bit?ECC??


接下来初始化配置NFCONT

原:

g_pNFConReg->NFCONT = (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0);

参照手册修改为:

copy
    g_pNFConReg->NFCONT?=?(0<<13)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);??



接下来直接看到

copy
    //?gjl??
  1. if(iSighForSlcMlc?==?1)??
  2. ????????????NUM_OF_BLOCKS?=?8192;??
  3. ????????????PAGES_PER_BLOCK?=?8;??
  4. ????????????SECTORS_PER_PAGE?=?4;??
  5. else??
  6. ????????????NUM_OF_BLOCKS?=?astNandSpec[nCnt].nNumOfBlks;??
  7. ????????????PAGES_PER_BLOCK?=?astNandSpec[nCnt].nPgsPerBlk;??
  8. ????????????SECTORS_PER_PAGE?=?astNandSpec[nCnt].nSctsPerPg;??
  9. ????}??
这里if中的NUM_OF_BLOCKS = 8192;这个定死了,不大好,咱改成(修改之后,可以同时兼容K9GAG08U0D 2G和K9LBG08U0D 4G的Nandflash)
copy
    NUM_OF_BLOCKS?=?astNandSpec[nCnt].nNumOfBlks;??

到此,FMD_Init()函数就基本上搞掂了。


3、FMD_ReadSector()

copy
    ????@func???BOOL?|?FMD_ReadSector?|?Reads?the?specified?sector(s)?from?NAND?flash.?
  1. ????@rdesc??TRUE?=?Success,?FALSE?=?Failure.?
  2. BOOL?FMD_ReadSector(SECTOR_ADDR?startSectorAddr,?LPBYTE?pSectorBuff,?PSectorInfo?pSectorInfoBuff,87); background-color:inherit; font-weight:bold">DWORD?dwNumSectors)??
  3. BOOL?bRet;??
  4. ??
  5. #if?(NAND_DEBUG)??
  6. "[FMD]?++FMD_ReadSector(0x%08x)?n"),?startSectorAddr));??
  7. if?(?IS_LB?)??
  8. ????????bRet?=?FMD_LB_ReadSector(startSectorAddr,?pSectorBuff,?pSectorInfoBuff,?dwNumSectors);??
  9. ????????bRet?=?FMD_SB_ReadSector(startSectorAddr,108); list-style:decimal-leading-zero outside; color:inherit; line-height:20px; margin:0px!important; padding:0px 3px 0px 10px!important"> #ifdef????SYNC_OP??
  10. ????LeaveCriticalSection(&g_csNandFlash);??
  11. #endif??
  12. #if?(NAND_DEBUG)??
  13. "[FMD]?--FMD_ReadSector()n")));??
  14. return?bRet;??
  15. }??
这里我们不需要做修改,不过其中调用的FMD_LB_ReadSector()函数待会需要修改一下(FMD_LB_ReadSector()是针对Nandflash,4bit或8bit的ECC;而FMD_SB_ReadSector()是针对Norflash,1bit的ecc校验)



4、FMD_EraseBlock() ?擦除块

copy
    ????@func???BOOL?|?FMD_EraseBlock?|?Erases?the?specified?flash?block.?
  1. BOOL?FMD_EraseBlock(BLOCK_ID?blockID)??
  2. BOOL????bRet?=?TRUE;??
  3. "[FMD]?++FMD_EraseBlock(0x%08x)?n"),?blockID));??
  4. ????EnterCriticalSection(&g_csNandFlash);??
  5. if?(?IS_LB?)??
  6. ????????bRet?=?FMD_LB_EraseBlock(blockID);??
  7. ????????bRet?=?FMD_SB_EraseBlock(blockID);??
  8. "[FMD]?--FMD_EraseBlock()n")));??
  9. return?bRet;??
  10. }??

这个函数也没有什么需要修改的,其中调用到的FMD_LB_EraseBlock()待会会讲到。



5、FMD_WriteSector()

copy
    ????@func???BOOL?|?FMD_WriteSector?|?Writes?the?specified?data?to?the?specified?NAND?flash?sector/page.?
  1. BOOL?FMD_WriteSector(SECTOR_ADDR?startSectorAddr,248); line-height:20px; margin:0px!important; padding:0px 3px 0px 10px!important"> #if?DEBUG_WRITE_READ_EQUAL??
  2. BYTE????pSectorBuffRead[4096];?//?gjl?2048??
  3. ????SectorInfo????SectorInfoBuffRead;??
  4. ????PSectorInfo????pSectorInfoBuffRead?=?&SectorInfoBuffRead;??
  5. BYTE?????*temp?=?(BYTE*)pSectorInfoBuff;??
  6. BYTE?????*temp1?=?(BYTE*)pSectorInfoBuffRead;??
  7. ????UINT16?nSectorLoop,j=40;??
  8. "[FMD]?++FMD_WriteSector(0x%08x)?n"),?startSectorAddr));??
  9. ????????bRet?=?FMD_LB_WriteSector(startSectorAddr,?dwNumSectors);??
  10. ????????FMD_LB_ReadSector(startSectorAddr,?pSectorBuffRead,?pSectorInfoBuffRead,153); background-color:inherit; font-weight:bold">for?(nSectorLoop?=?0;?nSectorLoop?<?2048;?nSectorLoop++)??
  11. ????????{??
  12. if(pSectorBuff[nSectorLoop]?!=?pSectorBuffRead[nSectorLoop])??
  13. ????????????????break;??
  14. ????????}??
  15. ????????RETAILMSG(1,?(TEXT("[FMD]?++FMD_WriteSector?equal?number?=?%x?n"),?nSectorLoop));??
  16. for?(nSectorLoop?=?0;?nSectorLoop?<?8;?nSectorLoop++)??
  17. if(temp1[nSectorLoop]?!=?temp[nSectorLoop])??
  18. "[FMD]?++FMD_WriteSector?informationequal?equal?number?=?%x?n"),?(TEXT("[FMD]?++FMD_WriteSector?sector?bytes:n")));??
  19. for?(nSectorLoop?=?0;?nSectorLoop?<?2048;?nSectorLoop++)??
  20. ????????????if(j--==0)??
  21. ????????????{??
  22. ????????????????j=40;??
  23. ????????????????RETAILMSG(1,?(TEXT("n")));??
  24. ????????????}??
  25. ????????????RETAILMSG(1,?(TEXT("%x?"),?pSectorBuff[nSectorLoop]));??
  26. "n?endn")));??
  27. "[FMD]?++FMD_ReadSector?sector?bytes:n")));??
  28. if(j--==0)??
  29. ????????????{??
  30. ????????????????j=40;??
  31. ????????????????RETAILMSG(1,?(TEXT("n")));??
  32. ????????????}??
  33. ????????????RETAILMSG(1,?pSectorBuffRead[nSectorLoop]));??
  34. "n?endn")));??
  35. if(g_MECCBuf_R[nSectorLoop]?!=?g_MECCBuf[nSectorLoop])??
  36. "[FMD]?++FMD_WriteSector?MECC?data?equal?number?=?%x?n"),153); background-color:inherit; font-weight:bold">if(g_SECCBuf_R[nSectorLoop]?!=?g_SECCBuf[nSectorLoop])??
  37. "[FMD]?++FMD_WriteSector?SECC?data?equal?number?=?%x?n"),248); line-height:20px; margin:0px!important; padding:0px 3px 0px 10px!important"> ??????????
  38. ????????bRet?=?FMD_SB_WriteSector(startSectorAddr,?(TEXT("[FMD]?--FMD_WriteSector()n")));??
  39. }??

该函数也没有什么地方需要修改的。



6、FMD_PowerUp()

copy
    VOID?FMD_PowerUp(VOID)??
  1. ?#if?(NAND_DEBUG)??
  2. ?????RETAILMSG(1,?(TEXT("[FMD]?FMD_PowerUp()?n")));??
  3. //?Set?up?initial?flash?controller?configuration.??
  4. ?????g_pNFConReg->NFCONF?=?(TACLS<<12)?|?(TWRPH0<<8)?|?(TWRPH1<<4);??
  5. ?????g_pNFConReg->NFCONT?=?(0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0);??
  6. ?????g_pNFConReg->NFSTAT?=?(1<<4);??
  7. ?}??

这里我们参照之前在FMD_Init()的配置,修改其中的NFCONF和NFCONT的配置为:

copy
    g_pNFConReg->NFCONF?=?(TACLS<<12)?|?(TWRPH0<<8)?|?(TWRPH1<<4)?|?(1<<2)?|?(0<<0);??
  1. g_pNFConReg->NFCONT?=?(0<<13)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);??



7、FMD_PowerDown()

copy
    VOID?FMD_PowerDown("[FMD]?FMD_PowerDown()?n")));??
  1. ?}??

该函数不需要修改什么。



接下来的这几个函数都不需要修改:

copy
    BOOL?FMD_OEMIoControl(DWORD?dwIoControlCode,87); background-color:inherit; font-weight:bold">PBYTE?pInBuf,87); background-color:inherit; font-weight:bold">DWORD?nInBufSize,87); background-color:inherit; font-weight:bold">PBYTE?pOutBuf,87); background-color:inherit; font-weight:bold">DWORD?nOutBufSize,?PDWORD?pBytesReturned)??
  1. switch(dwIoControlCode)??
  2. ?????????case?IOCTL_FMD_GET_INTERFACE:??
  3. ?????????{??
  4. ?????????????RETAILMSG(1,?(TEXT("[FMD]?FMD_OEMIoControl()?:?IOCTL_FMD_GET_INTERFACEn")));??
  5. ?????????????if?(!pOutBuf?||?nOutBufSize?<?sizeof(FMDInterface))??
  6. ?????????????{??
  7. ?????????????????DEBUGMSG(1,?(TEXT("FMD_OEMIoControl:?IOCTL_FMD_GET_INTERFACE?bad?parameter(s).n")));??
  8. ?????????????????return(FALSE);??
  9. ?????????????}??
  10. ?????????????PFMDInterface?pInterface?=?(PFMDInterface)pOutBuf;??
  11. ?????????????pInterface->cbSize?=?sizeof(FMDInterface);??
  12. ?????????????pInterface->pInit?=?FMD_Init;??
  13. ?????????????pInterface->pDeInit?=?FMD_Deinit;??
  14. ?????????????pInterface->pGetInfo?=?FMD_GetInfo;??
  15. ?????????????pInterface->pGetInfoEx?=?NULL;????????//FMD_GetInfoEx;??
  16. ?????????????pInterface->pGetBlockStatus?=?FMD_GetBlockStatus;??
  17. ?????????????pInterface->pSetBlockStatus?=?FMD_SetBlockStatus;??
  18. ?????????????pInterface->pReadSector?=?FMD_ReadSector;??
  19. ?????????????pInterface->pWriteSector?=?FMD_WriteSector;??
  20. ?????????????pInterface->pEraseBlock?=?FMD_EraseBlock;??
  21. ?????????????pInterface->pPowerUp?=?FMD_PowerUp;??
  22. ?????????????pInterface->pPowerDown?=?FMD_PowerDown;??
  23. ?????????????pInterface->pGetPhysSectorAddr?=?NULL;??
  24. ?????????}??
  25. case?IOCTL_FMD_LOCK_BLOCKS:??
  26. ?????????RETAILMSG(1,?(TEXT("[FMD:ERR]?FMD_OEMIoControl()?:?IOCTL_FMD_LOCK_BLOCKS?Not?Supportedn")));??
  27. ?????????return?FALSE;??
  28. case?IOCTL_FMD_UNLOCK_BLOCKS:??
  29. "[FMD:ERR]?FMD_OEMIoControl()?:?IOCTL_FMD_UNLOCK_BLOCKS?Not?Supportedn")));??
  30. case?IOCTL_FMD_READ_RESERVED:??
  31. "[FMD:ERR]?FMD_OEMIoControl()?:?IOCTL_FMD_READ_RESERVEDn")));??
  32. case?IOCTL_FMD_WRITE_RESERVED:??
  33. "[FMD:ERR]?FMD_OEMIoControl()?:?IOCTL_FMD_WRITE_RESERVEDn")));??
  34. case?IOCTL_FMD_GET_RESERVED_TABLE:??
  35. "[FMD:ERR]?FMD_OEMIoControl()?:?IOCTL_FMD_GET_RESERVED_TABLEn")));??
  36. case?IOCTL_FMD_SET_REGION_TABLE:??
  37. "[FMD:ERR]?FMD_OEMIoControl()?:?IOCTL_FMD_SET_REGION_TABLEn")));??
  38. case?IOCTL_FMD_SET_SECTORSIZE:??
  39. "[FMD:ERR]?FMD_OEMIoControl()?:?IOCTL_FMD_SET_SECTORSIZEn")));??
  40. case?IOCTL_FMD_RAW_WRITE_BLOCKS:??
  41. "[FMD:ERR]?FMD_OEMIoControl()?:?IOCTL_FMD_RAW_WRITE_BLOCKSn")));??
  42. case?IOCTL_FMD_GET_RAW_BLOCK_SIZE:??
  43. "[FMD:ERR]?FMD_OEMIoControl()?:?IOCTL_FMD_GET_RAW_BLOCK_SIZEn")));??
  44. case?IOCTL_FMD_GET_INFO:??
  45. "[FMD:ERR]?FMD_OEMIoControl()?:?IOCTL_FMD_GET_INFOn")));??
  46. case??IOCTL_FMD_SET_XIPMODE????:??
  47. "[FMD:ERR]?FMD_OEMIoControl()?:?IOCTL_FMD_SET_XIPMODEn")));??
  48. case??IOCTL_FMD_GET_XIPMODE:??
  49. "[FMD:ERR]?FMD_OEMIoControl()?:?IOCTL_FMD_GET_XIPMODEn")));??
  50. case??IOCTL_DISK_FLUSH_CACHE:??
  51. ???????????
  52. return?TRUE;??
  53. default:??
  54. "[FMD:ERR]?FMD_OEMIoControl()?:?Unknown?IOCTL?(0x%08x)n"),?dwIoControlCode));??
  55. ?????}??
  56. return?TRUE;??
  57. BOOL?FMD_Deinit(PVOID?hFMD)??
  58. ?#if?(NAND_DEBUG)??
  59. ?????RETAILMSG(1,?(TEXT("[FMD]?FMD_Deinit()?n")));??
  60. ?#endif??
  61. return(TRUE);??
  62. /*?
  63. ?????@func???BOOL?|?FMD_GetInfo?|?Provides?information?on?the?NAND?flash.?
  64. ?????@rdesc??TRUE?=?Success,?FALSE?=?Failure.?
  65. ?????@comm?
  66. ?????@xref?
  67. ?*/??
  68. BOOL?FMD_GetInfo(PFlashInfo?pFlashInfo)??
  69. //?Add?by?AlexLee?RunNo[5]??
  70. UINT32??nCnt;??
  71. UINT32?nNandID;??
  72. ?????UINT8?nMID,153); background-color:inherit; font-weight:bold">if?(pFlashInfo?==?NULL)??
  73. "[FMD:ERR]?FMD_GetInfo()?:?Invalid?Parametern")));??
  74. ?????pFlashInfo->flashType?=?NAND;??
  75. ?????EnterCriticalSection(&g_csNandFlash);??
  76. ?????nNandID?=?ReadFlashID();??
  77. ?????LeaveCriticalSection(&g_csNandFlash);??
  78. ?????nMID?=?nNandID?>>?8;??
  79. ?????nDID?=?nNandID?&?0xff;??
  80. for?(nCnt?=?0;?astNandSpec[nCnt].nMID?!=?0;?nCnt++)??
  81. ?????{??
  82. if?(nDID?==?astNandSpec[nCnt].nDID)??
  83. ?????????{??
  84. ????????????? ?????????}??
  85. //??OK,?instead?of?reading?it?from?the?chip,?we?use?the?hardcoded??
  86. //??numbers?here.??
  87. ?????pFlashInfo->dwNumBlocks?????????=?NUM_OF_BLOCKS;??
  88. ?????pFlashInfo->wSectorsPerBlock????=?PAGES_PER_BLOCK;??
  89. ?????pFlashInfo->wDataBytesPerSector?=?NAND_SECTOR_SIZE;??
  90. ?????pFlashInfo->dwBytesPerBlock?????=?(PAGES_PER_BLOCK?*?NAND_SECTOR_SIZE);??
  91. ??
  92. ?????@func???DWORD?|?FMD_GetBlockStatus?|?Returns?the?status?of?the?specified?block.?
  93. ?????@rdesc??Block?status?(see?fmd.h).?
  94. DWORD?FMD_GetBlockStatus(BLOCK_ID?blockID)??
  95. DWORD?dwResult?=?0;??
  96. "[FMD]?++FMD_GetBlockStatus(0x%08x)?n"),?blockID));??
  97. ?#ifdef????SYNC_OP??
  98. ?????EnterCriticalSection(&g_csNandFlash);??
  99. ?????????dwResult?=?FMD_LB_GetBlockStatus(blockID);??
  100. ?????????dwResult?=?FMD_SB_GetBlockStatus(blockID);??
  101. "[FMD]?--FMD_GetBlockStatus()n")));??
  102. return?dwResult;??
  103. ?????@func???BOOL?|?FMD_SetBlockStatus?|?Marks?the?block?with?the?specified?block?status.?
  104. ?????@comm?
  105. ?????@xref?
  106. ?*/??
  107. BOOL?FMD_SetBlockStatus(BLOCK_ID?blockID,87); background-color:inherit; font-weight:bold">DWORD?dwStatus)??
  108. "[FMD]?++FMD_SetBlockStatus(0x%08x,?0x%08x)?n"),?blockID,?dwStatus));??
  109. ?????????bRet?=?FMD_LB_SetBlockStatus(blockID,?dwStatus);??
  110. ?????????bRet?=?FMD_SB_SetBlockStatus(blockID,108); list-style:decimal-leading-zero outside; color:inherit; line-height:20px; margin:0px!important; padding:0px 3px 0px 10px!important"> ?????LeaveCriticalSection(&g_csNandFlash);??
  111. "[FMD]?--FMD_SetBlockStatus()n")));??
  112. ???


文章有点长,先到这里了,关键点将在下一篇介绍


接着上一篇

?

1、ECC_CorrectData()?? 查找ECC错误并矫正

[cpp]? view plain copy
    BOOL?ECC_CorrectData(SECTOR_ADDR?sectoraddr,87); background-color:inherit; font-weight:bold">LPBYTE?pData,87); background-color:inherit; font-weight:bold">UINT32?nRetEcc,?ECC_CORRECT_TYPE?nType)??
  1. DWORD??nErrDataNo;??
  2. DWORD??nErrBitNo;??
  3. //BYTE?Status;??
  4. BYTE?nErrDataNum;??
  5. ????UINT8??nErrByteNum;??
  6. ????UINT8?countdown?=?155;??
  7. BOOL?bRet?=?TRUE;??
  8. ??
  9. #if?0??
  10. if(?(nRetEcc?&?NF_ECC8ERR0_ECC_READY)?)??
  11. //?8bit?ECC?error?searching?engine?needs?mini?mum?372?cycles?to?find?any?error??
  12. ????countdown?=?372;??
  13. while(countdown--);??
copy
    //?等待ECC错误查找完毕??
  1. while(NF_ECC8_ERR0?&?0x80000000);??
copy
    //?获取8bit?ECC解码结果??
  1. nErrDataNum?=?NF_ECC8BIT_NUM;??
  2. //?No?error,?if?free?page?(all?0xff)??
  3. if(?(g_pNFConReg->NF8ECCERR0?>>?29)?&?0x1?){??
  4. ????nErrDataNum?=?0;??
  5. }??
  6. if?(nErrDataNum?==?0)??
  7. ????bRet?=?TRUE;??
  8. ????RETAILMSG(0,(TEXT("No?Errorn")));??
  9. goto?finished;??
  10. }??
  11. else?if?(nErrDataNum?==?9)??
  12. ????bRet?=?FALSE;??
  13. "More?than?8-bit?error,?uncorrectablen")));??
  14. if?(nErrDataNum?>?9)??
  15. "Reservedn")));??
  16. {??
copy
    //?获取错误位对应的位置??
  1. for?(nErrByteNum?=?1;?nErrByteNum?<=?nErrDataNum;?nErrByteNum++)??
  2. switch(nErrByteNum)??
  3. case?1:?????nErrDataNo?=?NF_ECC8LOCATION_BYTE1;??
  4. case?2:?????nErrDataNo?=?NF_ECC8LOCATION_BYTE2;??
  5. case?3:?????nErrDataNo?=?NF_ECC8LOCATION_BYTE3;??
  6. case?4:?????nErrDataNo?=?NF_ECC8LOCATION_BYTE4;??
  7. case?5:?????nErrDataNo?=?NF_ECC8LOCATION_BYTE5;??
  8. case?6:?????nErrDataNo?=?NF_ECC8LOCATION_BYTE6;??
  9. case?7:?????nErrDataNo?=?NF_ECC8LOCATION_BYTE7;??
  10. case?8:?????nErrDataNo?=?NF_ECC8LOCATION_BYTE8;??
  11. default: ????}??
copy
    //?定位到具体错误位的位置??
  1. nErrBitNo?=?NF_ECC8LOCATION_BIT(nErrByteNum);??
copy
    ????????//?矫正错误位??
  1. ????????(pData)[nErrDataNo]?^=?(1<<nErrBitNo);?????
  2. "8bit?ECC_CorrectData?%x,?%xn"),?nErrDataNum,?nErrByteNum,?nErrDataNo,?nErrBitNo));??
  3. inished:??
  4. ???return?bRet;??

这里是修改后的,支持8bit ECC校验。

注意到上面的
??// No error,if free page (all 0xff)
??if( (g_pNFConReg->NF8ECCERR0 >> 29) & 0x1 ){
??? ?nErrDataNum = 0;
??}

代码了吗?让我们对比手册看看这个NF8ECCERR0[29]是何许人也

看到了吧,NF8ECCERR0[29]是保留位。然而,我参考6410的MLC的BSP源码,发现里面有用到这个位来判断是否全为0xff。在飞凌最新发布的linux3.0的源码中也查看到有用到这个保留位,而且还是针对8bit ECC来使用的,参考的两个源码都支持这两个Nandflash。为什么6410的芯片文档上会写成是保留位?是笔误还是有所保留?为啥三星自己的MLC的BSP中也有使用?具体大家自己纠结去吧,反正上面这样使用了也没见着啥不良影响。

?

?

2、FMD_LB_ReadSector()

原来的代码:

copy
    BOOL?FMD_LB_ReadSector(SECTOR_ADDR?startSectorAddr,87); background-color:inherit; font-weight:bold">ULONG?SectorAddr?=?(ULONG)startSectorAddr;??
  1. DWORD???????i,?j;??
  2. DWORD????????rddata;??
  3. UINT32?nRetEcc?=?0;??
  4. DWORD?MECCBuf[16],tempMECCBuf[2];??//?gjl?8??
  5. int?NewSpareAddr?=?4096;??//gjl?2048??
  6. int?NewDataAddr?=?0;??
  7. int?NewSectorAddr?=?startSectorAddr;??
  8. int?SectorSpareAddr;??
  9. ????UINT8?TempSectorInfo[40];??
  10. BYTE?*pSectorBuff1?=?(BYTE?*)pSectorBuff;??
  11. ????UINT16?k=40;??
  12. #if?CHECK_SPAREECC??
  13. DWORD?SECCBuf[4];???//?gjl?2??
  14. "####?FMD_DRIVER:::FMD_LB_READSECTOR?%x?%xn"),startSectorAddr,NewDataAddr));??
  15. if?(!pSectorBuff?&&?!pSectorInfoBuff)??
  16. if?(?dwNumSectors?>?1?)??
  17. "########?FATAL?ERROR?=>?FMD::FMD_ReadSector->dwNumsectors?is?bigger?than?1.?n")));??
  18. return?FALSE;??
  19. if?(!pSectorBuff)??
  20. if?(!NAND_LB_ReadSectorInfo(startSectorAddr,?pSectorInfoBuff))??
  21. ????????????#if?(NAND_DEBUG)??
  22. "####?FMD_DRIVER:::54321n")));??
  23. ????????????#endif??
  24. ????????#if?(NAND_DEBUG)??
  25. "####?FMD_DRIVER:::12345n")));??
  26. ????????#endif??
  27. ????NF_nFCE_L();??
  28. ????NF_CLEAR_RB();??
  29. ????NF_CMD(CMD_READ);????????????????????????????//?Send?read?command.??
  30. ????NF_ADDR((NewSpareAddr)&0xff);??
  31. ????NF_ADDR((NewSpareAddr>>8)&0xff);??
  32. ????NF_ADDR((NewSectorAddr)?&?0xff);??
  33. ????NF_ADDR((NewSectorAddr?>>?8)?&?0xff);??
  34. #if????LB_NEED_EXT_ADDR??
  35. ????NF_ADDR((NewSectorAddr?>>?16)?&?0xff);??
  36. ????NF_CMD(CMD_READ3);????????????????????????//?2nd?command??
  37. ????NF_DETECT_RB();????????????????????????????????//?Wait?for?command?to?complete.??
  38. ????NF_MSGLENGTH_512();??
  39. ????NF_ECCTYPE_4BIT();??
  40. ??????
  41. if?(pSectorInfoBuff)??
  42. ????????pSectorInfoBuff->bBadBlock?=?NF_RDDATA_BYTE();??
  43. ????????pSectorInfoBuff->dwReserved1?=?NF_RDDATA_WORD();??
  44. ????????pSectorInfoBuff->bOEMReserved?=?NF_RDDATA_BYTE();??
  45. ????????pSectorInfoBuff->wReserved2?=?NF_RDDATA_BYTE();??
  46. ????????pSectorInfoBuff->wReserved2?|=?(NF_RDDATA_BYTE()<<8);??
  47. for(i=0;?i<sizeof(SectorInfo)/sizeof(DWORD);?i++)??
  48. ????????????rddata?=?(DWORD)?NF_RDDATA_WORD();????????//?read?and?trash?the?data??
  49. for?(nSectorLoop?=?0;?nSectorLoop?<?SECTORS_PER_PAGE*2;?nSectorLoop++)??
  50. ????????MECCBuf[nSectorLoop]?=?NF_RDDATA_WORD();??
  51. for?(nSectorLoop?=?0;?nSectorLoop?<?8;?nSectorLoop++)??
  52. ????????g_MECCBuf_R[nSectorLoop]?=?MECCBuf[nSectorLoop];??
  53. for?(nSectorLoop?=?0;?nSectorLoop?<?SECTORS_PER_PAGE;?nSectorLoop++)??
  54. ????????NewDataAddr?=?nSectorLoop?*?SECTOR_SIZE;??
  55. ????????NF_CMD(CMD_RDO);????????????????????????????//?Send?read?command.??
  56. ????????NF_ADDR((NewDataAddr)&0xff);??
  57. ????????NF_ADDR((NewDataAddr>>8)&0xff);??
  58. ????????NF_CMD(CMD_RDO2);???? ????????NF_MSGLENGTH_512();??
  59. ????????NF_ECCTYPE_4BIT();??
  60. ????????NF_RSTECC();??
  61. ????????NF_MECC_UnLock();??
  62. if(?((DWORD)?(pSectorBuff+nSectorLoop*SECTOR_SIZE))?&?0x3)??
  63. for(i=0;?i<SECTOR_SIZE/ ????????????????rddata?=?(DWORD)?NF_RDDATA_WORD();??
  64. ????????????????(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0]?=?(BYTE)(rddata?&?0xff);??
  65. ????????????????(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]?=?(BYTE)(rddata>>8?&?0xff);??
  66. ????????????????(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]?=?(BYTE)(rddata>>16?&?0xff);??
  67. ????????????????(pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]?=?(BYTE)(rddata>>24?&?0xff);??
  68. ????????????RdPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);????????????????????//?Read?page/sector?data.??
  69. ????????SectorSpareAddr?=?NewSpareAddr+8+nSectorLoop*8;??
  70. ????????NF_WRDATA_WORD(MECCBuf[2*nSectorLoop]);??
  71. ????????SectorSpareAddr?=?NewSpareAddr+8+nSectorLoop*8+4;??
  72. ????????NF_WRDATA_WORD(MECCBuf[2*nSectorLoop+1]);??
  73. ????????NF_MECC_Lock();??
  74. ????????//decode?done??
  75. while?(!(NF_RDSTAT?&?(1<<6)));??
  76. ????????tempMECCBuf[0]=?NF_RDMECC0();??
  77. ????????tempMECCBuf[1]?=?NF_RDMECC1();??
  78. ????????pSectorBuff1?=?pSectorBuff+nSectorLoop*SECTOR_SIZE;??
  79. if?(!ECC_CorrectData(startSectorAddr,?pSectorBuff1,?ECC_CORRECT_MAIN))??
  80. "ECC?ERRORn")));??
  81. }??

这个是飞凌BSP中的源码,里面需要修改的地方还是挺多的。

首先,来看定义部分的
DWORD MECCBuf[16],tempMECCBuf[2];? // gjl 8

由于将要用的是8bit的ECC校验,这个ECC的buffer就应该是32,1page=8*512byte,每读取512byte数据产生的ECC存放在4个32位的寄存器中,所以需要8*4个buffer:

DWORD MECCBuf[32];

至于tempMECCBuf,从上述代码中就可以看出就一垃圾,根本没用到,这里就把它删了。

定义完之后,我们需要使能一些相关的中断(不这样搞的话,发现无法正常校验ECC,具体原因请知道的朋友告知一声)

if (!pSectorBuff && !pSectorInfoBuff)
{
??????? return(FALSE);
}

的后面,我们添加以下代码:

copy
    g_pNFConReg->NFCONT?|=?(1<<10);????//?Enable?illegal?access?interrupt?control??
  1. g_pNFConReg->NFCONT?|=?(1<<9);?//?Enable?RnB?interrupt??
  2. g_pNFConReg->NFCONT?|=?(1<<12);????//?Enable?4bit,8bit?ECC?decoding?completion?interrupt?control??

?

接下来看到代码:(中间省略的那部分就不介绍了,大家有空可以参考一下LoongEmbedded的csdn blog)

NF_MSGLENGTH_512();

NF_ECCTYPE_4BIT();

我们使用8bit ECC,所以把 NF_ECCTYPE_4BIT(); 修改成

copy
    NF_ECCTYPE_8BIT();??

之后就是读取SectorInfo数据的操作,再过来就是读取ECC数据的操作:
??? for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*2; nSectorLoop++)
??? {
??????? MECCBuf[nSectorLoop] = NF_RDDATA_WORD();
??? }

由于,我们使用的是8bit ECC,上面只读取了8*2 * 4字节的ECC,而8bit的ECC需要8*4 *4字节,所以修改成:

copy
    for?(nSectorLoop?=?0;?nSectorLoop?<?SECTORS_PER_PAGE*4;?nSectorLoop++)???//?8bit?ECC,4096/page?=?8*512,?it?has?8*4(register)?ECC?data??
  1. ????MECCBuf[nSectorLoop]?=?NF_RDDATA_WORD();??
  2. }??



接下来直接看到循环读取一页数据的操作:

就是
??? for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE; nSectorLoop++)
??? {
??????? NewDataAddr = nSectorLoop * SECTOR_SIZE;

??????? NF_CMD(CMD_RDO);??????????????????????????? // Send read command.
??????? NF_ADDR((NewDataAddr)&0xff);
??????? NF_ADDR((NewDataAddr>>8)&0xff);
??????? NF_CMD(CMD_RDO2);??? // 2nd command


??NF_MSGLENGTH_512();
??NF_ECCTYPE_4BIT();

这里,把上面的 NF_ECCTYPE_4BIT(); 修改成:

copy
    NF_ECCTYPE_8BIT();??

顺便在上面这一句后面加上两句:

copy
    NF_ECC_8BIT_STOP();?//?init?8bit?ECC?decoding??
  1. NF_ECC_DIRECTION_IN();??//?4/8BIT?ECC?Decoding,?read?page??

接下来,原代码是:

??????? NF_RSTECC();
??????? NF_MECC_UnLock();

我这里把这两个操作的顺序换一下,变成:

copy
    NF_MECC_UnLock();??
  1. NF_RSTECC();??


在NF_RSTECC()之前必须设置 NF_ECC_8BIT_STOP(); ,因为文档中有说到: if you want to stop current work and start encoding/decoding?for new data,you must set 8bitStop(NFCONT[11]) before set InitMECC(NFCONT[5]) bit.

接下来的代码就是读取512字节数据的:
??????? if( ((DWORD) (pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
??????? {
??????????? for(i=0; i<SECTOR_SIZE/sizeof(DWORD); i++)
??????????? {
??????????????? rddata = (DWORD) NF_RDDATA_WORD();
??????????????? (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0] = (BYTE)(rddata & 0xff);
??????????????? (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1] = (BYTE)(rddata>>8 & 0xff);
??????????????? (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2] = (BYTE)(rddata>>16 & 0xff);
??????????????? (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3] = (BYTE)(rddata>>24 & 0xff);
??????????? }
??????? }
??????? else
??????? {
??????????? RdPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);??????????????????? // Read page/sector data.
??????? }

然后,就看到代码把前面读取到的ECC接着写进去了,这里应该是写进去的ECC与读取产生的ECC在ECC模块中进行对比,用于查找错误位
??????? SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8;
??NF_WRDATA_WORD(MECCBuf[2*nSectorLoop]);
??SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8+4;
??NF_WRDATA_WORD(MECCBuf[2*nSectorLoop+1]);
??????? NF_MECC_Lock();

这里,同样需要修改成写入8bit ECC的:

copy
    SectorSpareAddr?=?NewSpareAddr+8+nSectorLoop*8;??
  1. NF_WRDATA_WORD(MECCBuf[4*nSectorLoop]);??
  2. SectorSpareAddr?=?NewSpareAddr+8+nSectorLoop*8+4;??
  3. NF_WRDATA_WORD(MECCBuf[4*nSectorLoop+1]);??
  4. SectorSpareAddr?=?NewSpareAddr+8+nSectorLoop*8+8;??
  5. NF_WRDATA_WORD(MECCBuf[4*nSectorLoop+2]);??
  6. SectorSpareAddr?=?NewSpareAddr+8+nSectorLoop*8+12;??
  7. NF_WRDATA_WORD(MECCBuf[4*nSectorLoop+3]);??
  8. NF_MECC_Lock();??


之后,就是等待解码操作的完成:
??????? //decode done
??????? while (!(NF_RDSTAT & (1<<6)));
??????? tempMECCBuf[0]= NF_RDMECC0();
??????? tempMECCBuf[1] = NF_RDMECC1();

后面这两句含有tempMECCBuf的操作可以直接删除了,没用的。处理完这个之后,紧接着,就是查找ECC错误并进行矫正了:


??pSectorBuff1 = pSectorBuff+nSectorLoop*SECTOR_SIZE;

??????? if (!ECC_CorrectData(startSectorAddr,pSectorBuff1,nRetEcc,ECC_CORRECT_MAIN))
??????? {
???RETAILMSG(1,(TEXT("ECC ERRORn")));
??????????? return FALSE;
??????? }
??? }

?

??? NF_nFCE_H();

在 NF_nFCE_H(); 这句之前,我们需要把使能的一些中断关闭了:

copy
    g_pNFConReg->NFCONT?&=?~(1<<10);???//?Disable?illegal?access?interrupt?control??
  1. g_pNFConReg->NFCONT?&=?~(1<<9);????????//?Disable?RnB?interrupt??


?

?

?

3、NAND_LB_ReadSectorInfo()

原BSP代码:

copy
    BOOL?NAND_LB_ReadSectorInfo(SECTOR_ADDR?sectorAddr,?PSectorInfo?pInfo)??
  1. //gjl?2048??
  2. int?NewSectorAddr?=?sectorAddr;??
  3. DWORD?MECCBuf[16];??//?gjl?8??
  4. ????UINT16?nSectorLoop,?i;??
  5. ????UINT8?TempInfo[40];??
  6. #if?CHECK_SPAREECC??
  7. //gjl?2??
  8. UINT32?nRetEcc?=?0;??
  9. //?Send?read?confirm?command.??
  10. ????NF_ADDR((NewSectorAddr)&0xff);??
  11. ????NF_ADDR((NewSectorAddr>>8)?&?0xff);??
  12. ????NF_CMD(CMD_READ3);??
  13. ????NF_DETECT_RB();??
  14. ????pInfo->bBadBlock?=?NF_RDDATA_BYTE();??
  15. ????pInfo->dwReserved1??=?NF_RDDATA_WORD();??
  16. ????pInfo->bOEMReserved?=?NF_RDDATA_BYTE();??
  17. ????pInfo->wReserved2?=?NF_RDDATA_BYTE();??
  18. ????pInfo->wReserved2?|=?(NF_RDDATA_BYTE()<<8);??
  19. for?(nSectorLoop?=?0;?nSectorLoop?<?SECTORS_PER_PAGE*2;?nSectorLoop++)??
  20. ????????MECCBuf[nSectorLoop]?=?NF_RDDATA_WORD();??
  21. "####?FMD_DRIVER:::56565656n")));??
  22. }??

还是先看定义的 DWORD MECCBuf[16];? // gjl 8

这个我们要改成:

copy
    DWORD?MECCBuf[32];??

?

接着在 NF_nFCE_L(); 操作之前,添加:

copy
    //?use?8bit?ECC?type??
  1. NF_ECC_8BIT_STOP();?//?init?8bit?ECC?decoding??

?

然后,又看到读取ECC的操作:
??? for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*2; nSectorLoop++)
??? {
??????? MECCBuf[nSectorLoop] = NF_RDDATA_WORD();
??? }

这个,我们需要改成:

copy
    for?(nSectorLoop?=?0;?nSectorLoop?<?SECTORS_PER_PAGE*4;?nSectorLoop++)??
  1. }??



?

?

4、FMD_SB_ReadSector()

copy
    BOOL?FMD_SB_ReadSector(SECTOR_ADDR?startSectorAddr,87); background-color:inherit; font-weight:bold">ULONG?MECC;??
  1. UINT32?nRet?=?TRUE;??
  2. "####?FMD_DRIVER:::FMD_sbreadT?n")));??
  3. "[FMD:ERR]?FMD_SB_ReadSector(0x%08x,?0x%08x)?:?Invalid?Parametern"),?pSectorInfoBuff));??
  4. return(FALSE);??
  5. while?(dwNumSectors--)??
  6. ????????NF_nFCE_L();??
  7. ????????????NF_CLEAR_RB();??
  8. ????????????NF_CMD(CMD_READ2);????????????//?Send?read?confirm?command.??
  9. ????????????NF_ADDR(0);????????????????????????????????????//?Ignored.??
  10. ????????????NF_ADDR(SectorAddr?????????&?0xff);????????????//?Page?address.??
  11. ????????????NF_ADDR((SectorAddr?>>??8)?&?0xff);??
  12. #if????SB_NEED_EXT_ADDR??
  13. ????????????NF_ADDR((SectorAddr?>>?16)?&?0xff);??
  14. ????????????NF_DETECT_RB();??
  15. ????????????RdPageInfo((PBYTE)pSectorInfoBuff);????//?Read?page/sector?information.??
  16. ????????????pSectorInfoBuff++;??
  17. ????????????NF_CMD(CMD_READ);???????????????????? ????????????NF_ADDR(0);????????????????????????????????????//?Column?=?0.??
  18. ????????????NF_ADDR(SectorAddr?????????&?0xff);????????????//?Page?address.??
  19. ????????????NF_ADDR((SectorAddr?>>??8)?&?0xff);??
  20. #if????SB_NEED_EXT_ADDR??
  21. ????????????NF_ADDR((SectorAddr?>>?16)?&?0xff);??
  22. ????????????NF_DETECT_RB();????????????????????//?Wait?for?command?to?complete.??
  23. DWORD)?pSectorBuff)?&?0x3)??
  24. ????????????????RdPage512Unalign?(pSectorBuff);??
  25. ????????????????RdPage512(pSectorBuff);????????????????????//?Read?page/sector?data.??
  26. ????????????NF_MECC_Lock();??
  27. if?(pSectorInfoBuff)??
  28. ????????????????RdPageInfo((PBYTE)pSectorInfoBuff);???????? ????????????????pSectorInfoBuff?++;??
  29. ????????????????BYTE?TempInfo[8];??
  30. ????????????????RdPageInfo(TempInfo);??????????????????????? ????????????MECC??=?NF_RDDATA_BYTE()?<<?0;??
  31. ????????????MECC?|=?NF_RDDATA_BYTE()?<<?8;??
  32. ????????????MECC?|=?NF_RDDATA_BYTE()?<<?16;??
  33. ????????????MECC?|=?(NF_RDMECC0()?&0xff000000);??
  34. ????????????//MECC?|=?NF_RDDATA_BYTE()?<<?24;??
  35. ????????????NF_WRMECCD0(?((MECC&0xff00)<<8)|(MECC&0xff)?);??
  36. ?????????????NF_WRMECCD1(?((MECC&0xff000000)>>8)|((MECC&0xff0000)>>16)?);??
  37. ?????????????nRetEcc?=?NF_ECC_ERR0;??
  38. switch(nRetEcc?&?0x3)??
  39. ????????????????case?0:????//?No?Error??
  40. ????????????????????nRet?=?TRUE;??
  41. ????????????????????case?1:????//?1-bit?Error(Correctable)??
  42. ????????????????????RETAILMSG(1,(TEXT("ECC?correctable?error(0x%x)n"),?SectorAddr));??
  43. ????????????????????(pSectorBuff)[(nRetEcc>>7)&0x7ff]?^=?(1<<((nRetEcc>>4)&0x7));??
  44. ????????????????????nRet?=?TRUE;??
  45. ????????????????????case?2:????//?Multiple?Error??
  46. ????????????????????RETAILMSG(1,(TEXT("ECC?Uncorrectable?error(0x%x)n"),?SectorAddr));??
  47. ????????????????????nRet?=?FALSE;??
  48. case?3:????//?ECC?area?Error??
  49. "ECC?area?errorn")));??
  50. ????????????????????nRet?=?FALSE;??
  51. ????????????pSectorBuff?+=?NAND_SECTOR_SIZE;??
  52. ????????NF_nFCE_H();??
  53. ????????++SectorAddr;??
  54. return(nRet);??
  55. }??

FMD_SB_ReadSector()是介绍SLC读取操作的,这里不用修改。
?

?

到此,这一篇就把ECC矫正和读取数据的部分给搞掂了。下一篇将介绍写数据的部分

近段时间比较忙,接着上一篇,这篇主要介绍到写的部分

?

1、FMD_LB_WriteSector()? MLC写sector

[cpp]? view plain BOOL?FMD_LB_WriteSector(SECTOR_ADDR?startSectorAddr,87); background-color:inherit; font-weight:bold">DWORD???i;??
  • BOOL????bRet?=?TRUE;??
  • DWORD????wrdata;??
  • DWORD?MECCBuf[16];????//?16?gjl???
  • ????UINT16?nSectorLoop;??
  • //?2048?gjl??
  • int?NewDataAddr?=?0;??
  • int?NewSectorAddr?=?startSectorAddr;??
  • DWORD?SECCBuf[4];????//?2?gjl???
  • "FMD::FMD_LB_WriteSector?0x%x?n"),153); background-color:inherit; font-weight:bold">if?(!pSectorBuff?&&?!pSectorInfoBuff)??
  • "########?FATAL?ERROR?=>?FMD::FMD_WriteSector->dwNumsectors?is?bigger?than?1.?n")));??
  • ????????NAND_LB_WriteSectorInfo(startSectorAddr,?pSectorInfoBuff);??
  • //??Enable?Chip??
  • ????NF_nFCE_L();??
  • ????NF_CLEAR_RB();??
  • //??Issue?command??
  • ????NF_CMD(CMD_WRITE);??
  • //??Setup?address??
  • ????NF_ADDR((NewDataAddr)&0xff);??
  • ????NF_ADDR((NewDataAddr>>8)&0xff);??
  • ????NF_ADDR((NewSectorAddr)&0xff);??
  • ????NF_ADDR((NewSectorAddr>>8)&0xff);??
  • #if????LB_NEED_EXT_ADDR??
  • ????NF_ADDR((NewSectorAddr>>16)&0xff);??
  • for?(nSectorLoop?=?0;?nSectorLoop?<?SECTORS_PER_PAGE;?nSectorLoop++)??
  • (编辑:李大同)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

      推荐文章
        热点阅读