Nandflash 驱动移植
发布日期:2021-06-30 21:47:51 浏览次数:2 分类:技术文章

本文共 77704 字,大约阅读时间需要 259 分钟。

前段时间,研究了一下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, NFMECC1, NF8MECC2, 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:\WINCE600\PLATFORM\SMDK6410\src\common\nandflash\FMD\ 这个目录下边。

FMD的目录结构:

nand.s

cfnand.h

fmd_LB.h(实际并没用到)

fmd_SB.h(实际并没用到)

nand.h

fmd.cpp

sources

makefile

先看sources文件:

[cpp] 
  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.    
  18.      sources.  
  19.    
  20.  Abstract:  
  21.    
  22.      This file specifies the target component being built and the list of  
  23.      sources files needed to build that component.  Also specifies optional  
  24.      compiler switches and libraries that are unique for the component being  
  25.      built.  
  26.    
  27.  !ENDIF  
  28.    
  29.  TARGETNAME=nandflash_lib11  
  30.  TARGETTYPE=LIBRARY  
  31.  RELEASETYPE=PLATFORM  
  32.  SYNCHRONIZE_BLOCK=1  
  33.    
  34.  WINCEOEM=1  
  35.  WINCECPU=1  
  36.  NOMIPS16CODE=1  
  37.    
  38.  ADEFINES=-pd "_TGTCPU SETS \"$(_TGTCPU)\"" $(ADEFINES)  
  39.  LDEFINES=-subsystem:native /DEBUG /DEBUGTYPE:CV /FIXED:NO  
  40.    
  41.  INCLUDES=$(INCLUDES)  
  42.    
  43.  SOURCES=\  
  44.          fmd.cpp  
  45.    
  46.  ARM_SOURCES=\  
  47.          nand.s  
  48.    

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

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

cfnand.h文件:

[cpp] 
  1. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
  2.  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
  3.  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
  4.  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
  5.  PARTICULAR PURPOSE. 
  6.  Copyright (c) 2001  Microsoft Corporation 
  7.   
  8.  Module Name:    S3C6410.H 
  9.   
  10.  Abstract:        FLASH Media Driver Interface Samsung S3C6410 CPU with NAND Flash 
  11.                  controller. 
  12.   
  13.  Environment:    As noted, this media driver works on behalf of the FAL to directly 
  14.                  access the underlying FLASH hardware.  Consquently, this module 
  15.                  needs to be linked with FLASHFAL.LIB to produce the device driver 
  16.                  named FLASHDRV.DLL. 
  17.   
  18.  -----------------------------------------------------------------------------*/  
  19.  #ifndef _S3C6410_CFNAND_H  
  20.  #define _S3C6410_CFNAND_H  
  21.    
  22.  #include "FMD_LB.h"  
  23.  #include "FMD_SB.h"  
  24.  #include "nand.h"  
  25.    
  26.  #define BW_X08    (0)  
  27.  #define BW_X16    (1)  
  28.  #define BW_X32    (2)  
  29.    
  30.  #define MAX_SECTORS_PER_PAGE    (8)  
  31.    
  32.  /*****************************************************************************/  
  33.  /* S3C6410 Nand Flash Internal Data Structure Definition                                    */  
  34.  /*****************************************************************************/  
  35.  typedef struct  
  36.  {  
  37.      UINT16 nMID;            /* Manufacturer ID               */  
  38.      UINT16 nDID;                /* Device ID                     */  
  39.    
  40.      UINT16 nNumOfBlks;        /* Number of Blocks              */  
  41.      UINT16 nPgsPerBlk;        /* Number of Pages per block     */  
  42.      UINT16 nSctsPerPg;        /* Number of Sectors per page    */  
  43.      UINT16 nNumOfPlanes;    /* Number of Planes              */  
  44.      UINT16 nBlksInRsv;        /* The Number of Blocks in Reservior for Bad Blocks   */  
  45.      UINT8 nBadPos;            /* BadBlock Information Poisition*/  
  46.      UINT8 nLsnPos;            /* LSN Position                  */  
  47.      UINT8 nECCPos;            /* ECC Policy : HW_ECC, SW_ECC   */  
  48.      UINT16 nBWidth;            /* Nand Organization X8 or X16   */  
  49.    
  50.      UINT16 nTrTime;            /* Typical Read Op Time          */  
  51.      UINT16 nTwTime;            /* Typical Write Op Time         */  
  52.      UINT16 nTeTime;            /* Typical Erase Op Time         */  
  53.      UINT16 nTfTime;            /* Typical Transfer Op Time      */  
  54.  } FlashDevSpec;  
  55.    
  56.  static FlashDevSpec astNandSpec[] = {  
  57.      /*************************************************************************/  
  58.      /* nMID, nDID,                                                           */  
  59.      /*            nNumOfBlks                                                 */  
  60.      /*                  nPgsPerBlk                                           */  
  61.      /*                      nSctsPerPg                                       */  
  62.      /*                         nNumOfPlanes                                  */  
  63.      /*                            nBlksInRsv                                 */  
  64.      /*                                nBadPos                                */  
  65.      /*                                   nLsnPos                             */  
  66.      /*                                      nECCPos                          */  
  67.      /*                                         nBWidth                       */  
  68.      /*                                                nTrTime                */  
  69.      /*                                                    nTwTime            */  
  70.      /*                                                         nTeTime       */  
  71.      /*                                                                nTfTime*/  
  72.      /*************************************************************************/  
  73.      /* 8Gbit DDP NAND Flash */  
  74.      //{ 0xEC, 0xD3, 8192, 64, 4, 2,160, 0, 2, 8, BW_X08, 50, 350, 2000, 50},  
  75.     { 0xEC, 0xD3, 4096, 128, 4, 2,160, 0, 2, 8, BW_X08, 50, 350, 2000, 50},  
  76.     /* 16Gbit DDP NAND Flash */  
  77.     { 0xEC, 0xD5, 4096, 128, 8, 2,160, 0, 2, 8, BW_X08, 50, 350, 2000, 50}, // 8192  gjl   
  78.     /* 4Gbit DDP NAND Flash */  
  79.      { 0xEC, 0xAC, 4096, 64, 4, 2, 80, 0, 2, 8, BW_X08, 50, 350, 2000, 50},  
  80.      { 0xEC, 0xDC, 4096, 64, 4, 2, 80, 0, 2, 8, BW_X08, 50, 350, 2000, 50},  
  81.      //{ 0xEC, 0xBC, 4096, 64, 4, 2, 80, 0, 2, 8, BW_X16, 50, 350, 2000, 50},  
  82.      //{ 0xEC, 0xCC, 4096, 64, 4, 2, 80, 0, 2, 8, BW_X16, 50, 350, 2000, 50},  
  83.      /* 2Gbit NAND Flash */  
  84.      { 0xEC, 0xAA, 2048, 64, 4, 1, 40, 0, 2, 8, BW_X08, 50, 350, 2000, 50},  
  85.      { 0xEC, 0xDA, 2048, 64, 4, 1, 40, 0, 2, 8, BW_X08, 50, 350, 2000, 50},  
  86.      //{ 0xEC, 0xBA, 2048, 64, 4, 1, 40, 0, 2, 8, BW_X16, 50, 350, 2000, 50},  
  87.      //{ 0xEC, 0xCA, 2048, 64, 4, 1, 40, 0, 2, 8, BW_X16, 50, 350, 2000, 50},  
  88.      /* 2Gbit DDP NAND Flash */  
  89.      { 0xEC, 0xDA, 2048, 64, 4, 2, 40, 0, 2, 8, BW_X08, 50, 350, 2000, 50},  
  90.      { 0xEC, 0xAA, 2048, 64, 4, 2, 40, 0, 2, 8, BW_X08, 50, 350, 2000, 50},  
  91.      //{ 0xEC, 0xBA, 2048, 64, 4, 2, 40, 0, 2, 8, BW_X16, 50, 350, 2000, 50},  
  92.      //{ 0xEC, 0xCA, 2048, 64, 4, 2, 40, 0, 2, 8, BW_X16, 50, 350, 2000, 50},  
  93.      /*1Gbit NAND Flash */  
  94.      { 0xEC, 0xA1, 1024, 64, 4, 1, 20, 0, 2, 8, BW_X08, 50, 350, 2000, 50},  
  95.      { 0xEC, 0xF1, 1024, 64, 4, 1, 20, 0, 2, 8, BW_X08, 50, 350, 2000, 50},  
  96.      //{ 0xEC, 0xB1, 1024, 64, 4, 1, 20, 0, 2, 8, BW_X16, 50, 350, 2000, 50},  
  97.      //{ 0xEC, 0xC1, 1024, 64, 4, 1, 20, 0, 2, 8, BW_X16, 50, 350, 2000, 50},  
  98.      /* 1Gbit NAND Flash */  
  99.      { 0xEC, 0x79, 8192, 32, 1, 4,120, 5, 0, 6, BW_X08, 50, 350, 2000, 50},  
  100.      { 0xEC, 0x78, 8192, 32, 1, 4,120, 5, 0, 6, BW_X08, 50, 350, 2000, 50},  
  101.      //{ 0xEC, 0x74, 8192, 32, 1, 4,120,11, 0, 6, BW_X16, 50, 350, 2000, 50},  
  102.      //{ 0xEC, 0x72, 8192, 32, 1, 4,120,11, 0, 6, BW_X16, 50, 350, 2000, 50},  
  103.      /* 512Mbit NAND Flash */  
  104.      { 0xEC, 0x76, 4096, 32, 1, 4, 70, 5, 0, 6, BW_X08, 50, 350, 2000, 50},  
  105.      { 0xEC, 0x36, 4096, 32, 1, 4, 70, 5, 0, 6, BW_X08, 50, 350, 2000, 50},  
  106.    
  107.      /* 512Mbit XP Card */  
  108.      { 0x98, 0x76, 4096, 32, 1, 4, 70, 5, 0, 6, BW_X08, 50, 350, 2000, 50},  
  109.      { 0x98, 0x79, 4096, 32, 1, 4, 70, 5, 0, 6, BW_X08, 50, 350, 2000, 50},  
  110.    
  111.      //{ 0xEC, 0x56, 4096, 32, 1, 4, 70,11, 0, 6, BW_X16, 50, 350, 2000, 50},  
  112.      //{ 0xEC, 0x46, 4096, 32, 1, 4, 70,11, 0, 6, BW_X16, 50, 350, 2000, 50},  
  113.      /* 256Mbit NAND Flash */  
  114.      { 0xEC, 0x75, 2048, 32, 1, 1, 35, 5, 0, 6, BW_X08, 50, 350, 2000, 50},  
  115.      { 0xEC, 0x35, 2048, 32, 1, 1, 35, 5, 0, 6, BW_X08, 50, 350, 2000, 50},  
  116.      //{ 0xEC, 0x55, 2048, 32, 1, 1, 35,11, 0, 6, BW_X16, 50, 350, 2000, 50},  
  117.      //{ 0xEC, 0x45, 2048, 32, 1, 1, 35,11, 0, 6, BW_X16, 50, 350, 2000, 50},  
  118.      /* 128Mbit NAND Flash */  
  119.      { 0xEC, 0x73, 1024, 32, 1, 1, 20, 5, 0, 6, BW_X08, 50, 350, 2000, 50},  
  120.      { 0xEC, 0x33, 1024, 32, 1, 1, 20, 5, 0, 6, BW_X08, 50, 350, 2000, 50},  
  121.      //{ 0xEC, 0x53, 1024, 32, 1, 1, 20,11, 0, 6, BW_X16, 50, 350, 2000, 50},  
  122.      //{ 0xEC, 0x43, 1024, 32, 1, 1, 20,11, 0, 6, BW_X16, 50, 350, 2000, 50},  
  123.    
  124.      { 0x00, 0x00,    0,  0, 0, 0,  0, 0, 0, 0,      0,  0,   0,    0,  0}  
  125.  };  
  126.    
  127.  #endif _S3C6410_CFNAND_H  
  128.    
  129.    

且看

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

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

[cpp] 
  1. /* 32Gbit DDP NAND Flash */  
  2.     { 0xEC, 0xD7, 8192, 128, 8, 1,160, 0, 2, 8, BW_X08, 50, 350, 2000, 50},  


在看nand.h文件之前,我们先来看一下fmd.cpp中引用的#include "s3c6410_nand.h"头文件:(该文件在C:\WINCE600\PLATFORM\COMMON\SRC\SOC\S3C6410_SEC_V1\OAL\INC\s3c6410_nand.h)

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

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

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

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

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

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


nand.h文件:

[cpp] 
  1. //  
  2.  // Copyright (c) Microsoft Corporation.  All rights reserved.  
  3.  //  
  4.  //  
  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.  //  
  13.  #ifndef __NAND_H__  
  14.  #define __NAND_H__  
  15.    
  16.  //-----------------------------------------------------------------------------  
  17.    
  18.  typedef struct  
  19.  {  
  20.      UINT16 nNumOfBlks;  
  21.      UINT16 nPagesPerBlk;  
  22.      UINT16 nSctsPerPage;  
  23.  } NANDDeviceInfo;  
  24.    
  25.  NANDDeviceInfo stDeviceInfo;  
  26.    
  27.  #ifdef __cplusplus  
  28.  extern "C"  {  
  29.  #endif  
  30.  NANDDeviceInfo GetNandInfo(void);  
  31.  #ifdef __cplusplus  
  32.  }  
  33.  #endif  
  34.    
  35.  #define NUM_OF_BLOCKS        (stDeviceInfo.nNumOfBlks)  
  36.  #define PAGES_PER_BLOCK    (stDeviceInfo.nPagesPerBlk)  
  37.  #define SECTORS_PER_PAGE    (stDeviceInfo.nSctsPerPage)  
  38.    
  39.  #undef SECTOR_SIZE  
  40.  #define SECTOR_SIZE            (512)  
  41.  #define NAND_SECTOR_SIZE    (SECTOR_SIZE*SECTORS_PER_PAGE)  
  42.  #define NAND_PAGE_SIZE      (SECTOR_SIZE*SECTORS_PER_PAGE)  //< Physical Page Size  
  43.    
  44.  #define IS_LB                ((SECTORS_PER_PAGE == 4)||(SECTORS_PER_PAGE == 8))  
  45.    
  46.  //-----------------------------------------------------------------------------  
  47.    
  48.  #define USE_NFCE            (0)  
  49.  #define USE_GPIO            (0)  
  50.    
  51.  #define TACLS                (NAND_TACLS)  
  52.  #define TWRPH0                (NAND_TWRPH0)  
  53.  #define TWRPH1                (NAND_TWRPH1)  
  54.  #define ECCType                 (23)  
  55.    
  56.  //-----------------------------------------------------------------------------  
  57.    
  58.  #define CMD_READID            (0x90)    //  ReadID  
  59.  #define CMD_READ            (0x00)    //  Read  
  60.  #define CMD_READ2            (0x50)    //  Read2  
  61.  #define CMD_READ3            (0x30)    //  Read3  
  62.  #define CMD_RESET            (0xff)    //  Reset  
  63.  #define CMD_ERASE            (0x60)    //  Erase phase 1  
  64.  #define CMD_ERASE2            (0xd0)    //  Erase phase 2  
  65.  #define CMD_WRITE            (0x80)    //  Write phase 1  
  66.  #define CMD_WRITE2            (0x10)    //  Write phase 2  
  67.  #define CMD_STATUS            (0x70)    //  STATUS  
  68.  #define CMD_RDI                (0x85)    //  Random Data Input  
  69.  #define CMD_RDO                (0x05)    //  Random Data Output  
  70.  #define CMD_RDO2            (0xE0)    //  Random Data Output  
  71.    
  72.  #define BADBLOCKMARK        (0x00)  
  73.    
  74.  //  Status bit pattern  
  75.  #define STATUS_READY        (0x40)    //  Ready  
  76.  #define STATUS_ERROR        (0x01)    //  Error  
  77.  #define STATUS_ILLACC        (0x20)    // Illigar Access  
  78.    
  79.  #define NF_ECCERR0_ALL_FF    0x40000000  
  80.  #define NF_ECCERR0_ECC_READY    0x20000000  
  81.    
  82.  //-----------------------------------------------------------------------------  
  83.    
  84.  #define NF_CMD(cmd)                {g_pNFConReg->NFCMD   =  (unsigned char)(cmd);}  
  85.  #define NF_ADDR(addr)            {g_pNFConReg->NFADDR  =  (unsigned char)(addr);}  
  86.    
  87.  #define NF_nFCE_L()                {g_pNFConReg->NFCONT &= ~(1<<1);}  
  88.  #define NF_nFCE_H()                {g_pNFConReg->NFCONT |=  (1<<1);}  
  89.    
  90.  #define NF_ECC_DIRECTION_IN()         {g_pNFConReg->NFCONT &= ~(1<<18);}  
  91.  #define NF_ECC_DIRECTION_OUT()        {g_pNFConReg->NFCONT |= (1<<18);}  
  92.    
  93.  #define NF_ECC_8BIT_STOP()            {g_pNFConReg->NFCONT |= (1<<12);} //stop the last encode or decode of 8bit mode.  
  94.    
  95.  #define NF_RSTECC()                 {g_pNFConReg->NFCONT |=  ((1<<5) | (1<<4));}  
  96.    
  97.    
  98.  #define NF_MSGLENGTH_512()     {g_pNFConReg->NFCONF &= ~(1<<25);}  
  99.  #define NF_MSGLENGTH_24()      {g_pNFConReg->NFCONF |= (1<<25);}  
  100.  #define NF_ECCTYPE_CLR         (g_pNFConReg->NFCONF &= ~(3<<23))  
  101.  #define NF_ECCTYPE_1BIT()      {NF_ECCTYPE_CLR;}  
  102.  #define NF_ECCTYPE_4BIT()      {NF_ECCTYPE_CLR |= (1<<24);}  
  103.  #define NF_ECCTYPE_8BIT()      {NF_ECCTYPE_CLR |= (1<<23);}  
  104.    
  105.  #define NF_MECC_UnLock()        {g_pNFConReg->NFCONT &= ~(1<<7);}  
  106.  #define NF_MECC_Lock()            {g_pNFConReg->NFCONT |= (1<<7);}  
  107.  #define NF_SECC_UnLock()        {g_pNFConReg->NFCONT &= ~(1<<6);}  
  108.  #define NF_SECC_Lock()            {g_pNFConReg->NFCONT |= (1<<6);}  
  109.    
  110.  #define NF_CLEAR_RB()            {g_pNFConReg->NFSTAT |=  (1<<4);}                // Have write '1' to clear this bit.  
  111.    
  112.  #define NF_DETECT_RB()            {while((g_pNFConReg->NFSTAT&0x11)!=0x11);}        // RnB_Transdetect & RnB  
  113.  #define NF_WAITRB()                {while (!(g_pNFConReg->NFSTAT & (1<<0))) ; }  
  114.    
  115.  #define NF_RDDATA_BYTE()        (g_pNFConReg->NFDATA)  
  116.  #define NF_RDDATA_WORD()        (*(UINT32 *)0xb0200010)  
  117.    
  118.  #define NF_WRDATA_BYTE(data)    {g_pNFConReg->NFDATA  =  (UINT8)(data);}  
  119.  #define NF_WRDATA_WORD(data)    {*(UINT32 *)0xb0200010  =  (UINT32)(data);}  
  120.    
  121.  #define NF_RDMECC0()            (g_pNFConReg->NFMECC0)  
  122.  #define NF_RDMECC1()            (g_pNFConReg->NFMECC1)  
  123.  #define NF_RDSECC()                (g_pNFConReg->NFSECC)  
  124.    
  125.  #define NF_RDM8ECC0()            (g_pNFConReg->NFM8ECC0)  
  126.  #define NF_RDM8ECC1()            (g_pNFConReg->NFM8ECC1)  
  127.  #define NF_RDM8ECC2()            (g_pNFConReg->NFM8ECC2)  
  128.  #define NF_RDM8ECC3()            (g_pNFConReg->NFM8ECC3)  
  129.    
  130.  #define NF_RDMECCD0()            (g_pNFConReg->NFMECCD0)  
  131.  #define NF_RDMECCD1()            (g_pNFConReg->NFMECCD1)  
  132.  #define NF_RDSECCD()            (g_pNFConReg->NFSECCD)  
  133.    
  134.  #define NF_ECC_ERR0                (g_pNFConReg->NFECCERR0)  
  135.  #define NF_ECC_ERR1                (g_pNFConReg->NFECCERR1)  
  136.    
  137.  #define NF_ECC8BIT_NUM                  ((g_pNFConReg->NF8ECCERR0 & (0xf<<25))>>25)  
  138.  #define NF_ECC8LOCATION_BYTE1           (g_pNFConReg->NF8ECCERR0 & (0x3ff))  
  139.  #define NF_ECC8LOCATION_BYTE2           ((g_pNFConReg->NF8ECCERR0 & (0x3ff<<15))>>15)  
  140.  #define NF_ECC8LOCATION_BYTE3           (g_pNFConReg->NF8ECCERR1 & (0x3ff))  
  141.  #define NF_ECC8LOCATION_BYTE4           ((g_pNFConReg->NF8ECCERR1 & (0x3ff<<11))>>11)  
  142.  #define NF_ECC8LOCATION_BYTE5           ((g_pNFConReg->NF8ECCERR1 & (0x3ff<<22))>>22)  
  143.  #define NF_ECC8LOCATION_BYTE6           (g_pNFConReg->NF8ECCERR2 & (0x3ff))  
  144.  #define NF_ECC8LOCATION_BYTE7           ((g_pNFConReg->NF8ECCERR2 & (0x3ff<<11))>>11)  
  145.  #define NF_ECC8LOCATION_BYTE8           ((g_pNFConReg->NF8ECCERR2 & (0x3ff<<22))>>22)  
  146.    
  147.  #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))  
  148.    
  149.  #define NF_ECC4BIT_NUM                  ((g_pNFConReg->NFECCERR0 & (0x7<<26))>>26)  
  150.  #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)))  
  151.    
  152.  #define NF_ECC4LOCATION_BIT(n)          ((g_pNFConReg->NFMLCBITPT & (0xff<<((n-1)*8)))>>((n-1)*8))  
  153.    
  154.  #define NF_WRMECCD0(data)        {g_pNFConReg->NFMECCD0 = (data);}  
  155.  #define NF_WRMECCD1(data)        {g_pNFConReg->NFMECCD1 = (data);}  
  156.  #define NF_WRSECCD(data)        {g_pNFConReg->NFSECCD = (data);}  
  157.    
  158.  #define NF_RDSTAT                (g_pNFConReg->NFSTAT)  
  159.    
  160.  //-----------------------------------------------------------------------------  
  161.    
  162.  typedef enum  
  163.  {  
  164.      ECC_CORRECT_MAIN = 0,    // correct Main ECC  
  165.      ECC_CORRECT_SPARE1 = 1,     // correct Spare for Sector Info using Main ECC Result Area  
  166.      ECC_CORRECT_SPARE2 = 2,     // correct Spare for MECC using Main ECC Result Area  
  167.      ECC_CORRECT_SPARE = 3       // correct Spare using Spare ECC Result Area  
  168.  } ECC_CORRECT_TYPE;  
  169.    
  170.  //-----------------------------------------------------------------------------  
  171.    
  172.  #endif    // __NAND_H_.  
  173.    

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] 
  1. //  
  2.  // Copyright (c) Microsoft Corporation.  All rights reserved.  
  3.  //  
  4.  //  
  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.  //  
  13.  #include <fmd.h>  
  14.  #include <nkintr.h>  
  15.  #include <oal.h>  
  16.    
  17.  // BSP Configuration Files  
  18.  #include "bsp_cfg.h"  
  19.  #include "bsp_base_reg_cfg.h"  
  20.    
  21.  // Base Definitions  
  22.  #include "s3c6410_base_regs.h"  
  23.  #include "s3c6410_nand.h"  
  24.  #include "s3c6410_syscon.h"  
  25.    
  26.  //#include <ethdbg.h>  
  27.  #include "Cfnand.h"  
  28.  //#include <kitl.h>  
  29.    
  30.  //#define SYNC_OP  
  31.  #define CHECK_SPAREECC    (0)  // 1 gjl   
  32.  #define NAND_DEBUG        (0)  
  33.    
  34.  #define NAND_BASE        (0xB0200000)    // PA:0x70200000  
  35.  #define SYSCON_BASE        (0xB2A0F000)    // PA:0x7E00F000  
  36.    
  37.  #ifdef    SYNC_OP  
  38.  CRITICAL_SECTION    g_csNandFlash;  
  39.  #endif  
  40.    
  41.  #ifdef __cplusplus    // gjl  
  42.  extern "C" {  
  43.   int iSighForSlcMlc;   // gjl   
  44.  }  
  45.  #endif  
  46.    
  47.  static volatile S3C6410_NAND_REG *g_pNFConReg = NULL;  
  48.  static volatile S3C6410_SYSCON_REG *g_pSysConReg = NULL;  
  49.    
  50.  #define DEBUG_WRITE_READ_EQUAL 0  
  51.    
  52.  #if DEBUG_WRITE_READ_EQUAL  
  53.  DWORD g_MECCBuf[8];  
  54.  DWORD g_MECCBuf_R[8];  
  55.  DWORD g_SECCBuf[2];  
  56.  DWORD g_SECCBuf_R[2];  
  57.  #endif  
  58.    
  59.  extern "C"  
  60.  {  
  61.      void RdPage512(unsigned char *bufPt);  
  62.      void RdPage512Unalign(unsigned char *bufPt);  
  63.      void WrPage512(unsigned char *bufPt);  
  64.      void WrPage512Unalign(unsigned char *bufPt);  
  65.      void WrPageInfo(PBYTE pBuff);  
  66.      void RdPageInfo(PBYTE pBuff);  
  67.  }  
  68.    
  69.  NANDDeviceInfo GetNandInfo(void) { return stDeviceInfo; }  

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

1、读取Flash的ID:

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

2、flash初始化:

[cpp] 
  1. /* 
  2.     @func   PVOID | FMD_Init | Initializes the Smart Media NAND flash controller. 
  3.     @rdesc  Pointer to S3C2410 NAND controller registers. 
  4.     @comm 
  5.     @xref 
  6. */  
  7.   
  8. PVOID FMD_Init(LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)  
  9. {  
  10.     volatile DWORD nNandID;  
  11.     UINT8 nMID, nDID;  
  12.     UINT32 nCnt;  
  13.     BOOL bNandExt = FALSE;  
  14.   
  15.     RETAILMSG(1, (TEXT("[FMD] ++FMD_Init() *######\r\n")));  
  16.   
  17.   
  18.   
  19.       
  20.   
  21.     if (pRegIn && pRegIn->MemBase.Num && pRegIn->MemBase.Reg[0])  
  22.     {  
  23.         g_pNFConReg = (S3C6410_NAND_REG *)(pRegIn->MemBase.Reg[0]);  
  24.     }  
  25.     else  
  26.     {  
  27.         g_pNFConReg = (S3C6410_NAND_REG *)NAND_BASE;  
  28.     }  
  29.   
  30.     g_pSysConReg = (S3C6410_SYSCON_REG *)SYSCON_BASE;  
  31.   
  32. #ifdef    SYNC_OP  
  33.     InitializeCriticalSection(&g_csNandFlash);  
  34.   
  35.     EnterCriticalSection(&g_csNandFlash);  
  36. #endif  
  37.   
  38.     // Configure BUS Width and Chip Select for NAND Flash  
  39.     g_pSysConReg->MEM_SYS_CFG &= ~(1<<12);    // NAND Flash BUS Width -> 8 bit  
  40.     g_pSysConReg->MEM_SYS_CFG &= ~(0x1<<1);    // Xm0CS2 -> NFCON CS0  
  41.   
  42.     // Set up initial flash controller configuration.  
  43.     g_pNFConReg->NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);  
  44.     NF_ECCTYPE_4BIT();  
  45.     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);  
  46.     g_pNFConReg->NFSTAT = (1<<4);  
  47.   
  48.     nNandID = ReadFlashID();  
  49.   
  50. #ifdef    SYNC_OP  
  51.     LeaveCriticalSection(&g_csNandFlash);  
  52. #endif  
  53.   
  54.     nMID = (UINT8)(nNandID >> 8);  
  55.     nDID = (UINT8)(nNandID & 0xff);  
  56.   
  57.     RETAILMSG(1, (TEXT("[FMD:INF] FMD_Init() : Read ID = 0x%08x\n"), nNandID));  
  58.   
  59.     for (nCnt = 0; astNandSpec[nCnt].nMID != 0; nCnt++)  
  60.     {  
  61.         if (nDID == astNandSpec[nCnt].nDID)  
  62.         {  
  63.             bNandExt = TRUE;  
  64.             break;  
  65.         }  
  66.     }  
  67.   
  68.     if (!bNandExt)  
  69.     {  
  70.         RETAILMSG(1, (TEXT("[FMD:ERR] FMD_Init() : Unknown ID = 0x%08x\n"), nNandID));  
  71.         return NULL;  
  72.     }  
  73.   
  74.     NUM_OF_BLOCKS = astNandSpec[nCnt].nNumOfBlks;  
  75.     PAGES_PER_BLOCK = astNandSpec[nCnt].nPgsPerBlk;  
  76.     SECTORS_PER_PAGE = astNandSpec[nCnt].nSctsPerPg;  
  77.   
  78.   
  79.       
  80.     RETAILMSG(1, (TEXT("[FMD] FMD_Init() : NUM_OF_BLOCKS = %d\n"), NUM_OF_BLOCKS));  
  81.     RETAILMSG(1, (TEXT("[FMD] FMD_Init() : PAGES_PER_BLOCK = %d\n"), PAGES_PER_BLOCK));  
  82.     RETAILMSG(1, (TEXT("[FMD] FMD_Init() : SECTORS_PER_PAGE = %d\n"), SECTORS_PER_PAGE));  
  83.   
  84.     // gjl  
  85.     if(iSighForSlcMlc == 1)  
  86.     {  
  87.             NUM_OF_BLOCKS = 8192;  
  88.             PAGES_PER_BLOCK = 8;  
  89.             SECTORS_PER_PAGE = 4;  
  90.     }  
  91.     else  
  92.     {  
  93.             NUM_OF_BLOCKS = astNandSpec[nCnt].nNumOfBlks;  
  94.             PAGES_PER_BLOCK = astNandSpec[nCnt].nPgsPerBlk;  
  95.             SECTORS_PER_PAGE = astNandSpec[nCnt].nSctsPerPg;  
  96.   
  97.     }  
  98.   
  99.     RETAILMSG(1, (TEXT("[FMD] --FMD_Init()\n")));  
  100.   
  101.     return((PVOID)g_pNFConReg);  
  102. }  

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

// Set up initial flash controller configuration.

g_pNFConReg->NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);

这个我们对照手册看一下

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

[cpp] 
  1. g_pNFConReg->NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4) | (1<<2) | (0<<0);  

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

[cpp] 
  1. 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);

参照手册修改为:

[cpp] 
  1. g_pNFConReg->NFCONT = (0<<13)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);  


接下来直接看到

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

[cpp] 
  1. NUM_OF_BLOCKS = astNandSpec[nCnt].nNumOfBlks;  

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


3、FMD_ReadSector()

[cpp] 
  1. /* 
  2.     @func   BOOL | FMD_ReadSector | Reads the specified sector(s) from NAND flash. 
  3.     @rdesc  TRUE = Success, FALSE = Failure. 
  4.     @comm 
  5.     @xref 
  6. */  
  7. BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)  
  8. {  
  9.     BOOL bRet;  
  10.   
  11.     //RETAILMSG(1, (TEXT("[R:0x%08x] \n"), startSectorAddr));  
  12. #if (NAND_DEBUG)  
  13.     RETAILMSG(1, (TEXT("[FMD] ++FMD_ReadSector(0x%08x) \n"), startSectorAddr));  
  14. #endif  
  15.   
  16. #ifdef    SYNC_OP  
  17.     EnterCriticalSection(&g_csNandFlash);  
  18. #endif  
  19.   
  20.     if ( IS_LB )  
  21.     {  
  22.         bRet = FMD_LB_ReadSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors);  
  23.     }  
  24.     else  
  25.     {  
  26.         bRet = FMD_SB_ReadSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors);  
  27.     }  
  28.   
  29. #ifdef    SYNC_OP  
  30.     LeaveCriticalSection(&g_csNandFlash);  
  31. #endif  
  32.   
  33. #if (NAND_DEBUG)  
  34.     RETAILMSG(1, (TEXT("[FMD] --FMD_ReadSector()\n")));  
  35. #endif  
  36.   
  37.     return bRet;  
  38. }  
这里我们不需要做修改,不过其中调用的FMD_LB_ReadSector()函数待会需要修改一下(FMD_LB_ReadSector()是针对Nandflash,4bit或8bit的ECC;而FMD_SB_ReadSector()是针对Norflash,1bit的ecc校验)


4、FMD_EraseBlock()  擦除块

[cpp] 
  1. /* 
  2.     @func   BOOL | FMD_EraseBlock | Erases the specified flash block. 
  3.     @rdesc  TRUE = Success, FALSE = Failure. 
  4.     @comm 
  5.     @xref 
  6. */  
  7. BOOL FMD_EraseBlock(BLOCK_ID blockID)  
  8. {  
  9.     BOOL    bRet = TRUE;  
  10.   
  11. #if (NAND_DEBUG)  
  12.     RETAILMSG(1, (TEXT("[FMD] ++FMD_EraseBlock(0x%08x) \n"), blockID));  
  13. #endif  
  14.   
  15. #ifdef    SYNC_OP  
  16.     EnterCriticalSection(&g_csNandFlash);  
  17. #endif  
  18.   
  19.     if ( IS_LB )  
  20.     {  
  21.         bRet = FMD_LB_EraseBlock(blockID);  
  22.     }  
  23.     else  
  24.     {  
  25.         bRet = FMD_SB_EraseBlock(blockID);  
  26.     }  
  27.   
  28. #ifdef    SYNC_OP  
  29.     LeaveCriticalSection(&g_csNandFlash);  
  30. #endif  
  31.   
  32. #if (NAND_DEBUG)  
  33.     RETAILMSG(1, (TEXT("[FMD] --FMD_EraseBlock()\n")));  
  34. #endif  
  35.   
  36.     return bRet;  
  37. }  

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

5、FMD_WriteSector()

[cpp] 
  1. /* 
  2.     @func   BOOL | FMD_WriteSector | Writes the specified data to the specified NAND flash sector/page. 
  3.     @rdesc  TRUE = Success, FALSE = Failure. 
  4.     @comm 
  5.     @xref 
  6. */  
  7. BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)  
  8. {  
  9.     BOOL    bRet = TRUE;  
  10. #if DEBUG_WRITE_READ_EQUAL  
  11.     BYTE    pSectorBuffRead[4096]; // gjl 2048  
  12.     SectorInfo    SectorInfoBuffRead;  
  13.     PSectorInfo    pSectorInfoBuffRead = &SectorInfoBuffRead;  
  14.     BYTE     *temp = (BYTE*)pSectorInfoBuff;  
  15.     BYTE     *temp1 = (BYTE*)pSectorInfoBuffRead;  
  16.     UINT16 nSectorLoop,j=40;  
  17. #endif  
  18.   
  19. #if (NAND_DEBUG)  
  20.     RETAILMSG(1, (TEXT("[FMD] ++FMD_WriteSector(0x%08x) \n"), startSectorAddr));  
  21. #endif  
  22.   
  23. #ifdef    SYNC_OP  
  24.     EnterCriticalSection(&g_csNandFlash);  
  25. #endif  
  26.   
  27.     if ( IS_LB )  
  28.     {  
  29.         bRet = FMD_LB_WriteSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors);  
  30. #if DEBUG_WRITE_READ_EQUAL  
  31.         FMD_LB_ReadSector(startSectorAddr, pSectorBuffRead, pSectorInfoBuffRead, dwNumSectors);  
  32.         for (nSectorLoop = 0; nSectorLoop < 2048; nSectorLoop++)  
  33.         {  
  34.             if(pSectorBuff[nSectorLoop] != pSectorBuffRead[nSectorLoop])  
  35.                 break;  
  36.         }  
  37.         RETAILMSG(1, (TEXT("[FMD] ++FMD_WriteSector equal number = %x \n"), nSectorLoop));  
  38.         for (nSectorLoop = 0; nSectorLoop < 8; nSectorLoop++)  
  39.         {  
  40.             if(temp1[nSectorLoop] != temp[nSectorLoop])  
  41.                 break;  
  42.         }  
  43.         RETAILMSG(1, (TEXT("[FMD] ++FMD_WriteSector informationequal equal number = %x \n"), nSectorLoop));  
  44.         RETAILMSG(1, (TEXT("[FMD] ++FMD_WriteSector sector bytes:\n")));  
  45.         for (nSectorLoop = 0; nSectorLoop < 2048; nSectorLoop++)  
  46.         {  
  47.             if(j--==0)  
  48.             {  
  49.                 j=40;  
  50.                 RETAILMSG(1, (TEXT("\n")));  
  51.             }  
  52.             RETAILMSG(1, (TEXT("%x "), pSectorBuff[nSectorLoop]));  
  53.         }  
  54.         RETAILMSG(1, (TEXT("\n end\n")));  
  55.         RETAILMSG(1, (TEXT("[FMD] ++FMD_ReadSector sector bytes:\n")));  
  56.         for (nSectorLoop = 0; nSectorLoop < 2048; nSectorLoop++)  
  57.         {  
  58.             if(j--==0)  
  59.             {  
  60.                 j=40;  
  61.                 RETAILMSG(1, (TEXT("\n")));  
  62.             }  
  63.             RETAILMSG(1, (TEXT("%x "), pSectorBuffRead[nSectorLoop]));  
  64.         }  
  65.         RETAILMSG(1, (TEXT("\n end\n")));  
  66.         for (nSectorLoop = 0; nSectorLoop < 8; nSectorLoop++)  
  67.         {  
  68.             if(g_MECCBuf_R[nSectorLoop] != g_MECCBuf[nSectorLoop])  
  69.                 break;  
  70.         }  
  71.         RETAILMSG(1, (TEXT("[FMD] ++FMD_WriteSector MECC data equal number = %x \n"), nSectorLoop));  
  72.         for (nSectorLoop = 0; nSectorLoop < 8; nSectorLoop++)  
  73.         {  
  74.             if(g_SECCBuf_R[nSectorLoop] != g_SECCBuf[nSectorLoop])  
  75.                 break;  
  76.         }  
  77.         RETAILMSG(1, (TEXT("[FMD] ++FMD_WriteSector SECC data equal number = %x \n"), nSectorLoop));  
  78.           
  79. #endif  
  80.     }  
  81.     else  
  82.     {  
  83.         bRet = FMD_SB_WriteSector(startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors);  
  84.     }  
  85.   
  86. #ifdef    SYNC_OP  
  87.     LeaveCriticalSection(&g_csNandFlash);  
  88. #endif  
  89.   
  90. #if (NAND_DEBUG)  
  91.     RETAILMSG(1, (TEXT("[FMD] --FMD_WriteSector()\n")));  
  92. #endif  
  93.   
  94.     return bRet;  
  95. }  

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

6、FMD_PowerUp()

[cpp] 
  1. VOID FMD_PowerUp(VOID)  
  2.  {  
  3.  #if (NAND_DEBUG)  
  4.      RETAILMSG(1, (TEXT("[FMD] FMD_PowerUp() \n")));  
  5.  #endif  
  6.    
  7.      // Set up initial flash controller configuration.  
  8.      g_pNFConReg->NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);  
  9.      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);  
  10.      g_pNFConReg->NFSTAT = (1<<4);  
  11.  }  

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

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


7、FMD_PowerDown()

[cpp] 
  1. VOID FMD_PowerDown(VOID)  
  2.  {  
  3.  #if (NAND_DEBUG)  
  4.      RETAILMSG(1, (TEXT("[FMD] FMD_PowerDown() \n")));  
  5.  #endif  
  6.    
  7.  }  

该函数不需要修改什么。

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

[cpp] 
  1. BOOL FMD_OEMIoControl(DWORD dwIoControlCode, PBYTE pInBuf, DWORD nInBufSize, PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned)  
  2.  {  
  3.      switch(dwIoControlCode)  
  4.      {  
  5.          case IOCTL_FMD_GET_INTERFACE:  
  6.          {  
  7.              RETAILMSG(1, (TEXT("[FMD] FMD_OEMIoControl() : IOCTL_FMD_GET_INTERFACE\n")));  
  8.    
  9.              if (!pOutBuf || nOutBufSize < sizeof(FMDInterface))  
  10.              {  
  11.                  DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_GET_INTERFACE bad parameter(s).\n")));  
  12.                  return(FALSE);  
  13.              }  
  14.    
  15.              PFMDInterface pInterface = (PFMDInterface)pOutBuf;  
  16.    
  17.              pInterface->cbSize = sizeof(FMDInterface);  
  18.              pInterface->pInit = FMD_Init;  
  19.              pInterface->pDeInit = FMD_Deinit;  
  20.              pInterface->pGetInfo = FMD_GetInfo;  
  21.              pInterface->pGetInfoEx = NULL;        //FMD_GetInfoEx;  
  22.              pInterface->pGetBlockStatus = FMD_GetBlockStatus;  
  23.              pInterface->pSetBlockStatus = FMD_SetBlockStatus;  
  24.              pInterface->pReadSector = FMD_ReadSector;  
  25.              pInterface->pWriteSector = FMD_WriteSector;  
  26.              pInterface->pEraseBlock = FMD_EraseBlock;  
  27.              pInterface->pPowerUp = FMD_PowerUp;  
  28.              pInterface->pPowerDown = FMD_PowerDown;  
  29.              pInterface->pGetPhysSectorAddr = NULL;  
  30.    
  31.              break;  
  32.          }  
  33.    
  34.      case IOCTL_FMD_LOCK_BLOCKS:  
  35.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_LOCK_BLOCKS Not Supported\n")));  
  36.          return FALSE;  
  37.    
  38.      case IOCTL_FMD_UNLOCK_BLOCKS:  
  39.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_UNLOCK_BLOCKS Not Supported\n")));  
  40.          return FALSE;  
  41.    
  42.      case IOCTL_FMD_READ_RESERVED:  
  43.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_READ_RESERVED\n")));  
  44.          return FALSE;  
  45.    
  46.      case IOCTL_FMD_WRITE_RESERVED:  
  47.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_WRITE_RESERVED\n")));  
  48.          return FALSE;  
  49.    
  50.      case IOCTL_FMD_GET_RESERVED_TABLE:  
  51.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_GET_RESERVED_TABLE\n")));  
  52.          return FALSE;  
  53.    
  54.      case IOCTL_FMD_SET_REGION_TABLE:  
  55.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_SET_REGION_TABLE\n")));  
  56.          return FALSE;  
  57.    
  58.      case IOCTL_FMD_SET_SECTORSIZE:  
  59.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_SET_SECTORSIZE\n")));  
  60.          return FALSE;  
  61.    
  62.      case IOCTL_FMD_RAW_WRITE_BLOCKS:  
  63.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_RAW_WRITE_BLOCKS\n")));  
  64.          return FALSE;  
  65.    
  66.      case IOCTL_FMD_GET_RAW_BLOCK_SIZE:  
  67.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_GET_RAW_BLOCK_SIZE\n")));  
  68.          return FALSE;  
  69.    
  70.      case IOCTL_FMD_GET_INFO:  
  71.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_GET_INFO\n")));  
  72.          return FALSE;  
  73.    
  74.      case  IOCTL_FMD_SET_XIPMODE    :  
  75.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_SET_XIPMODE\n")));  
  76.          return FALSE;  
  77.    
  78.      case  IOCTL_FMD_GET_XIPMODE:  
  79.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_GET_XIPMODE\n")));  
  80.          return FALSE;  
  81.    
  82.      case  IOCTL_DISK_FLUSH_CACHE:  
  83.          //RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_DISK_FLUSH_CACHE\n")));  
  84.          return TRUE;  
  85.    
  86.      default:  
  87.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_OEMIoControl() : Unknown IOCTL (0x%08x)\n"), dwIoControlCode));  
  88.          return FALSE;  
  89.      }  
  90.    
  91.      return TRUE;  
  92.  }  
  93.    
  94.  BOOL FMD_Deinit(PVOID hFMD)  
  95.  {  
  96.  #if (NAND_DEBUG)  
  97.      RETAILMSG(1, (TEXT("[FMD] FMD_Deinit() \n")));  
  98.  #endif  
  99.    
  100.      return(TRUE);  
  101.  }  
  102.    
  103.    
  104.  /* 
  105.      @func   BOOL | FMD_GetInfo | Provides information on the NAND flash. 
  106.      @rdesc  TRUE = Success, FALSE = Failure. 
  107.      @comm 
  108.      @xref 
  109.  */  
  110.  BOOL FMD_GetInfo(PFlashInfo pFlashInfo)  
  111.  {  
  112.     // Add by AlexLee RunNo[5]  
  113.      UINT32  nCnt;  
  114.      UINT32 nNandID;  
  115.      UINT8 nMID, nDID;  
  116.    
  117.      if (pFlashInfo == NULL)  
  118.      {  
  119.          RETAILMSG(1, (TEXT("[FMD:ERR] FMD_GetInfo() : Invalid Parameter\n")));  
  120.          return(FALSE);  
  121.      }  
  122.    
  123.      pFlashInfo->flashType = NAND;  
  124.    
  125.  #ifdef    SYNC_OP  
  126.      EnterCriticalSection(&g_csNandFlash);  
  127.  #endif  
  128.    
  129.      nNandID = ReadFlashID();  
  130.    
  131.  #ifdef    SYNC_OP  
  132.      LeaveCriticalSection(&g_csNandFlash);  
  133.  #endif  
  134.    
  135.      nMID = nNandID >> 8;  
  136.      nDID = nNandID & 0xff;  
  137.    
  138.      for (nCnt = 0; astNandSpec[nCnt].nMID != 0; nCnt++)  
  139.      {  
  140.          if (nDID == astNandSpec[nCnt].nDID)  
  141.          {  
  142.              break;  
  143.          }  
  144.      }  
  145.    
  146.      //  OK, instead of reading it from the chip, we use the hardcoded  
  147.      //  numbers here.  
  148.    
  149.      pFlashInfo->dwNumBlocks         = NUM_OF_BLOCKS;  
  150.      pFlashInfo->wSectorsPerBlock    = PAGES_PER_BLOCK;  
  151.      pFlashInfo->wDataBytesPerSector = NAND_SECTOR_SIZE;  
  152.      pFlashInfo->dwBytesPerBlock     = (PAGES_PER_BLOCK * NAND_SECTOR_SIZE);  
  153.    
  154.      //RETAILMSG(1, (TEXT("[FMD] FMD_GetInfo() : NUMBLOCKS = %d(0x%x), SECTORSPERBLOCK = %d(0x%x), BYTESPERSECTOR = %d(0x%x) \n"), pFlashInfo->dwNumBlocks, pFlashInfo->dwNumBlocks, pFlashInfo->wSectorsPerBlock, pFlashInfo->wSectorsPerBlock, pFlashInfo->wDataBytesPerSector, pFlashInfo->wDataBytesPerSector)); // del by alexlee  
  155.    
  156.      return TRUE;  
  157.  }  
  158.    
  159.    
  160.  /* 
  161.      @func   DWORD | FMD_GetBlockStatus | Returns the status of the specified block. 
  162.      @rdesc  Block status (see fmd.h). 
  163.      @comm 
  164.      @xref 
  165.  */  
  166.  DWORD FMD_GetBlockStatus(BLOCK_ID blockID)  
  167.  {  
  168.      DWORD dwResult = 0;  
  169.    
  170.  #if (NAND_DEBUG)  
  171.      RETAILMSG(1, (TEXT("[FMD] ++FMD_GetBlockStatus(0x%08x) \n"), blockID));  
  172.  #endif  
  173.    
  174.  #ifdef    SYNC_OP  
  175.      EnterCriticalSection(&g_csNandFlash);  
  176.  #endif  
  177.    
  178.      if ( IS_LB )  
  179.      {  
  180.          dwResult = FMD_LB_GetBlockStatus(blockID);  
  181.      }  
  182.      else  
  183.      {  
  184.          dwResult = FMD_SB_GetBlockStatus(blockID);  
  185.      }  
  186.    
  187.  #ifdef    SYNC_OP  
  188.      LeaveCriticalSection(&g_csNandFlash);  
  189.  #endif  
  190.    
  191.  #if (NAND_DEBUG)  
  192.      RETAILMSG(1, (TEXT("[FMD] --FMD_GetBlockStatus()\n")));  
  193.  #endif  
  194.    
  195.      return dwResult;  
  196.  }  
  197.    
  198.    
  199.  /* 
  200.      @func   BOOL | FMD_SetBlockStatus | Marks the block with the specified block status. 
  201.      @rdesc  TRUE = Success, FALSE = Failure. 
  202.      @comm 
  203.      @xref 
  204.  */  
  205.  BOOL FMD_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)  
  206.  {  
  207.      BOOL    bRet = TRUE;  
  208.    
  209.  #if (NAND_DEBUG)  
  210.      RETAILMSG(1, (TEXT("[FMD] ++FMD_SetBlockStatus(0x%08x, 0x%08x) \n"), blockID, dwStatus));  
  211.  #endif  
  212.    
  213.  #ifdef    SYNC_OP  
  214.      EnterCriticalSection(&g_csNandFlash);  
  215.  #endif  
  216.    
  217.      if ( IS_LB )  
  218.      {  
  219.          bRet = FMD_LB_SetBlockStatus(blockID, dwStatus);  
  220.      }  
  221.      else  
  222.      {  
  223.          bRet = FMD_SB_SetBlockStatus(blockID, dwStatus);  
  224.      }  
  225.    
  226.  #ifdef    SYNC_OP  
  227.      LeaveCriticalSection(&g_csNandFlash);  
  228.  #endif  
  229.    
  230.  #if (NAND_DEBUG)  
  231.      RETAILMSG(1, (TEXT("[FMD] --FMD_SetBlockStatus()\n")));  
  232.  #endif  
  233.    
  234.      return bRet;  
  235.  }  
  236.    


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

接着上一篇

 

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

[cpp] 
  1. BOOL ECC_CorrectData(SECTOR_ADDR sectoraddr, LPBYTE pData, UINT32 nRetEcc, ECC_CORRECT_TYPE nType)  
  2. {  
  3.     DWORD  nErrDataNo;  
  4.     DWORD  nErrBitNo;  
  5.     //BYTE Status;  
  6.     BYTE nErrDataNum;  
  7.     UINT8  nErrByteNum;  
  8.     UINT8 countdown = 155;  
  9.     BOOL bRet = TRUE;  
  10.   
  11.     //RETAILMSG(1, (TEXT("#### FMD_DRIVER:::ECC_CorrectData %x, %x, %x\n"), sectoraddr, nRetEcc, nType));  
  12.   
  13. #if 0  
  14.     if( (nRetEcc & NF_ECC8ERR0_ECC_READY) )  
  15.         return TRUE;  
  16. #endif  
  17.     // 8bit ECC error searching engine needs mini mum 372 cycles to find any error  
  18.     countdown = 372;  
  19.     while(countdown--);  
[cpp] 
  1. // 等待ECC错误查找完毕  
  2. while(NF_ECC8_ERR0 & 0x80000000);  
[cpp] 
  1. // 获取8bit ECC解码结果  
  2. nErrDataNum = NF_ECC8BIT_NUM;  
  3.   
  4. // No error, if free page (all 0xff)  
  5. if( (g_pNFConReg->NF8ECCERR0 >> 29) & 0x1 ){  
  6.     nErrDataNum = 0;  
  7. }  
  8.   
  9. if (nErrDataNum == 0)  
  10. {  
  11.     bRet = TRUE;  
  12.     RETAILMSG(0,(TEXT("No Error\n")));  
  13.     goto finished;  
  14. }  
  15. else if (nErrDataNum == 9)  
  16. {  
  17.     bRet = FALSE;  
  18.     RETAILMSG(1,(TEXT("More than 8-bit error, uncorrectable\n")));  
  19.     goto finished;  
  20. }  
  21. else if (nErrDataNum > 9)  
  22. {  
  23.     bRet = FALSE;  
  24.     RETAILMSG(1,(TEXT("Reserved\n")));  
  25.     goto finished;  
  26. }  
  27. else  
  28. {  
[cpp] 
  1. // 获取错误位对应的位置  
  2. for (nErrByteNum = 1; nErrByteNum <= nErrDataNum; nErrByteNum++)  
  3. {  
  4.     switch(nErrByteNum)  
  5.     {  
  6.     case 1:     nErrDataNo = NF_ECC8LOCATION_BYTE1;  
  7.         break;  
  8.     case 2:     nErrDataNo = NF_ECC8LOCATION_BYTE2;  
  9.         break;  
  10.     case 3:     nErrDataNo = NF_ECC8LOCATION_BYTE3;  
  11.         break;  
  12.     case 4:     nErrDataNo = NF_ECC8LOCATION_BYTE4;  
  13.         break;  
  14.     case 5:     nErrDataNo = NF_ECC8LOCATION_BYTE5;  
  15.         break;  
  16.     case 6:     nErrDataNo = NF_ECC8LOCATION_BYTE6;  
  17.         break;  
  18.     case 7:     nErrDataNo = NF_ECC8LOCATION_BYTE7;  
  19.         break;  
  20.     case 8:     nErrDataNo = NF_ECC8LOCATION_BYTE8;  
  21.         break;  
  22.     default:break;  
  23.     }  
[cpp] 
  1. // 定位到具体错误位的位置  
  2. nErrBitNo = NF_ECC8LOCATION_BIT(nErrByteNum);  
[cpp] 
  1.         // 矫正错误位  
  2.         (pData)[nErrDataNo] ^= (1<<nErrBitNo);     
  3.         RETAILMSG(1, (TEXT("8bit ECC_CorrectData %x, %x, %x, %x\n"), nErrDataNum, nErrByteNum, nErrDataNo, nErrBitNo));  
  4.     }  
  5. }  
  6.   
  7. inished:  
  8.    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()

原来的代码:

[cpp] 
  1. BOOL FMD_LB_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)  
  2. {  
  3.     ULONG SectorAddr = (ULONG)startSectorAddr;  
  4.     DWORD       i, j;  
  5.     volatile DWORD        rddata;  
  6.     UINT32 nRetEcc = 0;  
  7.     DWORD MECCBuf[16],tempMECCBuf[2];  // gjl 8  
  8.     UINT16 nSectorLoop,nSectorLoop1;  
  9.     int NewSpareAddr = 4096;  //gjl 2048  
  10.     int NewDataAddr = 0;  
  11.     int NewSectorAddr = startSectorAddr;  
  12.     int SectorSpareAddr;  
  13.     UINT8 TempSectorInfo[40];  
  14.     BYTE *pSectorBuff1 = (BYTE *)pSectorBuff;  
  15.     UINT16 k=40;  
  16. #if CHECK_SPAREECC  
  17.     DWORD SECCBuf[4];   // gjl 2  
  18. #endif  
  19.   
  20. #if (NAND_DEBUG)  
  21.     RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_LB_READSECTOR %x %x\n"),startSectorAddr,NewDataAddr));  
  22. #endif  
  23.   
  24.     if (!pSectorBuff && !pSectorInfoBuff)  
  25.     {  
  26.         return(FALSE);  
  27.     }  
  28.   
  29.   
  30.         if ( dwNumSectors > 1 )  
  31.     {  
  32.         RETAILMSG(1, (TEXT("######## FATAL ERROR => FMD::FMD_ReadSector->dwNumsectors is bigger than 1. \n")));  
  33.         return FALSE;  
  34.     }  
  35.   
  36.   
  37.       
  38.     if (!pSectorBuff)  
  39.     {  
  40.         if (!NAND_LB_ReadSectorInfo(startSectorAddr, pSectorInfoBuff))  
  41.         {  
  42.             #if (NAND_DEBUG)  
  43.                 RETAILMSG(1,(TEXT("#### FMD_DRIVER:::54321\n")));  
  44.             #endif  
  45.       
  46.             return FALSE;  
  47.         }  
  48.         #if (NAND_DEBUG)  
  49.             RETAILMSG(1,(TEXT("#### FMD_DRIVER:::12345\n")));  
  50.         #endif  
  51.       
  52.         return TRUE;  
  53.     }  
  54.   
  55.   
  56.     NF_nFCE_L();  
  57.   
  58.     NF_CLEAR_RB();  
  59.   
  60.     NF_CMD(CMD_READ);                            // Send read command.  
  61.   
  62.     NF_ADDR((NewSpareAddr)&0xff);  
  63.     NF_ADDR((NewSpareAddr>>8)&0xff);  
  64.     NF_ADDR((NewSectorAddr) & 0xff);  
  65.     NF_ADDR((NewSectorAddr >> 8) & 0xff);  
  66. #if    LB_NEED_EXT_ADDR  
  67.     NF_ADDR((NewSectorAddr >> 16) & 0xff);  
  68. #endif  
  69.   
  70.     NF_CMD(CMD_READ3);                        // 2nd command  
  71.   
  72.     NF_DETECT_RB();                                // Wait for command to complete.  
  73.   
  74.     NF_MSGLENGTH_512();  
  75.     NF_ECCTYPE_4BIT();  
  76.       
  77.     if (pSectorInfoBuff)  
  78.     {  
  79.   
  80.         pSectorInfoBuff->bBadBlock = NF_RDDATA_BYTE();  
  81.         pSectorInfoBuff->dwReserved1 = NF_RDDATA_WORD();  
  82.         pSectorInfoBuff->bOEMReserved = NF_RDDATA_BYTE();  
  83.   
  84.         pSectorInfoBuff->wReserved2 = NF_RDDATA_BYTE();  
  85.         pSectorInfoBuff->wReserved2 |= (NF_RDDATA_BYTE()<<8);  
  86.     }  
  87.     else  
  88.     {  
  89.          for(i=0; i<sizeof(SectorInfo)/sizeof(DWORD); i++)  
  90.          {  
  91.             rddata = (DWORD) NF_RDDATA_WORD();        // read and trash the data  
  92.          }  
  93.     }  
  94.   
  95.     for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*2; nSectorLoop++)  
  96.     {  
  97.         MECCBuf[nSectorLoop] = NF_RDDATA_WORD();  
  98.     }  
  99.   
  100. #if DEBUG_WRITE_READ_EQUAL  
  101.     for (nSectorLoop = 0; nSectorLoop < 8; nSectorLoop++)  
  102.     {  
  103.         g_MECCBuf_R[nSectorLoop] = MECCBuf[nSectorLoop];  
  104.     }  
  105. #endif  
  106.   
  107.   
  108.       
  109.     for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE; nSectorLoop++)  
  110.     {  
  111.         NewDataAddr = nSectorLoop * SECTOR_SIZE;  
  112.   
  113.         NF_CMD(CMD_RDO);                            // Send read command.  
  114.         NF_ADDR((NewDataAddr)&0xff);  
  115.         NF_ADDR((NewDataAddr>>8)&0xff);  
  116.         NF_CMD(CMD_RDO2);    // 2nd command  
  117.   
  118.   
  119.         NF_MSGLENGTH_512();  
  120.         NF_ECCTYPE_4BIT();  
  121.   
  122.         NF_RSTECC();  
  123.         NF_MECC_UnLock();  
  124.   
  125.         if( ((DWORD) (pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)  
  126.         {  
  127.             for(i=0; i<SECTOR_SIZE/sizeof(DWORD); i++)  
  128.             {  
  129.                 rddata = (DWORD) NF_RDDATA_WORD();  
  130.                 (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0] = (BYTE)(rddata & 0xff);  
  131.                 (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1] = (BYTE)(rddata>>8 & 0xff);  
  132.                 (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2] = (BYTE)(rddata>>16 & 0xff);  
  133.                 (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3] = (BYTE)(rddata>>24 & 0xff);  
  134.             }  
  135.         }  
  136.         else  
  137.         {  
  138.             RdPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);                    // Read page/sector data.  
  139.         }  
  140.   
  141.         SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8;  
  142.         NF_WRDATA_WORD(MECCBuf[2*nSectorLoop]);  
  143.         SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8+4;  
  144.         NF_WRDATA_WORD(MECCBuf[2*nSectorLoop+1]);  
  145.         NF_MECC_Lock();  
  146.   
  147.         //decode done  
  148.         while (!(NF_RDSTAT & (1<<6)));  
  149.         tempMECCBuf[0]= NF_RDMECC0();  
  150.         tempMECCBuf[1] = NF_RDMECC1();  
  151.   
  152.         pSectorBuff1 = pSectorBuff+nSectorLoop*SECTOR_SIZE;  
  153.   
  154.         if (!ECC_CorrectData(startSectorAddr, pSectorBuff1, nRetEcc, ECC_CORRECT_MAIN))  
  155.         {  
  156.             RETAILMSG(1,(TEXT("ECC ERROR\n")));  
  157.             return FALSE;  
  158.         }  
  159.     }  
  160.   
  161.     NF_nFCE_H();  
  162.   
  163.   
  164.       
  165.     return TRUE;  
  166. }  

这个是飞凌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);
}

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

[cpp] 
  1. g_pNFConReg->NFCONT |= (1<<10);    // Enable illegal access interrupt control  
  2. g_pNFConReg->NFCONT |= (1<<9); // Enable RnB interrupt  
  3. 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(); 修改成

[cpp] 
  1. 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字节,所以修改成:

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

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

就是

    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(); 修改成:

[cpp] 
  1. NF_ECCTYPE_8BIT();  

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

[cpp] 
  1. NF_ECC_8BIT_STOP(); // init 8bit ECC decoding  
  2. NF_ECC_DIRECTION_IN();  // 4/8BIT ECC Decoding, read page  

接下来,原代码是:

        NF_RSTECC();

        NF_MECC_UnLock();

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

[cpp] 
  1. NF_MECC_UnLock();  
  2. 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的:

[cpp] 
  1. SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8;  
  2. NF_WRDATA_WORD(MECCBuf[4*nSectorLoop]);  
  3. SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8+4;  
  4. NF_WRDATA_WORD(MECCBuf[4*nSectorLoop+1]);  
  5. SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8+8;  
  6. NF_WRDATA_WORD(MECCBuf[4*nSectorLoop+2]);  
  7. SectorSpareAddr = NewSpareAddr+8+nSectorLoop*8+12;  
  8. NF_WRDATA_WORD(MECCBuf[4*nSectorLoop+3]);  
  9. 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 ERROR\n")));
            return FALSE;
        }
    }

 

    NF_nFCE_H();

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

[cpp] 
  1. g_pNFConReg->NFCONT &= ~(1<<10);   // Disable illegal access interrupt control  
  2. g_pNFConReg->NFCONT &= ~(1<<9);        // Disable RnB interrupt  

 

 

 

3、NAND_LB_ReadSectorInfo()

原BSP代码:

[cpp] 
  1. BOOL NAND_LB_ReadSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)  
  2. {  
  3.     BOOL bRet = TRUE;  
  4.     int NewSpareAddr = 4096;  //gjl 2048  
  5.     int NewSectorAddr = sectorAddr;  
  6.     DWORD MECCBuf[16];  // gjl 8  
  7.     UINT16 nSectorLoop, i;  
  8.     UINT8 TempInfo[40];  
  9. #if CHECK_SPAREECC  
  10.     DWORD SECCBuf[4];   //gjl 2  
  11.     UINT32 nRetEcc = 0;  
  12. #endif  
  13.   
  14.     NF_nFCE_L();  
  15.   
  16.     NF_CLEAR_RB();  
  17.   
  18.     NF_CMD(CMD_READ);                            // Send read confirm command.  
  19.   
  20.     NF_ADDR((NewSpareAddr)&0xff);  
  21.     NF_ADDR((NewSpareAddr>>8)&0xff);  
  22.     NF_ADDR((NewSectorAddr)&0xff);  
  23.     NF_ADDR((NewSectorAddr>>8) & 0xff);  
  24. #if    LB_NEED_EXT_ADDR  
  25.     NF_ADDR((NewSectorAddr >> 16) & 0xff);  
  26. #endif  
  27.   
  28.     NF_CMD(CMD_READ3);  
  29.   
  30.     NF_DETECT_RB();  
  31.   
  32.   
  33.     pInfo->bBadBlock = NF_RDDATA_BYTE();  
  34.     pInfo->dwReserved1  = NF_RDDATA_WORD();  
  35.     pInfo->bOEMReserved = NF_RDDATA_BYTE();  
  36.       
  37.     pInfo->wReserved2 = NF_RDDATA_BYTE();  
  38.     pInfo->wReserved2 |= (NF_RDDATA_BYTE()<<8);  
  39.   
  40.     for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*2; nSectorLoop++)  
  41.     {  
  42.         MECCBuf[nSectorLoop] = NF_RDDATA_WORD();  
  43.     }  
  44.   
  45.     NF_nFCE_H();  
  46.  #if (NAND_DEBUG)  
  47.     RETAILMSG(1,(TEXT("#### FMD_DRIVER:::56565656\n")));  
  48. #endif  
  49.       
  50.     return bRet;  
  51. }  

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

这个我们要改成:

[cpp] 
  1. DWORD MECCBuf[32];  

 

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

[cpp] 
  1. NF_ECCTYPE_8BIT();      // use 8bit ECC type  
  2. NF_ECC_8BIT_STOP(); // init 8bit ECC decoding  

 

然后,又看到读取ECC的操作:

    for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*2; nSectorLoop++)
    {
        MECCBuf[nSectorLoop] = NF_RDDATA_WORD();
    }

这个,我们需要改成:

[cpp] 
  1. for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*4; nSectorLoop++)  
  2. {  
  3.     MECCBuf[nSectorLoop] = NF_RDDATA_WORD();  
  4. }  

 

 

4、FMD_SB_ReadSector()

[cpp] 
  1. BOOL FMD_SB_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)  
  2. {  
  3.     ULONG SectorAddr = (ULONG)startSectorAddr;  
  4.     ULONG MECC;  
  5.     UINT32 nRet = TRUE;  
  6.     UINT32 nRetEcc = 0;  
  7.   
  8. #if (NAND_DEBUG)  
  9.     RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_sbreadT \n")));  
  10. #endif  
  11.   
  12.     if (!pSectorBuff && !pSectorInfoBuff)  
  13.     {  
  14.         RETAILMSG(1,(TEXT("[FMD:ERR] FMD_SB_ReadSector(0x%08x, 0x%08x) : Invalid Parameter\n"), pSectorBuff, pSectorInfoBuff));  
  15.         return(FALSE);  
  16.     }  
  17.   
  18.     while (dwNumSectors--)  
  19.     {  
  20.         NF_RSTECC();  
  21.         NF_MECC_UnLock();  
  22.         NF_nFCE_L();  
  23.   
  24.         if (!pSectorBuff)  
  25.         {  
  26.             NF_CLEAR_RB();  
  27.             NF_CMD(CMD_READ2);            // Send read confirm command.  
  28.   
  29.             NF_ADDR(0);                                    // Ignored.  
  30.             NF_ADDR(SectorAddr         & 0xff);            // Page address.  
  31.             NF_ADDR((SectorAddr >>  8) & 0xff);  
  32. #if    SB_NEED_EXT_ADDR  
  33.             NF_ADDR((SectorAddr >> 16) & 0xff);  
  34. #endif  
  35.   
  36.             NF_DETECT_RB();  
  37.   
  38.             RdPageInfo((PBYTE)pSectorInfoBuff);    // Read page/sector information.  
  39.   
  40.             pSectorInfoBuff++;  
  41.         }  
  42.         else  
  43.         {  
  44.             NF_CLEAR_RB();  
  45.   
  46.             NF_CMD(CMD_READ);                    // Send read command.  
  47.   
  48.             NF_ADDR(0);                                    // Column = 0.  
  49.             NF_ADDR(SectorAddr         & 0xff);            // Page address.  
  50.             NF_ADDR((SectorAddr >>  8) & 0xff);  
  51. #if    SB_NEED_EXT_ADDR  
  52.             NF_ADDR((SectorAddr >> 16) & 0xff);  
  53. #endif  
  54.   
  55.             NF_DETECT_RB();                    // Wait for command to complete.  
  56.   
  57.             if( ((DWORD) pSectorBuff) & 0x3)  
  58.             {  
  59.                 RdPage512Unalign (pSectorBuff);  
  60.             }  
  61.             else  
  62.             {  
  63.                 RdPage512(pSectorBuff);                    // Read page/sector data.  
  64.             }  
  65.   
  66.             NF_MECC_Lock();  
  67.   
  68.             if (pSectorInfoBuff)  
  69.             {  
  70.                 RdPageInfo((PBYTE)pSectorInfoBuff);        // Read page/sector information.  
  71.                 pSectorInfoBuff ++;  
  72.             }  
  73.             else  
  74.             {  
  75.                 BYTE TempInfo[8];  
  76.                 RdPageInfo(TempInfo);                       // Read page/sector information.  
  77.             }  
  78.   
  79.             MECC  = NF_RDDATA_BYTE() << 0;  
  80.             MECC |= NF_RDDATA_BYTE() << 8;  
  81.             MECC |= NF_RDDATA_BYTE() << 16;  
  82.             MECC |= (NF_RDMECC0() &0xff000000);  
  83.             //MECC |= NF_RDDATA_BYTE() << 24;  
  84.   
  85.             NF_WRMECCD0( ((MECC&0xff00)<<8)|(MECC&0xff) );  
  86.              NF_WRMECCD1( ((MECC&0xff000000)>>8)|((MECC&0xff0000)>>16) );  
  87.   
  88.              nRetEcc = NF_ECC_ERR0;  
  89.   
  90.             switch(nRetEcc & 0x3)  
  91.             {  
  92.                 case 0:    // No Error  
  93.                     nRet = TRUE;  
  94.                     break;  
  95.                 case 1:    // 1-bit Error(Correctable)  
  96.                     RETAILMSG(1,(TEXT("ECC correctable error(0x%x)\n"), SectorAddr));  
  97.                     (pSectorBuff)[(nRetEcc>>7)&0x7ff] ^= (1<<((nRetEcc>>4)&0x7));  
  98.                     nRet = TRUE;  
  99.                     break;  
  100.                 case 2:    // Multiple Error  
  101.                     RETAILMSG(1,(TEXT("ECC Uncorrectable error(0x%x)\n"), SectorAddr));  
  102.                     nRet = FALSE;  
  103.                     break;  
  104.                 case 3:    // ECC area Error  
  105.                     RETAILMSG(1,(TEXT("ECC area error\n")));  
  106.                 default:  
  107.                     nRet = FALSE;  
  108.                     break;  
  109.             }  
  110.             pSectorBuff += NAND_SECTOR_SIZE;  
  111.         }  
  112.         NF_nFCE_H();  
  113.         ++SectorAddr;  
  114.     }  
  115.   
  116.     return(nRet);  
  117. }  

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

 

 

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

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

 

1、FMD_LB_WriteSector()  MLC写sector

[cpp] 
  1. BOOL FMD_LB_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)  
  2. {  
  3.     DWORD   i;  
  4.     BOOL    bRet = TRUE;  
  5.     volatile DWORD    wrdata;  
  6.     DWORD MECCBuf[16];    // 16 gjl   
  7.     UINT16 nSectorLoop;  
  8.     int NewSpareAddr = 4096;  // 2048 gjl  
  9.     int NewDataAddr = 0;  
  10.     int NewSectorAddr = startSectorAddr;  
  11. #if CHECK_SPAREECC  
  12.     DWORD SECCBuf[4];    // 2 gjl   
  13. #endif  
  14.   
  15. #if (NAND_DEBUG)  
  16.     RETAILMSG(1, (TEXT("FMD::FMD_LB_WriteSector 0x%x \n"), startSectorAddr));  
  17. #endif  
  18.   
  19.     if (!pSectorBuff && !pSectorInfoBuff)  
  20.         return(FALSE);  
  21.   
  22.     if ( dwNumSectors > 1 )  
  23.     {  
  24.         RETAILMSG(1, (TEXT("######## FATAL ERROR => FMD::FMD_WriteSector->dwNumsectors is bigger than 1. \n")));  
  25.         return FALSE;  
  26.     }  
  27.   
  28.     if (!pSectorBuff)  
  29.     {  
  30.         NAND_LB_WriteSectorInfo(startSectorAddr, pSectorInfoBuff);  
  31.         return TRUE;  
  32.     }  
  33.   
  34.     //  Enable Chip  
  35.     NF_nFCE_L();  
  36.   
  37.     NF_CLEAR_RB();  
  38.   
  39.     //  Issue command  
  40.     NF_CMD(CMD_WRITE);  
  41.       
  42.     //  Setup address  
  43.     NF_ADDR((NewDataAddr)&0xff);  
  44.     NF_ADDR((NewDataAddr>>8)&0xff);  
  45.     NF_ADDR((NewSectorAddr)&0xff);  
  46.     NF_ADDR((NewSectorAddr>>8)&0xff);  
  47. #if    LB_NEED_EXT_ADDR  
  48.     NF_ADDR((NewSectorAddr>>16)&0xff);  
  49. #endif  
  50.   
  51.     for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE; nSectorLoop++)  
  52.     {  
  53.         //  Initialize ECC register  
  54.         NF_MSGLENGTH_512();  
  55.         NF_ECCTYPE_4BIT();  
  56.   
  57.         NF_RSTECC();  
  58.         NF_MECC_UnLock();  
  59.   
  60.         //  Special case to handle un-aligned buffer pointer.  
  61.         //  
  62.         if( ((DWORD) (pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)  
  63.         {  
  64.             //  Write the data  
  65.             for(i=0; i<SECTOR_SIZE/sizeof(DWORD); i++)  
  66.             {  
  67.                 wrdata = (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0];  
  68.                 wrdata |= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]<<8;  
  69.                 wrdata |= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]<<16;  
  70.                 wrdata |= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]<<24;  
  71.                 NF_WRDATA_WORD(wrdata);  
  72.             }  
  73.         }  
  74.         else  
  75.         {  
  76.             WrPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);  
  77.         }  
  78.   
  79.         //  Read out the ECC value generated by HW  
  80.         NF_MECC_Lock();  
  81.         //encode done  
  82.         while (!(NF_RDSTAT & (1<<7)));  
  83.   
  84.         MECCBuf[2*nSectorLoop] = NF_RDMECC0();  
  85.         MECCBuf[2*nSectorLoop+1] = NF_RDMECC1();  
  86. #if DEBUG_WRITE_READ_EQUAL  
  87.     g_MECCBuf[2*nSectorLoop] = MECCBuf[2*nSectorLoop];  
  88.     g_MECCBuf[2*nSectorLoop+1] = MECCBuf[2*nSectorLoop+1];  
  89. #endif  
  90.     }  
  91.   
  92.     NF_CMD(CMD_RDI);  
  93.     NF_ADDR((NewSpareAddr)&0xff);  
  94.     NF_ADDR((NewSpareAddr>>8)&0xff);  
  95.   
  96.     // Write the SectorInfo data to the media  
  97.     // NOTE: This hardware is odd: only a byte can be written at a time and it must reside in the  
  98.     //       upper byte of a USHORT.  
  99.     if(pSectorInfoBuff)  
  100.     {  
  101.   
  102.         //  Write the first reserved field (DWORD)  
  103.         NF_WRDATA_BYTE(pSectorInfoBuff->bBadBlock);  
  104.         NF_WRDATA_WORD(pSectorInfoBuff->dwReserved1);  
  105.         NF_WRDATA_BYTE(pSectorInfoBuff->bOEMReserved);  
  106.   
  107.         NF_WRDATA_BYTE(pSectorInfoBuff->wReserved2&0xff);  
  108.         NF_WRDATA_BYTE((pSectorInfoBuff->wReserved2>>8)&0xff);  
  109.     }  
  110.     else  
  111.     {  
  112.         // Make sure we advance the Flash's write pointer (even though we aren't writing the SectorInfo data)  
  113.         for(i=0; i<sizeof(SectorInfo)/sizeof(DWORD); i++)  
  114.         {  
  115.             NF_WRDATA_WORD(0xffffffff);  
  116.         }  
  117.     }  
  118.   
  119.     //  Write the ECC value to the flash  
  120.     for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*2; nSectorLoop++)  
  121.         NF_WRDATA_WORD(MECCBuf[nSectorLoop]);  
  122.   
  123.     //  Finish up the write operation  
  124.     NF_CMD(CMD_WRITE2);  
  125.   
  126.     //  Wait for RB  
  127.     NF_DETECT_RB();     // Wait tR(max 12us)  
  128.   
  129.     if ( NF_RDSTAT & STATUS_ILLACC )  
  130.     {  
  131.         RETAILMSG(1, (TEXT("FMD_WriteSector() ######## Error Programming page (Illigar Access) %d!\n"), startSectorAddr));  
  132.         g_pNFConReg->NFSTAT =  STATUS_ILLACC;    // Write 1 to clear.  
  133.         bRet = FALSE;  
  134.     }  
  135.     else  
  136.     {  
  137.         //  Check the status  
  138.         NF_CMD(CMD_STATUS);  
  139.   
  140.         if(NF_RDDATA_BYTE() & STATUS_ERROR)  
  141.         {  
  142.             RETAILMSG(1, (TEXT("FMD_WriteSector() ######## Error Programming page %d!\n"), startSectorAddr));  
  143.             bRet = FALSE;  
  144.         }  
  145.     }  
  146.   
  147.     //  Disable the chip  
  148.     NF_nFCE_H();  
  149.   
  150.     return bRet;  
  151. }  

这个是飞凌的源码,这里需要修改成8bit的ECC。

变量定义这里需要把 DWORD MECCBuf[16]; 修改成:

[cpp] 
  1. DWORD MECCBuf[32];  

    if (!pSectorBuff)
    {
        NAND_LB_WriteSectorInfo(startSectorAddr, pSectorInfoBuff);
        return TRUE;
    }

操作之前,添加使能中断的操作:

[cpp] 
  1. g_pNFConReg->NFCONT |= (1<<10);    // Enable illegal access interrupt control  
  2. g_pNFConReg->NFCONT |= (1<<9); // Enable RnB interrupt  

for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE; nSectorLoop++)这里是循环写一个block的页数据。

        NF_MSGLENGTH_512();

        NF_ECCTYPE_4BIT();

中的 NF_ECCTYPE_4BIT(); 修改成:

[cpp] 
  1. NF_ECCTYPE_8BIT();  
  2. NF_ECC_8BIT_STOP();  
  3. NF_ECC_DIRECTION_OUT();  

//encode done

        while (!(NF_RDSTAT & (1<<7)));

处理的后面,把

        MECCBuf[2*nSectorLoop] = NF_RDMECC0();

        MECCBuf[2*nSectorLoop+1] = NF_RDMECC1();

修改成:

[cpp] 
  1. MECCBuf[4*nSectorLoop] = NF_RDM8ECC0();       
  2. MECCBuf[4*nSectorLoop+1] = NF_RDM8ECC1();     
  3. MECCBuf[4*nSectorLoop+2] = NF_RDM8ECC2();     
  4. MECCBuf[4*nSectorLoop+3] = NF_RDM8ECC3() & 0xff;  

在for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE; nSectorLoop++)循环结束的后面,

NF_CMD(CMD_RDI);

    NF_ADDR((NewSpareAddr)&0xff);
    NF_ADDR((NewSpareAddr>>8)&0xff);

操作之前,添加:

[cpp] 
  1. NF_ECCTYPE_8BIT();  
  2. NF_ECC_8BIT_STOP();  

看到写入ECC数据部分:

    //  Write the ECC value to the flash

    for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*2; nSectorLoop++)
        NF_WRDATA_WORD(MECCBuf[nSectorLoop]);

这里需要把for修改成:

[cpp] 
  1. for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*4; nSectorLoop++)  

在片选操作 

   //  Disable the chip

    NF_nFCE_H();

之前添加:

[cpp] 
  1. g_pNFConReg->NFCONT &= ~(1<<10);   // Disable illegal access interrupt control  
  2. g_pNFConReg->NFCONT &= ~(1<<9);        // Disable RnB interrupt  

到此,写入部分修改完毕

 

 

 

2、NAND_LB_WriteSectorInfo()   写sector信息

[cpp] 
  1. BOOL NAND_LB_WriteSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)  
  2. {  
  3.     BOOL    bRet = TRUE;  
  4.     int NewSpareAddr = 4096;   // gjl 2048  
  5.     int NewSectorAddr = sectorAddr;  
  6. #if CHECK_SPAREECC  
  7.     DWORD SECCBuf[4];    // gjl 2  
  8. #endif  
  9.   
  10.     //  Chip enable  
  11.     NF_nFCE_L();  
  12.   
  13.     NF_CLEAR_RB();  
  14.   
  15.     //  Write the command  
  16.     //  First, let's point to the spare area  
  17.     NF_CMD(CMD_WRITE);  
  18.       
  19.     //  Write the address  
  20.     NF_ADDR((NewSpareAddr)&0xff);  
  21.     NF_ADDR((NewSpareAddr>>8)&0xff);  
  22.     NF_ADDR((NewSectorAddr)&0xff);  
  23.     NF_ADDR((NewSectorAddr>>8)&0xff);  
  24. #if    LB_NEED_EXT_ADDR  
  25.     NF_ADDR((NewSectorAddr>>16)&0xff);  
  26. #endif  
  27.     NF_MSGLENGTH_512();  
  28.     NF_ECCTYPE_4BIT();  
  29.   
  30.   
  31.     //  Now let's write the SectorInfo data  
  32.     //  
  33.     //  Write the first reserved field (DWORD)  
  34.     NF_WRDATA_BYTE(pInfo->bBadBlock);  
  35.     NF_WRDATA_WORD(pInfo->dwReserved1);  
  36.     NF_WRDATA_BYTE(pInfo->bOEMReserved);  
  37.   
  38.     NF_WRDATA_BYTE(pInfo->wReserved2&0xff);  
  39.     NF_WRDATA_BYTE((pInfo->wReserved2>>8)&0xff);  
  40.   
  41.     NF_WRDATA_WORD(0xffffffff);  // Mecc[0]  
  42.     NF_WRDATA_WORD(0xffffffff);  // Mecc[1]  
  43.     NF_WRDATA_WORD(0xffffffff);  // Mecc[2]  
  44.     NF_WRDATA_WORD(0xffffffff);  // Mecc[3]  
  45.     NF_WRDATA_WORD(0xffffffff);  // Mecc[4]  
  46.     NF_WRDATA_WORD(0xffffffff);  // Mecc[5]  
  47.     NF_WRDATA_WORD(0xffffffff);  // Mecc[6]  
  48.     NF_WRDATA_WORD(0xffffffff);  // Mecc[7]  
  49.      
  50.   
  51.     //  Issue the write complete command  
  52.     NF_CMD(CMD_WRITE2);  
  53.   
  54.     //  Check ready bit  
  55.     NF_DETECT_RB();     // Wait tR(max 12us)  
  56.   
  57.     if ( NF_RDSTAT & STATUS_ILLACC )  
  58.     {  
  59.         RETAILMSG(1, (TEXT("NAND_LB_WriteSectorInfo() ######## Error Programming page (Illigar Access) %d!\n"), sectorAddr));  
  60.         g_pNFConReg->NFSTAT =  STATUS_ILLACC;    // Write 1 to clear.  
  61.            bRet = FALSE;  
  62.     }  
  63.     else  
  64.     {  
  65.         //  Check the status of program  
  66.         NF_CMD(CMD_STATUS);  
  67.   
  68.         if( NF_RDDATA_BYTE() & STATUS_ERROR) {  
  69.             RETAILMSG(1, (TEXT("NAND_LB_WriteSectorInfo() ######## Error Programming page %d!\n"), sectorAddr));  
  70.             bRet = FALSE;  
  71.         }  
  72.     }  
  73.   
  74.     NF_nFCE_H();  
  75.   
  76.     return bRet;  
  77. }  

这个是飞凌给的源码,从上面可以看出也是只用到了4bit的ECC。下面我们将其改成8bit的ECC:

看到

    NF_MSGLENGTH_512();
    NF_ECCTYPE_4BIT();

这两个处理,我们把其中的 NF_ECCTYPE_4BIT(); 修改成

[cpp] 
  1. NF_ECCTYPE_8BIT();          // use 8bit ECC type  
  2. NF_ECC_8BIT_STOP();     // init 8bit ECC decoding  

然后,就开始写入sector的信息数据了,这里主要看写入主ECC数据部分,原文的是
    NF_WRDATA_WORD(0xffffffff);  // Mecc[0]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[1]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[2]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[3]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[4]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[5]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[6]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[7]

这里需要修改成:

[cpp] 
  1. // 16 byte Sector0 ECC data  
  2.    NF_WRDATA_WORD(0xffffffff);  // Mecc[0]  
  3.    NF_WRDATA_WORD(0xffffffff);  // Mecc[1]  
  4.    NF_WRDATA_WORD(0xffffffff);  // Mecc[2]  
  5.    NF_WRDATA_WORD(0xffffffff);  // Mecc[3]  
  6. // 16 byte Sector1 ECC data  
  7.    NF_WRDATA_WORD(0xffffffff);  // Mecc[4]  
  8.    NF_WRDATA_WORD(0xffffffff);  // Mecc[5]  
  9.    NF_WRDATA_WORD(0xffffffff);  // Mecc[6]  
  10.    NF_WRDATA_WORD(0xffffffff);  // Mecc[7]  
  11. // 16 byte Sector2 ECC data  
  12.    NF_WRDATA_WORD(0xffffffff);  // Mecc[8]  
  13.    NF_WRDATA_WORD(0xffffffff);  // Mecc[9]  
  14.    NF_WRDATA_WORD(0xffffffff);  // Mecc[10]  
  15.    NF_WRDATA_WORD(0xffffffff);  // Mecc[11]  
  16. // 16 byte Sector3 ECC data  
  17.    NF_WRDATA_WORD(0xffffffff);  // Mecc[12]  
  18.    NF_WRDATA_WORD(0xffffffff);  // Mecc[13]  
  19.    NF_WRDATA_WORD(0xffffffff);  // Mecc[14]  
  20.    NF_WRDATA_WORD(0xffffffff);  // Mecc[15]  
  21. // 16 byte Sector4 ECC data  
  22.    NF_WRDATA_WORD(0xffffffff);  // Mecc[16]  
  23.    NF_WRDATA_WORD(0xffffffff);  // Mecc[17]  
  24.    NF_WRDATA_WORD(0xffffffff);  // Mecc[18]  
  25.    NF_WRDATA_WORD(0xffffffff);  // Mecc[19]  
  26. // 16 byte Sector5 ECC data  
  27.    NF_WRDATA_WORD(0xffffffff);  // Mecc[20]  
  28.    NF_WRDATA_WORD(0xffffffff);  // Mecc[21]  
  29.    NF_WRDATA_WORD(0xffffffff);  // Mecc[22]  
  30.    NF_WRDATA_WORD(0xffffffff);  // Mecc[23]  
  31. // 16 byte Sector6 ECC data  
  32.    NF_WRDATA_WORD(0xffffffff);  // Mecc[24]  
  33.    NF_WRDATA_WORD(0xffffffff);  // Mecc[25]  
  34.    NF_WRDATA_WORD(0xffffffff);  // Mecc[26]  
  35.    NF_WRDATA_WORD(0xffffffff);  // Mecc[27]  
  36. // 16 byte Sector7 ECC data  
  37.    NF_WRDATA_WORD(0xffffffff);  // Mecc[28]  
  38.    NF_WRDATA_WORD(0xffffffff);  // Mecc[29]  
  39.    NF_WRDATA_WORD(0xffffffff);  // Mecc[30]  
  40.    NF_WRDATA_WORD(0xffffffff);  // Mecc[31]  

该函数中剩余的部分就不需要修改了。

这里之所以这样修改,是因为每512字节的主数据就产生4*4字节的ECC,而我们这里每个block有4096字节,即8个512字节,也就是8 * 16个字节的ECC数据。

 

 

 

3、FMD_SB_WriteSector()

[cpp] 
  1. BOOL FMD_SB_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)  
  2. {  
  3.     BYTE Status;  
  4.     ULONG SectorAddr = (ULONG)startSectorAddr;  
  5.     ULONG MECC;  
  6.   
  7.     if (!pSectorBuff && !pSectorInfoBuff)  
  8.         return(FALSE);  
  9.   
  10. #if (NAND_DEBUG)  
  11.     RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_sbwrite \n")));  
  12. #endif  
  13.   
  14.     NF_nFCE_L();                        // Select the flash chip.  
  15.   
  16.     while (dwNumSectors--)  
  17.     {  
  18.         if (!pSectorBuff)    // Only spare area  
  19.         {  
  20.             // If we are asked just to write the SectorInfo, we will do that separately  
  21.             NF_CMD(CMD_READ2);                             // Send read command.  
  22.   
  23.             NF_CMD(CMD_WRITE);                            // Send write command.  
  24.             NF_ADDR(0);                                    // Column = 0.  
  25.             NF_ADDR(SectorAddr         & 0xff);            // Page address.  
  26.             NF_ADDR((SectorAddr >>  8) & 0xff);  
  27. #if    SB_NEED_EXT_ADDR  
  28.             NF_ADDR((SectorAddr >> 16) & 0xff);  
  29. #endif  
  30.   
  31.             // Write the SectorInfo data to the media.  
  32.             // Spare area[7:0]  
  33.             WrPageInfo((PBYTE)pSectorInfoBuff);  
  34.   
  35.             NF_CLEAR_RB();  
  36.             NF_CMD(CMD_WRITE2);                // Send write confirm command.  
  37.             NF_DETECT_RB();  
  38.   
  39.             NF_CMD(CMD_STATUS);  
  40.             Status = NF_RDDATA_BYTE();                    // Read command status.  
  41.   
  42.             if (Status & STATUS_ERROR)  
  43.             {  
  44.                 NF_nFCE_H();                            // Deselect the flash chip.  
  45.                 //SetKMode (bLastMode);  
  46.                 return(FALSE);  
  47.             }  
  48.             pSectorInfoBuff++;  
  49.         }  
  50.         else         // Main area+Spare area.  
  51.         {  
  52.             NF_CMD(CMD_READ);                             // Send read command.  
  53.             NF_CMD(CMD_WRITE);                            // Send write command.  
  54.             NF_ADDR(0);                                    // Column = 0.  
  55.             NF_ADDR(SectorAddr         & 0xff);            // Page address.  
  56.             NF_ADDR((SectorAddr >>  8) & 0xff);  
  57. #if    SB_NEED_EXT_ADDR  
  58.             NF_ADDR((SectorAddr >> 16) & 0xff);  
  59. #endif  
  60.   
  61.             //  Special case to handle un-aligned buffer pointer.  
  62.             NF_RSTECC();  
  63.             NF_MECC_UnLock();  
  64.             if( ((DWORD) pSectorBuff) & 0x3)  
  65.             {  
  66.                 WrPage512Unalign (pSectorBuff);  
  67.             }  
  68.             else  
  69.             {  
  70.                 WrPage512(pSectorBuff);                    // Write page/sector data.  
  71.             }  
  72.             NF_MECC_Lock();  
  73.   
  74.             // Write the SectorInfo data to the media.  
  75.             // Spare area[7:0]  
  76.             if(pSectorInfoBuff)  
  77.             {  
  78.                 WrPageInfo((PBYTE)pSectorInfoBuff);  
  79.                 pSectorInfoBuff++;  
  80.             }  
  81.             else    // Make sure we advance the Flash's write pointer (even though we aren't writing the SectorInfo data)  
  82.             {  
  83.                 BYTE TempInfo[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};  
  84.                 WrPageInfo(TempInfo);  
  85.             }  
  86.   
  87.             // Write the SectorInfo data to the media.  
  88.             // Spare area[11:8]  
  89.             // Get the ECC data from status register.  
  90.             MECC = NF_RDMECC0();  
  91.             // Now, Write the ECC data to Spare area[11:8]  
  92.             NF_WRDATA_BYTE((UCHAR)((MECC      ) & 0xff));        // Spare area offset 8  
  93.             NF_WRDATA_BYTE((UCHAR)((MECC >>  8) & 0xff));    // Spare area offset 9  
  94.             NF_WRDATA_BYTE((UCHAR)((MECC >> 16) & 0xff));    // Spare area offset 10  
  95.             NF_WRDATA_BYTE((UCHAR)((MECC >> 24) & 0xff));    // Spare area offset 11  
  96.   
  97.             NF_CLEAR_RB();  
  98.             NF_CMD(CMD_WRITE2);                            // Send write confirm command.  
  99.             NF_DETECT_RB();  
  100.   
  101.             do  
  102.             {  
  103.                 NF_CMD(CMD_STATUS);  
  104.                 Status = NF_RDDATA_BYTE();                    // Read command status.  
  105.             }while(!(Status & STATUS_READY));  
  106.   
  107.             if (Status & STATUS_ERROR)  
  108.             {  
  109.                 NF_nFCE_H();                            // Deselect the flash chip.  
  110.                 return(FALSE);  
  111.             }  
  112.             pSectorBuff += NAND_SECTOR_SIZE;  
  113.         }  
  114.         ++SectorAddr;  
  115.     }  
  116.     NF_nFCE_H();                                        // Deselect the flash chip.  
  117.   
  118.     return(TRUE);  
  119. }  

这部分就不需要修改了,上面的代码是处理SLC部分的

 

 

 

4、FMD_LB_EraseBlock()   擦出块

[cpp] 
  1. BOOL FMD_LB_EraseBlock(BLOCK_ID blockID)  
  2. {  
  3.     BOOL    bRet = TRUE;  
  4.     DWORD   dwPageID = blockID << LB_NAND_LOG_2_PAGES_PER_BLOCK;  
  5.   
  6. #if (NAND_DEBUG)  
  7.     RETAILMSG(1, (TEXT("FMD_LB_EraseBlock 0x%x \n"), blockID));  
  8. #endif  
  9.   
  10.     //  Enable the chip  
  11.     NF_nFCE_L();        // Select the flash chip.  
  12.   
  13.     NF_CLEAR_RB();  
  14.     NF_MSGLENGTH_512();  
  15.     //  Issue command  
  16.     NF_CMD(CMD_ERASE);  
  17.   
  18.     //  Set up address  
  19.     NF_ADDR((dwPageID) & 0xff);  
  20.     NF_ADDR((dwPageID >> 8) & 0xff);  
  21. #if    LB_NEED_EXT_ADDR  
  22.     NF_ADDR((dwPageID >> 16) & 0xff);  
  23. #endif  
  24.   
  25.     //  Complete erase operation  
  26.     NF_CMD(CMD_ERASE2);  
  27.   
  28.     //  Wait for ready bit  
  29.     NF_DETECT_RB();     // Wait tR(max 12us)  
  30.   
  31.     if ( NF_RDSTAT & STATUS_ILLACC )  
  32.     {  
  33.             RETAILMSG(1, (TEXT("LB######## Error Erasing block (Illigar Access) %d!\n"), blockID));  
  34.         g_pNFConReg->NFSTAT =  STATUS_ILLACC;    // Write 1 to clear.  
  35.         bRet = FALSE;  
  36.     }  
  37.     else  
  38.     {  
  39.         //  Check the status  
  40.         NF_CMD(CMD_STATUS);  
  41.   
  42.         if( NF_RDDATA_BYTE() & STATUS_ERROR)  
  43.         {  
  44.             RETAILMSG(1, (TEXT("LB######## Error Erasing block %d!\n"), blockID));  
  45.             bRet = FALSE;  
  46.         }  
  47.     }  
  48.   
  49.     NF_nFCE_H();                        // Select the flash chip.  
  50.   
  51.     return bRet;  
  52. }  

上述是飞凌的源码,这里我们需要稍作修改。

在使能片选 NF_nFCE_L();  之前,我们需要使能一些中断:

[cpp] 
  1. g_pNFConReg->NFCONT |= (1<<10);    // Enable illegal access interrupt control  
  2. g_pNFConReg->NFCONT |= (1<<9); // Enable RnB interrupt  

擦除操作处理完之后,在 NF_nFCE_H(); 之前,需要关闭前面使能的中断:

[cpp] 
  1. g_pNFConReg->NFCONT &= ~(1<<10);   // Disable illegal access interrupt control  
  2. g_pNFConReg->NFCONT &= ~(1<<9);        // Disable RnB interrupt  

 

 

 

5、FMD_SB_EraseBlock()

[cpp] 
  1. BOOL FMD_SB_EraseBlock(BLOCK_ID blockID)  
  2. {  
  3.     BOOL    bRet = TRUE;  
  4.     DWORD   dwPageID = blockID << SB_NAND_LOG_2_PAGES_PER_BLOCK;  
  5.   
  6.     //  Enable the chip  
  7.     NF_nFCE_L();                        // Select the flash chip.  
  8.   
  9.     //  Issue command  
  10.     NF_CMD(CMD_ERASE);  
  11.   
  12.     //  Set up address  
  13.     NF_ADDR((dwPageID) & 0xff);  
  14.     NF_ADDR((dwPageID >> 8) & 0xff);  
  15. #if    SB_NEED_EXT_ADDR  
  16.     NF_ADDR((dwPageID >> 16) & 0xff);  
  17. #endif  
  18.   
  19.     NF_CLEAR_RB();  
  20.   
  21.     //  Complete erase operation  
  22.     NF_CMD(CMD_ERASE2);  
  23.   
  24.     //  Wait for ready bit  
  25.     NF_DETECT_RB();     // Wait tR(max 12us)  
  26.   
  27.     if ( NF_RDSTAT & STATUS_ILLACC )  
  28.     {  
  29.         RETAILMSG(1, (TEXT("SB######## Error Erasing block (Illigar Access) %d!\n"), blockID));  
  30.         g_pNFConReg->NFSTAT =  STATUS_ILLACC;    // Write 1 to clear.  
  31.         bRet = FALSE;  
  32.     }  
  33.     else  
  34.     {  
  35.         //  Check the status  
  36.         NF_CMD(CMD_STATUS);  
  37.   
  38.         if( NF_RDDATA_BYTE() & STATUS_ERROR)  
  39.         {  
  40.             RETAILMSG(1, (TEXT("SB######## Error Erasing block %d!\n"), blockID));  
  41.             bRet = FALSE;  
  42.         }  
  43.     }  
  44.   
  45.     NF_nFCE_H();                        // Select the flash chip.  
  46.   
  47.     return bRet;  
  48. }  

SLC擦除块操作,这里不需要修改

 

 

 

6、FMD_LB_GetBlockStatus()  MLC获取块的状态

[cpp] 
  1. DWORD FMD_LB_GetBlockStatus(BLOCK_ID blockID)  
  2. {  
  3.     BLOCK_ID blockID_bad = blockID + 1;  
  4.     SECTOR_ADDR sectorAddr = (blockID_bad << LB_NAND_LOG_2_PAGES_PER_BLOCK) - 1;  
  5.     SectorInfo SI;  
  6.     DWORD dwResult = 0;  
  7.   
  8.     //RETAILMSG(1, (TEXT("FMD_LB_GetBlockStatus (0x%x)0x%x \n"), blockID, sectorAddr));  
  9.   
  10.     if(!FMD_LB_ReadSector(sectorAddr, NULL, &SI, 1))  
  11.     {  
  12.             return BLOCK_STATUS_UNKNOWN;  
  13.     }  
  14.   
  15.     if(!(SI.bOEMReserved & OEM_BLOCK_READONLY))  
  16.     {  
  17.         dwResult |= BLOCK_STATUS_READONLY;  
  18.     }  
  19.   
  20.     if (!(SI.bOEMReserved & OEM_BLOCK_RESERVED))  
  21.     {  
  22.         dwResult |= BLOCK_STATUS_RESERVED;  
  23.     }  
  24.   
  25.     if(SI.bBadBlock != 0xFF)  
  26.     {  
  27.         dwResult |= BLOCK_STATUS_BAD;  
  28.     }  
  29.   
  30.     return dwResult;  
  31. }  

 

 

 

7、FMD_SB_GetBlockStatus()  SLC读取块状态

[cpp] 
  1. DWORD FMD_SB_GetBlockStatus(BLOCK_ID blockID)  
  2. {  
  3.     SECTOR_ADDR sectorAddr = blockID << SB_NAND_LOG_2_PAGES_PER_BLOCK;  
  4.     SectorInfo SI;  
  5.     DWORD dwResult = 0;  
  6.   
  7.     //RETAILMSG(1, (TEXT("FMD_SB_GetBlockStatus (0x%x)0x%x \n"), blockID, sectorAddr));  
  8.   
  9.     if(!FMD_SB_ReadSector(sectorAddr, NULL, &SI, 1))  
  10.     {  
  11.         return BLOCK_STATUS_UNKNOWN;  
  12.     }  
  13.   
  14.     if(!(SI.bOEMReserved & OEM_BLOCK_READONLY))  
  15.     {  
  16.         dwResult |= BLOCK_STATUS_READONLY;  
  17.     }  
  18.   
  19.     if(SI.bBadBlock != 0xFF)  
  20.     {  
  21.         dwResult |= BLOCK_STATUS_BAD;  
  22.     }  
  23.   
  24.     return dwResult;  
  25. }  

 

 

 

8、FMD_LB_SetBlockStatus()、FMD_SB_SetBlockStatus()  设置块的状态

[cpp] 
  1. BOOL FMD_LB_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)  
  2. {  
  3.     BYTE bStatus = 0;  
  4.   
  5.     if(dwStatus & BLOCK_STATUS_BAD)  
  6.     {  
  7.         if(!LB_MarkBlockBad (blockID))  
  8.         {  
  9.             return FALSE;  
  10.         }  
  11.     }  
  12.   
  13.     // We don't currently support setting a block to read-only, so fail if request is  
  14.     // for read-only and block is not currently read-only.  
  15.     if(dwStatus & BLOCK_STATUS_READONLY)  
  16.     {  
  17.         if(!(FMD_LB_GetBlockStatus(blockID) & BLOCK_STATUS_READONLY))  
  18.         {  
  19.             return FALSE;  
  20.         }  
  21.     }  
  22.   
  23.     return TRUE;  
  24. }  
  25.   
  26. BOOL FMD_SB_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)  
  27. {  
  28.     SECTOR_ADDR sectorAddr = blockID << SB_NAND_LOG_2_PAGES_PER_BLOCK;  
  29.     BYTE bStatus = 0;  
  30.   
  31.     //RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_sbsetblock \n")));  
  32.   
  33.     if(dwStatus & BLOCK_STATUS_BAD)  
  34.     {  
  35.         if(!SB_MarkBlockBad (blockID))  
  36.         {  
  37.             return FALSE;  
  38.         }  
  39.     }  
  40.   
  41.     // We don't currently support setting a block to read-only, so fail if request is  
  42.     // for read-only and block is not currently read-only.  
  43.     if(dwStatus & BLOCK_STATUS_READONLY)  
  44.     {  
  45.         if(!(FMD_SB_GetBlockStatus(blockID) & BLOCK_STATUS_READONLY))  
  46.         {  
  47.             return FALSE;  
  48.         }  
  49.     }  
  50.   
  51.     return TRUE;  
  52. }  

 

 

 

9、LB_MarkBlockBad()、SB_MarkBlockBad()   标记坏块

[cpp] 
  1. BOOL LB_MarkBlockBad(BLOCK_ID blockID)  
  2. {  
  3.     BLOCK_ID blockID_bad = blockID + 1;  
  4.     DWORD   dwStartPage = (blockID_bad << LB_NAND_LOG_2_PAGES_PER_BLOCK) - 1;  
  5.     BOOL    bRet = TRUE;  
  6.   
  7.     //    RETAILMSG(1, (TEXT("LB_MarkBlockBad 0x%x \n"), dwStartPage));  
  8.   
  9.     //  Enable chip  
  10.     NF_nFCE_L();  
  11.     NF_CLEAR_RB();  
  12.     NF_MSGLENGTH_512();  
  13.     //  Issue command  
  14.     //  We are dealing with spare area  
  15.     NF_CMD(CMD_WRITE);  
  16.   
  17.     //  Set up address  
  18.     NF_ADDR((4096+LB_POS_BADBLOCK)&0xff);   // gjl 2048  
  19.     NF_ADDR(((4096+LB_POS_BADBLOCK)>>8)&0xff);  // gjl 2048  
  20.     NF_ADDR((dwStartPage) & 0xff);  
  21.     NF_ADDR((dwStartPage >> 8) & 0xff);  
  22. #if    LB_NEED_EXT_ADDR  
  23.     NF_ADDR((dwStartPage >> 16) & 0xff);  
  24. #endif  
  25.   
  26.     NF_WRDATA_BYTE(BADBLOCKMARK);  
  27.   
  28.     //  Copmlete the write  
  29.     NF_CMD(CMD_WRITE2);  
  30.   
  31.     //  Wait for RB  
  32.     NF_DETECT_RB();     // Wait tR(max 12us)  
  33.   
  34.     if ( NF_RDSTAT & STATUS_ILLACC )  
  35.     {  
  36.         RETAILMSG(1, (TEXT("NAND_LB_WriteSectorInfo() ######## Error Programming page (Illigar Access) %d!\n")));  
  37.         g_pNFConReg->NFSTAT =  STATUS_ILLACC;    // Write 1 to clear.  
  38.         bRet = FALSE;  
  39.     }  
  40.     else  
  41.     {  
  42.         //  Check the status of program  
  43.         NF_CMD(CMD_STATUS);  
  44.   
  45.         if( NF_RDDATA_BYTE() & STATUS_ERROR)  
  46.         {  
  47.             RETAILMSG(1, (TEXT("NAND_LB_WriteSectorInfo() ######## Error Programming page %d!\n")));  
  48.             bRet = FALSE;  
  49.         }  
  50.     }  
  51.   
  52.     //  Disable chip select  
  53.     NF_nFCE_H();  
  54.   
  55.     return bRet;  
  56. }  
  57.   
  58. BOOL SB_MarkBlockBad(BLOCK_ID blockID)  
  59. {  
  60.     DWORD   dwStartPage = blockID << SB_NAND_LOG_2_PAGES_PER_BLOCK;  
  61.     BOOL    bRet = TRUE;  
  62.   
  63.     //RETAILMSG(1, (TEXT("SB_MarkBlockBad 0x%x \n"), dwStartPage));  
  64.   
  65.     //  Enable chip  
  66.     NF_nFCE_L();  
  67.     NF_CLEAR_RB();  
  68.   
  69.     //  Issue command  
  70.     //  We are dealing with spare area  
  71.     NF_CMD(CMD_READ2);  
  72.     NF_CMD(CMD_WRITE);  
  73.   
  74.     //  Set up address  
  75.     NF_ADDR(SB_POS_BADBLOCK);  
  76.     NF_ADDR((dwStartPage) & 0xff);  
  77.     NF_ADDR((dwStartPage >> 8) & 0xff);  
  78. #if    SB_NEED_EXT_ADDR  
  79.     NF_ADDR((dwStartPage >> 16) & 0xff);  
  80. #endif  
  81.   
  82.     NF_WRDATA_BYTE(BADBLOCKMARK);  
  83.   
  84.     //  Copmlete the write  
  85.     NF_CMD(CMD_WRITE2);  
  86.   
  87.     //  Wait for RB  
  88.     NF_DETECT_RB();     // Wait tR(max 12us)  
  89.   
  90.     if ( NF_RDSTAT & STATUS_ILLACC )  
  91.     {  
  92.         RETAILMSG(1, (TEXT("NAND_LB_WriteSectorInfo() ######## Error Programming page (Illigar Access) %d!\n")));  
  93.         g_pNFConReg->NFSTAT =  STATUS_ILLACC;    // Write 1 to clear.  
  94.         bRet = FALSE;  
  95.     }  
  96.     else  
  97.     {  
  98.         //  Check the status of program  
  99.         NF_CMD(CMD_STATUS);  
  100.   
  101.         if( NF_RDDATA_BYTE() & STATUS_ERROR)  
  102.         {  
  103.             RETAILMSG(1, (TEXT("NAND_LB_WriteSectorInfo() ######## Error Programming page %d!\n")));  
  104.             bRet = FALSE;  
  105.         }  
  106.     }  
  107.   
  108.     //  Disable chip select  
  109.     NF_nFCE_H();  
  110.   
  111.     return bRet;  
  112. }  

 

 

 

10、LB_IsBlockBad()、SB_IsBlockBad()  判断是否为坏块

[cpp] 
  1. BOOL LB_IsBlockBad(BLOCK_ID blockID)  
  2. {  
  3.     BLOCK_ID blockID_bad = blockID + 1;  
  4.     DWORD   dwPageID = (blockID_bad << LB_NAND_LOG_2_PAGES_PER_BLOCK) - 1;  
  5.     BOOL    bRet = FALSE;  
  6.     BYTE    wFlag;  
  7.   
  8.     //  Enable the chip  
  9.     NF_nFCE_L();  
  10.     NF_CLEAR_RB();  
  11.     NF_MSGLENGTH_512();  
  12.     //  Issue the command  
  13.     NF_CMD(CMD_READ);  
  14.   
  15.     //  Set up address  
  16.     NF_ADDR((4096+LB_POS_BADBLOCK)&0xff);  //gjl 2048  
  17.     NF_ADDR(((4096+LB_POS_BADBLOCK)>>8)&0xff);  // gjl 2048  
  18.     NF_ADDR((dwPageID) & 0xff);  
  19.     NF_ADDR((dwPageID >> 8) & 0xff);  
  20. #if    LB_NEED_EXT_ADDR  
  21.     NF_ADDR((dwPageID >> 16) & 0xff);  
  22. #endif  
  23.   
  24.     NF_CMD(CMD_READ3);  
  25.   
  26.     //  Wait for Ready bit  
  27.     NF_DETECT_RB();     // Wait tR(max 12us)  
  28.   
  29.     //  Now get the byte we want  
  30.     wFlag = (BYTE)(NF_RDDATA_BYTE()&0xff);  
  31.   
  32.     if(wFlag != 0xff)  
  33.     {  
  34.         RETAILMSG(1, (TEXT("FMDLB: IsBlockBad - Page #: 0x%x \n"), dwPageID));  
  35.         bRet = TRUE;  
  36.     }  
  37.   
  38.     //  Disable the chip  
  39.     NF_nFCE_H();  
  40.   
  41.     return bRet;  
  42. }  
  43.   
  44. BOOL SB_IsBlockBad(BLOCK_ID blockID)  
  45. {  
  46.     DWORD   dwPageID = blockID << SB_NAND_LOG_2_PAGES_PER_BLOCK;  
  47.     BOOL    bRet = FALSE;  
  48.     BYTE    wFlag;  
  49.   
  50.     //RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_sbisblockbad \n")));  
  51.   
  52.     //  Enable the chip  
  53.     NF_nFCE_L();  
  54.     NF_CLEAR_RB();  
  55.     //  Issue the command  
  56.     NF_CMD(CMD_READ2);  
  57.   
  58.     //  Set up address  
  59.     NF_ADDR(SB_POS_BADBLOCK);  
  60.     NF_ADDR((dwPageID) & 0xff);  
  61.     NF_ADDR((dwPageID >> 8) & 0xff);  
  62. #if    SB_NEED_EXT_ADDR  
  63.     NF_ADDR((dwPageID >> 16) & 0xff);  
  64. #endif  
  65.   
  66.     //  Wait for Ready bit  
  67.     NF_DETECT_RB();     // Wait tR(max 12us)  
  68.   
  69.     //  Now get the byte we want  
  70.     wFlag = (BYTE) NF_RDDATA_BYTE();  
  71.   
  72.     if(wFlag != 0xff)  
  73.     {  
  74.         RETAILMSG(1, (TEXT("FMDSB: IsBlockBad - Page #: 0x%x \n"), dwPageID));  
  75.         bRet = TRUE;  
  76.     }  
  77.   
  78.     //  Disable the chip  
  79.     NF_nFCE_H();  
  80.   
  81.     return bRet;  
  82. }  

 

时间比较仓促,这个Nandflash移植系列的就到这里结束了。

链接:http://blog.csdn.net/brantyou/article/details/8220591

转载地址:https://loongembedded.blog.csdn.net/article/details/23903777 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:s3c6410 开发板Linux系统支持 K9GAG08U0E的方法
下一篇:Windows Embedded Compact 2013升级:VS2013也能编译

发表评论

最新留言

很好
[***.229.124.182]2024年05月02日 17时23分43秒