blob: be766045e899296609f883da059253200085b0e9 [file] [log] [blame]
/******************************************************************************
**
** COPYRIGHT (C) 2002, 2003 Intel Corporation.
**
** This software as well as the software described in it is furnished under
** license and may only be used or copied in accordance with the terms of the
** license. The information in this file is furnished for informational use
** only, is subject to change without notice, and should not be construed as
** a commitment by Intel Corporation. Intel Corporation assumes no
** responsibility or liability for any errors or inaccuracies that may appear
** in this document or any software that may be provided in association with
** this document.
** Except as permitted by such license, no part of this document may be
** reproduced, stored in a retrieval system, or transmitted in any form or by
** any means without the express written consent of Intel Corporation.
**
** FILENAME: Flash.c
**
** PURPOSE: Contain template OEM boot code flash operations
**
******************************************************************************/
#include "Flash.h"
#include "nand.h"
#include "general.h"
#include "xllp_dfc.h"
#include "FM.h"
#include "ProtocolManager.h"
#if COPYIMAGESTOFLASH
#include "BootLoader.h"
#endif
#if USE_DMA
#include "xllp_dmac.h"
#endif
#include "dma.h"
#include "BBM.h"
NAND_Properties_T NAND_Prop; // Only need one
extern UINT_T NandID;
extern UINT_T nand_data_dma, nand_cmd_dma;
P_NAND_Properties_T GetNANDProperties(void)
{
return &NAND_Prop;
}
UINT_T GetSpareAreaSize(FlashBootType_T fbt)
{
return GetNANDProperties()->SpareAreaSize;
}
UINT_T GetBlockSize(FlashBootType_T fbt)
{
return GetNANDProperties()->BlockSize;
}
UINT_T GetPageSize(FlashBootType_T fbt)
{
return GetNANDProperties()->PageSize;
}
/*
* Function initializes NAND device and fills out Flash Properties Struct
*/
UINT_T InitializeNANDDevice(UINT8_T FlashNum, FlashBootType_T FlashBootType, UINT8_T* P_DefaultPartitionNum)
{
UINT_T Retval = NoError;
P_NAND_Properties_T pNandP = GetNANDProperties();
P_FlashProperties_T pFlashP = GetFlashProperties(FlashBootType);
// Set Current FlashBootType so XllpDfcInit can determine why it is called.
SetCurrentFlashBootType(FlashBootType);
// Pick correct bus width and set the ECC type
switch (FlashNum)
{
case NAND_FLASH_X16_HM_P:
pNandP->FlashBusWidth = FlashBusWidth16;
pNandP->ECCMode = ECC_HAMMING;
break;
case NAND_FLASH_X16_BCH_P:
pNandP->FlashBusWidth = FlashBusWidth16;
pNandP->ECCMode = ECC_BCH;
break;
case NAND_FLASH_X8_HM_P:
pNandP->FlashBusWidth = FlashBusWidth8;
pNandP->ECCMode = ECC_HAMMING;
break;
case NAND_FLASH_X8_BCH_P:
pNandP->FlashBusWidth = FlashBusWidth8;
pNandP->ECCMode = ECC_BCH;
break;
default:
return DFCInitFailed;
}
PlatformNandClocksEnable();
Retval = XllpDfcInit(pNandP->FlashBusWidth, pNandP);
if (Retval != NoError)
//return DFCInitFailed;
return NANDNotFound;
//set ECC with the correct ECCMode
xdfc_enable_ecc( 1 );
//define functions
pFlashP->ReadFromFlash = &ReadNAND;
pFlashP->WriteToFlash = &WriteNAND;
pFlashP->EraseFlash = &EraseNAND;
pFlashP->ResetFlash = &ResetNAND;
pFlashP->BlockSize = pNandP->BlockSize;
pFlashP->PageSize = pNandP->PageSize;
pFlashP->NumBlocks = pNandP->NumOfBlocks;
pFlashP->FlashSettings.UseBBM = 1;
pFlashP->FlashSettings.UseSpareArea = 0;
pFlashP->FlashSettings.SASize = 0;
pFlashP->FlashSettings.UseHwEcc = 1; // default is HW ECC ON
pFlashP->FlashType = NAND_FLASH;
pFlashP->GenerateFBBT = GenerateFBBTNAND;
// init the TIM load address
//---------------------------------------
pFlashP->TimFlashAddress = TIMOffset_NAND;
pFlashP->StreamingFlash = FALSE;
*P_DefaultPartitionNum = NAND_DEFAULT_PART;
pFlashP->FinalizeFlash = NULL;
NandID = (pNandP->FlashID << 8) | pNandP->ManufacturerCode;
GetDMAReqNum(&nand_data_dma, &nand_cmd_dma);
return Retval;
}
UINT_T GetDMAReqNum(UINT_T *data, UINT_T *cmd)
{
UINT_T NAND_DMA_DataReqNum = DMAC_NAND_DATA;
UINT_T NAND_DMA_CMDReqNum = DMAC_NAND_CMD;
#if NZA3
switch (PlatformGetRevisionID())
{
case 0xF0:
case 0xF2:
NAND_DMA_DataReqNum = DMAC_NAND_DATA_Z2;
NAND_DMA_CMDReqNum = DMAC_NAND_CMD_Z2;
break;
case 0xF3:
default:
break;
}
#endif
*data = NAND_DMA_DataReqNum;
*cmd = NAND_DMA_CMDReqNum;
}
/*
This routine will read in data from the DFC.
*/
#if !SHRINK_BINARY_SIZE
UINT_T ReadNAND_nonDMA(UINT_T Address, UINT_T Destination, UINT_T ReadAmount, FlashBootType_T FlashBootType)
{
P_NAND_Properties_T pNAND_Prop;
pNAND_Prop = GetNANDProperties();
UINT_T temp_buffer[2]; // temp use, no data needed
// For monolithic operation call legacy read routine
if (pNAND_Prop->PageSize <= TWO_KB)
{
if (upload_nand_spare == TRUE)
{
return xdfc_read_nonDMA((UINT_T *)Destination, Address, ReadAmount, temp_buffer, pNAND_Prop);
}
else
{
return xdfc_read_nonDMA((UINT_T *)Destination, Address, ReadAmount, NULL, pNAND_Prop);
}
}
else{ // Call the new routine that reads page at a time.
#if NAND_LP
return xdfc_read_LP((UINT_T *)Destination, Address, ReadAmount, NULL, pNAND_Prop);
#else
return NoError;
#endif
}
}
#endif
UINT_T ReadNAND (UINT_T Address, UINT_T Destination, UINT_T ReadAmount, FlashBootType_T FlashBootType)
{
return xdfc_read(Destination, Address, ReadAmount, NULL, GetNANDProperties());
}
/*
WriteNAND - This function is a wrapper to work with DFC
*/
UINT_T WriteNAND (UINT_T flash_addr, UINT_T source, UINT_T WriteAmount, FlashBootType_T FlashBootType)
{
UINT_T Retval = NoError;
P_NAND_Properties_T pNandP = GetNANDProperties();
P_FlashProperties_T pFlashP = GetFlashProperties(FlashBootType);
if (pNandP->PageSize <= TWO_KB)
{
Retval = xdfc_write((UINT_T *) source,
flash_addr,
WriteAmount,
pFlashP->FlashSettings.UseSpareArea,
pFlashP->FlashSettings.UseHwEcc,
pNandP);
}
else
{
#if NAND_LP
Retval = xdfc_write_LP((UINT_T *) source,
flash_addr,
WriteAmount,
pFlashP->FlashSettings.UseSpareArea,
pNandP);
#endif
}
return Retval; // Return value
}
/*
*
* Erases one block at a time
* note: if user inputs determine that a partial block should be erased,
* this function will erase that WHOLE block: no partial blocks allowed
*
*/
UINT_T EraseNAND (UINT_T flashoffset, UINT_T size, FlashBootType_T fbt)
{
return xdfc_erase(flashoffset, GetNANDProperties());
}
//Wrapper to link the dfc reset routine to the flash API
UINT_T ResetNAND(FlashBootType_T fbt)
{
return xdfc_reset(GetNANDProperties());
}
static UINT8_T page_buffer[2048]; //temp buffer to read dummy
UINT_T GenerateFBBTNAND(UINT16 *badblocklist)
{
unsigned int Retval, SA, i, j, temp, max, zero = 0, badblocks = 0;
unsigned int PageSize, BlockSize, block_good;
unsigned int *pRB0, *pRB1;
P_NAND_Properties_T pNandP = GetNANDProperties();
P_FlashProperties_T pFlashProp = GetFlashProperties(BOOT_FLASH);
UINT_T bUseHwEcc = FALSE;
unsigned int *dumy_buf = page_buffer;
unsigned char *ptemp = 0;
PageSize = pNandP->PageSize;
BlockSize = pNandP->BlockSize;
max = (pFlashProp->NumBlocks * LEGACY_BBM_RELOC_PERCENTAGE + 99) / 100; //max number of relocation is 2% of device
ptemp = malloc(BlockSize);
if(ptemp == NULL)
return HeapExhaustedError;
//buffers used to capture the entire spare area for page 0 and 1, respectively
pRB0 = (unsigned int *) (((unsigned int)ptemp + 16) & 0xFFFFFFF0); //align to 16 byte aligned
pRB1 = (unsigned int *) (((unsigned int)pRB0 + pNandP->SpareAreaSize + 16) & 0xFFFFFFF0); //ditto
//AddMessageError(REPORT_NOTIFICATION, PlatformBusy);
bUseHwEcc = GetUseHwEcc(BOOT_FLASH );
SetUseSpareArea( 1, BOOT_FLASH );
SetUseHwEcc( FALSE , BOOT_FLASH); //Turn Off ECC
//Block 0 is for TIM, scan from block1
for (i = 1; i < pFlashProp->NumBlocks; i++)
{
// address of 1st page in each block
SA = i * BlockSize;
// Read first page(including spare area) and second page of the block.
Retval = xdfc_read(dumy_buf, SA , PageSize, pRB0, pNandP);
Retval |= xdfc_read(dumy_buf, SA + PageSize, PageSize, pRB1, pNandP);
if(Retval != NoError) break; //read failure? something wrong with driver. return
//finished reading Spare Area in both page 0 and 1
//now check it:
// if it is all FFFFs, page is good
// else if byte 0 or byte 6 are not FFs, factory marked bad
// else try a erase/write cycle to termine bad v. just needed an erase cycle
block_good = TRUE;
for(j = 0; (block_good == TRUE) && (j < xdfc_getSpareAreaSize(pNandP)); j++)
if( (pRB0[j] != 0xFFFFFFFF) || (pRB1[j] != 0xFFFFFFFF) )
block_good = FALSE; //check for non FFFFs in spare area
//is this block 'good'?
if(block_good == FALSE) //nope
{ //check bytes 0 and 6 of both spare areas. if any byte != FF, block is factory bad
if( ((pRB0[0] & 0xFF) != 0xFF) || ((pRB0[1] & 0xFF0000) != 0xFF0000) ||
((pRB1[0] & 0xFF) != 0xFF) || ((pRB1[1] & 0xFF0000) != 0xFF0000) )
badblocklist[badblocks++] = i;
else
{ //try erase/program attempt
memcpy(pRB0, &zero, PageSize); //get a page worth of zeros
//erase the block
Retval = xdfc_erase(SA, pNandP);
//try writing all the pages to 0
for(j = 0; (j < BlockSize) && (Retval == NoError); j += PageSize)
Retval = WriteNAND (SA + j, (unsigned int) pRB0, PageSize, BOOT_FLASH);
//now erase the block again (to see if any bits get stuck at 0)
if(Retval == NoError)
Retval = xdfc_erase(SA, pNandP);
//any failure indicates a bad block
if(Retval != NoError)
badblocklist[badblocks++] = i;
}
}
//if we hit a critical number, return now and let the upper level handle it
if(badblocks >= max)
break;
}
SetUseHwEcc( bUseHwEcc , BOOT_FLASH); //Turn On ECC
//AddMessageError(REPORT_NOTIFICATION, PlatformReady);
SetUseSpareArea( 0 , BOOT_FLASH);
free(ptemp);
return badblocks;
}
UINT32 OBMI_FlashEntryAddr = 0;
UINT32 OBMI_ImageSize = 0;
static INT_T OBMBlock = -1;
void DisableSpareAreaForOBM(UINT_T OBMSartAddr, UINT_T OBMSize)
{
P_NAND_Properties_T pNandP = GetNANDProperties();
UINT_T BlockNum;
if(OBMSize > pNandP->BlockSize)
{
obm_printf("Error: OBM Size too big.\n\r");
}
if(OBMBlock == -1) {
OBMBlock = OBMSartAddr/pNandP->BlockSize;
}
if(OBMSize == 0){ //OBMSize == 0, means OBM block is relocating
BlockNum = OBMSartAddr/pNandP->BlockSize;
}else{
BlockNum = LocateBlock(OBMBlock, BOOT_FLASH);
}
OBMI_FlashEntryAddr = BlockNum * pNandP->BlockSize;
if(OBMSize != 0)
OBMI_ImageSize = OBMSize;
}
INT_T IsAccessOBMBlock(UINT32 Address)
{
UINT32 BlockSize = GetNANDProperties()->BlockSize;
UINT32 BlockNum;
BlockNum = Address/BlockSize;
return (BlockNum == OBMBlock);
}