Nandflash 驱动移植 (六)

Nandflash驱动移植系列文章导航:

Nandflash 驱动移植 (一)

Nandflash 驱动移植 (二)

Nandflash 驱动移植 (三)

Nandflash 驱动移植 (四)

Nandflash 驱动移植 (五)

Nandflash 驱动移植 (六)

一共六篇

 

 

 

近段时间比较忙,接着上一篇,这篇主要介绍到写的部分

 

1、FMD_LB_WriteSector()  MLC写sector

BOOL FMD_LB_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
{
    DWORD   i;
    BOOL    bRet = TRUE;
    volatile DWORD    wrdata;
    DWORD MECCBuf[16];    // 16 gjl 
    UINT16 nSectorLoop;
    int NewSpareAddr = 4096;  // 2048 gjl
    int NewDataAddr = 0;
    int NewSectorAddr = startSectorAddr;
#if CHECK_SPAREECC
    DWORD SECCBuf[4];    // 2 gjl 
#endif

#if (NAND_DEBUG)
    RETAILMSG(1, (TEXT("FMD::FMD_LB_WriteSector 0x%x \n"), startSectorAddr));
#endif

    if (!pSectorBuff && !pSectorInfoBuff)
        return(FALSE);

    if ( dwNumSectors > 1 )
    {
        RETAILMSG(1, (TEXT("######## FATAL ERROR => FMD::FMD_WriteSector->dwNumsectors is bigger than 1. \n")));
        return FALSE;
    }

    if (!pSectorBuff)
    {
        NAND_LB_WriteSectorInfo(startSectorAddr, pSectorInfoBuff);
        return TRUE;
    }

    //  Enable Chip
    NF_nFCE_L();

    NF_CLEAR_RB();

    //  Issue command
    NF_CMD(CMD_WRITE);
	
    //  Setup address
    NF_ADDR((NewDataAddr)&0xff);
    NF_ADDR((NewDataAddr>>8)&0xff);
    NF_ADDR((NewSectorAddr)&0xff);
    NF_ADDR((NewSectorAddr>>8)&0xff);
#if    LB_NEED_EXT_ADDR
    NF_ADDR((NewSectorAddr>>16)&0xff);
#endif

    for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE; nSectorLoop++)
    {
        //  Initialize ECC register
        NF_MSGLENGTH_512();
        NF_ECCTYPE_4BIT();

        NF_RSTECC();
        NF_MECC_UnLock();

        //  Special case to handle un-aligned buffer pointer.
        //
        if( ((DWORD) (pSectorBuff+nSectorLoop*SECTOR_SIZE)) & 0x3)
        {
            //  Write the data
            for(i=0; i<SECTOR_SIZE/sizeof(DWORD); i++)
            {
                wrdata = (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+0];
                wrdata |= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+1]<<8;
                wrdata |= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+2]<<16;
                wrdata |= (pSectorBuff+nSectorLoop*SECTOR_SIZE)[i*4+3]<<24;
                NF_WRDATA_WORD(wrdata);
            }
        }
        else
        {
            WrPage512(pSectorBuff+nSectorLoop*SECTOR_SIZE);
        }

        //  Read out the ECC value generated by HW
        NF_MECC_Lock();
        //encode done
        while (!(NF_RDSTAT & (1<<7)));

        MECCBuf[2*nSectorLoop] = NF_RDMECC0();
        MECCBuf[2*nSectorLoop+1] = NF_RDMECC1();
#if DEBUG_WRITE_READ_EQUAL
	g_MECCBuf[2*nSectorLoop] = MECCBuf[2*nSectorLoop];
	g_MECCBuf[2*nSectorLoop+1] = MECCBuf[2*nSectorLoop+1];
#endif
    }

    NF_CMD(CMD_RDI);
    NF_ADDR((NewSpareAddr)&0xff);
    NF_ADDR((NewSpareAddr>>8)&0xff);

    // Write the SectorInfo data to the media
    // NOTE: This hardware is odd: only a byte can be written at a time and it must reside in the
    //       upper byte of a USHORT.
    if(pSectorInfoBuff)
    {

        //  Write the first reserved field (DWORD)
        NF_WRDATA_BYTE(pSectorInfoBuff->bBadBlock);
        NF_WRDATA_WORD(pSectorInfoBuff->dwReserved1);
        NF_WRDATA_BYTE(pSectorInfoBuff->bOEMReserved);

        NF_WRDATA_BYTE(pSectorInfoBuff->wReserved2&0xff);
        NF_WRDATA_BYTE((pSectorInfoBuff->wReserved2>>8)&0xff);
    }
    else
    {
        // Make sure we advance the Flash's write pointer (even though we aren't writing the SectorInfo data)
        for(i=0; i<sizeof(SectorInfo)/sizeof(DWORD); i++)
        {
            NF_WRDATA_WORD(0xffffffff);
        }
    }

    //  Write the ECC value to the flash
    for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*2; nSectorLoop++)
        NF_WRDATA_WORD(MECCBuf[nSectorLoop]);

    //  Finish up the write operation
    NF_CMD(CMD_WRITE2);

    //  Wait for RB
    NF_DETECT_RB();     // Wait tR(max 12us)

    if ( NF_RDSTAT & STATUS_ILLACC )
    {
        RETAILMSG(1, (TEXT("FMD_WriteSector() ######## Error Programming page (Illigar Access) %d!\n"), startSectorAddr));
        g_pNFConReg->NFSTAT =  STATUS_ILLACC;    // Write 1 to clear.
        bRet = FALSE;
    }
    else
    {
        //  Check the status
        NF_CMD(CMD_STATUS);

        if(NF_RDDATA_BYTE() & STATUS_ERROR)
        {
            RETAILMSG(1, (TEXT("FMD_WriteSector() ######## Error Programming page %d!\n"), startSectorAddr));
            bRet = FALSE;
        }
    }

    //  Disable the chip
    NF_nFCE_H();

    return bRet;
}

这个是飞凌的源码,这里需要修改成8bit的ECC。

变量定义这里需要把 DWORD MECCBuf[16]; 修改成:

DWORD MECCBuf[32];



    if (!pSectorBuff)
    {
        NAND_LB_WriteSectorInfo(startSectorAddr, pSectorInfoBuff);
        return TRUE;
    }

操作之前,添加使能中断的操作:

	g_pNFConReg->NFCONT |= (1<<10);	// Enable illegal access interrupt control
	g_pNFConReg->NFCONT |= (1<<9);	// Enable RnB interrupt


for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE; nSectorLoop++)这里是循环写一个block的页数据。

        NF_MSGLENGTH_512();
        NF_ECCTYPE_4BIT();

中的 NF_ECCTYPE_4BIT(); 修改成:

		NF_ECCTYPE_8BIT();
		NF_ECC_8BIT_STOP();
		NF_ECC_DIRECTION_OUT();


//encode done
        while (!(NF_RDSTAT & (1<<7)));

处理的后面,把

        MECCBuf[2*nSectorLoop] = NF_RDMECC0();
        MECCBuf[2*nSectorLoop+1] = NF_RDMECC1();

修改成:

		MECCBuf[4*nSectorLoop] = NF_RDM8ECC0();		
		MECCBuf[4*nSectorLoop+1] = NF_RDM8ECC1();	
		MECCBuf[4*nSectorLoop+2] = NF_RDM8ECC2();	
		MECCBuf[4*nSectorLoop+3] = NF_RDM8ECC3() & 0xff;


在for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE; nSectorLoop++)循环结束的后面,

NF_CMD(CMD_RDI);
    NF_ADDR((NewSpareAddr)&0xff);
    NF_ADDR((NewSpareAddr>>8)&0xff);

操作之前,添加:

	NF_ECCTYPE_8BIT();
	NF_ECC_8BIT_STOP();


看到写入ECC数据部分:

    //  Write the ECC value to the flash
    for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*2; nSectorLoop++)
        NF_WRDATA_WORD(MECCBuf[nSectorLoop]);

这里需要把for修改成:

    for (nSectorLoop = 0; nSectorLoop < SECTORS_PER_PAGE*4; nSectorLoop++)


在片选操作 

   //  Disable the chip
    NF_nFCE_H();

之前添加:

	g_pNFConReg->NFCONT &= ~(1<<10);	// Disable illegal access interrupt control
	g_pNFConReg->NFCONT &= ~(1<<9);		// Disable RnB interrupt


到此,写入部分修改完毕

 

 

 

2、NAND_LB_WriteSectorInfo()   写sector信息

BOOL NAND_LB_WriteSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)
{
    BOOL    bRet = TRUE;
    int NewSpareAddr = 4096;   // gjl 2048
    int NewSectorAddr = sectorAddr;
#if CHECK_SPAREECC
    DWORD SECCBuf[4];    // gjl 2
#endif

    //  Chip enable
    NF_nFCE_L();

    NF_CLEAR_RB();

    //  Write the command
    //  First, let's point to the spare area
    NF_CMD(CMD_WRITE);
	
    //  Write the address
    NF_ADDR((NewSpareAddr)&0xff);
    NF_ADDR((NewSpareAddr>>8)&0xff);
    NF_ADDR((NewSectorAddr)&0xff);
    NF_ADDR((NewSectorAddr>>8)&0xff);
#if    LB_NEED_EXT_ADDR
    NF_ADDR((NewSectorAddr>>16)&0xff);
#endif
    NF_MSGLENGTH_512();
    NF_ECCTYPE_4BIT();


    //  Now let's write the SectorInfo data
    //
    //  Write the first reserved field (DWORD)
    NF_WRDATA_BYTE(pInfo->bBadBlock);
    NF_WRDATA_WORD(pInfo->dwReserved1);
    NF_WRDATA_BYTE(pInfo->bOEMReserved);

    NF_WRDATA_BYTE(pInfo->wReserved2&0xff);
    NF_WRDATA_BYTE((pInfo->wReserved2>>8)&0xff);

    NF_WRDATA_WORD(0xffffffff);  // Mecc[0]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[1]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[2]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[3]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[4]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[5]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[6]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[7]
   

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

    //  Check ready bit
    NF_DETECT_RB();     // Wait tR(max 12us)

    if ( NF_RDSTAT & STATUS_ILLACC )
    {
        RETAILMSG(1, (TEXT("NAND_LB_WriteSectorInfo() ######## Error Programming page (Illigar Access) %d!\n"), sectorAddr));
        g_pNFConReg->NFSTAT =  STATUS_ILLACC;    // Write 1 to clear.
           bRet = FALSE;
    }
    else
    {
        //  Check the status of program
        NF_CMD(CMD_STATUS);

        if( NF_RDDATA_BYTE() & STATUS_ERROR) {
            RETAILMSG(1, (TEXT("NAND_LB_WriteSectorInfo() ######## Error Programming page %d!\n"), sectorAddr));
            bRet = FALSE;
        }
    }

    NF_nFCE_H();

    return bRet;
}

这个是飞凌给的源码,从上面可以看出也是只用到了4bit的ECC。下面我们将其改成8bit的ECC:

看到
    NF_MSGLENGTH_512();
    NF_ECCTYPE_4BIT();

这两个处理,我们把其中的 NF_ECCTYPE_4BIT(); 修改成

	NF_ECCTYPE_8BIT();			// use 8bit ECC type
	NF_ECC_8BIT_STOP();		// init 8bit ECC decoding


然后,就开始写入sector的信息数据了,这里主要看写入主ECC数据部分,原文的是
    NF_WRDATA_WORD(0xffffffff);  // Mecc[0]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[1]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[2]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[3]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[4]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[5]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[6]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[7]

这里需要修改成:

	// 16 byte Sector0 ECC data
    NF_WRDATA_WORD(0xffffffff);  // Mecc[0]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[1]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[2]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[3]
	// 16 byte Sector1 ECC data
    NF_WRDATA_WORD(0xffffffff);  // Mecc[4]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[5]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[6]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[7]
	// 16 byte Sector2 ECC data
    NF_WRDATA_WORD(0xffffffff);  // Mecc[8]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[9]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[10]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[11]
	// 16 byte Sector3 ECC data
    NF_WRDATA_WORD(0xffffffff);  // Mecc[12]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[13]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[14]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[15]
	// 16 byte Sector4 ECC data
    NF_WRDATA_WORD(0xffffffff);  // Mecc[16]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[17]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[18]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[19]
	// 16 byte Sector5 ECC data
    NF_WRDATA_WORD(0xffffffff);  // Mecc[20]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[21]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[22]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[23]
	// 16 byte Sector6 ECC data
    NF_WRDATA_WORD(0xffffffff);  // Mecc[24]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[25]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[26]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[27]
	// 16 byte Sector7 ECC data
    NF_WRDATA_WORD(0xffffffff);  // Mecc[28]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[29]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[30]
    NF_WRDATA_WORD(0xffffffff);  // Mecc[31]


该函数中剩余的部分就不需要修改了。

这里之所以这样修改,是因为每512字节的主数据就产生4*4字节的ECC,而我们这里每个block有4096字节,即8个512字节,也就是8 * 16个字节的ECC数据。

 

 

 

3、FMD_SB_WriteSector()

BOOL FMD_SB_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
{
    BYTE Status;
    ULONG SectorAddr = (ULONG)startSectorAddr;
    ULONG MECC;

    if (!pSectorBuff && !pSectorInfoBuff)
        return(FALSE);

#if (NAND_DEBUG)
    RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_sbwrite \n")));
#endif

    NF_nFCE_L();                        // Select the flash chip.

    while (dwNumSectors--)
    {
        if (!pSectorBuff)    // Only spare area
        {
            // If we are asked just to write the SectorInfo, we will do that separately
            NF_CMD(CMD_READ2);                             // Send read command.

            NF_CMD(CMD_WRITE);                            // Send write command.
            NF_ADDR(0);                                    // Column = 0.
            NF_ADDR(SectorAddr         & 0xff);            // Page address.
            NF_ADDR((SectorAddr >>  8) & 0xff);
#if    SB_NEED_EXT_ADDR
            NF_ADDR((SectorAddr >> 16) & 0xff);
#endif

            // Write the SectorInfo data to the media.
            // Spare area[7:0]
            WrPageInfo((PBYTE)pSectorInfoBuff);

            NF_CLEAR_RB();
            NF_CMD(CMD_WRITE2);                // Send write confirm command.
            NF_DETECT_RB();

            NF_CMD(CMD_STATUS);
            Status = NF_RDDATA_BYTE();                    // Read command status.

            if (Status & STATUS_ERROR)
            {
                NF_nFCE_H();                            // Deselect the flash chip.
                //SetKMode (bLastMode);
                return(FALSE);
            }
            pSectorInfoBuff++;
        }
        else         // Main area+Spare area.
        {
            NF_CMD(CMD_READ);                             // Send read command.
            NF_CMD(CMD_WRITE);                            // Send write command.
            NF_ADDR(0);                                    // Column = 0.
            NF_ADDR(SectorAddr         & 0xff);            // Page address.
            NF_ADDR((SectorAddr >>  8) & 0xff);
#if    SB_NEED_EXT_ADDR
            NF_ADDR((SectorAddr >> 16) & 0xff);
#endif

            //  Special case to handle un-aligned buffer pointer.
            NF_RSTECC();
            NF_MECC_UnLock();
            if( ((DWORD) pSectorBuff) & 0x3)
            {
                WrPage512Unalign (pSectorBuff);
            }
            else
            {
                WrPage512(pSectorBuff);                    // Write page/sector data.
            }
            NF_MECC_Lock();

            // Write the SectorInfo data to the media.
            // Spare area[7:0]
            if(pSectorInfoBuff)
            {
                WrPageInfo((PBYTE)pSectorInfoBuff);
                pSectorInfoBuff++;
            }
            else    // Make sure we advance the Flash's write pointer (even though we aren't writing the SectorInfo data)
            {
                BYTE TempInfo[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
                WrPageInfo(TempInfo);
            }

            // Write the SectorInfo data to the media.
            // Spare area[11:8]
            // Get the ECC data from status register.
            MECC = NF_RDMECC0();
            // Now, Write the ECC data to Spare area[11:8]
            NF_WRDATA_BYTE((UCHAR)((MECC      ) & 0xff));        // Spare area offset 8
            NF_WRDATA_BYTE((UCHAR)((MECC >>  8) & 0xff));    // Spare area offset 9
            NF_WRDATA_BYTE((UCHAR)((MECC >> 16) & 0xff));    // Spare area offset 10
            NF_WRDATA_BYTE((UCHAR)((MECC >> 24) & 0xff));    // Spare area offset 11

            NF_CLEAR_RB();
            NF_CMD(CMD_WRITE2);                            // Send write confirm command.
            NF_DETECT_RB();

            do
            {
                NF_CMD(CMD_STATUS);
                Status = NF_RDDATA_BYTE();                    // Read command status.
            }while(!(Status & STATUS_READY));

            if (Status & STATUS_ERROR)
            {
                NF_nFCE_H();                            // Deselect the flash chip.
                return(FALSE);
            }
            pSectorBuff += NAND_SECTOR_SIZE;
        }
        ++SectorAddr;
    }
    NF_nFCE_H();                                        // Deselect the flash chip.

    return(TRUE);
}


这部分就不需要修改了,上面的代码是处理SLC部分的

 

 

 

4、FMD_LB_EraseBlock()   擦出块

BOOL FMD_LB_EraseBlock(BLOCK_ID blockID)
{
    BOOL    bRet = TRUE;
    DWORD   dwPageID = blockID << LB_NAND_LOG_2_PAGES_PER_BLOCK;

#if (NAND_DEBUG)
    RETAILMSG(1, (TEXT("FMD_LB_EraseBlock 0x%x \n"), blockID));
#endif

    //  Enable the chip
    NF_nFCE_L();        // Select the flash chip.

    NF_CLEAR_RB();
    NF_MSGLENGTH_512();
    //  Issue command
    NF_CMD(CMD_ERASE);

    //  Set up address
    NF_ADDR((dwPageID) & 0xff);
    NF_ADDR((dwPageID >> 8) & 0xff);
#if    LB_NEED_EXT_ADDR
    NF_ADDR((dwPageID >> 16) & 0xff);
#endif

    //  Complete erase operation
    NF_CMD(CMD_ERASE2);

    //  Wait for ready bit
    NF_DETECT_RB();     // Wait tR(max 12us)

    if ( NF_RDSTAT & STATUS_ILLACC )
    {
            RETAILMSG(1, (TEXT("LB######## Error Erasing block (Illigar Access) %d!\n"), blockID));
        g_pNFConReg->NFSTAT =  STATUS_ILLACC;    // Write 1 to clear.
        bRet = FALSE;
    }
    else
    {
        //  Check the status
        NF_CMD(CMD_STATUS);

        if( NF_RDDATA_BYTE() & STATUS_ERROR)
        {
            RETAILMSG(1, (TEXT("LB######## Error Erasing block %d!\n"), blockID));
            bRet = FALSE;
        }
    }

    NF_nFCE_H();                        // Select the flash chip.

    return bRet;
}

上述是飞凌的源码,这里我们需要稍作修改。

在使能片选 NF_nFCE_L();  之前,我们需要使能一些中断:

	g_pNFConReg->NFCONT |= (1<<10);	// Enable illegal access interrupt control
	g_pNFConReg->NFCONT |= (1<<9);	// Enable RnB interrupt


擦除操作处理完之后,在 NF_nFCE_H(); 之前,需要关闭前面使能的中断:

	g_pNFConReg->NFCONT &= ~(1<<10);	// Disable illegal access interrupt control
	g_pNFConReg->NFCONT &= ~(1<<9);		// Disable RnB interrupt

 

 

 

5、FMD_SB_EraseBlock()

BOOL FMD_SB_EraseBlock(BLOCK_ID blockID)
{
    BOOL    bRet = TRUE;
    DWORD   dwPageID = blockID << SB_NAND_LOG_2_PAGES_PER_BLOCK;

    //  Enable the chip
    NF_nFCE_L();                        // Select the flash chip.

    //  Issue command
    NF_CMD(CMD_ERASE);

    //  Set up address
    NF_ADDR((dwPageID) & 0xff);
    NF_ADDR((dwPageID >> 8) & 0xff);
#if    SB_NEED_EXT_ADDR
    NF_ADDR((dwPageID >> 16) & 0xff);
#endif

    NF_CLEAR_RB();

    //  Complete erase operation
    NF_CMD(CMD_ERASE2);

    //  Wait for ready bit
    NF_DETECT_RB();     // Wait tR(max 12us)

    if ( NF_RDSTAT & STATUS_ILLACC )
    {
        RETAILMSG(1, (TEXT("SB######## Error Erasing block (Illigar Access) %d!\n"), blockID));
        g_pNFConReg->NFSTAT =  STATUS_ILLACC;    // Write 1 to clear.
        bRet = FALSE;
    }
    else
    {
        //  Check the status
        NF_CMD(CMD_STATUS);

        if( NF_RDDATA_BYTE() & STATUS_ERROR)
        {
            RETAILMSG(1, (TEXT("SB######## Error Erasing block %d!\n"), blockID));
            bRet = FALSE;
        }
    }

    NF_nFCE_H();                        // Select the flash chip.

    return bRet;
}


SLC擦除块操作,这里不需要修改

 

 

 

6、FMD_LB_GetBlockStatus()  MLC获取块的状态

DWORD FMD_LB_GetBlockStatus(BLOCK_ID blockID)
{
    BLOCK_ID blockID_bad = blockID + 1;
    SECTOR_ADDR sectorAddr = (blockID_bad << LB_NAND_LOG_2_PAGES_PER_BLOCK) - 1;
    SectorInfo SI;
    DWORD dwResult = 0;

    //RETAILMSG(1, (TEXT("FMD_LB_GetBlockStatus (0x%x)0x%x \n"), blockID, sectorAddr));

    if(!FMD_LB_ReadSector(sectorAddr, NULL, &SI, 1))
    {
            return BLOCK_STATUS_UNKNOWN;
    }

    if(!(SI.bOEMReserved & OEM_BLOCK_READONLY))
    {
        dwResult |= BLOCK_STATUS_READONLY;
    }

    if (!(SI.bOEMReserved & OEM_BLOCK_RESERVED))
    {
        dwResult |= BLOCK_STATUS_RESERVED;
    }

    if(SI.bBadBlock != 0xFF)
    {
        dwResult |= BLOCK_STATUS_BAD;
    }

    return dwResult;
}


 

 

 

7、FMD_SB_GetBlockStatus()  SLC读取块状态

DWORD FMD_SB_GetBlockStatus(BLOCK_ID blockID)
{
    SECTOR_ADDR sectorAddr = blockID << SB_NAND_LOG_2_PAGES_PER_BLOCK;
    SectorInfo SI;
    DWORD dwResult = 0;

    //RETAILMSG(1, (TEXT("FMD_SB_GetBlockStatus (0x%x)0x%x \n"), blockID, sectorAddr));

    if(!FMD_SB_ReadSector(sectorAddr, NULL, &SI, 1))
    {
        return BLOCK_STATUS_UNKNOWN;
    }

    if(!(SI.bOEMReserved & OEM_BLOCK_READONLY))
    {
        dwResult |= BLOCK_STATUS_READONLY;
    }

    if(SI.bBadBlock != 0xFF)
    {
        dwResult |= BLOCK_STATUS_BAD;
    }

    return dwResult;
}


 

 

 

8、FMD_LB_SetBlockStatus()、FMD_SB_SetBlockStatus()  设置块的状态

BOOL FMD_LB_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)
{
    BYTE bStatus = 0;

    if(dwStatus & BLOCK_STATUS_BAD)
    {
        if(!LB_MarkBlockBad (blockID))
        {
            return FALSE;
        }
    }

    // We don't currently support setting a block to read-only, so fail if request is
    // for read-only and block is not currently read-only.
    if(dwStatus & BLOCK_STATUS_READONLY)
    {
        if(!(FMD_LB_GetBlockStatus(blockID) & BLOCK_STATUS_READONLY))
        {
            return FALSE;
        }
    }

    return TRUE;
}

BOOL FMD_SB_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)
{
    SECTOR_ADDR sectorAddr = blockID << SB_NAND_LOG_2_PAGES_PER_BLOCK;
    BYTE bStatus = 0;

    //RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_sbsetblock \n")));

    if(dwStatus & BLOCK_STATUS_BAD)
    {
        if(!SB_MarkBlockBad (blockID))
        {
            return FALSE;
        }
    }

    // We don't currently support setting a block to read-only, so fail if request is
    // for read-only and block is not currently read-only.
    if(dwStatus & BLOCK_STATUS_READONLY)
    {
        if(!(FMD_SB_GetBlockStatus(blockID) & BLOCK_STATUS_READONLY))
        {
            return FALSE;
        }
    }

    return TRUE;
}


 

 

 

9、LB_MarkBlockBad()、SB_MarkBlockBad()   标记坏块

BOOL LB_MarkBlockBad(BLOCK_ID blockID)
{
    BLOCK_ID blockID_bad = blockID + 1;
    DWORD   dwStartPage = (blockID_bad << LB_NAND_LOG_2_PAGES_PER_BLOCK) - 1;
    BOOL    bRet = TRUE;

    //    RETAILMSG(1, (TEXT("LB_MarkBlockBad 0x%x \n"), dwStartPage));

    //  Enable chip
    NF_nFCE_L();
    NF_CLEAR_RB();
    NF_MSGLENGTH_512();
    //  Issue command
    //  We are dealing with spare area
    NF_CMD(CMD_WRITE);

    //  Set up address
    NF_ADDR((4096+LB_POS_BADBLOCK)&0xff);   // gjl 2048
    NF_ADDR(((4096+LB_POS_BADBLOCK)>>8)&0xff);  // gjl 2048
    NF_ADDR((dwStartPage) & 0xff);
    NF_ADDR((dwStartPage >> 8) & 0xff);
#if    LB_NEED_EXT_ADDR
    NF_ADDR((dwStartPage >> 16) & 0xff);
#endif

    NF_WRDATA_BYTE(BADBLOCKMARK);

    //  Copmlete the write
    NF_CMD(CMD_WRITE2);

    //  Wait for RB
    NF_DETECT_RB();     // Wait tR(max 12us)

    if ( NF_RDSTAT & STATUS_ILLACC )
    {
        RETAILMSG(1, (TEXT("NAND_LB_WriteSectorInfo() ######## Error Programming page (Illigar Access) %d!\n")));
        g_pNFConReg->NFSTAT =  STATUS_ILLACC;    // Write 1 to clear.
        bRet = FALSE;
    }
    else
    {
        //  Check the status of program
        NF_CMD(CMD_STATUS);

        if( NF_RDDATA_BYTE() & STATUS_ERROR)
        {
            RETAILMSG(1, (TEXT("NAND_LB_WriteSectorInfo() ######## Error Programming page %d!\n")));
            bRet = FALSE;
        }
    }

    //  Disable chip select
    NF_nFCE_H();

    return bRet;
}

BOOL SB_MarkBlockBad(BLOCK_ID blockID)
{
    DWORD   dwStartPage = blockID << SB_NAND_LOG_2_PAGES_PER_BLOCK;
    BOOL    bRet = TRUE;

    //RETAILMSG(1, (TEXT("SB_MarkBlockBad 0x%x \n"), dwStartPage));

    //  Enable chip
    NF_nFCE_L();
    NF_CLEAR_RB();

    //  Issue command
    //  We are dealing with spare area
    NF_CMD(CMD_READ2);
    NF_CMD(CMD_WRITE);

    //  Set up address
    NF_ADDR(SB_POS_BADBLOCK);
    NF_ADDR((dwStartPage) & 0xff);
    NF_ADDR((dwStartPage >> 8) & 0xff);
#if    SB_NEED_EXT_ADDR
    NF_ADDR((dwStartPage >> 16) & 0xff);
#endif

    NF_WRDATA_BYTE(BADBLOCKMARK);

    //  Copmlete the write
    NF_CMD(CMD_WRITE2);

    //  Wait for RB
    NF_DETECT_RB();     // Wait tR(max 12us)

    if ( NF_RDSTAT & STATUS_ILLACC )
    {
        RETAILMSG(1, (TEXT("NAND_LB_WriteSectorInfo() ######## Error Programming page (Illigar Access) %d!\n")));
        g_pNFConReg->NFSTAT =  STATUS_ILLACC;    // Write 1 to clear.
        bRet = FALSE;
    }
    else
    {
        //  Check the status of program
        NF_CMD(CMD_STATUS);

        if( NF_RDDATA_BYTE() & STATUS_ERROR)
        {
            RETAILMSG(1, (TEXT("NAND_LB_WriteSectorInfo() ######## Error Programming page %d!\n")));
            bRet = FALSE;
        }
    }

    //  Disable chip select
    NF_nFCE_H();

    return bRet;
}


 

 

 

10、LB_IsBlockBad()、SB_IsBlockBad()  判断是否为坏块

BOOL LB_IsBlockBad(BLOCK_ID blockID)
{
    BLOCK_ID blockID_bad = blockID + 1;
    DWORD   dwPageID = (blockID_bad << LB_NAND_LOG_2_PAGES_PER_BLOCK) - 1;
    BOOL    bRet = FALSE;
    BYTE    wFlag;

    //  Enable the chip
    NF_nFCE_L();
    NF_CLEAR_RB();
    NF_MSGLENGTH_512();
    //  Issue the command
    NF_CMD(CMD_READ);

    //  Set up address
    NF_ADDR((4096+LB_POS_BADBLOCK)&0xff);  //gjl 2048
    NF_ADDR(((4096+LB_POS_BADBLOCK)>>8)&0xff);  // gjl 2048
    NF_ADDR((dwPageID) & 0xff);
    NF_ADDR((dwPageID >> 8) & 0xff);
#if    LB_NEED_EXT_ADDR
    NF_ADDR((dwPageID >> 16) & 0xff);
#endif

    NF_CMD(CMD_READ3);

    //  Wait for Ready bit
    NF_DETECT_RB();     // Wait tR(max 12us)

    //  Now get the byte we want
    wFlag = (BYTE)(NF_RDDATA_BYTE()&0xff);

    if(wFlag != 0xff)
    {
        RETAILMSG(1, (TEXT("FMDLB: IsBlockBad - Page #: 0x%x \n"), dwPageID));
        bRet = TRUE;
    }

    //  Disable the chip
    NF_nFCE_H();

    return bRet;
}

BOOL SB_IsBlockBad(BLOCK_ID blockID)
{
    DWORD   dwPageID = blockID << SB_NAND_LOG_2_PAGES_PER_BLOCK;
    BOOL    bRet = FALSE;
    BYTE    wFlag;

    //RETAILMSG(1,(TEXT("#### FMD_DRIVER:::FMD_sbisblockbad \n")));

    //  Enable the chip
    NF_nFCE_L();
    NF_CLEAR_RB();
    //  Issue the command
    NF_CMD(CMD_READ2);

    //  Set up address
    NF_ADDR(SB_POS_BADBLOCK);
    NF_ADDR((dwPageID) & 0xff);
    NF_ADDR((dwPageID >> 8) & 0xff);
#if    SB_NEED_EXT_ADDR
    NF_ADDR((dwPageID >> 16) & 0xff);
#endif

    //  Wait for Ready bit
    NF_DETECT_RB();     // Wait tR(max 12us)

    //  Now get the byte we want
    wFlag = (BYTE) NF_RDDATA_BYTE();

    if(wFlag != 0xff)
    {
        RETAILMSG(1, (TEXT("FMDSB: IsBlockBad - Page #: 0x%x \n"), dwPageID));
        bRet = TRUE;
    }

    //  Disable the chip
    NF_nFCE_H();

    return bRet;
}


 

时间比较仓促,这个Nandflash移植系列的就到这里结束了。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在am335x中,可以通过移植MX30LFxG18AC NAND Flash驱动程序来控制NAND Flash的读写操作。下面是移植MX30LFxG18AC NAND Flash驱动程序的步骤: 1. 确定NAND Flash的连接方式。在移植MX30LFxG18AC NAND Flash驱动程序时,需要先确定NAND Flash的连接方式,例如:数据线、地址线、片选线、控制线等的连接方式。 2. 获取MX30LFxG18AC NAND Flash驱动程序。可以从MX30LFxG18AC NAND Flash的厂商网站或其他开发者的代码库中获取NAND Flash驱动程序。 3. 修改驱动程序中的代码。在获取MX30LFxG18AC NAND Flash驱动程序后,需要根据am335x的硬件特性对驱动程序进行修改,以便驱动程序能够正确地控制NAND Flash的读写操作。 4. 编写板级支持包(Board Support Package,BSP)。在移植MX30LFxG18AC NAND Flash驱动程序时,需要编写相应的BSP来支持驱动程序的运行。BSP主要包括引脚复用、中断控制、时钟控制、电源控制等。 5. 编译内核。完成驱动程序和BSP的编写后,需要重新编译内核,以便支持MX30LFxG18AC NAND Flash的读写操作。 通过以上步骤,就可以移植MX30LFxG18AC NAND Flash驱动程序到am335x中,以便控制NAND Flash的读写操作。需要注意的是,在进行移植时需要对硬件有一定的了解,并且需要编写相应的驱动程序和BSP来支持驱动程序的运行。因此,建议使用设备树来配置NAND Flash的参数,以便更加方便地控制NAND Flash的读写操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值