⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nand.c

📁 S3C2450BSP开发包,里面有很多资料。可以提供大家参考下。有什么需要解决问题。可以联系我QQ:314661
💻 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 + -