📄 nand.c
字号:
#include <windows.h>
#include "s2450addr.h"
#include "utils.h"
#include "nand.h"
#define DEV_ADDR_CYCLE (5)
///////////////////////////////////////////////
// NAND Controller Macro
///////////////////////////////////////////////
#define NF_CE_L(bank) { \
if (bank == 0) rNFCONT &= ~NF_NFCE0; \
else if (bank == 1) rNFCONT &= ~NF_NFCE1; \
}
#define NF_CE_H(bank) { \
if (bank == 0) rNFCONT |= NF_NFCE0; \
else if (bank == 1) rNFCONT |= NF_NFCE1; \
}
#define NF_CMD(cmd) (rNFCMD = (unsigned char)cmd)
#define NF_ADDR(addr) (rNFADDR = (unsigned char)addr)
#define NF_DATA_R() (rNFDATA8)
#define NF_DATA_R4() (rNFDATA32)
#define NF_DATA_W4(n) (rNFDATA32 = (DWORD)n)
#define NF_SET_ECC_DEC() (rNFCONT &= ~NF_4BIT_ECC_ENC)
#define NF_MECC_Reset() (rNFCONT |= NF_INIT_MECC)
#define NF_MECC_Lock() (rNFCONT |= NF_MAIN_ECC_LOCK)
#define NF_MECC_UnLock() (rNFCONT &= ~NF_MAIN_ECC_LOCK)
#define NF_CLEAR_ECC_DEC_DONE() (rNFSTAT |= NF_ECC_DEC_DONE)
#define NF_WAIT_ECC_DEC_DONE() { \
while(!(rNFSTAT&NF_ECC_DEC_DONE)); \
}
#define NF_WRMECCD0(data) {rNFMECCD0 = (data);}
#define NF_WRMECCD1(data) {rNFMECCD1 = (data);}
#define NF_ECC_DEC_ERROR() ((rNFECCERR0>>26)&0x7)
#define NF_ECC_ERR0() (rNFECCERR0)
#define NF_ECC_ERR1() (rNFECCERR1)
#define NF_ECC_ERR_PATTERN() (rNFMLCBITPT)
#if 0 // Busy Check using RnB Pin
#define NF_WAIT_RnB(bank) { \
while(!(rNFSTAT&NF_RNB_READY)); \
}
#else // Busy Check using I/O[6] Pin (Need Dummy READ Command)
#define NF_WAIT_RnB(bank) { \
NF_CMD(CMD_READ_STATUS); \
while(!(NF_DATA_R()&0x40)); \
}
#endif
#define NF_SET_ADDR(nPpn, nOffset) { \
NF_ADDR(nOffset&0xFF); \
NF_ADDR((nOffset>>8)&0xFF); \
NF_ADDR(nPpn&0xFF); \
NF_ADDR((nPpn>>8)&0xFF); \
if (DEV_ADDR_CYCLE > 4) \
NF_ADDR((nPpn>>16)&0xFF); \
}
#define NF_SET_CLK(tacls, twrph0, twrph1) (rNFCONF = (rNFCONF&~0x7770) \
|NF_TACLS(tacls) | NF_TWRPH0(twrph0) | NF_TWRPH1(twrph1))
///////////////////////////////////////////////
// Assembly Read Function (in nand.s)
///////////////////////////////////////////////
void _Read_512Byte(unsigned char* pBuf);
void _Write_Dummy_Byte_AllFF(int nByteSize); // nByteSize is the multifilication of 4
extern BOOL b4KPage;
void NAND_Init(void)
{
#ifdef SUPPORTSLC
// Initialize NAND Flash Controller for MLC NAND Flash
rNFCONF = NF_1BIT_ECC | NF_TACLS(DEFAULT_TACLS) | NF_TWRPH0(DEFAULT_TWRPH0) | NF_TWRPH1(DEFAULT_TWRPH1);
rNFCONT = NF_MAIN_ECC_LOCK | NF_SPARE_ECC_LOCK | NF_INIT_MECC | NF_INIT_SECC | NF_NFCE1 | NF_NFCE0 | NF_NFCON_EN;
rNFSTAT = NF_RNB_READY; // Clear RnB Transition Detect Bit
#endif
#ifdef SUPPORTMLC
// Initialize NAND Flash Controller for MLC NAND Flash
rNFCONF = NF_4BIT_ECC | NF_TACLS(DEFAULT_TACLS) | NF_TWRPH0(DEFAULT_TWRPH0) | NF_TWRPH1(DEFAULT_TWRPH1);
rNFCONT = NF_MAIN_ECC_LOCK | NF_SPARE_ECC_LOCK | NF_INIT_MECC | NF_INIT_SECC | NF_NFCE1 | NF_NFCE0 | NF_NFCON_EN;
rNFSTAT = NF_RNB_READY; // Clear RnB Transition Detect Bit
#endif // SUPPORTMLC
NAND_Reset(0);
}
void NAND_Reset(DWORD dwBank)
{
// Chip Select
NF_CE_L(dwBank);
// Reset Command is accepted during Busy
NF_CMD(CMD_RESET);
// Chip Unselect
NF_CE_H(dwBank);
}
#ifdef SUPPORTSLC
BOOL NAND_Read(DWORD dwBank, DWORD dwPage, unsigned char *pBuf)
{
DWORD dwCnt;
unsigned char bECC[4];
BOOL bRet = TRUE;
DWORD dwRet;
unsigned char uSctCnt, uSEccOffset;
if (b4KPage == TRUE)
{
uSctCnt = 8;
uSEccOffset = NAND_MECC_OFFSET_4K;
}
else
{
uSctCnt = 4;
uSEccOffset = NAND_MECC_OFFSET;
}
// Chip Select
NF_CE_L(dwBank);
NF_WAIT_RnB(dwBank);
NF_CMD(CMD_READ);
NF_SET_ADDR(dwPage, 0);
NF_CMD(CMD_READ_CONFIRM);
NF_WAIT_RnB(dwBank);
// Dummy Command to Set Proper Pointer to Read Position after NF_WAIT_RnB()
NF_CMD(CMD_READ);
NF_MECC_Reset();
NF_MECC_UnLock();
// Read Main Area
for (dwCnt=0; dwCnt<uSctCnt; dwCnt++)
{
_Read_512Byte(pBuf+NAND_SECTOR_SIZE*dwCnt);
}
return 1;
NF_MECC_Lock();
for (dwCnt = 0; dwCnt < uSEccOffset; dwCnt++ )
{
bECC[0] = NF_DATA_R();
}
bECC[0] = NF_DATA_R();
bECC[1] = NF_DATA_R();
bECC[2] = NF_DATA_R();
bECC[3] = NF_DATA_R();
NF_WRMECCD0(((bECC[1]&0xff)<<16)|(bECC[0]&0xff));
NF_WRMECCD1(((bECC[3]&0xff)<<16)|(bECC[2]&0xff));
dwRet = NF_ECC_ERR0();
switch(dwRet & 0x3)
{
case 0: // No Error
break;
case 1: // 1-bit Error(Correctable)
(pBuf)[(dwRet>>7)&0x7ff] ^= (1<<((dwRet>>4)&0x7));
break;
case 2: // Multiple Error
case 3: // ECC area Error
// while(1);
break;
}
// Chip Unselect
NF_CE_H(dwBank);
return 1;
}
#endif // SUPPORTSLC
#ifdef SUPPORTMLC
BOOL NAND_Read(DWORD dwBank, DWORD dwPage, unsigned char *pBuf)
{
DWORD SpareCxt[21]; // max size of spare context. 5 word spare context, 16 word main ECC(4KByte/Page)
DWORD dwOffset;
DWORD dwCnt;
unsigned char uSctCnt;
BOOL bRet = TRUE;
if (b4KPage == TRUE) uSctCnt = 8;
else uSctCnt = 4;
// Chip Select
NF_CE_L(dwBank);
NF_WAIT_RnB(dwBank);
if (Read_Spare(dwBank, dwPage, SpareCxt, 0))
{
if (Read_Spare(dwBank, dwPage, SpareCxt, 1))
{
if (Read_Spare(dwBank, dwPage, SpareCxt, 2))
{
// Uncorrectable Error
//Uart_SendString("Uncorrectable Error");
return FALSE;
}
}
}
// Read Main Area
for (dwCnt=0; dwCnt<uSctCnt; dwCnt++)
{
dwOffset = NAND_SECTOR_SIZE*dwCnt;
// Random data output command
NF_CMD(CMD_RANDOM_DATA_OUTPUT);
NF_ADDR(dwOffset&0xFF);
NF_ADDR((dwOffset>>8)&0xFF);
NF_CMD(CMD_RANDOM_DATA_OUTPUT_CONFIRM);
// Initialize 4-bit ECC Decoding
NF_SET_ECC_DEC();
NF_MECC_Reset();
NF_MECC_UnLock();
_Read_512Byte(pBuf+NAND_SECTOR_SIZE*dwCnt);
//NF_MECC_Lock(); // Do NOT Lock MECC when using 4-bit ECC Decoding
// Read 7 bytes ECC for Sector
NF_CLEAR_ECC_DEC_DONE();
NF_CE_H(dwBank);
NF_SET_CLK(DUMMY_R_TACLS, DUMMY_R_TWRPH0, DUMMY_R_TWRPH1); // Don't set clk to (0, 0, 0) !!! Decoding error occurs
NF_DATA_W4(SpareCxt[dwCnt*2+(1+uSctCnt/2)]); // 1st location of real spare data for sector
NF_DATA_W4(SpareCxt[dwCnt*2+1+(1+uSctCnt/2)]); // 2nd location of real spare data for sector
NF_SET_CLK(DEFAULT_TACLS, DEFAULT_TWRPH0, DEFAULT_TWRPH1);
NF_CE_L(dwBank);
NF_WAIT_ECC_DEC_DONE();
if (Decoding_ECC(pBuf+NAND_SECTOR_SIZE*dwCnt, 512))
{
// Uncorrectable ECC Error
bRet = FALSE;
}
}
// Chip Unselect
NF_CE_H(dwBank);
return bRet;
}
BOOL Read_Spare(DWORD dwBank, DWORD dwPage, DWORD *pSpareCxt, UINT8 bSecondTry)
{
DWORD dwOffset;
BOOL bRet = FALSE;
DWORD i;
static UINT32 nSECC[4];
DWORD uSpareCxtCnt;
DWORD nValidBufLength;
if (b4KPage == TRUE)
{
dwOffset = NAND_MAINPAGE_SIZE*2+NAND_SCXT_OFFSET; // Position to SpareContext (Skipped BadMark, CleanMark, 2 byte Reserved)
nValidBufLength = NAND_SECC_OFFSET_4K - NAND_SCXT_OFFSET; // 20B + 8*8B
uSpareCxtCnt = nValidBufLength/4; // 5+8*2
}
else
{
dwOffset = NAND_MAINPAGE_SIZE+NAND_SCXT_OFFSET; // Position to SpareContext (Skipped BadMark, CleanMark, 2 byte Reserved)
nValidBufLength = NAND_SECC_OFFSET - NAND_SCXT_OFFSET; // 12B + 8*4B
uSpareCxtCnt = nValidBufLength/4; // 3+8
}
if (bSecondTry)
{
// Random data output command
NF_CMD(CMD_RANDOM_DATA_OUTPUT);
NF_ADDR(dwOffset&0xFF);
NF_ADDR((dwOffset>>8)&0xFF);
NF_CMD(CMD_RANDOM_DATA_OUTPUT_CONFIRM);
}
else
{
NF_CMD(CMD_READ);
NF_SET_ADDR(dwPage, dwOffset);
NF_CMD(CMD_READ_CONFIRM);
NF_WAIT_RnB(dwBank);
// Dummy Command to Set Proper Pointer to Read Position after NF_WAIT_RnB()
NF_CMD(CMD_READ);
}
// Initialize 4-bit ECC Decoding
NF_SET_ECC_DEC();
NF_MECC_Reset();
NF_MECC_UnLock();
for (i=0; i<uSpareCxtCnt; i++)
{
pSpareCxt[i] = NF_DATA_R4(); // read spare context
}
NF_CE_H(dwBank);
NF_SET_CLK(DUMMY_R_TACLS, DUMMY_R_TWRPH0, DUMMY_R_TWRPH1); // Don't set clk to (0, 0, 0) !!! Decoding error occurs
if (b4KPage == TRUE)
_Write_Dummy_Byte_AllFF(428);
else
_Write_Dummy_Byte_AllFF(468);
NF_SET_CLK(DEFAULT_TACLS, DEFAULT_TWRPH0, DEFAULT_TWRPH1);
NF_CE_L(dwBank);
//NF_MECC_Lock(); // Do NOT Lock MECC when using 4-bit ECC Decoding
// Read Spare ECC
NF_CLEAR_ECC_DEC_DONE();
if (bSecondTry)
{
if (b4KPage == TRUE)
dwOffset = NAND_MAINPAGE_SIZE*2+NAND_SECC2_OFFSET_4K+32; // Position to Spare ECC 2nd copy for 4KByte/Page
else
dwOffset = NAND_MAINPAGE_SIZE+NAND_SECC2_OFFSET; // Position to Spare ECC 2nd copy for 2KByte/Page
// Random data output command
NF_CMD(CMD_RANDOM_DATA_OUTPUT);
NF_ADDR(dwOffset&0xFF);
NF_ADDR((dwOffset>>8)&0xFF);
NF_CMD(CMD_RANDOM_DATA_OUTPUT_CONFIRM);
if (bSecondTry == 1)
{
NF_DATA_W4(nSECC[0]); // Write modified ECC for the 53th bit on SECC data
NF_DATA_W4(nSECC[1]^(1<<19)); // position to be modified on SECC[1]
}
if (bSecondTry == 2)
{
NF_DATA_W4(nSECC[2]); // Read 2nd Spare ECC
NF_DATA_W4(nSECC[3]); // position to be modified on SECC[1]
}
}
else
{
nSECC[0] = NF_DATA_R4(); // 8 byte Spare ECC data
nSECC[1] = NF_DATA_R4(); // Actually after read 7th byte, ECC decoding starts!!
}
// Wait Spare ECC Compare Done
NF_WAIT_ECC_DEC_DONE();
nSECC[2] = NF_DATA_R4();
nSECC[3] = NF_DATA_R4();
return Decoding_ECC((UINT8 *)pSpareCxt, nValidBufLength);
}
BOOL Decoding_ECC(UINT8* pBuf, DWORD nValidBufLength)
{
UINT32 nError0, nError1;
UINT32 nErrorCnt;
UINT32 nRet = 0;
nError0 = NF_ECC_ERR0();
nError1 = NF_ECC_ERR1();
nErrorCnt = (nError0>>26)&0x7;
if (nErrorCnt == 0)
{
// No ECC Error
return FALSE;
}
else if (nErrorCnt > 4)
{
// Uncorrectable ECC Error
return TRUE;
}
else // Check ECC error occurs in first 32 bytes (468 byte is Dummy 0xFF)
{
UINT32 nErrorByte, nErrorPattern;
nErrorPattern = NF_ECC_ERR_PATTERN();
// 1st Bit Error Correction
nErrorByte = nError0&0x3ff;
if (nErrorByte < nValidBufLength)
{
pBuf[nErrorByte] = pBuf[nErrorByte]^(nErrorPattern&0xff);
}
else if (nErrorByte < 512)
{
// Error in Dummy
return FALSE;
}
if (nErrorCnt > 1)
{
// 2nd Bit Error Correction
nErrorByte = (nError0>>16)&0x3ff;
if (nErrorByte < nValidBufLength)
{
pBuf[nErrorByte] = pBuf[nErrorByte]^((nErrorPattern>>8)&0xff);
}
else if (nErrorByte < 512)
{
// Error in Dummy
return FALSE;
}
if (nErrorCnt > 2)
{
// 3rd Bit Error Correction
nErrorByte = nError1&0x3ff;
if (nErrorByte < nValidBufLength)
{
pBuf[nErrorByte] = pBuf[nErrorByte]^((nErrorPattern>>16)&0xff);
}
else if (nErrorByte < 512)
{
// Error in Dummy
return FALSE;
}
if (nErrorCnt > 3)
{
// 4 th Bit Error Correction
nErrorByte = (nError1>>16)&0x3ff;
if (nErrorByte < nValidBufLength)
{
pBuf[nErrorByte] = pBuf[nErrorByte]^((nErrorPattern>>24)&0xff);
}
else if (nErrorByte < 512)
{
// Error in Dummy
return FALSE;
}
}
}
}
// Correctable ECC Error
return FALSE;
}
}
#endif // SUPPORTMLC
void Read_DeviceID(DWORD dwBank, unsigned char *pDID, unsigned char *pHID)
{
unsigned char ucMID, ucDID, ucHID[3];
int i;
// Chip Select
NF_CE_L(dwBank);
NF_WAIT_RnB(dwBank);
// Read ID Command
NF_CMD(CMD_READ_ID);
NF_ADDR(0x00);
// Find Maker Code
for (i=0; i<10; i++)
{
ucMID = NF_DATA_R(); // Maker Code
if (ucMID == 0xEC) break;
}
// Read Device Code
ucDID = NF_DATA_R(); // Device Code
ucHID[0] = NF_DATA_R(); // Internal Chip Number
ucHID[1] = NF_DATA_R(); // Page, Block, Redundant Area Size
ucHID[2] = NF_DATA_R(); // Plane Number, Size
// Chip Unselect
NF_CE_H(dwBank);
if (ucMID == 0xEC)
{
*pDID = ucDID;
*pHID = ucHID[0];
}
else
{
*pDID = 0x00;
*pHID = 0x00;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -