/* --------------------------------------------------------------------------
FILE : nand.c
PROJECT : TI Booting and Flashing Utilities
AUTHOR : Daniel Allred
DESC : Generic NAND driver file for EMIFA peripheral
-------------------------------------------------------------------------- */
/************************************************************
* Include Files *
************************************************************/
// General type include
#include "tistdtypes.h"
// Device specific CSL
#include "device.h"
#ifndef USE_IN_ROM
// Util functions
#include "util.h"
// Debug functions for non-ROMed version
#include "debug.h"
#endif
// This module's header file
#include "nand.h"
// Device NAND specific stuff
#include "device_nand.h"
/************************************************************
* Explicit External Declarations *
************************************************************/
// The device specific table of supported NAND devices
extern NAND_CHIP_InfoObj DEVICE_NAND_CHIP_infoTable[];
// The device specific ECC info struct
extern NAND_ECC_InfoObj DEVICE_NAND_ECC_info;
// The device specific BB info struct
extern NAND_BB_InfoObj DEVICE_NAND_BB_info;
// The device specific PAGE layout structure
extern NAND_PAGE_LayoutObj DEVICE_NAND_PAGE_layout;
/************************************************************
* Local Macro Declarations *
************************************************************/
/************************************************************
* Local Function Declarations *
************************************************************/
// Low-level NAND functions read, write, and command functions
static VUint8 *LOCAL_flashMakeAddr (Uint32 baseAddr, Uint32 offset);
static void LOCAL_flashWriteData(NAND_InfoHandle hNandInfo, Uint32 offset, Uint32 data);
static Uint32 LOCAL_flashReadData(NAND_InfoHandle hNandInfo);
// Address byte write functions
static void LOCAL_flashWriteColAddrBytes(NAND_InfoHandle hNandInfo, Uint32 offset);
static void LOCAL_flashWriteRowAddrBytes(NAND_InfoHandle hNandInfo, Uint32 page);
#ifndef USE_IN_ROM
// Array data writing functions
static void LOCAL_flashWriteBytes (NAND_InfoHandle hNandInfo, void *pSrc, Uint32 numBytes);
// Function to erase a block
static Uint32 LOCAL_eraseBlock(NAND_InfoHandle hNandInfo, Uint32 block, Bool force);
#endif
// Array data reading functions
static void LOCAL_flashReadBytes(NAND_InfoHandle hNandInfo, void *pDest, Uint32 numBytes);
// Wait for ready signal seen at NANDFSCR
static Uint32 LOCAL_flashWaitForRdy(Uint32 timeout);
// Wait for status result from device to read good
static Uint32 LOCAL_flashWaitForStatus(NAND_InfoHandle hNandInfo, Uint32 timeout);
// page Pointer set function
static Uint32 LOCAL_setPagePtr(NAND_InfoHandle hNandInfo,NAND_RegionType regtionType, Uint32 opNum);
// Get Chip details
static Uint32 LOCAL_flashGetDetails(NAND_InfoHandle hNandInfo);
// ONFI CRC check for Read Parameter Page command
static Bool LOCAL_onfiParamPageCRCCheck(Uint8 *paramPageData);
/************************************************************
* Local Variable Definitions *
************************************************************/
/************************************************************
* Global Variable Definitions *
************************************************************/
#ifdef USE_IN_ROM
NAND_InfoObj gNandInfo;
#endif
/************************************************************
* Global Function Definitions *
************************************************************/
// Initialze NAND interface and find the details of the NAND used
NAND_InfoHandle NAND_open(Uint32 baseCSAddr, Uint8 busWidth)
{
NAND_InfoHandle hNandInfo;
// Set NandInfo handle
#ifdef USE_IN_ROM
hNandInfo = (NAND_InfoHandle) &gNandInfo;
#else
hNandInfo = (NAND_InfoHandle) UTIL_allocMem(sizeof(NAND_InfoObj));
#endif
// Set NAND flash base address
hNandInfo->flashBase = baseCSAddr;
// Init the current block number and good flag
hNandInfo->currBlock = -1;
hNandInfo->isBlockGood = FALSE;
// Use device specific page layout and ECC layout
hNandInfo->hPageLayout = &DEVICE_NAND_PAGE_layout;
hNandInfo->hEccInfo = &DEVICE_NAND_ECC_info;
hNandInfo->hBbInfo = &DEVICE_NAND_BB_info;
hNandInfo->hChipInfo = DEVICE_NAND_CHIP_infoTable;
// Get the CSOffset ( can be 0 through (DEVICE_EMIF_NUMBER_CE_REGION -1) )
hNandInfo->CSOffset = 0;
while (hNandInfo->CSOffset < DEVICE_EMIF_NUMBER_CE_REGION)
{
if ( (hNandInfo->flashBase >= (DEVICE_EMIF_FIRST_CE_START_ADDR + (DEVICE_EMIF_INTER_CE_REGION_SIZE * (hNandInfo->CSOffset+0)))) &&
(hNandInfo->flashBase < (DEVICE_EMIF_FIRST_CE_START_ADDR + (DEVICE_EMIF_INTER_CE_REGION_SIZE * (hNandInfo->CSOffset+1))))
)
{
break;
}
hNandInfo->CSOffset++;
}
if (hNandInfo->CSOffset == DEVICE_EMIF_NUMBER_CE_REGION)
return NULL;
// Set EMIF bus width
hNandInfo->busWidth = busWidth;
// Setup AEMIF registers for NAND
AEMIF->NANDFCR |= (0x1 << (hNandInfo->CSOffset)); // NAND enable for CSx
(*hNandInfo->hEccInfo->fxnEnable)(hNandInfo);
// Send reset command to NAND
if ( NAND_reset(hNandInfo) != E_PASS )
return NULL;
// Get and set device details
if ( LOCAL_flashGetDetails(hNandInfo) != E_PASS )
return NULL;
#ifdef IPNC_DM365
if(hNandInfo->devID == 0x75 && hNandInfo->manfID ==0xec){
SYSTEM->PINMUX[2] |= 0x80;
GPIO->DIR23 &= 0xfeffffff;
GPIO->CLRDATA23 = 0x01000000;
}
#endif
// Send reset command to NAND
if ( NAND_reset(hNandInfo) != E_PASS )
return NULL;
return hNandInfo;
}
// Routine to check a particular block to see if it is good or bad
Uint32 NAND_badBlockCheck(NAND_InfoHandle hNandInfo, Uint32 block)
{
Uint8 spareBytes[256];
if (!hNandInfo->hBbInfo->BBCheckEnable)
{
return E_PASS;
}
else if (hNandInfo->currBlock != block)
{
hNandInfo->currBlock = block;
// Read and check spare bytes of first page of block (ONFI and normal)
NAND_readSpareBytesOfPage(hNandInfo, block, 0, spareBytes);
if ((*hNandInfo->hBbInfo->fxnBBCheck)(hNandInfo,spareBytes) != E_PASS)
{
hNandInfo->isBlockGood = FALSE;
return E_FAIL;
}
// Read and check spare bytes of second page of block (normal)
NAND_readSpareBytesOfPage(hNandInfo, block, 1, spareBytes);
if ((*hNandInfo->hBbInfo->fxnBBCheck)(hNandInfo,spareBytes) != E_PASS)
{
hNandInfo->isBlockGood = FALSE;
return E_FAIL;
}
if (hNandInfo->isONFI)
{
// Read and check spare bytes of last page of block (for ONFI)
NAND_readSpareBytesOfPage(hNandInfo, block, (hNandInfo->pagesPerBlock - 1), spareBytes);
if ((*hNandInfo->hBbInfo->fxnBBCheck)(hNandInfo,spareBytes) != E_PASS)
{
hNandInfo->isBlockGood = FALSE;
return E_FAIL;
}
}
hNandInfo->isBlockGood = TRUE;
return E_PASS;
}
else if (hNandInfo->isBlockGood == FALSE)
{
return E_FAIL;
}
else
{
return E_PASS;
}
}
// Routine to reset the NAND device
Uint32 NAND_reset(NAND_InfoHandle hNandInfo)
{
// Send reset command to NAND
LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_RESET );
return LOCAL_flashWaitForRdy(NAND_TIMEOUT);
}
// Routine to read a page from NAND
Uint32 NAND_readPage(NAND_InfoHandle hNandInfo, Uint32 block, Uint32 page, Uint8 *dest)
{
Uint32 i, currPagePtr, nextPagePtr;
//FIXME: the size of this array should be determined by the calcECCByteCnt
Uint8 readECC[16];
// This is enough to support 8 Kbyte page devices
Uint8 spareBytes[256];
// Get spare bytes of page