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

📄 nand.c

📁 支持大页面的nand flash的类库, 可由用户自由定制。
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Craftsman Software.  All rights reserved.
//
//	AUTHOR	: junwei cheng
//	E-MAIL	: chjw_ch@yahoo.com
//
#include "nand.h"
#include "2440lib.h"

#ifdef __cplusplus
extern "C" {
#endif
	
//0 - no debug, 1 - debug command output
#define DEBUG_COMMAND	0
	
#ifdef DEBUG_COMMAND
#define DebugPrintf(x)		{if(DEBUG_COMMAND) Uart_Printf x;}
#else
#define DebugPrintf(x)
#endif

	//
	//Advance NAND flash memory for auto-booting
	//NAND_Normal, NAND_Advance
	static int AdvFlash;
	
	//NAND flash memory Address cycle for auto-booting AdvFlash AddrCycle.
	//ADDR_CYCLE_3, ADDR_CYCLE_4
	static int AddrCycle;
	
	//Spare size
	static int SpareSize;		//16, 64
	
	
	//pages per block bits count, used to convert data
	static int PagesPerBlockBits;
	
	//flash chip information
	static FlashInfo g_ChipInfo;
	
	//ChipID 2 NumBlocks
	static DWORD ChipID2NumBlocks[][2] =
	{
			{0xECA1, 1024},			//K9F1G08Q0M
			{0xECF1, 1024},			//K9F1G08U0M
			{0xECB1, 1024},			//K9F1G16Q0M
			{0xECC1, 1024},			//K9F1G16U0M
			
			{0xECAA, 2048},			//K9F2G08Q0M
			{0xECDA, 2048},			//K9F2G08U0M
			{0xECBA, 2048},			//K9F2G16Q0M
			{0xECCA, 2048},			//K9F2G16U0M
			
			{0xECAC, 4096},			//K9K4G08Q0M
			{0xECDC, 4096},			//K9K4G08U0M
			{0xECBC, 4096},			//K9K4G16Q0M
			{0xECCC, 4096},			//K9K4G16U0M
					
			{0xECD3, 8192},			//K9K8G08U0M, K9WAG08U1M
	};
	
	//----------------------------------------------------------------------------------------
	// NAND Flash Macros
	//----------------------------------------------------------------------------------------
	#define NF_ENABLE()		{rNFCONT |= 1;}
	#define NF_DISABLE()	{rNFCONT &= ~1;}
	
	#define NF_nFCE_L()		{rNFCONT &= ~(1<<1);}
	#define NF_nFCE_H()		{rNFCONT |= (1<<1);}
	
	#define NF_CMD(cmd)		{rNFCMD = (BYTE)(cmd); DebugPrintf(("rNFCMD =0x%02x\n",cmd));}
	#define NF_ADDR(addr)	{rNFADDR = (BYTE)(addr);DebugPrintf(("rNFADDR=0x%02x\n",addr));}
	
	#define NF_RDATA()		(rNFDATA)
	#define NF_WDATA(dat)	{rNFDATA=(dat);}
	
	#define NF_RDATA8()		(rNFDATA8)
	#define NF_WDATA8(dat)	{rNFDATA8=(BYTE)(dat);}
	
	//ready to operate?
	#define NF_RnB()		(rNFSTAT&1)
	
	
	#define NF_WAIT_RnB()	{while(!NF_RnB());DebugPrintf(("WaitRnB\n"));}
	
	
	//ECC -----------------------------------------------------------------------------------
	#define NF_InitECC()		{rNFCONT |= (1<<4);}
	
	#define NF_MainECCLock()	{rNFCONT |= (1<<5);}
	#define NF_MainECCUnlock()	{rNFCONT &= ~(1<<5);}
	
	//n= 0, 1, 2, 3
	#define NF_MECCData8(n)		((rNFMECCD##(n>>1) << ((n&1) * 16) & 0xff)
	#define NF_MECCData(n)		((rNFMECCD##(n>>1) << ((n&1) * 16) & 0xffff)
	
	
	#define NF_SpareECCLock()	{rNFCONT |= (1<<6);}
	#define NF_SpareECCUnlock()	{rNFCONT &= ~(1<<6);}
	
	//n= 0, 1
	#define NF_SECCData8(n)		((rNFSECCD << ((n&1) * 16) & 0xff)
	#define NF_SECCData(n)		((rNFSECCD << ((n&1) * 16) & 0xffff)
	
	
	//---------------------------------------------------------------------------------------
	
	//status bits
	#define NF_STATUS_FAILED(status)			(status&(1<<0))
	#define NF_STATUS_READY(status)				(status&(1<<6))
	#define NF_STATUS_NotProtected(status)		(status&(1<<7))
	
	//macros
	#define BLOCK_TO_PAGE(block)	(block << PagesPerBlockBits)
	#define PAGE_TO_BLOCK(page)		(page >> PagesPerBlockBits)
	
	 
	
	#define NF_ADDR_COL(col_addr) \
		NF_ADDR(col_addr); \
		if(AdvFlash == NAND_Advance) \
		{ \
			NF_ADDR(col_addr >> 8); \
		} \
		
	
	#define NF_ADDR_ROW(row_addr) \
		NF_ADDR(row_addr); \
		NF_ADDR(row_addr >> 8); \
		if(AddrCycle == ADDR_CYCLE_4) \
		{ \
			NF_ADDR(row_addr >> 16); \
		} \
	
	#define NF_READ_STATUS(status_var) \
		NF_CMD(CMD_ReadStatus); \
		status_var = NF_RDATA8(); \
	
	
	// Private method
	// Normal mode (512)
	static BOOL NF_Write(SECTOR_ADDR pages, DWORD offset_bytes, const void* pdata, DWORD len);
	static BOOL NF_Read(SECTOR_ADDR pages, DWORD offset_bytes, void* pdata, DWORD len);
	
	static BOOL NF_WriteSpare(SECTOR_ADDR pages, const void* pdata, DWORD len);
	static BOOL NF_ReadSpare(SECTOR_ADDR pages, void* pdata, DWORD len);
	
	// Advanced mode (2048)
	static BOOL NF_WriteAdv(SECTOR_ADDR pages, DWORD offset_bytes, const void* pdata, DWORD len);
	static BOOL NF_ReadAdv(SECTOR_ADDR pages, DWORD offset_bytes, void* pdata, DWORD len);
	
	static BOOL NF_WriteSpareAdv(SECTOR_ADDR pages, const void* pdata, DWORD len);
	static BOOL NF_ReadSpareAdv(SECTOR_ADDR pages, void* pdata, DWORD len);
	
	static BOOL NF_ReadChipInfo(FlashInfo *pFlashInfo);
	
	//others
	#ifdef __cplusplus
	extern "C" {
	#endif
		void __RdPageBytes(void* buffer, int count);
		void __WrPageBytes(const void* buffer, int count);
	#ifdef __cplusplus
	}
	#endif
	
	//----------------------------------------------------------------------------------------
	//
	// HCLK=133Mhz
	//----------------------------------------------------------------------------------------
	#define TACLS		0
	#define TWRPH0		6
	#define TWRPH1		0
	
	
	//----------------------------------------------------------------------------------------
	// NAND Flash Intefaces
	//----------------------------------------------------------------------------------------
	
	DWORD Nand_BlockToPage(BLOCK_ID blockID)
	{
		return BLOCK_TO_PAGE(blockID);
	}
	
	DWORD Nand_PageToBlock(DWORD page)
	{
		return PAGE_TO_BLOCK(page);
	}
	
	/*
	 * Nand flash characterisc
	 *
	 * Return
	 *		[0]	   0 - 8-Bit bus width,1 - 16-Bit bus width
	 *		[1]    0 - 3,4 cycles, 	1 - 4,5 cycles
	 *		[2]    0 - By word, 		1 - By byte
	 *		[3]    0 - Normal,		 	1 - Advance
	 *		[4-31] Reserved.
	 */
	DWORD Nand_Characteristic(void)
	{
		return 	(rNFCONF & 0xF);
	}
	
	/*
	 * page size
	 *
	 * Return
	 *     page size, 512, 2048
	 */
	DWORD Nand_PageSize(void)
	{
		return g_ChipInfo.wDataBytesPerSector;
	}
	
	/*
	 * pages of one block
	 *
	 * Return
	 *     pages per block , 32, 64
	 */
	DWORD Nand_PagesPerBlock(void)
	{
		return g_ChipInfo.wSectorsPerBlock;
	}
	
	/*
	 * Init Nand Flash register
	 */
	BOOL Nand_Init(void)
	{
		DebugPrintf(("TACLS=%d,TWRPH0=%d,TWRPH1=%d\n", TACLS, TWRPH0, TWRPH1));
		// for S3C2440
		rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);	
		// TACLS		[13:12]	CLE&ALE duration = HCLK*TACLS.
		// TWRPH0		[10:8]	TWRPH0 duration = HCLK*(TWRPH0+1)
		// TWRPH1		[6:4]	TWRPH1 duration = HCLK*(TWRPH1+1)
		// AdvFlash(R)	[3]		Advanced NAND, 0:256/512, 1:1024/2048
		// PageSize(R)	[2]		NAND memory page size
		//						when [3]==0, 0:256, 1:512 bytes/page.
		//						when [3]==1, 0:1024, 1:2048 bytes/page.
		// AddrCycle(R)	[1]		NAND flash addr size
		//						when [3]==0, 0:3-addr, 1:4-addr.
		//						when [3]==1, 0:4-addr, 1:5-addr.
		// BusWidth(R/W) [0]	NAND bus width. 0:8-bit, 1:16-bit.
		
		rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(1<<1)|(1<<0);
		// Lock-tight	[13]	0:Disable lock, 1:Enable lock.
		// Soft Lock	[12]	0:Disable lock, 1:Enable lock.
		// EnablillegalAcINT[10]	Illegal access interupt control. 0:Disable, 1:Enable
		// EnbRnBINT	[9]		RnB interrupt. 0:Disable, 1:Enable
		// RnB_TrandMode[8]		RnB transition detection config. 0:Low to High, 1:High to Low
		// SpareECCLock	[6]		0:Unlock, 1:Lock
		// MainECCLock	[5]		0:Unlock, 1:Lock
		// InitECC(W)	[4]		1:Init ECC decoder/encoder.
		// Reg_nCE		[1]		0:nFCE=0, 1:nFCE=1.
		// NANDC Enable	[0]		operating mode. 0:Disable, 1:Enable.
		
		rNFSTAT = 0;
		
		//-------------------------------------------------------------------------------------------------------------
		//Read Extended Information
		AdvFlash 		= (rNFCONF >> 3) & 1;
		AddrCycle		= (rNFCONF >> 1) & 1;
		// AdvFlash (Read only) [3]	Advance NAND flash memory for auto-booting
		//								0: Support 256 or 512 byte/page NAND flash memory
		//								1: Support 1024 or 2048 byte/page NAND flash memory
		//							This bit is determined by NCON0 pin status during reset and wake-up from sleep mode
		// PageSize (Read only)	[2] NAND flash memory page size for auto-booting AdvFlash PageSize
		//							When AdvFlash is 0,
		//								0: 256 Word/page, 1: 512 Bytes/page
		//							When AdvFlash is 1,
		//								0: 1024 Word/page, 1: 2048 Bytes/page
		//							This bit is determined by GPG13 pin status during reset and wake-up from sleep mode. 
		//							After reset, the GPG13 can be used as general I/O port or External interrupt.
		//AddrCycle (Read only) [1] NAND flash memory Address cycle for auto-booting AdvFlash AddrCycle
		//							When AdvFlash is 0,
		//								0: 3 address cycle 1: 4 address cycle
		//							When AdvFlash is 1,
		//								0: 4 address cycle 1: 5 address cycle
		//							This bit is determined by GPG14pin status during reset and wake-up from sleep mode. 
		//							After reset, the GPG14can be used as general I/O port or External interrupt.
		g_ChipInfo.flashType = NAND;
		
		//pre-calculate parameters
		if(AdvFlash == NAND_Advance)
		{
			SpareSize			= 64;
			PagesPerBlockBits	= 6;
			
			g_ChipInfo.wDataBytesPerSector		= 2048;
			g_ChipInfo.wSectorsPerBlock			= (1 << PagesPerBlockBits);
			g_ChipInfo.dwBytesPerBlock			= (g_ChipInfo.wDataBytesPerSector + SpareSize) * g_ChipInfo.wSectorsPerBlock;
		}
		else
		{
			SpareSize			= 16;
			PagesPerBlockBits	= 5;
			
			g_ChipInfo.wDataBytesPerSector		= 512;
			g_ChipInfo.wSectorsPerBlock		= (1 << PagesPerBlockBits);
			g_ChipInfo.dwBytesPerBlock			= (g_ChipInfo.wDataBytesPerSector + SpareSize) * g_ChipInfo.wSectorsPerBlock;
		}
		
		if(!NF_ReadChipInfo(&g_ChipInfo))
		{
			return FALSE;
		}
		
		return TRUE;
	}
	
	/*
	 * Reset Nand Flash Chip
	 */
	void Nand_Reset(void)
	{
		NF_nFCE_L();
		
		NF_CMD(CMD_Reset);
		
		NF_WAIT_RnB();
		
		NF_nFCE_H();
	}
	
	/*
	 * Read Nand Flash Chip ID
	 *	
	 * Return
	 *    Flash Chip ID
	 */
	U16	Nand_ReadID(void)
	{
		U16 id;
		
		NF_nFCE_L();
		
		NF_CMD(CMD_ReadID);
		NF_ADDR(0x00);
		
		id = NF_RDATA8() << 8;
		id |= NF_RDATA8();
		
		NF_nFCE_H();
		
		return (id);
	}
	
	//  Nand_GetInfo
	//
	//  Return the Flash information
	//
	BOOL Nand_GetInfo(PFlashInfo pFlashInfo)
	{
	    pFlashInfo->flashType = NAND;
	
	    //  OK, instead of reading it from the chip, we use the hardcoded
	    //  numbers here.
	
	    pFlashInfo->dwNumBlocks			= NUM_BLOCKS;
	    pFlashInfo->wSectorsPerBlock	= Nand_PagesPerBlock();
	    pFlashInfo->wDataBytesPerSector = Nand_PageSize();
	
	    return TRUE;
	}
	
	/*
	 * Read Nand Flash Operation Status
	 *
	 * Return
	 *    status byte
	 */
	BYTE Nand_ReadStatus(void)
	{
		BYTE status;
		
		NF_nFCE_L();
		
		NF_READ_STATUS(status);
		
		NF_nFCE_H();
		
		return status;
	}
	
	/*
	 * Erase a block
	 *
	 * Parameter

⌨️ 快捷键说明

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