📄 inand.c
字号:
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 page, zz, z;
WORD 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
if ((gBank != z) || (zz != gCurZone)) // need to reload when bank switch
{
gBank = z; // update bank
gCurZone = zz; // update zone
//=================================================================
// BuildTable();
// This function build the LUT for Logical to Physical translation
// need gCurZone
//=================================================================
memset16((xbyte*)gLog2Phy, MSB(cBLK_INIT), (cMaxBlock*2)/16);
((BYTE *)&gPhyAdd)[3] = 0;
((BYTE *)&gPhyAdd)[2] = 0; // optimize for speed
((BYTE *)&gPhyAdd)[1] = gCurZone; // gPhyAdd <<= 16;
for (wi=0; wi<cMaxBlock; wi++)
{ // read the redundant section of the page into EP6
xbyte *p = &gLog2Phy[wi]; // get address pointer
NandSetAdd(cNAND_READ_DATA, 4);
Fifo6In();
NandRead(cEP6, cNAND_RSIZ);
bFreeBlk = (EP6FIFOBUF[0] == 0xff) && (EP6FIFOBUF[1] == 0xff);
if (!bFreeBlk)
*p |= MSB(cBLK_CFG); // special block or bad block
else
{
((BYTE *)&wTmp)[0] = EP6FIFOBUF[cAddOffset]; // MSB address1
// check if the block is not free
if (((BYTE *)&wTmp)[0] != 0xff)
{
((BYTE *)&wTmp)[1] = EP6FIFOBUF[cAddOffset+1]; // LSB address1
if ( (((BYTE *)&wTmp)[0] == EP6FIFOBUF[cAddOffset+2]) && // check if both addresses are matched
(((BYTE *)&wTmp)[1] == EP6FIFOBUF[cAddOffset+3]) )
{
xword *pTmp = &gLog2Phy[wTmp];
wTmp = *pTmp;
if (wTmp & cBLK_INIT) // multiple blocks map check
{ *pTmp = ( wTmp & cBLK_uMSK ) | wi; // store the remap block
*p |= MSB(cBLK_USE); // Set Block Use
}
else
{
nand_blk_erase(gPhyAdd);
*(xbyte*)0xe100 = 0xee;
}
}
} // else this block is free
}
gPhyAdd += c2KPageSize; // next block for 2K NAND
} // for wi
bFreeFound = 0; // cross the Zone, reset the Free Block Found
} // update table again
wTmp = zz << cMaxBlock2N; // compute Zone
pDst = gLog2Phy + gDst; // pDst = &gLog2Phy[gDst]
gSrc = *pDst & cBLK_aMSK; // gLog2Phy[gDst]: Get Physical block
if (directionIn) // read just get the table
{
wTmp |= gSrc;
((BYTE *)&gPhyAdd)[3] = ( ((BYTE *)&wTmp)[1] << 6 ) | (page>>2);
((BYTE *)&gPhyAdd)[2] = ( ((BYTE *)&wTmp)[1] >> 2 ) | ( ((BYTE *)&wTmp)[0] << 6 );
((BYTE *)&gPhyAdd)[1] = ( ((BYTE *)&wTmp)[0] >> 2 );
NandSetAdd(cNAND_READ_DATA, (page&3));
}
else
{
xbyte *p;
nGetFreeBlk(); // get Free Block
wi = gFreeBlk;
if (gSrc&cBLK_INIT) gSrc=wi; // default value set to free block
bNeedErase = (wi != gSrc); // don't erase if Src = Dst && block free
// *(xbyte*)&gLog2Phy[gSrc] &= MSB(~cBLK_USE); // set this block free
p = (xbyte*)&gLog2Phy[gSrc]; // point to the SRC block
// July-07-05 Free Block must exclude CFG block as well
bFreeBlk = !(*p & MSB(cBLK_uMSK)); // free block
*p = *p & MSB(~cBLK_USE); // set this block free
*(xbyte*)&gLog2Phy[wi] |= MSB(cBLK_USE); // Set this block is used
*pDst = (*pDst & cBLK_uMSK) | wi; // update Logical address
wi |= wTmp;
((BYTE *)&gPhyAdd)[3] = ( ((BYTE *)&wi)[1] << 6 );
((BYTE *)&gPhyAdd)[2] = ( ((BYTE *)&wi)[1] >> 2 ) | ( ((BYTE *)&wi)[0] << 6 );
((BYTE *)&gPhyAdd)[1] = ( ((BYTE *)&wi)[0] >> 2 );
wTmp |= gSrc;
gSrcBlk0 = ((BYTE *)&gSrcAdd)[3] = ( ((BYTE *)&wTmp)[1] << 6 );
((BYTE *)&gSrcAdd)[2] = ( ((BYTE *)&wTmp)[1] >> 2 ) | ( ((BYTE *)&wTmp)[0] << 6 );
((BYTE *)&gSrcAdd)[1] = ( ((BYTE *)&wTmp)[0] >> 2 );
if (page) NAND_PCPY(page, 0);
}
#else
BYTE npage;
if (bErr) return;
gSrc = (WORD)dwLBA;
((BYTE *)&gDst)[0] = ((BYTE *)&dwLBA)[0]; // MSB: gDst = (WORD)(dwLBA>>16);
((BYTE *)&gDst)[1] = ((BYTE *)&dwLBA)[1]; // LSB
if (bInterLeave)
{
page = xLBA3 & cInterLeaveMsk;
npage = page>>1; // remove bit0 for interleave
gDst <<= 16-(c512PageSize2N+1); // dwLBA >>= c512PageSize2N+1
gSrc >>= c512PageSize2N+1;
}
else
{
npage = page = xLBA3 & (c512PageSize-1); // mask page 5-bits 0x1F
gDst <<= 16-c512PageSize2N; // dwLBA >>= c512PageSize2N
gSrc >>= c512PageSize2N;
}
gDst |= gSrc; // gDst = dwLBA/c512PageSize
z = 0;
while (gDst >= cMaxLogical) { gDst -= cMaxLogical; z++; } // z = gDst/cMaxLogical
zz = z & (gZones-1); // zz = zone numbers within a NAND
z /= gZones; // gZones=8=8192, gZones=4=4096
#ifdef USE_2NAND
CE0_ON(),CE1_ON(); // enable both NAND chip select
#else
gEnableBanks = IOD = aBanks[z]; // pre-load fast variables
#endif
// Reload the LUT when cross bank and zone
if ( zz != gCurZone || z != gBank)
{
#ifndef USE_2NAND
gEnableBank0 = aBank0[z]; // pre-load fast variables
gEnableBank1 = aBank1[z]; // pre-load fast variables
#endif
gBank = z; // update bank
gCurZone = zz;
// 1K Zone
// gPhyAdd = ((DWORD)gCurZone << (cMaxBlock2N+c512PageSize2N)); // Get Page address
((BYTE *)&gPhyAdd)[3] = 0;
((BYTE *)&gPhyAdd)[2] = gCurZone<<7;
((BYTE *)&gPhyAdd)[1] = gCurZone>>1;
// 2K Zone
//((BYTE *)&gPhyAdd)[3] = 0;
//((BYTE *)&gPhyAdd)[2] = 0; // optimize for speed
//((BYTE *)&gPhyAdd)[1] = gCurZone;
//==========================================================================
// This function build the LUT for Logical to Physical translation
// need gCurZone
//==========================================================================
memset16((xbyte*)gLog2Phy, MSB(cBLK_INIT), (cMaxBlock*2)/16);
for (wi=0; wi<cMaxBlock; wi++)
{ // read the redundant section of the page into EP6
NandSetAdd(cNAND_READ_REDUNDANT, 0);
for (z=0; z <3; z++) // retry 3 times
{
xbyte *p = &gLog2Phy[wi]; // get address pointer
// for InterLeave case
// if either block in bank0 or bank1 is bad, will mark both blocks bad
if (bInterLeave) bank_select(cBank0); // check bank0
Fifo6In();
NandRead(cEP6, 16);
bFreeBlk = (EP6FIFOBUF[0] == 0xff) && (EP6FIFOBUF[1] == 0xff);
if (bInterLeave) // check bank1
{
bank_select(cBank1);
NandRead(cEP6, 16);
if (EP6FIFOBUF[16] != 0xff || EP6FIFOBUF[17] != 0xff) bFreeBlk = 0;
}
if (!bFreeBlk)
{
*p |= MSB(cBLK_CFG); // special block or bad block
break;
}
else
{
((BYTE *)&wTmp)[0] = EP6FIFOBUF[cAddOffset]; // MSB address1
if (((BYTE *)&wTmp)[0]==0xff) break; // free block
((BYTE *)&wTmp)[1] = EP6FIFOBUF[cAddOffset+1]; // LSB address1
if ( (((BYTE *)&wTmp)[0] == EP6FIFOBUF[cAddOffset+2]) && // check if both addresses are matched
(((BYTE *)&wTmp)[1] == EP6FIFOBUF[cAddOffset+3]) )
{
xword *pTmp = &gLog2Phy[wTmp];
wTmp = *pTmp;
if (wTmp & cBLK_INIT) // multiple blocks map check
{
*pTmp = ( wTmp & cBLK_uMSK ) | wi; // store the remap block
*p |= MSB(cBLK_USE); // Set Block Use
}
else
{
NandSendCmd(cNAND_RESET); // fix the multiple blocks case
nand_blk_erase(gPhyAdd);
}
break;
}
}
if (z == 2) *p |= MSB(cBLK_BAD);
}
gPhyAdd += c512PageSize; // next block
} // for gi
bank_default(); // set default
NandSendCmd(cNAND_RESET); // must reset afer REDUNDANT read
bFreeFound = 0; // cross the Zone, reset the Free Block Found
} // update table again
wTmp = zz << cMaxBlock2N; // compute Zone
pDst = gLog2Phy + gDst; // pDst = &gLog2Phy[gDst]
gSrc = *pDst & cBLK_aMSK; // gLog2Phy[gDst]: Get Physical block
if (directionIn) // Host Read data
{
wTmp |= gSrc;
nand_ready3();
NAND_CLE = 1;
P_XGPIFSGLDATLX = cNAND_READ_DATA;
NAND_CLE = 0;
NAND_ALE = 1;
P_XGPIFSGLDATLX = 0;
P_XGPIFSGLDATLX = ( ((BYTE *)&wTmp)[1] << 5 ) | npage;
P_XGPIFSGLDATLX = ( ((BYTE *)&wTmp)[1] >> 3 ) | ( ((BYTE *)&wTmp)[0] << 5 );
P_XGPIFSGLDATLX = ( ((BYTE *)&wTmp)[0] >> 3 );
NAND_ALE = 0;
Fifo6In();
if (bInterLeave) ready_ignore();
nand_ready3();
}
else
{
nGetFreeBlk(); // get Free Block
wi = gFreeBlk;
if (gSrc&cBLK_INIT) gSrc=wi; // default value set to free block
bNeedErase = (wi != gSrc); // don't erase if Src = Dst && block free
*(xbyte*)&gLog2Phy[gSrc] &= MSB(~cBLK_USE); // set this block free
*(xbyte*)&gLog2Phy[wi] |= MSB(cBLK_USE); // Set this block is used
*pDst = (*pDst & cBLK_uMSK) | wi; // update Logical address
wi |= wTmp;
//gPhyAdd = ((DWORD)(wTmp | wi) << c512PageSize2N);
((BYTE *)&gPhyAdd)[3] = ( ((BYTE *)&wi)[1] << 5 );
((BYTE *)&gPhyAdd)[2] = ( ((BYTE *)&wi)[1] >> 3 ) | ( ((BYTE *)&wi)[0] << 5 );
((BYTE *)&gPhyAdd)[1] = ( ((BYTE *)&wi)[0] >> 3 );
//gSrcAdd = ((DWORD)(wTmp | gSrc) << c512PageSize2N);
wTmp |= gSrc;
gSrcBlk0 = ((BYTE *)&gSrcAdd)[3] = ( ((BYTE *)&wTmp)[1] << 5 );
((BYTE *)&gSrcAdd)[2] = ( ((BYTE *)&wTmp)[1] >> 3 ) | ( ((BYTE *)&wTmp)[0] << 5 );
((BYTE *)&gSrcAdd)[1] = ( ((BYTE *)&wTmp)[0] >> 3 );
// check for head copy here
if (page) nCopyPages(page, 0);
}
#endif
DBUG_DUMP();
}
//==========================================================================
// Nand Copy Pages:
// always perform ECC correction for SOFT error.
// If more than 2-bit error, return b2BitErr will be set
//==========================================================================
void nCopyPages(BYTE cnt, BYTE cc)
{
#ifdef NAND_2K
BYTE msk=cc&3;
do
{
Fifo6In();
P_GPIFTCB1 = MSB(cNAND_DSIZE+8); // setup GPIF Count
P_ECCRESET = P_GPIFTCB0 = LSB(cNAND_DSIZE+8); // Reading 512+2(status)+6(ECC)
n2k_radd(gSrcAdd, msk);
GPIFTRIG = 0x04 | cEP6; // Arm EP6
bCnt = --cnt;
// When copy pages, all the data will have ECC correction
AUTOPTR1H = MSB(cEP6FIFO);
AUTOPTR1L = LSB(cEP6FIFO);
while (P_GPIFTCB1); // Read the first 256 ECC registers
ecc0[0] = P_ECC1B0[0]; // save to local buffers
ecc0[1] = P_ECC1B0[1];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -