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

📄 nand.c

📁 s3c6410基于USB OTG下载内核至NORFLASH的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/**************************************************************************************
* 
*	Project Name : S3C6410 Validation
*
*	Copyright 2006 by Samsung Electronics, Inc.
*	All rights reserved.
*
*	Project Description :
*		This software is only for validating functions of the S3C6410.
*		Anybody can use this software without our permission.
*  
*--------------------------------------------------------------------------------------
* 
*	File Name : nand.c
*  
*	File Description : This file implements the API functons for Nand controller.
*
*	Author : Heemyung.noh
*	Dept. : AP Development Team
*	Created Date : 2006/12/05
*	Version : 0.1 
* 
*	History
*	- Created(Heemyung.noh 2006/12/05)
*  
**************************************************************************************/

#include <stdio.h>

#include "def.h"
#include "option.h"
#include "library.h"
#include "sfr6410.h"
#include "system.h"
#include "sysc.h"
#include "intc.h"
#include "nand.h"
#include "dma.h"
#include "gpio.h"

#define NAND_REG_BUG		(TRUE)

#define NAND(__n) 		( ( volatile oNAND_REGS * ) ( NAND_pBase[__n] ) )

typedef struct tag_NAND_REGS
{
	u32 rNFCONF;
	u32 rNFCONT;
	u32 rNFCMMD;
	u32 rNFADDR;
	u32 rNFDATA;
	u32 rNFMECCD0;
	u32 rNFMECCD1;
	u32 rNFSECCD;
	u32 rNFSBLK;
	u32 rNFEBLK;
	u32 rNFSTAT;
	u32 rNFECCERR0;
	u32 rNFECCERR1;
	u32 rNFMECC0;
	u32 rNFMECC1;
	u32 rNFSECC;
	u32 rNFMLCBITPT;
} 
oNAND_REGS;

static void *NAND_pBase[NAND_CONNUM];
static u8 aNand_Spare_Data[NAND_SPARE_MAX] = {	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
												0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
												0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
												0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
u8 aNand_Spare_Data_Temp[NAND_SPARE_MAX] = {	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
												0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
												0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
												0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static volatile u32 g_Nand_RnBTransition, g_Nand_4bitEccEncDone, g_Nand_4bitEccDecDone, g_Nand_IllegalAccError;
NAND_oInform NAND_Inform[NAND_CONNUM];
NAND_oEccError NAND_EccError;

#if (NAND_TRANSFER_MODE == DMA_TRANSFER)
	static volatile u32 Nand_DmaDone;
#endif
	
DMAC g_oNandDmac1;

//////////
// Function Name : NAND_Init
// Function Description : This function initializes a certain Nand Controller
// Input : 	Controller - Nand Controller Port Number 
// Output : 	TRUE - Memory Device is initialized
//			FALSE - Memory Device is not initialized
bool	NAND_Init(u32 Controller)
{
	u32 uBaseAddress, uTemp;
	u32 uTacls, uTwrph0, uTwrph1;

	if(Controller == 0)
	{
		uBaseAddress = NFCON_BASE;
	}
	else
	{
		return FALSE;
	}
	
	NAND_pBase[Controller] = (void *)uBaseAddress;

	INTC_SetVectAddr(NUM_NFC, NAND_ISR0);
	
	NAND_GetDurationValue(Controller, &uTacls, &uTwrph0, &uTwrph1);

	if(NAND_Inform[Controller].uNandType == NAND_Normal8bit)
	{
		Outp32(&NAND(Controller)->rNFCONF, (uTacls<<12)|(uTwrph0<<8)|(uTwrph1<<4)|(0<<3)|(1<<2)|((NAND_Inform[Controller].uAddrCycle-3)<<1));
		Outp32(&NAND(Controller)->rNFCONT, (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0));
	}
	else if(NAND_Inform[Controller].uNandType == NAND_Advanced8bit)
	{
		Outp32(&NAND(Controller)->rNFCONF, (uTacls<<12)|(uTwrph0<<8)|(uTwrph1<<4)|(1<<3)|(1<<2)|((NAND_Inform[Controller].uAddrCycle-4)<<1));
		Outp32(&NAND(Controller)->rNFCONT, (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0));
	}
	else if(NAND_Inform[Controller].uNandType == NAND_MLC8bit)
	{
		Outp32(&NAND(Controller)->rNFCONF, (1<<24)|(uTacls<<12)|(uTwrph0<<8)|(uTwrph1<<4)|(1<<3)|(1<<2)|((NAND_Inform[Controller].uAddrCycle-4)<<1));
		Outp32(&NAND(Controller)->rNFCONT, (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0));

		uTemp = Inp32(&(NAND(Controller)->rNFCONF));
		if(g_HCLK  > 66000000)
			uTemp &= ~(1<<30);
		else
			uTemp |= (1<<30);
		Outp32(&(NAND(Controller)->rNFCONF), uTemp);
	}
	else
	{
		return FALSE;
	}		

	NAND_Reset(Controller);
	
#if NAND_TRANSFER_MODE == DMA_TRANSFER
		DMAC_InitCh(DMA1, DMA_ALL, &g_oNandDmac1);
		INTC_SetVectAddr(NUM_DMA1,  NAND_DmaISR);
		SYSC_SelectDMA(eSEL_PWM, 1);
		INTC_Enable(NUM_DMA1);
#endif	

	//GPIO_SetMem0DrvStrength(0xffffffff);

	return TRUE;
}


void	NAND_GetDurationValue(u32 Controller, u32 *uTacls, u32 *uTwrph0, u32 *uTwrph1)
{
	u32 uTemp;
	float fTemp;

	uTemp = (NAND_Inform[Controller].uTacls * (g_HCLK/1000))/1000000;
	fTemp = (((float)NAND_Inform[Controller].uTacls * (float)(g_HCLK/1000))/(float)1000000);
	fTemp -= uTemp;

	if(fTemp != (float)0)
		*uTacls = uTemp+1;
	else
		*uTacls = uTemp;

	uTemp = (NAND_Inform[Controller].uTwrph0 * (g_HCLK/1000))/1000000;
	fTemp = (((float)NAND_Inform[Controller].uTwrph0 * (float)(g_HCLK/1000))/(float)1000000);
	fTemp -= uTemp;

	if(fTemp != (float)0)
		*uTwrph0 = uTemp;
	else
	{
		if(uTemp > 0)
			*uTwrph0 = uTemp-1;
		else
			*uTwrph0 = 0;
	}
	
	uTemp = (NAND_Inform[Controller].uTwrph1 * (g_HCLK/1000))/1000000;
	fTemp = (((float)NAND_Inform[Controller].uTwrph1 * (float)(g_HCLK/1000))/(float)1000000);
	fTemp -= uTemp;

	if(fTemp != (float)0)
		*uTwrph1 = uTemp;
	else
	{
		if(uTemp > 0)
			*uTwrph1 = uTemp-1;
		else
			*uTwrph1 = 0;
	}
}
	

//////////
// Function Name : NAND_ISR
// Function Description : Nand IRQ routine
// Input : 	None
// Output : 	None
void __irq NAND_ISR0(void)
{
	u32 uIntSource;
	
	// rb1004 : must be modified
	//INT_Disable1(BIT_INT_NFC);
	INTC_Disable(NUM_NFC);

	uIntSource = Inp32(&NAND(0)->rNFSTAT);

	if(uIntSource & NAND_4BITECC_ENC)
	{
		Outp32(&NAND(0)->rNFSTAT, (1<<7));
		g_Nand_4bitEccEncDone = 1;
	}
	else if(uIntSource & NAND_4BITECC_DEC)
	{
		Outp32(&NAND(0)->rNFSTAT, (1<<6));
		g_Nand_4bitEccDecDone = 1;
	}
	else if(uIntSource & NAND_ILLEGAL_ACCESS)
	{
		Outp32(&NAND(0)->rNFSTAT, (1<<5));
		g_Nand_IllegalAccError = 1;
		printf("NAND Illegal Access Error.........!!\n");
		getchar();
	}
	else if(uIntSource & NAND_RnB_TRANS)
	{
		Outp32(&NAND(0)->rNFSTAT, (1<<4));
		g_Nand_RnBTransition = 1;
	}

	// rb1004 : must be modified
	//INT_Enable1(BIT_INT_NFC);
	//Write_VECTADDR(0x0);	
	INTC_Enable(NUM_NFC);
	INTC_ClearVectAddr();
}


//////////
// Function Name : NAND_DmaISR
// Function Description : Nand DMA transfer IRQ routine
// Input : 	None
// Output : 	None
#if (NAND_TRANSFER_MODE == DMA_TRANSFER)
void __irq NAND_DmaISR(void)
{
  	DMACH_ClearIntPending(&g_oNandDmac1);

	//printf ("DMA ISR %d\n", Nand_DmaDone);

	Nand_DmaDone = 1;
	INTC_ClearVectAddr();
}
#endif

//////////
// Function Name : NAND_ReadID
// Function Description : This function get the ID of external NAND Device
// Input : 	Controller - Nand Controller Port Number 
// Output : 	Nand Memory ID
u32 NAND_ReadID(u32 Controller)
{
	u32 i;
	//u8 ucID1, ucID2, ucID3, ucID4;
	u32 usID;

	NF_nFCE_L(Controller);
	
	NF_CMD(Controller, 0x90);
	NF_ADDR(Controller, 0x0);

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

#if 0
	ucID1 = (u8)NF_RDDATA8(Controller);	// read 4byte.
	ucID2 = (u8)NF_RDDATA8(Controller);
	ucID3 = (u8)NF_RDDATA8(Controller);
	ucID4 = (u8)NF_RDDATA8(Controller);
	usID = (ucID4<<24)|(ucID3<<16)|(ucID2<<8)|(ucID1<<0);
#else
	usID = NF_RDDATA(Controller);
#endif

	NF_nFCE_H(Controller);
	
	return 	usID;	
}

//////////
// Function Name : NAND_Reset
// Function Description : This function reset the external NAND Device
// Input : 	Controller - Nand Controller Port Number 
// Output : 	None
void NAND_Reset(u32 Controller)
{
    	u32 i;
   
	NF_nFCE_L(Controller);

	NF_CLEAR_RnB(Controller);
	NF_CMD(Controller, 0xFF);	//reset command

	if(NAND_Inform[Controller].uNandType == NAND_Normal8bit)
	{
		for(i=0;i<1000;i++);
	}
	else
	{
		for(i=0;i<10;i++);  //tWB = 100ns. //??????
		NF_DETECT_RnB(Controller);
	}
	NF_nFCE_H(Controller);
}

//////////
// Function Name : NAND_CheckInvalidBlock
// Function Description : This function check the invalid block of external NAND device
// Input : 	Controller - Nand Controller Port Number 
//			uBlock - Check Block
// Output : 	Nand Error Type
NAND_eERROR NAND_CheckInvalidBlock(u32 Controller, u32 uBlock)
{
	u32 uBlockPage, uPageSize;
	u8 ucData;

	if(NAND_Inform[Controller].uNandType == NAND_Normal8bit)
	{
		uBlockPage=(uBlock<<5);
		//uPageSize = NAND_PAGE_512;
		uPageSize = NAND_Inform[Controller].uPageSize;
	}
	else if(NAND_Inform[Controller].uNandType == NAND_Advanced8bit)
	{
		uBlockPage=(uBlock<<6);
		//uPageSize = NAND_PAGE_2048;
		uPageSize = NAND_Inform[Controller].uPageSize;
	}
	else if(NAND_Inform[Controller].uNandType == NAND_MLC8bit)
	{
		uBlockPage=(uBlock<<7);
		//uPageSize = NAND_PAGE_2048;
		uPageSize = NAND_Inform[Controller].uPageSize;
	}
	else
		return eNAND_EtcError;

	NF_nFCE_L(Controller);
	NF_CLEAR_RnB(Controller);

	//if(NAND_Inform[Controller].uNandType == NAND_Normal8bit)
	if(NAND_Inform[Controller].uAddrCycle == 4)
	{
		NF_CMD(Controller, 0x50);		 		// Spare array read command
		NF_ADDR(Controller, (uPageSize+5)&0xf);	// 6th byte in the Spare Area
	}
	else	 if(NAND_Inform[Controller].uAddrCycle == 5)
	{
		NF_CMD(Controller, 0x00);				// 1st Read Command
		NF_ADDR(Controller, (uPageSize+0)&0xff);			
		NF_ADDR(Controller, ((uPageSize+0)>>8)&0xff);		// 1st byte in the Spare Area		
	}			

	NF_ADDR(Controller, uBlockPage&0xff);	 // The mark of bad block is in 0 page
	NF_ADDR(Controller, (uBlockPage>>8)&0xff);	 // For block number A[24:17]
	NF_ADDR(Controller, (uBlockPage>>16)&0xff);  // For block number A[25]

	if((NAND_Inform[Controller].uNandType == NAND_Advanced8bit) || (NAND_Inform[Controller].uNandType == NAND_MLC8bit) )
		NF_CMD(Controller, 0x30);	// 2'nd command
	 
	NF_DETECT_RnB(Controller);	 // Wait tR(max 12us)
	NF_CLEAR_RnB(Controller);

	ucData=NF_RDDATA8(Controller);

	NF_CMD(Controller, 0x00);	// Define the starting address of the 1st half of the register

	NF_nFCE_H(Controller);    

	if(ucData!=0xff)
	{
		//printf("[block %d has been marked as a bad block(%x)]\n",uBlock,ucData);
		return eNAND_InvalidBlock;
	}
	else
	{
		return eNAND_NoError;
	}
}



//////////
// Function Name : NAND_CheckECCError
// Function Description : This function check the ECC Error
// Input : 	Controller - Nand Controller Port Number 
// Output :  	ECC Error Type 
NAND_eERROR NAND_CheckECCError(u32 Controller)
{
	u32 uEccError0;
	//u32 uEccError1;
	NAND_eERROR eError;	

	eError = eNAND_NoError;
	if((NAND_Inform[Controller].uNandType == NAND_Normal8bit) || (NAND_Inform[Controller].uNandType == NAND_Advanced8bit) )
	{
		uEccError0 = Inp32(&NAND(Controller)->rNFECCERR0);
		switch (uEccError0 & 0x03)
		{
			case 0x00 : 	eError = eNAND_NoError;
						break;
			case 0x01 : 	eError = eNAND_1bitEccError;
						break;
			case 0x02 : 	eError = eNAND_MultiError;
						break;
			case 0x03 : 	eError = eNAND_EccAreaError;
						break;
		}

		if(NAND_Inform[Controller].uPerformanceCheck == 0)

⌨️ 快捷键说明

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