blob: d5b53d0819cfc36f52aa1b2d916e501dadbec602 [file] [log] [blame]
/******************************************************************************
*
* (C)Copyright 2005 - 2008 Marvell. All Rights Reserved.
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL.
* The copyright notice above does not evidence any actual or intended
* publication of such source code.
* This Module contains Proprietary Information of Marvell and should be
* treated as Confidential.
* The information in this file is provided for the exclusive use of the
* licensees of Marvell.
* Such users have the right to use, modify, and incorporate this code into
* products for purposes authorized by the license agreement provided they
* include this notice and the associated copyright notice with any such
* product.
* The information in this file is provided "AS IS" without warranty.
*
* FILENAME: xllp_dfc.c
*
* PURPOSE: XLLP interface to the data flash controller (DFC).
*
******************************************************************************/
#include "Flash.h"
#include "xllp_dfc.h"
#include "xllp_dfc_defs.h"
#include "platform_dfc_timing.h"
#include "PlatformConfig.h"
#include "PMUA.h"
//++
//************************************************************
// Unit Test Support
#ifdef _DFC_EM
#include "em_devlib.h"
#endif
//************************************************************
//--
/*
* NAND Small block device ID's
*/
char Samsung[] ={ 0x71, 0x78, 0x79, 0x72,
0x74, 0x36, 0x76, 0x46,
0x56, 0x35, 0x75, 0x45,
0x55, 0x33, 0x73, 0x43,
0x53, 0x39, 0xE6, 0x49,
0x59, 0x00};
char ST[] = {0x73, 0x35, 0x75, 0x45,
0x55, 0x76, 0x36, 0x46,
0x56, 0x79, 0x39, 0x49,
0x59, 0x00};
char Micron[] = {0x00};
char Hynix[] = {0x76, 0x56, 0x36, 0x46,
0x75, 0x55, 0x35, 0x45,
0x73, 0x53, 0x49, 0x00};
char Toshiba[] = {0x46, 0x79, 0x75, 0x73, 0x72, 0xE6, 0x00};
/*
* Large block NAND table
* This table contains the Manufacturer and Device ID's for the
* new MLC parts with a different Read ID formart
*/
// Manufacturer, Device,
char LargeBlockTable[] = { SAMSUNG_CODE, 0xD5,
SAMSUNG_CODE, 0xD7,
HYNIX_CODE, 0xD5, //H27UAG8T2A
// not yet known HYNIX_CODE, 0xD7, //H27UCG8V5A
0x0, 0x0}; //terminator
/*
* Default settings:
* Large block:
* read - CMD1 = 0x00 pg_program - CMD1 = 0x80
* CMD2 = 0x30 CMD2 = 0x10
* ADDR_CYC = 5 ADDR_CYC = 5
* DBC = 1 DBC = 1
* NC = 0 NC = 0
* CMD_TYPE = 0x0 CMD_TYPE = 0x1
* CSEL = 0 CSEL = 0
* AUTO_RS = 0 AUTO_RS = 0
* read_id - CMD1 = 0x90 blk_erase- CMD1 = 0x60
* CMD2 = 0x00 CMD2 = 0xD0
* ADDR_CYC = 1 ADDR_CYCLE = 0X3
* DBC = 0 DBC = 1
* NC = 0 NC = 0
* CMD_TYPE = 0x3 CMD_TPYE = 0X3
* CSEL = 0 CSEL = 0
* AUTO_RS = 0 AUTO_RS = 0
* read_status - CMD1 = 0x70 CMD2 = 0x00
* ADDR_CYC = 0
* DBC = 0
* NC = 0
* CMD_TYPE = 0x6
* CSEL = 0
* AUTO_RS = 0
* Small Block
* read - CMD1 = 0x00 pg_program - CMD1 = 0x80
* CMD2 = 0x00 CMD2 = 0x10
* ADDR_CYC = 4 ADDR_CYC = 5
* DBC = 0 DBC = 1
* NC = 0 NC = 0
* CMD_TYPE = 0x0 CMD_TYPE = 0x1
* CSEL = 0 CSEL = 0
* AUTO_RS = 0 AUTO_RS = 0
* read_id - CMD1 = 0x90 blk_erase- CMD1 = 0x60
* CMD2 = 0x00 CMD2 = 0xD0
* ADDR_CYC = 1 ADDR_CYCLE = 0x3
* DBC = 0 DBC = 1
* NC = 0 NC = 0
* CMD_TYPE = 0x3 CMD_TPYE = 0x3
* CSEL = 0 CSEL = 0
* AUTO_RS = 0 AUTO_RS = 0
* read_status - CMD1 = 0x70
* CMD2 = 0x00
* ADDR_CYC = 0
* DBC = 0
* NC = 0
* CMD_TYPE = 0x6
* CSEL = 0
* AUTO_RS = 0
*
*
*/
// Read ReadID ReadStat Program Erase Reset
static CMD_BLOCK CMD_ARRAY[DEVICE_TYPE_SIZE] =
{
//LARGE
// Read ,ReadID ,ReadStat ,Program ,Erase ,Reset ,ReadONFIParameter
{ 0x000D3000,0x00610090,0x00800070,0x002D1080,0x004BD060,0x00A000ff,0x100100EC},
//SMALL
// Read ,ReadID ,ReadStat ,Program ,Erase ,Reset ,Reserved
{ 0x00040000,0x00610090,0x00800070,0x002D1080,0x004BD060,0x00A000ff,0x00000000}
};
static unsigned int DFCSetupCount = 0;
/***********************************************************************
////////////
/////////////
////////// D F C I N T E R F A C E R O U T I N E S
////////////
///////////
/***********************************************************************/
UINT_T XllpDfcInit(unsigned int width, P_NAND_Properties_T pNAND_Prop)
{
NDCR_REG dfc_control_reg;
NDTR0CS0_REG dfc_timing0_reg;
NDTR1CS0_REG dfc_timing1_reg;
NDECCCTRL_REG dfc_ecc_ctrl_reg;
unsigned int buf[2]; // Read ID data should not be more than 5 bytes.
unsigned int Retval = 0;
unsigned int count = 0;
unsigned int OnfiSignature[2];
int status = NoError;
FlashBootType_T FlashBootType;
/*
** Why Are we here?
** Assume the first time, we're attempting to Boot and
** will configure the DFC to the default timing and
** specified bus width as passed in via the NAND properties structure.
** If it's not the first time, but the current FlashBootType
** is BOOT_FLASH, then adjust the bus width to that passed in (probably from 16 bit to 8 bit),
** becasue the probe order was wrong the first time.
** If it's not the first time, and the current FlashBootType is
** SAVE_STATE_FLASH, don't do anyting. We're assuming that the SaveStateFlash
** is identical to the BootFlash and the DFC doesn't need to be setup again.
*/
FlashBootType = GetCurrentFlashBootType();
/*
* Setup Multifunction pins for NAND
*/
ChipSelectDFC();
/*
* Initial DFC state:
* See values in xllp_dfc_defs.h
* - Disable all interrupts
* - Read_ID count = 2
* - SPARE and ECC enabled
* - DMA disabled
* - DWIDTH is x16
* - Small block PAGE_SZ
*
* Set timing to the worst (i.e. slowest) possible timing
* This can be adjusted after we determine the Flash type
*/
dfc_control_reg.value = DFC_INITIAL_CONTROL;
dfc_control_reg.bits.DMWIDTH_M = (width == 8)? 0 : 1;
dfc_control_reg.bits.DMWIDTH_C = (width == 8)? 0 : 1;
dfc_timing0_reg.value = DFC_INITIAL_TIMING0;
dfc_timing1_reg.value = DFC_INITIAL_TIMING1;
// Write out Timing and Control registers
DFC_REG_WRITE(DFC_DREDEL, 0xFFFFFFFF);
DFC_REG_WRITE(DFC_TIMING_0, dfc_timing0_reg.value);
DFC_REG_WRITE(DFC_TIMING_1, dfc_timing1_reg.value);
DFC_REG_WRITE(DFC_CONTROL, dfc_control_reg.value);
//make sure BCH is off
DFC_REG_READ(DFC_ECCCTRL, dfc_ecc_ctrl_reg.value );
dfc_ecc_ctrl_reg.bits.BCH_EN = 0;
DFC_REG_WRITE(DFC_ECCCTRL, dfc_ecc_ctrl_reg.value );
// Only issue a reset on the first call
if (!DFCSetupCount)
{ /*
* First, issue a reset command
*/
Retval = xdfc_reset(pNAND_Prop);
if ( Retval != NoError )
return Retval;
DFCSetupCount++;
}
// not use ONFI anymore
//Legacy Read ID code
/*
* Get the device ID first and check if it is small block
* or large block. If large block go back and read all 4
* bytes from the read id to get device parameters.
*/
buf[0] = 0; buf[1] = 0;
Retval = xdfc_readID(&buf[0], SMALL);
CheckErrorReturn(Retval);
if ( Retval == 0 )
{
pNAND_Prop->NAND_type = XllpCheckDeviceType(&buf[0], pNAND_Prop);
/*
* Once we determine Large or Small block set up the flash
* parameters structure and adjust the DFC Control register settings
*/
if(pNAND_Prop->NAND_type == LARGE)
{
Retval = xdfc_readID(&buf[0], LARGE);
if ( Retval != 0 )
return Retval;
if ((buf[0] == 0) && (buf[1] == 0))
return DFCInitFailed;
pNAND_Prop->device_cmds = &CMD_ARRAY[LARGE];
XllpLoadProperties(&buf[0], pNAND_Prop);
//dfc_control_reg.value = *DFC_CONTROL;
DFC_REG_READ(DFC_CONTROL, dfc_control_reg.value);
dfc_control_reg.bits.PAGE_SZ = 1;
dfc_control_reg.bits.RA_START = 1;
//need to figure this out from PagesPerBlock param in NAND struct
//remember DFC funny, where 32 -> 0, 64-> 2, 128 -> 1, 256 -> 3
switch (pNAND_Prop->PagesPerBlock)
{
case(32):
dfc_control_reg.bits.PG_PER_BLK = 0;
break;
case(128):
dfc_control_reg.bits.PG_PER_BLK = 1;
break;
case(256):
dfc_control_reg.bits.PG_PER_BLK = 3;
break;
case(64):
default: //default to 64, just in case
dfc_control_reg.bits.PG_PER_BLK = 2;
break;
}
}
else // Its Small Block
{
pNAND_Prop->device_cmds = &CMD_ARRAY[SMALL];
pNAND_Prop->PageSize = 512;
pNAND_Prop->SpareAreaSize = 16;
//dfc_control_reg.value = *DFC_CONTROL;
DFC_REG_READ(DFC_CONTROL, dfc_control_reg.value);
dfc_control_reg.bits.PAGE_SZ = 0;
dfc_control_reg.bits.PG_PER_BLK = 0; // Assume 32 PG_PER_BLK
dfc_control_reg.bits.RA_START = 0;
pNAND_Prop->BlockSize = 512 * 32;
}
//*DFC_CONTROL = dfc_control_reg.value;
DFC_REG_WRITE(DFC_CONTROL, dfc_control_reg.value);
}//End xdfc_readID retval OK
/* Overwrite Some Device Specific Data
* NumOfBlocks and Timing are done by the DKB/OBM only since DKB/OBM needs to support more than
* what BootROM needs. BootROM does not use ScanNANDForBadBlocks routine
*/
#if !(BOOTROM)
XllpDfcDeviceSpecificInit(pNAND_Prop);
#endif
return Retval;
}//End XllpDfcInit
void XllpDfcDeviceSpecificInit(P_NAND_Properties_T pNAND_Prop)
{
FLASH_TIMING* pFT; // For use in timing override
switch (pNAND_Prop->ManufacturerCode)
{
case SAMSUNG_CODE:
{
if (pNAND_Prop->FlashID == 0xAA) // LARGE Block - Part K9K2G08R0A
{
pNAND_Prop->NumOfBlocks = 2048;
pFT = &SAMSUNG_MFG_TIMING[3]; // Override Timing
xdfc_setTiming(pFT);
}
else if (pNAND_Prop->FlashID == 0xBA) // JIL board
{
pNAND_Prop->NumOfBlocks = 2048;
pFT = &SAMSUNG_MFG_TIMING[4]; // Override Timing
xdfc_setTiming(pFT);
}
else if (pNAND_Prop->FlashID == 0xBC) // JIL 1.5 board
{
pNAND_Prop->NumOfBlocks = 4096;
pFT = &SAMSUNG_MFG_TIMING[4]; // Override Timing
xdfc_setTiming(pFT);
}
else // SMALL Block - All Supported
{
pNAND_Prop->NumOfBlocks = 4096;
pFT = &SAMSUNG_MFG_TIMING[1]; // Override Timing
xdfc_setTiming(pFT);
}
break;
}
case TOSHIBA_CODE:
{
if ((pNAND_Prop->FlashID == 0xBA) || (pNAND_Prop->FlashID == 0xAA)) // LARGE Block
{
pNAND_Prop->NumOfBlocks = 2048;
pNAND_Prop->PageSize = 2048;
pFT = &TOSHIBA_MFG_TIMING[1]; // Override Timing
xdfc_setTiming(pFT);
}
else if ((pNAND_Prop->FlashID == 0xB1) || (pNAND_Prop->FlashID == 0xA1))
{
pNAND_Prop->NumOfBlocks = 1024;
pNAND_Prop->PageSize = 2048;
pFT = &TOSHIBA_MFG_TIMING[0]; // Override Timing
xdfc_setTiming(pFT);
}
else if (pNAND_Prop->FlashID == 0xAC)
{
pNAND_Prop->NumOfBlocks = 2048;
pNAND_Prop->PageSize = 4096; // 4KB page
pFT = &TOSHIBA_MFG_TIMING[2]; // Override Timing
xdfc_setTiming(pFT);
}
break;
}
case HYNIX_CODE:
{
if ((pNAND_Prop->FlashID == 0xBC) || (pNAND_Prop->FlashID == 0xAC))
{
pNAND_Prop->NumOfBlocks = 4096;
pFT = &HYNIX_MFG_TIMING[1]; // Override Timing
xdfc_setTiming(pFT);
}
else if ((pNAND_Prop->FlashID == 0xBA) || (pNAND_Prop->FlashID == 0xAA))
{
pNAND_Prop->NumOfBlocks = 2048;
pFT = &HYNIX_MFG_TIMING[0]; // Override Timing
xdfc_setTiming(pFT);
}
else if (pNAND_Prop->FlashID == 0xA1)
{
pNAND_Prop->NumOfBlocks = 1024;
}
break;
}
case ST_CODE:
break;
case MICRON_CODE:
{
// Cover Parts #MT29F1GXXABA LB
if ((pNAND_Prop->FlashID == 0xA1) || (pNAND_Prop->FlashID == 0xB1))
{
pNAND_Prop->NumOfBlocks = 1024;
pFT = &MICRON_MFG_TIMING[1]; // Override Timing
xdfc_setTiming(pFT);
}
//if ((pNAND_Prop->FlashID == 0xBA) || (pNAND_Prop->FlashID == 0xAA))
if (pNAND_Prop->FlashID == 0xBA)
{
pNAND_Prop->NumOfBlocks = 2048;
pFT = &MICRON_MFG_TIMING[1]; // Override Timing
xdfc_setTiming(pFT);
}
if (pNAND_Prop->FlashID == 0xAA)
{
/* ESMT FM6BD2G1GXA (2A) */
pNAND_Prop->NumOfBlocks = 2048;
pFT = &ESMT_MFG_TIMING[1]; // Override Timing
xdfc_setTiming(pFT);
}
if (pNAND_Prop->FlashID == 0xAC)
{
pNAND_Prop->NumOfBlocks = 4096;
pFT = &MICRON_MFG_TIMING[2]; // Override Timing
xdfc_setTiming(pFT);
}
if (pNAND_Prop->FlashID == 0xBC)
{
pNAND_Prop->NumOfBlocks = 4096;
pFT = &MICRON_MFG_TIMING[3]; // Override Timing
xdfc_setTiming(pFT);
}
if (pNAND_Prop->FlashID == 0xB3)
{
pNAND_Prop->NumOfBlocks = 8192;
pFT = &MICRON_MFG_TIMING[3]; // Override Timing
xdfc_setTiming(pFT);
}
if (pNAND_Prop->FlashID == 0xD3)
{
pNAND_Prop->NumOfBlocks = 16384;
pFT = &MICRON_MFG_TIMING[4]; // Override Timing
xdfc_setTiming(pFT);
}
break;
}
case ESMT_CODE:
{
if ((pNAND_Prop->FlashID == 0xA1) || (pNAND_Prop->FlashID == 0xB1) ||
(pNAND_Prop->FlashID == 0x81) || (pNAND_Prop->FlashID == 0x61))
{
pNAND_Prop->NumOfBlocks = 1024;
pFT = &ESMT_MFG_TIMING[0]; // Override Timing
xdfc_setTiming(pFT);
}
if (pNAND_Prop->FlashID == 0xAA)
{
pNAND_Prop->NumOfBlocks = 2048;
pFT = &ESMT_MFG_TIMING[0]; // Override Timing
xdfc_setTiming(pFT);
}
break;
}
case JSC_CODE:
{
if ((pNAND_Prop->FlashID == 0xA1) || (pNAND_Prop->FlashID == 0xB1)
|| (pNAND_Prop->FlashID == 0xAC) || (pNAND_Prop->FlashID == 0xBC))
{
pNAND_Prop->NumOfBlocks = 1024;
pFT = &JSC_MFG_TIMING[0]; // Override Timing
xdfc_setTiming(pFT);
}
break;
}
case FIDILEX_CODE:
{
if ((pNAND_Prop->FlashID == 0xA1) || (pNAND_Prop->FlashID == 0xB1))
{
pNAND_Prop->NumOfBlocks = 1024;
pFT = &FIDILEX_MFG_TIMING[0]; // Override Timing
xdfc_setTiming(pFT);
}
break;
}
case MACRONIX_CODE:
{
if ((pNAND_Prop->FlashID == 0xAA) || (pNAND_Prop->FlashID == 0xBA))
{
pNAND_Prop->NumOfBlocks = 2048;
pFT = &MACRONIX_MFG_TIMING[0]; // Override Timing
xdfc_setTiming(pFT);
}
if ((pNAND_Prop->FlashID == 0xAC) || (pNAND_Prop->FlashID == 0xBC))
{
pNAND_Prop->NumOfBlocks = 4096;
pFT = &MACRONIX_MFG_TIMING[0]; // Override Timing
xdfc_setTiming(pFT);
}
break;
}
case WINBOND_CODE:
{
if ((pNAND_Prop->FlashID == 0xA1) || (pNAND_Prop->FlashID == 0xB1))
{
pNAND_Prop->NumOfBlocks = 1024;
pFT = &WINBOND_MFG_TIMING[0]; // Override Timing
xdfc_setTiming(pFT);
}
if (pNAND_Prop->FlashID == 0xAA)
{
pNAND_Prop->NumOfBlocks = 2048;
pFT = &WINBOND_MFG_TIMING[1]; // Override Timing
xdfc_setTiming(pFT);
}
break;
}
default:
//assume that there are only 1K blocks
pNAND_Prop->NumOfBlocks = 1024;
break;
}//End switch (pNAND_Prop->ManufacturerCode)
}
DEVICE_TYPE XllpCheckDeviceType( P_DFC_BUFFER buffer, P_NAND_Properties_T pNAND_Prop)
{
char maker, device;
DEVICE_TYPE type = LARGE;
int match = 0;
char * search_list;
maker = pNAND_Prop->ManufacturerCode = (buffer[0] & 0xFF);
device = pNAND_Prop->FlashID = ((buffer[0] >> 8) & 0xFF);
/*
* Check to see if this is a known small block device
*/
switch (maker){
case SAMSUNG_CODE:
search_list = &Samsung[0];
break;
case TOSHIBA_CODE:
search_list = &Toshiba[0];
break;
case HYNIX_CODE:
search_list = &Hynix[0];
break;
case ST_CODE:
search_list = &ST[0];
break;
case MICRON_CODE:
search_list = &Micron[0];
break;
default:
return (type);
}
while (match == 0)
{
if(*search_list == device)
{
match = 1;
type = SMALL;
}
if(*search_list == 0)
match = 1;
search_list++;
}
return (type);
}
void XllpLoadProperties(P_DFC_BUFFER buffer, P_NAND_Properties_T pNAND_Prop)
{
char maker, device, properties, planes, plane_size;
char pg_size, blk_size, spare_size, cell_type, organization;
int i;
maker = buffer[0] & 0xFF;
device = (buffer[0] >> 0x8) & 0xFF;
properties = (buffer[0] >> 24) & 0xFF;
pg_size = properties & 0x3;
/* initialize properties using legacy Read ID format */
//bits 2 and 3 of the 3rd ID byte tell us if its SLC or MLC
cell_type = (buffer[0] >> 18) & 0x3;
blk_size = (properties >> 4) & 0x3;
organization = (properties >> 6) & 0x1;
pNAND_Prop->PageSize = 1024 << pg_size;
pNAND_Prop->BlockSize = (64*1024) << blk_size;
/* now check for new MLC Read ID formats and overwrite properties if found */
for(i = 0; ; i+=2)
{
//check termination case
if(LargeBlockTable[i] == 0)
break;
//check for match
if((LargeBlockTable[i] == maker) && (LargeBlockTable[i+1] == device))
{
pNAND_Prop->PageSize = 2048 << pg_size;
//blk size indication bits in 4th byte: 0xB0 (bits 7, 5 and 4)
blk_size = ((properties >> 5) & 0x4) | ((properties >> 4) & 0x3);
pNAND_Prop->BlockSize = (128*1024) << blk_size;
cell_type = 2; //just used to indicate MLC
break;
}
}
switch(maker)
{
case MICRON_CODE:
if(cell_type == 0x0) //SLC
pNAND_Prop->SpareAreaSize = 64; //only documented size
else //MLC
if(pNAND_Prop->PageSize == 2048)
pNAND_Prop->SpareAreaSize = 112;
else
pNAND_Prop->SpareAreaSize = 218;
break;
case SAMSUNG_CODE:
if(cell_type != 0x0) //MLC
{
if((properties & 0x4) == 0x4)
pNAND_Prop->SpareAreaSize = 128;
if((properties & 0x8) == 0x8)
pNAND_Prop->SpareAreaSize = 218;
break;
}//let SLC parts fall thru to default statement
case TOSHIBA_CODE:
case HYNIX_CODE:
case ST_CODE:
default:
spare_size = (properties >> 2) & 0x1;
if(spare_size == 0)
{
pNAND_Prop->SpareAreaSize = (pNAND_Prop->PageSize / 512) * 8;
}
else
{
pNAND_Prop->SpareAreaSize = (pNAND_Prop->PageSize / 512) * 16;
}
}
//lastly, figure out how many pages there are per block
pNAND_Prop->PagesPerBlock = pNAND_Prop->BlockSize / pNAND_Prop->PageSize;
}