Nandflash 驱动移植 (六)

来源:互联网 发布:环保大数据 编辑:程序博客网 时间:2024/05/22 14:54

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_EQUALg_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 controlg_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 controlg_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 typeNF_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 controlg_pNFConReg->NFCONT |= (1<<9);// Enable RnB interrupt


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

g_pNFConReg->NFCONT &= ~(1<<10);// Disable illegal access interrupt controlg_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移植系列的就到这里结束了。