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 + -
显示快捷键?