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

📄 nand.c

📁 SMDK6400_WinCE_Nand 驅動源代碼
💻 C
字号:
#include <windows.h>
#include <bsp_cfg.h>
#include <s3c6400.h>
#include "s3c6400_addr.h"
#include "utils.h"

//----------------------------------------------------------------------------------

#define NF_CMD(cmd)			{rNFCMD=cmd;}
#define NF_ADDR(addr)		{rNFADDR=addr;}

#define NF_nFCE_L()			{rNFCONT &= ~(1 << 1);}
#define NF_nFCE_H()			{rNFCONT |=  (1 << 1);}

#define NF_RSTECC()			{rNFCONT |=  ((1<<5)|(1<<4));}

#define NF_MECC_UnLock()	{rNFCONT &= ~(1<<7);}
#define NF_MECC_Lock()		{rNFCONT |= (1<<7);}

#define NF_SECC_UnLock()	{rNFCONT &= ~(1<<6);}
#define NF_SECC_Lock()		{rNFCONT |= (1<<6);}

#define NF_CLEAR_RB()		{rNFSTAT |=  (1 << 4);}
#define NF_DETECT_RB()		{ while((rNFSTAT&0x11)!=0x11);}	// RnB_Transdetect & RnB
#define NF_WAITRB()			{while (!(rNFSTAT & (1 << 0)));}

#define NF_RDDATA()			(rNFDATA)
#define NF_RDDATA8()		(unsigned char)(rNFDATA8)
#define NF_RDDATA32()		(rNFDATA32)
#define NF_WRDATA(data)		{rNFDATA=data;}

#define NF_RDMECC0()		(rNFMECC0)
#define NF_RDMECC1()		(rNFMECC1)

#define NF_RDMECCD0()		(rNFMECCD0)
#define NF_RDMECCD1()		(rNFMECCD1)

#define NF_WRMECCD0(data)	{rNFMECCD0 = (data);}
#define NF_WRMECCD1(data)	{rNFMECCD1 = (data);}

//----------------------------------------------------------------------------------

#define CMD_READ		(0x00)	//  Read
#define CMD_READ1		(0x01)	//  Read1
#define CMD_READ2		(0x50)	//  Read2
#define CMD_READ3		(0x30)	//  Read3
#define CMD_RDO			(0x05)	//  Random Data Output
#define CMD_RDO2		(0xE0)	//  Random Data Output

//----------------------------------------------------------------------------------

#define TACLS				(NAND_TACLS)
#define TWRPH0				(NAND_TWRPH0)
#define TWRPH1				(NAND_TWRPH1)

//----------------------------------------------------------------------------------

typedef enum {
    ECC_CORRECT_MAIN = 0,  // correct Main ECC
    ECC_CORRECT_SPARE = 1,  // correct Main ECC
} ECC_CORRECT_TYPE;

//----------------------------------------------------------------------------------

BOOL g_bLargeBlock = FALSE;

static void NF_Reset(void);
static BOOL ReadFlashID(DWORD *pID);
extern void _Read_512Byte(BYTE *bufPt);		// in "nand_opt.s"

BOOL ECC_CorrectData(unsigned int sectoraddr, UINT8* pData, UINT32 nRetEcc, ECC_CORRECT_TYPE nType)
{
	DWORD  nErrStatus;
	DWORD  nErrDataNo;
	DWORD  nErrBitNo;
	UINT32 nErrDataMask;
	UINT32 nErrBitMask = 0x7;
	BOOL bRet = TRUE;

	if (nType == ECC_CORRECT_MAIN)
	{
		nErrStatus   = 0;
		nErrDataNo   = 7;
		nErrBitNo    = 4;
		nErrDataMask = 0x7ff;
	}
	else if (nType == ECC_CORRECT_SPARE)
	{
		nErrStatus   = 2;
		nErrDataNo   = 21;
		nErrBitNo    = 18;
		nErrDataMask = 0xf;
	}
	else
	{
		return FALSE;
	}

	switch((nRetEcc>>nErrStatus) & 0x3)
	{
		case 0:	// No Error
			bRet = TRUE;
			break;
		case 1:	// 1-bit Error(Correctable)
			(pData)[(nRetEcc>>nErrDataNo)&nErrDataMask] ^= (1<<((nRetEcc>>nErrBitNo)&nErrBitMask));
			bRet = TRUE;
			break;
		case 2:	// Multiple Error
			Uart_SendString("M ECC Err\n");
			//Uart_SendDWORD(sectoraddr,1);
			bRet = FALSE;
			break;
		case 3:	// ECC area Error
			Uart_SendString("ECC Err\n");
		default:
			bRet = FALSE;
			break;
	}

	return bRet;
}

void NAND_Init(void)
{
	DWORD ReadID;

	// Configure BUS Width and Chip Select for NAND Flash
	rMEM_SYS_CFG &= ~(1<<12);	// NAND Flash BUS Width -> 8 bit
	rMEM_SYS_CFG &= ~(0x1<<1);	// Xm0CS2 -> NFCON CS0

	// Initialize NAND Flash Controller
	rNFCONF = (TACLS << 12) | (TWRPH0 <<  8) | (TWRPH1 <<  4) | (0<<0);
	rNFCONT = (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0);
	rNFSTAT = (1<<4);

	NF_Reset();

	// Get manufacturer and device codes.
	if (!ReadFlashID(&ReadID))
	{
		Uart_SendString("ID Err\n");
		//Uart_SendDWORD(ReadID,1);
		//Uart_SendString("!\n");
	}
}

BOOL NAND_ReadPage(UINT32 block, UINT32 sector, UINT8 *buffer)
{
	register UINT8 * bufPt=buffer;
	unsigned int RowAddr, ColAddr;
	DWORD MECCBuf, rddata1, rddata2;
	UINT32 nRetEcc;
	int nRet = FALSE;
	int nSectorLoop;

	for (nSectorLoop = 0; nSectorLoop < (g_bLargeBlock==TRUE?4:1); nSectorLoop++)
	{
		ColAddr = nSectorLoop * 512;

		NF_nFCE_L();

		NF_CMD(CMD_READ);					// Read command

		if (g_bLargeBlock == TRUE)
		{
			RowAddr = (block<<6) + sector;

			NF_ADDR((ColAddr)   &0xff);		// 1st cycle
			NF_ADDR((ColAddr>>8)&0xff);		// 2nd cycle
			NF_ADDR((RowAddr)   &0xff);		// 3rd cycle
			NF_ADDR((RowAddr>>8)&0xff);	// 4th cycle
#if	1	//	LB_NEED_EXT_ADDR
			NF_ADDR((RowAddr>>16)&0xff);	// 5th cycle
#endif
		}
		else
		{
			RowAddr = (block<<5) + sector;

			NF_ADDR((ColAddr)   &0xff);		// 1st cycle
			NF_ADDR((RowAddr)   &0xff);		// 2nd cycle
			NF_ADDR((RowAddr>>8)&0xff);	// 3rd cycle
#if	1	//	SB_NEED_EXT_ADDR
			NF_ADDR((RowAddr>>16)&0xff);	// 4th cycle
#endif
		}

		NF_CLEAR_RB();
		NF_CMD(CMD_READ3);				// Read command
		NF_DETECT_RB();

		NF_RSTECC();    // Initialize ECC
		NF_MECC_UnLock();

		_Read_512Byte(bufPt+nSectorLoop*512);	// Read 512 bytes.

		NF_MECC_Lock();

		if (g_bLargeBlock == TRUE)
		{
			ColAddr = 2048;

			NF_CMD(CMD_RDO);				// Random Data Output In a Page, 1st Cycle
			NF_ADDR((ColAddr)   &0xff);		// 1st cycle
			NF_ADDR((ColAddr>>8)&0xff);		// 2nd cycle
			NF_CMD(CMD_RDO2);				// Random Data Output In a Page. 2nd Cycle

			rddata1 = NF_RDDATA8();				// check bad block
			rddata2 = NF_RDDATA32();			// read dwReserved1
			rddata2 = NF_RDDATA8();				// check bOEMResetved

			if (((rddata1&0xff) != 0xff) && ((rddata2 & 0xff) != 0x03))
			{
				Uart_SendString("BAD\n");
				return nRet;  // bad block && !(OEM_BLOCK_RESERVED | OEM_BLOCK_READONLY)
		}

		}
		else
		{
			rddata1 = NF_RDDATA32();
			rddata2 = NF_RDDATA32();				// check bOEMResetved and bad block

			if ((((rddata2>>8) & 0xff) != 0xff) && ((rddata2 & 0xff) != 0x03))
		{
			Uart_SendString("BAD\n");
			return nRet;  // bad block && !(OEM_BLOCK_RESERVED | OEM_BLOCK_READONLY)
		}
		}

		if (g_bLargeBlock == TRUE)
		{
			ColAddr = 2048 + 8 + nSectorLoop*4;

			NF_CMD(CMD_RDO);				// Random Data Output In a Page, 1st Cycle
			NF_ADDR((ColAddr)   &0xff);		// 1st cycle
			NF_ADDR((ColAddr>>8)&0xff);		// 2nd cycle
			NF_CMD(CMD_RDO2);				// Random Data Output In a Page. 2nd Cycle
		}

		MECCBuf = NF_RDDATA32();

		NF_WRMECCD0( ((MECCBuf&0x0000ff00)<<8) | ((MECCBuf&0x000000ff)    ) );
		NF_WRMECCD1( ((MECCBuf&0xff000000)>>8) | ((MECCBuf&0x00ff0000)>>16) );

		nRetEcc = rNFECCERR0;

		nRet = ECC_CorrectData(RowAddr, bufPt+nSectorLoop*512, nRetEcc, ECC_CORRECT_MAIN);

		NF_nFCE_H();

		if (nRet == FALSE)
		{
			return nRet;
		}
	}

	return nRet;
}

static void NF_Reset(void)
{
	volatile int i;

	NF_nFCE_L();

	NF_CLEAR_RB();
	NF_CMD(0xFF);	//reset command

	for(i=0; i<10; i++);  //tWB = 100ns. //??????

	NF_DETECT_RB();

	NF_nFCE_H();
}

static BOOL ReadFlashID(DWORD *pID)
{
	BYTE MID, DID, i;

	NF_nFCE_L();

	NF_CLEAR_RB();

	NF_CMD(0x90);			// Send flash ID read command.

	NF_ADDR(0x00);

	for (i=0; i<100; i++);

	for (i=0; i<10; i++)
	{
		MID = (BYTE)NF_RDDATA8();	// Manufacturer ID

		if (MID == 0xEC || MID == 0x98) break;
	}

	DID = (BYTE)NF_RDDATA8();		// Device ID

	NF_nFCE_H();

	g_bLargeBlock = FALSE;

	if (MID == 0xEC)		// Samsung NAND
	{
		if (DID >= 0xA0) g_bLargeBlock = TRUE;

		*pID = (DWORD)((MID<<8) | (DID));

		return TRUE;
	}
	else if (MID == 0x98)	// xD-Picture Card
	{
		*pID = (DWORD)((MID<<8) | (DID));

		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -