?? nand.c
字號:
/**************************************************************************************
*
*
* Copyright 2006 by Samsung Electronics, Inc.
* All rights reserved.
*
* Project Description :
* This software is only for validating functions of the S3C6400.
* 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 "sfr6400.h"
#include "system.h"
#include "sysc.h"
#include "intc.h"
#include "nand.h"
#include "dma.h"
#include "gpio.h"
#define NAND_REG_BUG (FALSE)
//#define NAND_EVT1 (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 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
{
// S3C6400 has 1 Nand Controller
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;
UART_Printf("uTwrph1 = %x",*uTwrph1);}
else
{
if(uTemp > 0)
*uTwrph1 = uTemp-1;
else
*uTwrph1 = 0;
}
}
//////////
// Function Name : NAND_TimingParaSetting
// Function Description : This function set the Timing Parameter(TACLS, TWRPH0, TWRPH1)
// Input : Controller - Nand Controller Port Number
// Output : None
void NAND_TimingParaSetting(u32 Controller)
{
u32 uTacls, uTwrph0, uTwrph1, uTemp0, uTemp1;
NAND_GetDurationValue(Controller, &uTacls, &uTwrph0, &uTwrph1);
uTemp0 = Inp32(&NAND(Controller)->rNFCONF);
uTemp0 = (uTemp0 & ~((0x07<<12)|(0x07<<8)|(0x07<<4))) | ((uTacls<<12)|(uTwrph0<<8)|(uTwrph1<<4));
Outp32(&NAND(Controller)->rNFCONF, uTemp0);
if(NAND_Inform[Controller].uNandType == NAND_MLC8bit)
{
uTemp1 = Inp32(&(NAND(Controller)->rNFCONF));
if(g_HCLK > 66000000)
uTemp1 &= ~(1<<30);
else
uTemp1 |= (1<<30);
Outp32(&(NAND(Controller)->rNFCONF), uTemp1);
}
UART_Printf("Nand Timing Parameter : TACLS(%d Clock), TWRPH0(%d Clock), TWRPH1(%d Clock)\n", uTacls, uTwrph0+1, uTwrph1+1);
}
//////////
// 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;
UART_Printf("NAND Illegal Access Error.........!!\n");
UART_Getc();
}
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);
//UART_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)
{
//UART_Printf("[block %d has been marked as a bad block(%x)]\n",uBlock,ucData);
return eNAND_InvalidBlock;
}
else
{
return eNAND_NoError;
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -