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移植系列的就到这里结束了。