inand.c

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

C
985
字号
    if ((gBank != z) || (zz != gCurZone))     // need to reload when bank switch
    { 
		//UM_SendString("\nREFISH************\n");
        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);
			////////////////////////////////////////////////
			//LigangWang for debug
			//if(dwLBA == 0)
			//{
			//	UM_SendString("\n");
			//	for(i = 0;i < (cNAND_RSIZ+1);i++)
			//		UM_SendByte(EP6FIFOBUF[i]);
			//}
			////////////////////////////////////////////////
            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
	
	//UM_SendString("R:LBA=");
	//UM_SendByte(((BYTE *)&dwLBA)[3]);
	//UM_SendByte(((BYTE *)&dwLBA)[2]);
	//UM_SendByte(((BYTE *)&dwLBA)[1]);
	//UM_SendByte(((BYTE *)&dwLBA)[0]);
    
	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));
		
		//UM_SendString("RPHY=");
		//UM_SendByte(((BYTE *)&gPhyAdd)[3]);
		//UM_SendByte(((BYTE *)&gPhyAdd)[2]);
		//UM_SendByte(((BYTE *)&gPhyAdd)[1]);
		//UM_SendString("\n");
    }
    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);
		}

		//UM_SendString("WPHY=");
		//UM_SendByte(((BYTE *)&gPhyAdd)[3]);
		//UM_SendByte(((BYTE *)&gPhyAdd)[2]);
		//UM_SendByte(((BYTE *)&gPhyAdd)[1]);

	  	//UM_SendString("SPHY=");
		//UM_SendByte(((BYTE *)&gSrcAdd)[3]);
		//UM_SendByte(((BYTE *)&gSrcAdd)[2]);
		//UM_SendByte(((BYTE *)&gSrcAdd)[1]);
	  	//UM_SendString("\n");
		
    }
#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 xdata 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]; 
        ecc0[2] = P_ECC1B0[2]; 
        while (!gpifIdle());

        
		//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

⌨️ 快捷键说明

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