nand.c

来自「SAMSUNG S3C6410 CPU BSP for winmobile6」· C语言 代码 · 共 393 行

C
393
字号
#include <windows.h>
#include "s3c6410.h"
#include "s3c6410_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_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 ID_K9S1208V0M	  0xec76

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

#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

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

// TODO: Need to be calculated...
#if		(S3C6410_HCLK == CLK_100MHz)
#define TACLS		7	// 1-clk(0ns) 
#define TWRPH0		7	// 3-clk(25ns)
#define TWRPH1		7	// 1-clk(10ns)  //TACLS+TWRPH0+TWRPH1>=50ns
#elif	(S3C6410_HCLK == CLK_133MHz)
#define TACLS		7	// 1-clk(0ns) 
#define TWRPH0		7	// 3-clk(25ns)
#define TWRPH1		7	// 1-clk(10ns)  //TACLS+TWRPH0+TWRPH1>=50ns
#endif


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

BOOL g_bLargeBlock = FALSE;

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

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 SMC Chip Select Mux for NAND
	//
	rMEM_SYS_CFG = (rMEM_SYS_CFG & ~(0x1000)); // 8-bit data width
	rMEM_SYS_CFG = (rMEM_SYS_CFG & ~(0x3F)) | (0x00); // Xm0CSn[2] = NFCON CS0

	// Configure NAND 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);
	
	NAND_Reset();

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

BOOL NAND_ReadPage(UINT32 block, UINT32 sector, UINT8 *buffer)
//BOOL NAND_ReadPage(UINT32 block, UINT32 page, 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<<8) + 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, nRetEcc, ECC_CORRECT_MAIN);

		NF_nFCE_H();

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

	return nRet;	
	
/*	
	register UINT8 * bufPt=buffer;
	unsigned int blockPage;
	ULONG MECC;
	int NewDataAddr;

	if (g_bLargeBlock == TRUE)
	{
		blockPage = (block<<6) + page/4;
		NewDataAddr = 512*(page%4);
		NF_RSTECC();    // Initialize ECC
		NF_MECC_UnLock();

		NF_nFCE_L();
		NF_CMD(0x00);   // Read command

		NF_ADDR((NewDataAddr)&0xff);
		NF_ADDR(((NewDataAddr)>>8)&0xff);
		NF_ADDR(blockPage&0xff);	    //
		NF_ADDR((blockPage>>8)&0xff);   // Block & Page num.
	}
	else
	{
        //blockPage = (block<<5) + page;
        blockPage=(block<<8)+page;
        NewDataAddr=0;
        NF_RSTECC();	// Initialize ECC
        NF_MECC_UnLock();
        
        NF_nFCE_L();	
        NF_CMD(0x00);   // Read command
        
        NF_ADDR((NewDataAddr)&0xff);
        NF_ADDR(blockPage&0xff);		//
        NF_ADDR((blockPage>>8)&0xff);   // Block & Page num.
        NF_ADDR((blockPage>>16)&0xff);   // Block & Page num.
	}

	NF_CLEAR_RB();
	NF_CMD(0x30);
	NF_DETECT_RB();

	_Read_512Byte(bufPt);
	NF_MECC_Lock();

	MECC = NF_RDDATA32();
	MECC = NF_RDDATA32();

	MECC = NF_RDDATA32();
	NF_WRMECCD0( ((MECC&0xff00	)<<8) |  (MECC&0xff	)	  );
	NF_WRMECCD1( ((MECC&0xff000000)>>8) | ((MECC&0xff0000)>>16) );

	NF_nFCE_H();	

	if(rNFECCERR0 & 0x3)
	{
		Uart_SendString("ECC ERROR block");
		Uart_SendDWORD(block,0);
		Uart_SendString("page");
		Uart_SendDWORD(page,1);
		return FALSE;
	}
	else
	{
		return TRUE;
	}
*/	
}

static void NAND_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();
	
	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 + =
减小字号Ctrl + -
显示快捷键?