inand.c

来自「linux下数据下载器的设计与实现」· C语言 代码 · 共 985 行 · 第 1/3 页

C
985
字号
//-----------------------------------------------------------------------------
// Copyright (c) 2005 Cypress Semiconductor, Inc. All rights reserved
//
// File: inand.c
//  Contents: 
//    Interleave NAND support the bInterLeave Flag will enable
//    Odd number NAND chips, the interleave FW will be disable
//    Even number NAND chips, then interleave FW will be enable
//

//-----------------------------------------------------------------------------
#include "globals.h"


WORD xdata gLog2Phy[cMaxBlock] ;         // bit0-11 addr map, bit12=1=free, 0=used
BYTE  xdata gCurZone, gZones, gBankSel, gPartialCpy;  // Use this byte to reload the Table
WORD  gDst, gSrc, gFreeBlk;             // These variable will be shared

DWORD gSrcAdd, gPhyAdd, gNextLBA;       // sharing variables in multiple subrountines
BYTE  ecc0[6], ecc1[6];                 // Optimize ECC variables
BYTE  xdata gSrcBlk0;                         // use for EraseBlock
xword *pDst;

#ifndef USE_2NAND
// fast coding for bank select
const char code aBanks[4]={0xfc, 0xf3, 0xcf, 0x3f};  // interleave bank
const char code aBank0[4]={0xfe, 0xfb, 0xef, 0xbf};  // interleave bank
const char code aBank1[4]={0xfd, 0xf7, 0xdf, 0x7f};  // interleave bank
const char code nBank[8]={0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};
BYTE  xdata gEnableBanks;

#ifndef NAND_2K
BYTE  gEnableBank0, gEnableBank1;      // optimize variables
#endif

#endif


// Note: These variables below will be used to optimize speed
// These variables use in conjunction with MPAGE that map to 0xE6xx
pbyte P_GPIFTCB0        _at_ 0xd1;    // GPIFTCB0
pbyte P_GPIFTCB1        _at_ 0xd0;    // GPIFTCB1
pbyte P_XAUTODAT1       _at_ 0x7b;    // XAUTODAT1
pbyte P_XAUTODAT2       _at_ 0x7c;    // XAUTODAT2
pbyte P_ECC1B0[6]       _at_ 0x2a;    // 6 bytes ECC registers
pbyte P_INPKTEND        _at_ 0x48;    // INPKTEND
pbyte P_OUTPKTEND       _at_ 0x49;    // OUTPKTEND
pbyte P_ECCCFG          _at_ 0x28;    // ECCCFG
pbyte P_ECCRESET        _at_ 0x29;    // ECCRESET
pbyte P_EP6BCH          _at_ 0x98;    // EP6BCH
pbyte P_EP6BCL          _at_ 0x99;    // EP6BCL
pbyte P_EP4BCH          _at_ 0x94;    // EP4BCH
pbyte P_EP4BCL          _at_ 0x95;    // EP4BCL
pbyte P_GPIFREADYSTAT   _at_ 0xf4;    // GPIFREADYSTAT
pbyte P_FIFORESET       _at_ 0x04;    // FIFORESET
pbyte P_EP6CFG          _at_ 0x14;    // EP6CFG
pbyte P_EP2FIFOCFG      _at_ 0x18;    // EP2FIFOCFG
pbyte P_XGPIFSGLDATLX   _at_ 0xf1;    // XGPIFSGLDATLX
pbyte P_XGPIFSGLDATLNOX _at_ 0xf2;    // XGPIFSGLDATLNOX
pbyte P_EP2CS           _at_ 0xa3;    // EP2CS
pbyte P_EP4CS           _at_ 0xa4;    // EP4CS
pbyte P_EP6CS           _at_ 0xa5;    // EP4CS


//==========================================================================
// NAND Hardware/software init
//   Donot call this subroutine during the SOFT RESET (i.e. softReset)
//==========================================================================
void InitNAND()
{
	gNandBits = 0;      // all the NAND bits variables = 0
    FwCfg = 0;
    NandCfg = 0;
    gFreeBlk = 0; 
    gPartialCpy = 0;
    dwLBA = 0;
    GetNandCfg();       // Get NAND Configuration from MFG TOOL
    directionIn=1;      // Compute Log2Phy Table at init time
    NAND_WP = 1;
    gCurZone = 0xff;    // Load current zone
	//UM_SendChar('A');
	//UM_SendString("InitNand:Log2phy\n");
    Log2Phy();
    ready_default();    // restore default value
#ifndef NO_WP
    bWPSwitchState = NAND_WP_SWITCH;
#endif
    DISABLE_NAND();    
}

//==========================================================================
// Get Free block from LUT
// This search always return a free block
//==========================================================================
void nGetFreeBlk()
{
    while (!bFreeFound)          // search until found free block
        nSearchFreeBlock(0);     // will search for 256 entries
    bFreeFound = 0;
}

//==========================================================================
// NAND EraseBlocks on both banks
//  input: gSrcAdd     = Current Src Block
//==========================================================================
void nEraseBlock()
{
    if (bNeedErase)              // only erase if needed
    {   // erase both banks in the interleave mode
#ifndef NAND_2K
#ifdef USE_2NAND
        CE0_ON(), CE1_ON();      // Enable both banks for interleave mode
#else
        IOD=gEnableBanks;        // non-interleave this should be only 1 bank
#endif
#endif
        xSrcAdd = gSrcBlk0;
        nand_blk_erase(gSrcAdd);    
        // after erasing the NAND, there are some spare time for background search
        nSearchFreeBlock(0);     // will search for 256 entries
    }
}

#pragma OT(7, SPEED)            // Use this optimize for the speed

//==========================================================================
// Clear 16-byte each pass.  
// Maximun 4K buffer 
//==========================================================================
void memset16(BYTE xdata *dest, BYTE c, BYTE len)
{
    AUTOPTR1H = MSB(dest); AUTOPTR1L = LSB(dest);
    do
    {    // Unrole the loop to speed up memory fill
         P_XAUTODAT1 = P_XAUTODAT1 = P_XAUTODAT1 = P_XAUTODAT1 = 
         P_XAUTODAT1 = P_XAUTODAT1 = P_XAUTODAT1 = P_XAUTODAT1 = 
         P_XAUTODAT1 = P_XAUTODAT1 = P_XAUTODAT1 = P_XAUTODAT1 = 
         P_XAUTODAT1 = P_XAUTODAT1 = P_XAUTODAT1 = P_XAUTODAT1 = c;
    } while (--len>0);
}

//==========================================================================
// Read NAND Pages: Supports for both interleave and non-interleave
//   return bErr and b2BitErr, which will send STALL to USB Host
// Modify:
//    ecc0[] and ecc1[]
//    bMsk, bCnt
//==========================================================================
void nReadPages()
{
#ifdef NAND_2K
    Log2Phy();                                      // remap logical blocks

    // Read the first 512 byte data and save all the ECC data in ecc0[]
    // and ecc1[] buffers.  The CheckECC will be called to verify the ECC
    // during the polling for GPIF DMA done (USB data transfer to USB Host)
   
    P_GPIFTCB1 = MSB(cNAND_PSIZE);                  // Setup GPIF count high
    P_ECCRESET = P_GPIFTCB0 = LSB(cNAND_PSIZE);     // Reset ECC and GPIF low count
    GPIFTRIG = 0x04 | cEP4;                         // Arm EP4
    // Compute while GPIF Busy
    ECCSetup(EP4FIFO);                              // Poll GPIF and store ECC data
    if (!bMsk)
    {
        if (bReload) { CheckECC(); Log2Phy(); }     // check if need to remap page
        else n2k_set_radd();
    }
    if (bCnt)
    {
        do
        {
            P_GPIFTCB1 = MSB(cNAND_PSIZE);              // Setup GPIF count high
            P_ECCRESET = P_GPIFTCB0 = LSB(cNAND_PSIZE); // Reset ECC and GPIF low count
            GPIFTRIG = 0x04 | cEP4;                     // Arm EP4
            //=========================================================================
            // local computation while polling GPIF done to optimize the speed
            //=========================================================================
            CheckECC();                                 // Verify previous ECC data
            ECCSetup(EP4FIFO);
            if (!bMsk) 
            {
                if (bReload) Log2Phy(); 
                else n2k_set_radd();
            }
        } while (bCnt);
    }
    CheckECC();                              // Verify last ECC data
#else
    Log2Phy();                               // remap logical blocks
    if (bInterLeave)                         // interleave FW
    {
        bank_select(cBank0);                 // select bank 0
        if (bLBA0)                           // if Odd sector, need aligment
        {
            FifoRd(cEP6, 528);               // dummy read-> next sector
            bank_select(cBank1);
        }
    }
    // Read the first 512 byte data and save all the ECC data in ecc0[]
    // and ecc1[] buffers.  The CheckECC will be called to verify the ECC
    // during the polling for GPIF DMA done (USB data transfer to USB Host)
    P_GPIFTCB1 = MSB(cNAND_PSIZE);               // Setup GPIF count high
    P_ECCRESET = P_GPIFTCB0 = LSB(cNAND_PSIZE);  // Reset ECC and GPIF low count
    GPIFTRIG = 0x04 | cEP4;                      // Arm EP4
    // Compute while GPIF Busy
    ECCSetup(EP4FIFO);
    if (bReload) { CheckECC(); Log2Phy(); }      // check if need to remap page
    if (bCnt)
    {
       AUTOPTRH2 = MSB(cGPIFBANK);
       AUTOPTRL2 = LSB(cGPIFBANK);
       do
       {
            P_GPIFTCB1 = MSB(cNAND_PSIZE);               // Setup GPIF count high
            P_ECCRESET = P_GPIFTCB0 = LSB(cNAND_PSIZE);  // Reset ECC and GPIF low count
            fast_bank_sel(gBankSel);                     // use AUTO PTR2
            GPIFTRIG = 0x04 | cEP4;                      // Arm EP4
            AUTOPTRL2 = LSB(cGPIFBANK);                  // init again
            //=========================================================================
            // local computation while polling GPIF done to optimize the speed
            //=========================================================================
            CheckECC();
            ECCSetup(EP4FIFO);
            if (bReload) Log2Phy(); 
        }  while (bCnt);
        AUTOPTRH2 = MSB(EP4FIFOBUF);
    }
    CheckECC();                              // if ECC error, will send stall
    bank_default();
#endif
    DISABLE_NAND();
}

//==========================================================================
// Setup AUTO pointer for P_XAUTODAT1
// Read ECC registers when first 256 ECC calculation done
// Read 512 byte data and save:
//     ecc0[] contains GPIF HW generate 6 ECC bytes
//     ecc1[] contains ECC data from redundant area
//==========================================================================
void ECCSetup(WORD offset)
{
    dwLBA++;                // next sector     
    bCnt = --gSectorcount && !bErr;
    // Loading the Pointer of stored 6-bytes ECC data
    AUTOPTR1H = MSB(offset);
    AUTOPTR1L = LSB(offset);
#ifdef NAND_2K
    bReload   = xLBA3 ==0 && bCnt;    // compute bReload
    bMsk      = xLBA3 & 3;   
    if (!bMsk) xPhyAdd++;             // 2K NAND address inc
#else
    if (bInterLeave)
    {   
        // Set this flag when all the pages in the block are done
        // Interleave total pages are 64
        // Non-Interleave total pages are 32
        bReload   = (xLBA3 & cInterLeaveMsk)==0 && bCnt;    // compute bReload
        // Select bank base on the dwLBA bit 0
        if (bLBA0) gBankSel = cBank1; else gBankSel = cBank0;
    }
    else
    {
        gBankSel = cBank3;     // non interleave keep the default value
        bReload   = (xLBA3 & (c512PageSize-1))==0 && bCnt;    // compute bReload
    }
#endif
    while (P_GPIFTCB1);          // Read the first 256 ECC registers
    ecc0[0] = P_ECC1B0[0];       // save to local buffers
    ecc0[1] = P_ECC1B0[1]; 
    ecc0[2] = P_ECC1B0[2]; 
    while (P_GPIFTCB0 & 0xf8);   // Read second 256 ECC registers       
    ecc0[3] = P_ECC1B0[3];       // save ECC 
    ecc0[4] = P_ECC1B0[4];       // GPIF will be done afer reading these
    ecc0[5] = P_ECC1B0[5];       // registers
    // Stored 6-byte ECC data from NAND Flash
    ecc1[0] = P_XAUTODAT1;    
    ecc1[1] = P_XAUTODAT1;    
    ecc1[2] = P_XAUTODAT1;    
    ecc1[3] = P_XAUTODAT1;    
    ecc1[4] = P_XAUTODAT1;    
    ecc1[5] = P_XAUTODAT1;    
    P_INPKTEND   = 0x84;          // skip 16-byte of the redundant data
}

//==========================================================================
//  Check ECC, if fail, return bErr=1
//  Should call CorrectData if more than ECC 2bit error, the b2BitErr will 
//  be set.
//  Modify:
//     bCnt = 0 will terminate the while loop
//     bErr = 1 will send STALL to USB Host
//==========================================================================
void CheckECC()
{
     if   ( (ecc0[0] != ecc1[0]) || (ecc0[1] != ecc1[1]) || (ecc0[2] != ecc1[2]) ||
            (ecc0[3] != ecc1[3]) || (ecc0[4] != ecc1[4]) || (ecc0[5] != ecc1[5]) )
     {
         bErr = 1; bCnt = 0; // Will stall in the Status phase
     }
}

//==========================================================================
// Get Physical block from LUT
// return gCurZone    = (dwLBA/PageSize)/cMaxLogical
//                    = (dwLBA/PageSize) % cMaxLogical
//        gPhyAdd     = Physical block
//        gSrcAdd     = Physical Source Address for Write
//==========================================================================
void Log2Phy()
{
    BYTE xdata page, zz, z;
    WORD xdata wi, wTmp;
#ifdef NAND_2K
    if (bErr) return;    
    page    = xLBA3;                           // 2K: pagesize = 256
    ((BYTE *)&gDst)[0] = ((BYTE *)&dwLBA)[1];  // MSB: gDst = (WORD)(dwLBA>>16);
    ((BYTE *)&gDst)[1] = ((BYTE *)&dwLBA)[2];  // LSB:  Dst = 2K Block number   
    z = 0;
    while (gDst >= cMaxLogical) { gDst -= cMaxLogical; z++; }  // z = gDst/cMaxLogical
  
    zz  = z & (gZones-1);
    z   /= gZones;                     // z = number of NAND bank
#ifdef USE_2NAND
    if (z==0) CE0_ON(), CE1_OFF(); else CE1_ON(), CE0_OFF();
#else
    gEnableBanks = IOD = nBank[z];     // enable banks
#endif

⌨️ 快捷键说明

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