⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fmd.c

📁 WINce的ECC算法,和读写函数,可对比MTD NAND ECC来学习
💻 C
📖 第 1 页 / 共 2 页
字号:
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 2002  Microsoft Corporation

Module Name:	FMD.CPP

Abstract:		FLASH Media Driver Interface Samsung K9F2808UOB NAND Flash Chip
                on AT-Rise development board.

Notes:			Currently, *only* the CE 3.0 (and earlier) power management logic
				is implemented (i.e. the PowerUp() and PowerDown() APIs).

Environment:	As noted, this media driver works on behalf of the FAL to directly
				access the underlying FLASH hardware.  Consquently, this module
				needs to be linked with FAL.LIB to produce the device driver
				named FLASHDRV.DLL.

-----------------------------------------------------------------------------*/
#include "fmd.h"

//#include "s2410.h"
#include "cfnand.h"
#include "loader.h"
#include "2410lib.h"
#include "2410addr.h"

/*
#define READ_REGISTER_USHORT(p)  			(p)
//#define WRITE_REGISTER_USHORT(p, v) 	(*(volatile PUSHORT)(p)) = (v)   直接使用应该没问题
#define READ_REGISTER_ULONG(p)  			(p)
#define WRITE_REGISTER_USHORT(p, v) 	(p) = (v)

/*
  eboot下操作寄存器是虚拟地址,u241mon下直接操作寄存器地址,下面的函数使用寄存器地址时会出现异常终止

//  Use Macros here to avoid extra over head for c function calls
#define READ_REGISTER_USHORT(p) (*(volatile PUSHORT) (p))
#define WRITE_REGISTER_USHORT(p, v) (*(volatile PUSHORT)(p)) = (v)
#define READ_REGISTER_ULONG(p)  (*(volatile PULONG) (p))
*/

//  Registers
//volatile PUSHORT pNFReg;
volatile PUSHORT pNFCONF;
volatile PUSHORT pNFCMD;
volatile PUSHORT pNFADDR;
volatile PUSHORT pNFDATA;
volatile PUSHORT pNFSTAT;
volatile PULONG  pNFECC;
//volatile CLKPWRreg *v_s2410CLKPWR;


//  Status bit pattern
#define STATUS_READY                0x40
#define STATUS_ERROR                0x01


//  MACROS
/*
#define NF_CE_L()       WRITE_REGISTER_USHORT(pNFCONF, (USHORT) (READ_REGISTER_USHORT(pNFCONF) & ~(1<<11)))
#define NF_CE_H()       WRITE_REGISTER_USHORT(pNFCONF, (USHORT) (READ_REGISTER_USHORT(pNFCONF) | (1<<11)))
#define NF_CMD(cmd)     WRITE_REGISTER_USHORT(pNFCMD, (USHORT) (cmd))
#define NF_ADDR(addr)   WRITE_REGISTER_USHORT(pNFADDR, (USHORT) (addr))
#define NF_DATA_R()     READ_REGISTER_USHORT(pNFDATA)
#define NF_DATA_W(val)  WRITE_REGISTER_USHORT(pNFDATA, (USHORT) (val))
#define NF_STAT()       READ_REGISTER_USHORT(pNFSTAT)
#define NF_RSTECC()			WRITE_REGISTER_USHORT(pNFCONF, (USHORT) (READ_REGISTER_USHORT(pNFCONF) | (1<<12)))
#define NF_WAITRB()     {while(!(NF_STAT() & 0x01)) ;}
#define NF_ECC()        READ_REGISTER_ULONG(pNFECC)
* /
#define NF_CE_L()       WRITE_REGISTER_USHORT(rNFCONF, (USHORT) (READ_REGISTER_USHORT(rNFCONF) & ~(1<<11)))
#define NF_CE_H()       WRITE_REGISTER_USHORT(rNFCONF, (USHORT) (READ_REGISTER_USHORT(rNFCONF) | (1<<11)))
#define NF_CMD(cmd)     WRITE_REGISTER_USHORT(rNFCMD, (USHORT) (cmd))
#define NF_ADDR(addr)   WRITE_REGISTER_USHORT(rNFADDR, (USHORT) (addr))
#define NF_DATA_R()     READ_REGISTER_USHORT(rNFDATA)
#define NF_DATA_W(val)  WRITE_REGISTER_USHORT(rNFDATA, (USHORT) (val))
#define NF_STAT()       READ_REGISTER_USHORT(rNFSTAT)
#define NF_RSTECC()			WRITE_REGISTER_USHORT(rNFCONF, (USHORT) (READ_REGISTER_USHORT(rNFCONF) | (1<<12)))
//#define NF_WAITRB()     {while(!(NF_STAT() & 0x01)) ;}
#define NF_WAITRB()			{while(!(rNFSTAT & 1)); }
#define NF_ECC()        READ_REGISTER_ULONG(rNFECC)
*/


//  write  from nboot by scyclone
#define NF_CE_L()				{rNFCONF &= ~(1<<11);}
#define NF_CE_H()				{rNFCONF |=  (1<<11);}
#define NF_CMD(cmd)			{rNFCMD = (cmd);}
#define NF_ADDR(addr)		{rNFADDR = (addr);}
#define NF_DATA_R()			rNFDATA
#define NF_DATA_W(d)		{rNFDATA = (d);}
#define NF_STAT()				rNFSTAT
#define NF_RSTECC()			{rNFCONF |= (1<<12);}
#define NF_WAITRB()			{while(!(rNFSTAT & 1));}
#define NF_ECC()				rNFECC






//  External function

BOOL ECC_CorrectData(LPBYTE pData, LPBYTE pExistingECC, LPBYTE pNewECC);


//  Flags and pointers
#define BADBLOCKMARK                0x00
//  VALIDADDR is 5 << 8
//
//  Explain:    5 means the 6th byte in spare area (517 byte in the sector)
//              Shift 8 bit to the left to form the correct address for 16bit port
//
#define VALIDADDR   0x05

#define OEMADDR		0x04					// 5th byte in spare area


//  Reset the chip
//
void NF_Reset()
{
    NF_CE_L();
    NF_CMD(CMD_RESET);
    NF_WAITRB();
    NF_CE_H();
}

/*
 Here is the statement from SamSung's K9F2808U0B datasheet:

 All device locations are erased (FFh) except location where the invalid block(s)
 information is written prior to shipping. The invalid block(s) status is defined
 by the 6th byte in the spare area. Samsung makes sure that either the 1st or 2nd
 page of every invalid block has non-FFh data at the column address of 517. Since
 the invalid block information is also erasable in most cases, it is impossible to
 recover the information once it has been erased.

 Here is the logic we are taking:

 If the block is invalid, non-FFh value in column address of 517, we don't use that
 block anyway. Otherwise, the whole spare area is subject to use by our program. If
 we found additional bad block later on, we don't necessary have to use column 517
 to represent invalid block. We could use any of the 16 byte spare area.

 But for simplicity, in our current implementation, we avoid to touch column 517. So
 the we allocate SectorInfo as following:

  - - - - - - - - - - - - - - - -
 |R|R|R|R|O|V|R|R|E|E|E|E|E|E|E|E|
  - - - - - - - - - - - - - - - -

 Where  Rs are reserved bytes used by the FAL
        O is a byte for use by the OEM
        V is a byte indicating if the block is valid (a.k.a. bad)
        Es are bytes used for ECC

 */

/*
 *  NAND_ReadSectorInfo
 *
 *  Read SectorInfo out of the spare area. The current implementation only handles
 *  one sector at a time.
 */
void NAND_ReadSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)
{
    //  Chip enable
    NF_CE_L();

    //  Write the command
    NF_CMD(CMD_READ2);

    //  Write the address
    NF_ADDR(0x00);
    NF_ADDR(sectorAddr & 0xff);
    NF_ADDR((sectorAddr >> 8) & 0xff);

		NF_ADDR((sectorAddr >> 16) & 0xff);

    //  Wait for the Ready bit
    NF_WAITRB();

    //  Read the SectorInfo data (we only need to read first 8 bytes)
    pInfo->dwReserved1  = (DWORD) ((BYTE) NF_DATA_R()) << 24;
    pInfo->dwReserved1 |= (DWORD) ((BYTE) NF_DATA_R()) << 16;
    pInfo->dwReserved1 |= (DWORD) ((BYTE) NF_DATA_R()) << 8;
    pInfo->dwReserved1 |= (DWORD) ((BYTE) NF_DATA_R());

    //  OEM byte
    pInfo->bOEMReserved = (BYTE) NF_DATA_R();

    //  Read the bad block mark
    pInfo->bBadBlock = (BYTE) NF_DATA_R();

    //  Second reserved field (WORD)
    pInfo->wReserved2 = ((BYTE) NF_DATA_R() << 8);
    pInfo->wReserved2 |= ((BYTE) NF_DATA_R());

    NF_CE_H();
}

/*
 *  NAND_WriteSectorInfo
 *
 *  Write SectorInfo out to the spare area. The current implementation only handles
 *  one sector at a time.
 */
BOOL NAND_WriteSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)
{
    BOOL    bRet = TRUE;

    //  Chip enable
    NF_CE_L();

    //  Write the command
    //  First, let's point to the spare area
    NF_CMD(CMD_READ2);
    NF_CMD(CMD_WRITE);

    //  Write the address
    NF_ADDR(0x00);
    NF_ADDR(sectorAddr & 0xff);
    NF_ADDR((sectorAddr >> 8) & 0xff);

    NF_ADDR((sectorAddr >> 16) & 0xff);

    //  Now let's write the SectorInfo data
    //
    //  Write the first reserved field (DWORD)
    NF_DATA_W( (pInfo->dwReserved1 >> 24) & 0xff );
    NF_DATA_W( (pInfo->dwReserved1 >> 16) & 0xff );
    NF_DATA_W( (pInfo->dwReserved1 >> 8 ) & 0xff );
    NF_DATA_W( (pInfo->dwReserved1) & 0xff );

    //  Write OEM reserved flag
    NF_DATA_W( (pInfo->bOEMReserved) );

    //  Write the bad block flag
    NF_DATA_W( (pInfo->bBadBlock) );

    //  Write the second reserved field
    NF_DATA_W( (pInfo->wReserved2 >> 8) & 0xff );
    NF_DATA_W( (pInfo->wReserved2) );

    //  Issue the write complete command
    NF_CMD(CMD_WRITE2);

    //  Check ready bit
    NF_WAITRB();

    //  Check the status of program
    NF_CMD(CMD_STATUS);

    if(NF_DATA_R() & STATUS_ERROR) {
        Uart_Printf("NAND_WriteSectorInfo() ######## Error Programming page %d!\n", sectorAddr);
        bRet = FALSE;
    }

    NF_CE_H();

    return bRet;
}

/*-----------------------------------------------------------------------------
 *  FMD Interface functions
 *
 *----------------------------------------------------------------------------*/
//  FMD_Init
//
//  Initialize the flash chip
//	@@@@@@@@@@@@@@@@@@@@@@   modified by scyclone @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//  Note: Presently, the Flash size characteristics are hardcoded in CFNAND.H
//		  and are NOT stored in the registry.  Refer to the StratFlash FMD in
//		  %WINCEROOT%\PUBLIC\COMMON\OAK\DRIVERS\BLOCK\... for an example of how
//		  to use the registry for storing this information.
//
/*
// CLOCK & POWER MANAGEMENT
#define rLOCKTIME   (*(volatile unsigned *)0x4c000000) //PLL lock time counter
#define rMPLLCON    (*(volatile unsigned *)0x4c000004) //MPLL Control
#define rUPLLCON    (*(volatile unsigned *)0x4c000008) //UPLL Control
#define rCLKCON     (*(volatile unsigned *)0x4c00000c) //Clock generator control
#define rCLKSLOW    (*(volatile unsigned *)0x4c000010) //Slow clock control
#define rCLKDIVN    (*(volatile unsigned *)0x4c000014) //Clock divider control
*/
/*
// NAND flash
#define rNFCONF     (*(volatile unsigned *)0x4e000000)      //NAND Flash configuration
#define rNFCMD      (*(volatile U8 *)0x4e000004)            //NADD Flash command
#define rNFADDR     (*(volatile U8 *)0x4e000008)            //NAND Flash address
#define rNFDATA     (*(volatile U8 *)0x4e00000c)            //NAND Flash data
#define rNFSTAT     (*(volatile unsigned *)0x4e000010)      //NAND Flash operation status
#define rNFECC      (*(volatile unsigned *)0x4e000014)      //NAND Flash ECC
#define rNFECC0     (*(volatile U8  *)0x4e000014)
#define rNFECC1     (*(volatile U8  *)0x4e000015)
#define rNFECC2     (*(volatile U8  *)0x4e000016)
*/
// FMD_Init 主要就是创建一块虚拟内存,恰好是 CLOCK, NAND的寄存器地址,然后给NAND提供时钟然后enable nand

PVOID FMD_Init(void)
{


#ifdef Debug2410mon
		Uart_Printf("FMD_Init \r\n");
#endif

		//  Enable the clock to NAND controller
		rCLKCON |= (1<<4);

		//pNFReg = (PUSHORT) (NFC_BASE | 0x20000000);
		pNFDATA = (PUSHORT)rNFDATA;
		pNFCMD  = (PUSHORT)rNFCMD;
		pNFADDR = (PUSHORT)rNFADDR;
		pNFSTAT = (PUSHORT)rNFSTAT;
		pNFECC  = (PULONG)rNFECC;

		//  Now we need enable the NAND Flash controller
    rNFCONF = NFCONF_INIT;

    return (PVOID)rNFCONF;
    /*
    v_s2410CLKPWR->rCLKCON |= (1<<4);

    pNFCONF = pNFReg;
    pNFCMD  = (PUSHORT) ((PBYTE) pNFReg + 0x04);
    pNFADDR = (PUSHORT) ((PBYTE) pNFReg + 0x08);
    pNFDATA = (PUSHORT) ((PBYTE) pNFReg + 0x0C);
    pNFSTAT = (PUSHORT) ((PBYTE) pNFReg + 0x10);
    pNFECC  = (PULONG)  ((PBYTE) pNFReg + 0x14);

    WRITE_REGISTER_USHORT(pNFCONF, NFCONF_INIT);
		*/
}



//  FMD_GetInfo
//
//  Return the Flash information
//
BOOL  FMD_GetInfo(PFlashInfo pFlashInfo)
{
    pFlashInfo->flashType = NAND;

    //  OK, instead of reading it from the chip, we use the hardcoded numbers here.

    pFlashInfo->dwNumBlocks					= NUM_BLOCKS;
    pFlashInfo->wSectorsPerBlock		= PAGES_PER_BLOCK;
    pFlashInfo->wDataBytesPerSector = SECTOR_SIZE;

    return TRUE;
}

//  FMD_ReadSector
//
//  Read the content of the sector.
//
//  startSectorAddr: Starting page address
//  pSectorBuff  : Buffer for the data portion
//  pSectorInfoBuff: Buffer for Sector Info structure
//  dwNumSectors : Number of sectors
//

typedef union _ECCRegVal
{
    DWORD   dwECCVal;
    BYTE    bECCBuf[4];
} ECCRegVal;

BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
{
    DWORD       i;
    BYTE        eccBuf[8];
    ECCRegVal   eccRegVal;

		//  RETAILMSG(1, (TEXT("FMD_ReadSector!\n")));
		//	RETAILMSG(1, (TEXT("startSectorAddr = %x, pSectorBuff = %x, pSectorInfoBuff = %x, dwNumSectors = %x\n"), startSectorAddr, pSectorBuff, pSectorInfoBuff, dwNumSectors));
    //  Sanity check
    if (!pSectorBuff && !pSectorInfoBuff || dwNumSectors > 1) {
        Uart_Printf("Invalid parameters!\r\n");
        return FALSE;
    }

		NF_Reset();

    if(!pSectorBuff) {
        //  We are reading spare only
        NAND_ReadSectorInfo(startSectorAddr, pSectorInfoBuff);

        //  There is no ECC for the sector info, so the read always succeed.
        return TRUE;
    }

    //  Initialize ECC register
    NF_RSTECC();

    //  Enable the chip
    NF_CE_L();

    //  Issue command
    NF_CMD(CMD_READ);

    //  Set up address
    NF_ADDR(0x00);
    NF_ADDR((startSectorAddr) & 0xff);
    NF_ADDR((startSectorAddr >> 8) & 0xff);

    NF_ADDR((startSectorAddr >> 16) & 0xff);

    NF_WAITRB();


/*  暂时屏蔽  用C来读NAND 数据
    //  BUGBUG, because Media Player for Pocket PC sometimes pass us un-aligned buffer
    //  we have to waste cycle here to work around this problem
    if( ((DWORD) pSectorBuff) & 0x3) {
        for(i=0; i<SECTOR_SIZE; i++) {
            pSectorBuff[i] = (BYTE) NF_DATA_R();
        }
    }
    else {
        //  The right way.
         ReadPage512(pSectorBuff, pNFDATA);  // eboot
        //__RdPage512(pSectorBuff);   nboot
    }
    */
    for(i=0; i<SECTOR_SIZE; i++)
            pSectorBuff[i] = (BYTE) NF_DATA_R();

    //  Do the ECC thing here
    //  We read the ECC value from the ECC register pFNECC
    eccRegVal.dwECCVal = NF_ECC();

    //  Read the SectorInfo data
    if(pSectorInfoBuff) {
        //  Read the SectorInfo data (we only need to read first 8 bytes)
        pSectorInfoBuff->dwReserved1  = (DWORD) ((BYTE) NF_DATA_R()) << 24;
        pSectorInfoBuff->dwReserved1 |= (DWORD) ((BYTE) NF_DATA_R()) << 16;
        pSectorInfoBuff->dwReserved1 |= (DWORD) ((BYTE) NF_DATA_R()) << 8;
        pSectorInfoBuff->dwReserved1 |= (DWORD) ((BYTE) NF_DATA_R());

        //  OEM byte
        pSectorInfoBuff->bOEMReserved = (BYTE) NF_DATA_R();

        //  Read the bad block mark
        pSectorInfoBuff->bBadBlock = (BYTE) NF_DATA_R();

        //  Second reserved field (WORD)
        pSectorInfoBuff->wReserved2 = ((BYTE) NF_DATA_R() << 8);
        pSectorInfoBuff->wReserved2 |= ((BYTE) NF_DATA_R());
    }
    else {
        //  Advance the read pointer
        for(i=0; i<sizeof(SectorInfo); i++) {
            eccBuf[i] = (BYTE) NF_DATA_R();
        }
    }

    //  Verify the ECC values
    //
    //  Read the ECC buffer
    for(i=0; i<3; i++) {
        eccBuf[i] = (BYTE) NF_DATA_R();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -