blob: 82171b6045fceccd665bbf23b877b0ef678b5970 [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.
*
******************************************************************************/
#include "Flash.h"
#include "general.h"
#include "Typedef.h"
#include "misc.h"
#include "Errors.h"
#include "FM.h"
#include "sparse_format.h"
#include "PlatformConfig.h"
#include "downloader.h"
/**************** Steps to add a new Flash Device **********************
*
* 1. add #include 'file.h' below
* 2. add pointer to the initialize function of the new flash device
* in the InitRoutines function pointer array at the correct
* location - should aligned with Fuse Config number for that flash
*
*************************************************************************/
//flash device includes
#include "nand.h"
#include "xllp_dfc.h"
#include "sdmmc_api.h"
#include "spi.h"
#include "SPINAND.h"
#if QSPINOR_CODE
#include "spi_nor.h"
#elif SPINOR_CODE
#include "SPINOR.h"
#endif
#if QSPINAND_CODE
#include "spi_nand.h"
#endif
/*static*/ FlashProperties_T FlashProp[2]; // 0 - Boot Flash, 1- Caddo Save State Flash
static FlashBootType_T CurrentFlashBootType;
extern SkipBlocksInfoStruct *pSkipAddress;
UINT_T MMCEraseAll = 0;
P_FlashProperties_T GetFlashProperties(FlashBootType_T FlashBootType)
{
if (FlashBootType == BOOT_FLASH)
return &FlashProp[0];
if (FlashBootType == SAVE_STATE_FLASH)
return &FlashProp[1];
}
FlashBootType_T GetCurrentFlashBootType()
{
return CurrentFlashBootType;
}
void SetCurrentFlashBootType(FlashBootType_T FlashBootType)
{
CurrentFlashBootType = FlashBootType;
return;
}
InitFlash_F GetInitRoutine(UINT8_T FlashNum){
InitFlash_F Routine = NULL;
switch(FlashNum){
case NAND_FLASH_X16_HM_P:
case NAND_FLASH_X8_HM_P:
case NAND_FLASH_X16_BCH_P:
case NAND_FLASH_X8_BCH_P:
#if NAND_CODE
Routine = &InitializeNANDDevice;
#endif
break;
case CS0_XIP_FLASH_P:
//case CS2_XIP_SIBLEY_P:
#if NOR_CODE
Routine = &InitializeXIPDevice;
#endif
break;
case SDMMC_FLASH_OPT1_P:
case SDMMC_FLASH_OPT2_P:
case SDMMC_FLASH_OPT3_P:
case SDMMC_FLASH_OPT4_P:
#if MMC_CODE
Routine = &InitializeSDMMCDevice;
#endif
break;
case SPI_NOR_FLASH_P:
case QSPI_NOR_FLASH_P:
//TODO, may seperate, need swd/blf changes
#if QSPINOR_CODE
Routine = &InitializeQSPIDevice;
#elif SPINOR_CODE
Routine = &InitializeSPIDevice;
#endif
break;
case SPI_NAND_FLASH_P:
case QSPI_NAND_FLASH_P:
//TODO, may seperate, need swd/blf changes
#if QSPINAND_CODE
Routine = &InitializeQSPINAND;
#elif SPINAND_CODE
Routine = &InitializeSPINAND;
#endif
break;
default:
break;
}
return Routine;
}
//--------------------------------------------------------------------------------------
// Configure_Flashes()
//
// This routine will configure the flashes according what the fuse settings passed in.
//--------------------------------------------------------------------------------------
UINT_T Configure_Flashes (UINT8_T FlashNum, FlashBootType_T fbt)
{
UINT_T Retval = InvalidBootTypeError;
UINT_T i;
InitFlash_F InitializeFunction;
P_FlashProperties_T pFlashProp, pFlashPropBoot;
P_FMProperties_T pFMProp = GetFMProperties();
UINT8_T DefaultPartitionNum;
// Get a pointer to the FlashProperties structure
pFlashProp = GetFlashProperties(fbt);
// Need to force grabbing the BOOT_FLASH struct for reasons found in for loop below
pFlashPropBoot = GetFlashProperties(BOOT_FLASH);
// Check, Are we initializing the SaveStateFlash and has the BootFlash already been initialized?
// And are they the save flash device?
// If so, no need to init hardware again, just copy FlashProperties
if ((fbt == SAVE_STATE_FLASH) && (pFlashPropBoot->FlashSettings.FlashInitialized == TRUE))
{
if(pFlashPropBoot->FlashSettings.FlashNum == FlashNum)
{
for(i = 0; i < (sizeof(FlashProperties_T) / 4); i++)
((UINT_T *)pFlashProp)[i] = ((UINT_T *)pFlashPropBoot)[i];
return NoError;
}
}
// If the flash that is passed in has already been initialized, return no error.
if ((pFlashProp->FlashSettings.FlashNum == FlashNum) && (pFlashProp->FlashSettings.FlashInitialized == TRUE) )
return NoError;
//Clear the Flash properties structure
// (Null out pointers)
//-------------------------------------
memset( pFlashProp, 0, sizeof(FlashProperties_T));
//See if we get a pointer to the appropriate
//init function for the assigned flash
//------------------------------------------
InitializeFunction = GetInitRoutine(FlashNum);
if(InitializeFunction == NULL) {
return InvalidBootTypeError;
}
Retval = InitializeFunction(FlashNum, fbt, &DefaultPartitionNum);
if (Retval == NoError)
{
pFMProp->PI_num = DefaultPartitionNum; // The default partition this device sets to.
pFlashProp->FlashSettings.FlashInitialized = TRUE;
pFlashProp->FlashSettings.FlashNum = FlashNum;
//Clear out the FM properties structure, to get rid of stale data
if(fbt == BOOT_FLASH)
ClearFM(BOOT_FLASH);
}
return Retval;
}
UINT_T Finalize_Flashes(FlashBootType_T fbt)
{
UINT_T Retval = NoError;
P_FlashProperties_T pFlashProp = GetFlashProperties(fbt);
FinalizeFlash_F final = pFlashProp->FinalizeFlash;
//if the flash is currently not initialized, just return
if (pFlashProp->FlashSettings.FlashInitialized == FALSE)
return NoError;
#if COPYIMAGESTOFLASH
//Finish any Flash Management
if(fbt == BOOT_FLASH)
FinalizeFM(fbt);
#endif
//Shutdown the flash if the appropriate function is linked
if(final != NULL)
Retval = final(fbt);
//Clear out the Properties structure
//Clear the Flash properties structure
// (Null out pointers)
//-------------------------------------
memset( pFlashProp, 0, sizeof(FlashProperties_T));
return Retval;
}
#if COPYIMAGESTOFLASH
/* Check if a certain block is in skip list*/
int CheckIfSkip(int blk_num)
{
int i, temp;
temp = pSkipAddress->Total_Number_Of_SkipBlocks;
for (i = 0; i < temp; i++)
if(blk_num == pSkipAddress->Skip_Blocks[i])
return TRUE;
return FALSE;
}
#endif
/* ReadFlash
* This API function calls the relative Flash device read command to read data.
* This function calls the low level read on a block basis, in order to use
* upper level FlashManagement
*
* Inputs:
* flash_addr - address of where to begin read in flash device ++
* buffer - pointer to location of where to load the data to
* total_size - amount of data, in bytes, to read
* fbt - flash boot type: BOOT_FLASH or SAVE_STATE_FLASH
* Outputs:
* None
* Retval value:
* NoError - on successful completion
* <Other> - Flash device specific read error
*
* ++ if a partition table is being used, this address MUST be relative the partition's
* start address, and not the entire flash device
*/
UINT_T ReadFlash(UINT_T flash_addr, UINT_T buffer, UINT_T total_size, FlashBootType_T fbt)
{
UINT_T Retval = NoError, Status = NoError;
UINT_T BlkNum, BlkSize, BlockMask, PartitionOffset, read_size, read_addr, RelocatedBlock;
ReadFlash_F read;
P_FlashProperties_T pFlashP = GetFlashProperties(fbt);
#if NAND_CODE
P_NAND_Properties_T pNandP = GetNANDProperties();
UINT_T spare_size = pNandP->SpareAreaSize;
UINT_T page_per_block = pNandP->PagesPerBlock;
UINT_T total_spare_size = spare_size * page_per_block;
#endif
read = pFlashP->ReadFromFlash;
if(read == NULL)
return FlashFuncNotDefined;
if (total_size == 0)
return NoError;
#if SPINOR_CODE
Retval = read(flash_addr, buffer, total_size, fbt);
#else
if(total_size & 0x3) //make size 4bytes-align
total_size = (total_size+4)&(~3);
//if flash_addr isn't page(2k) align, then return.
//if (flash_addr != 0xffffffff)
//{
// if((flash_addr & (pFlashP->PageSize-1)) )
// return FlashAddrNotChunkAlign;
//}
//set up initial values
BlkSize = GetBlockSize(fbt);
BlockMask = (BlkSize - 1); // Mask to get offset into a block
PartitionOffset = GetPartitionOffset(fbt);
#ifdef ENABLE_BBM
//If the flash uses BBM, read a block at a time
if(pFlashP->FlashSettings.UseBBM)
{
//for the first read, only read to the end of the initial block
read_size = BlkSize - (BlockMask & flash_addr);
while (total_size)
{
// Find block number
BlkNum = (flash_addr / BlkSize);
// Check for relocations
BlkNum = LocateBlock(BlkNum, fbt);
// calculate the read address, in case of relocation
// Read Address = new block * block size + offset into the block
read_addr = (BlkNum * BlkSize) + (flash_addr & BlockMask);
// Check read amount
read_size = read_size > total_size ? total_size : read_size;
// Read in to the buffer
Retval = read(read_addr + PartitionOffset, buffer, read_size, fbt);
// save off any read disturb data
#ifdef BITFLIPS_SCRUBBING
if (Retval == ReadDisturbError){
Retval = ScrubBlock_LegacyExt(BlkNum, &RelocatedBlock);
}
#else
if (Retval == ReadDisturbError){
Retval = AddReadDisturbEntry(GetFMProperties()->PI_num, BlkNum);
}
#endif
if (Retval != NoError)
break;
//update counting stats
// - address pointers
flash_addr += read_size;
buffer += read_size;
#if NAND_CODE
if (upload_nand_spare == TRUE)
{
buffer += total_spare_size;
}
#endif
// - size pointers
total_size -= read_size;
read_size = BlkSize;
} // End of while
//make sure to return any ReadDisturb that was caught
// if(Retval == NoError) TBD_TNA - Read disturbs should be saved in another manner.
// Retval = Status;
}
else //BBM not being used, just read the whole thing
#endif
{
#if MMC_CODE
// DMA max is 16M
while(total_size)
{
if(total_size > 0x1000000)
{
Retval = read(flash_addr + PartitionOffset, buffer, 0x1000000, fbt);
if(Retval != NoError)
return Retval;
flash_addr += 0x1000000 / 512; // use sector address as default
total_size -= 0x1000000;
buffer += 0x1000000;
}
else
{
Retval = read(flash_addr + PartitionOffset, buffer, total_size, fbt);
total_size = 0;
}
}
#else
// this media has no BBM support. use call the media-specific write routine.
Retval = read(flash_addr + PartitionOffset, buffer, total_size, fbt);
#endif
}
#endif
return Retval;
}
/* WriteFlash
* This API function calls the relative Flash device write command to program data.
* This function calls the low level program on a block basis, in order to use
* upper level FlashManagement.
*
* Inputs:
* flash_addr - address of where to begin write in flash device
* buffer - pointer to location of the data
* total_size - amount of data, in bytes, to program
* fbt - flash boot type: BOOT_FLASH or SAVE_STATE_FLASH
* Outputs:
* None
* Retval value:
* NoError - on successful completion
* <Other> - Flash device specific read error
*/
UINT_T WriteFlash(UINT_T flash_addr, UINT_T buffer, UINT_T total_size, FlashBootType_T fbt)
{
UINT_T Retval = NoError, sparesize;
#if COPYIMAGESTOFLASH
UINT_T BlkNum, BlkSize, BlockMask, PartitionOffset, write_size, write_addr, retry;
P_FlashProperties_T pFlashP = GetFlashProperties(fbt);
WriteFlash_F write = pFlashP->WriteToFlash;
UINT_T PageSize, PageMask;
UINT_T UseSpareFlag;
ReadFlash_F read = pFlashP->ReadFromFlash;
EraseFlash_F erase = pFlashP->EraseFlash;
UINT_T RestoreBuffer = 0, RestoreAddr = 0, RestoreLen = 0;
UseSpareFlag = GetUseSpareArea(BOOT_FLASH);
//if write is not defined, return with error
if(write == NULL)
return FlashFuncNotDefined;
if (total_size == 0)
return NoError;
#if SPINOR_CODE
Retval = write(flash_addr, buffer, total_size, fbt);
#else
//set up initial values
retry = TRUE;
BlkSize = GetBlockSize(fbt);
BlockMask = (BlkSize - 1); // Mask to get offset into a block
PartitionOffset = GetPartitionOffset(fbt);
PageSize = pFlashP->PageSize;
PageMask = (PageSize-1);
//for the first write, only write to the end of the initial block
write_size = BlkSize - (BlockMask & flash_addr);
if(total_size & 0x3) //make size 4bytes-align
total_size = (total_size+4)&(~3);
//if flash_addr isn't page(2k) align, then return.
//if (flash_addr != 0xffffffff)
//{
// if((flash_addr & PageMask) )
// return FlashAddrNotChunkAlign;
//}
#ifdef ENABLE_BBM
// if this media has BBM support, then attempt retries on failures:
if( pFlashP->FlashSettings.UseBBM)
{
while (total_size)
{
// Find block number
BlkNum = (flash_addr / BlkSize);
// add here to judge if this block is in the skip list, if it is in skip list, then continue to next block;
if(pSkipAddress != NULL)
{
if(CheckIfSkip(BlkNum))
goto NEXT_BLOCK;
}
// Check for relocations
BlkNum = LocateBlock(BlkNum, fbt);
// calculate the writeaddress, in case of relocation
// Write Address = new block * block size + offset into the block
write_addr = (BlkNum * BlkSize) + (flash_addr & BlockMask);
if( UseSpareFlag)
{
sparesize = (write_size >> 5);
write_size = write_size + sparesize;
}
// Check write amount
write_size = write_size > total_size ? total_size : write_size;
if (RestoreBuffer) {
/* new restore addr due to relocation */
RestoreAddr = (write_addr + PartitionOffset) & (~BlockMask);
Retval = write(RestoreAddr, RestoreBuffer, RestoreLen, fbt);
if (Retval == NoError) {
free(RestoreBuffer);
RestoreBuffer = 0;
Retval = write(write_addr + PartitionOffset, buffer, write_size, fbt);
}
} else {
// Write from the buffer
Retval = write(write_addr + PartitionOffset, buffer, write_size, fbt);
}
//if we hit an error, retry once, then Relocate
if (Retval != NoError)
{
/* write addr is not block aligned, need to save previous content */
if(((write_addr + PartitionOffset) & (BlockMask)) && (RestoreBuffer == 0))
{
RestoreAddr = (write_addr + PartitionOffset) & (~BlockMask);
RestoreLen = (write_addr + PartitionOffset) - RestoreAddr;
RestoreBuffer = malloc(PageSize);
if (RestoreBuffer) {
Retval = read(RestoreAddr, RestoreBuffer, RestoreLen, fbt);
if (Retval != NoError) {
free(RestoreBuffer);
RestoreBuffer = 0;
}
}
}
if(retry == TRUE)
{
//turn off retry flag
retry = FALSE;
//try erasing the block
Retval = erase(((write_addr + PartitionOffset) & (~BlockMask)), BlkSize, fbt);
if (Retval != NoError)
Retval = erase(((write_addr + PartitionOffset) & (~BlockMask)), BlkSize, fbt);
if (Retval == NoError) {
if (RestoreBuffer) {
Retval = write(RestoreAddr, RestoreBuffer, RestoreLen, fbt);
}
}
//if the erase(restore) succeeded, retry writing same block
if(Retval == NoError) {
if (RestoreBuffer) {
free(RestoreBuffer);
RestoreBuffer = 0;
}
continue;
}
//if erase failed, fall through to relocate
}
//reset retry flag, since we will be using a different block on the next try
retry = TRUE;
//no need to capture the return BlkNum, as the next LocateBlock will catch it
Retval = RelocateBlock(BlkNum, &BlkNum, fbt);
if(Retval != NoError)
return Retval;
#if NAND_CODE //To word around the issue that BootROM disable sprare area
else if(IsAccessOBMBlock(flash_addr))
DisableSpareAreaForOBM(BlkNum*BlkSize, 0);
#endif
//retry writing, with the updated block
continue;
}
//update counting stats
// - address pointers
NEXT_BLOCK:
if(UseSpareFlag)
flash_addr += (write_size-sparesize);
else
flash_addr += write_size;
buffer += write_size;
// - size pointers
total_size -= write_size;
write_size = BlkSize;
retry = TRUE;
} // End of while
}
else
#endif
{
#if MMC_CODE
// DMA max is 16M
while(total_size)
{
if(total_size > 0x1000000)
{
Retval = write(flash_addr + PartitionOffset, buffer, 0x1000000, fbt);
if(Retval != NoError)
return Retval;
flash_addr += 0x1000000 / 512; // use sector addres as default
total_size -= 0x1000000;
buffer += 0x1000000;
}
else
{
Retval = write(flash_addr + PartitionOffset, buffer, total_size, fbt);
total_size = 0;
}
}
#else
// this media has no BBM support. use call the media-specific write routine.
Retval = write(flash_addr + PartitionOffset, buffer, total_size, fbt);
#endif
}
#endif
#endif
return Retval;
}
void ResetBBT()
{
// create a new BBT
#ifdef BBM_LEGACY_EXT
CreateBBT_LegacyExt(NULL);
#else
CreateBBT_Legacy(NULL);
#endif
}
#if MMC_CODE
UINT_T EraseAllFlash(FlashBootType_T fbt)
{
UINT_T Retval = NoError, flash_addr = 0;
P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
Retval = SetPartition(MMC_SD_USER_PARTITION, fbt);
if (Retval != NoError)
return Retval;
#if 0
MMCEraseAll = 1;
UINT_T user_partition_size = pSDMMCP->CardCapacity;
Retval = EraseFlash(0, user_partition_size, fbt);
#else
MMCEraseAll = 0;
UINT64 user_partition_size = pSDMMCP->CardCapacity;
#define SIZE_1GB 0x40000000
user_partition_size = user_partition_size * 512;
flash_addr = 0;
while(user_partition_size)
{
if(user_partition_size > SIZE_1GB)
{
Retval = EraseFlash(flash_addr, SIZE_1GB, fbt);
if(Retval != NoError)
return Retval;
flash_addr += SIZE_1GB / 512; // use sector address as default
user_partition_size -= SIZE_1GB;
}
else
{
Retval = EraseFlash(flash_addr, user_partition_size, fbt);
user_partition_size = 0;
}
}
#endif
return Retval;
}
UINT_T EraseAllFlashWithoutBurn(FlashBootType_T fbt)
{
UINT_T Retval = NoError;
P_SDMMC_Properties_T pSDMMCP = GetSDMMCProperties();
UINT_T user_partition_size = pSDMMCP->CardCapacity;
UINT_T boot_partition_size = pSDMMCP->BootPartitionSize;
EraseAllFlash(fbt);
MMCEraseAll = 1;
Retval = SetPartition(MMC_SD_BOOT_PARTITION, fbt);
if (Retval != NoError)
return Retval;
Retval = EraseFlash(0, boot_partition_size, fbt);
if (Retval != NoError)
return Retval;
Retval = SetPartition(MMC_SD_BOOT_PARTITION2, fbt);
if (Retval != NoError)
return Retval;
Retval = EraseFlash(0, boot_partition_size, fbt);
if (Retval != NoError)
return Retval;
return Retval;
}
#else
UINT_T EraseAllFlash(FlashBootType_T fbt)
{
UINT_T Retval = NoError;
#if (COPYIMAGESTOFLASH)
P_FlashProperties_T pFlashP = GetFlashProperties(fbt);
P_FMProperties_T pFMProps = GetFMProperties();
UINT_T initial_blk, end_blk;
#if SPINOR_CODE
Retval = SPINOR_Wipe();
#else
#if defined(NAND_CODE) || defined(SPINAND_CODE)
initial_blk = pFlashP->NumBlocks - 1;
#endif
#ifdef BBM_LEGACY_EXT
initial_blk -= ABBT_BLOCK_NUM;
//Erase the ABBT blocks
Retval = EraseFlash((initial_blk+1)*pFlashP->BlockSize, pFlashP->BlockSize*2, fbt);
if(Retval != NoError)
return Retval;
SetABBTState(BBT_ERASED, fbt);
#endif
end_blk = initial_blk - (pFlashP->NumBlocks * LEGACY_BBM_RELOC_PERCENTAGE + 99) / 100;
// erase all blocks except reserved area
Retval = EraseFlash(0, pFlashP->BlockSize*(end_blk+1), fbt);
#endif
#endif
return Retval;
}
UINT_T EraseAllFlashWithoutBurn(FlashBootType_T fbt)
{
UINT_T Retval = NoError;
#if (COPYIMAGESTOFLASH)
P_FlashProperties_T pFlashP = GetFlashProperties(fbt);
P_FMProperties_T pFMProps = GetFMProperties();
UINT_T initial_blk, end_blk;
#if SPINOR_CODE
Retval = SPINOR_Wipe();
#else
#if defined(NAND_CODE) || defined(SPINAND_CODE)
initial_blk = pFlashP->NumBlocks - 1;
#endif
#ifdef BBM_LEGACY_EXT
initial_blk -= ABBT_BLOCK_NUM;
//Erase the ABBT blocks
Retval = EraseFlash((initial_blk+1)*pFlashP->BlockSize, pFlashP->BlockSize*2, fbt);
if(Retval != NoError)
return Retval;
SetABBTState(BBT_ERASED, fbt);
#endif
end_blk = initial_blk - (pFlashP->NumBlocks * LEGACY_BBM_RELOC_PERCENTAGE + 99) / 100;
// erase all blocks except reserved area
Retval = EraseFlash(0, pFlashP->BlockSize*(end_blk-1), fbt);
#endif
#endif
return Retval;
}
#endif
UINT_T EraseFlash(UINT_T flash_addr, UINT_T size, FlashBootType_T fbt)
{
UINT_T Retval = NoError;
#if (COPYIMAGESTOFLASH)
UINT_T erase_addr, total_blks, BlkSize, PageSize, PartitionOffset, BlkNum, retry;
P_FlashProperties_T pFlashP = GetFlashProperties(fbt);
P_FMProperties_T pFMProps = GetFMProperties();
EraseFlash_F erase = pFlashP->EraseFlash;
if(erase == NULL)
return FlashFuncNotDefined;
if (size == 0)
return NoError;
#if MMC_CODE
Retval = erase(flash_addr, size, BOOT_FLASH);
return Retval;
#elif SPINOR_CODE
Retval = erase(flash_addr, size, fbt);
return Retval;
#else
//set up initial values
BlkSize = pFlashP->BlockSize;
PageSize = pFlashP->PageSize;
retry = TRUE;
PartitionOffset = GetPartitionOffset(fbt);
// normalize addr and size to the whole blocks
BlkNum = (flash_addr / BlkSize);
erase_addr = BlkNum * BlkSize;
while (erase_addr < (flash_addr + size))
{
// add here to judge if this block is in the skip list, if it is in skip list, then continue to next block;
if(pSkipAddress != NULL)
{
if(CheckIfSkip(BlkNum))
goto NEXT_BLOCK;
}
//check to see if the block being erase contains a BBT or PT
CheckFMEraseState(BlkNum, fbt);
// Check for relocations
BlkNum = LocateBlock(BlkNum, fbt);
// erase the current block
Retval = erase( (BlkNum * BlkSize) + PartitionOffset, BlkSize, fbt);
//erase failure means either the block is bad, or device is wedged
if (Retval != NoError)
{
//try a reset first
if(retry == TRUE)
{ //clear the flag, and reset the device
retry = FALSE;
Retval = ResetFlash(fbt);
//if the reset failed, device is wedged. return error
if(Retval != NoError)
return Retval;
else //if reset succeeded, try the block again
continue;
}
else
{ //at this point, reset didn't help. so block is BAD
// if this media doesn't support BBM, there is no other recovery possible.
if( !pFlashP->FlashSettings.UseBBM)
return Retval;
//relocate block, but don't worry about catching new BlkNum, as next LocateBlock will pick it up
Retval = RelocateBlock(BlkNum, &BlkNum, fbt);
if(Retval != NoError)
return Retval;
#if NAND_CODE //To word around the issue that BootROM disable sprare area
else if(IsAccessOBMBlock(flash_addr))
DisableSpareAreaForOBM(BlkNum*BlkSize, 0);
#endif
//reset flag for the new block
retry = TRUE;
continue;
}
}
NEXT_BLOCK:
//update counting stats
// - address pointers
erase_addr += BlkSize;
BlkNum = erase_addr / BlkSize;
retry = TRUE;
}// End of while
#endif
#endif
return Retval;
}
UINT_T ResetFlash(FlashBootType_T fbt)
{
ResetFlash_F reset = GetFlashProperties(fbt)->ResetFlash;
if(reset == NULL)
return FlashFuncNotDefined;
else
return reset(fbt);
}
UINT_T ReadOTP(UINT_T OTPAddress, UINT_T LocalBuffer, UINT_T size, FlashBootType_T fbt)
{
#if (COPYIMAGESTOFLASH)
ReadOTP_F readotp = GetFlashProperties(fbt)->ReadOTP;
if(readotp == NULL)
return FlashFuncNotDefined;
else
return readotp(OTPAddress, LocalBuffer, size);
#else
return NoError;
#endif
}
UINT_T WriteOTP(UINT_T OTPAddress, UINT_T LocalBuffer, UINT_T size, FlashBootType_T fbt)
{
#if (COPYIMAGESTOFLASH)
WriteOTP_F writeotp = GetFlashProperties(fbt)->WriteOTP;
if(writeotp == NULL)
return FlashFuncNotDefined;
else
return writeotp(OTPAddress, LocalBuffer, size);
#else
return NoError;
#endif
}
UINT_T LockOTP(FlashBootType_T fbt)
{
#if (COPYIMAGESTOFLASH)
LockOTP_F lockotp = GetFlashProperties(fbt)->LockOTP;
if(lockotp == NULL)
return FlashFuncNotDefined;
else
return lockotp();
#else
return NoError;
#endif
}
#if !NAND_CODE
UINT_T GetBlockSize(FlashBootType_T fbt)
{
return GetFlashProperties(fbt)->BlockSize;
}
UINT_T GetPageSize(FlashBootType_T fbt)
{
return GetFlashProperties(fbt)->PageSize;
}
#endif
UINT_T GetEraseRegionSize(FlashBootType_T fbt)
{
return GetFlashProperties(fbt)->BlockSize;
}
#if COPYIMAGESTOFLASH
UINT_T GetUseSpareArea(FlashBootType_T fbt)
{
return GetFlashProperties(fbt)->FlashSettings.UseSpareArea;
}
UINT_T SetUseSpareArea(UINT_T bUseSpareArea, FlashBootType_T fbt)
{
P_FlashProperties_T pFlashProps = GetFlashProperties(fbt);
pFlashProps->FlashSettings.UseSpareArea = ((bUseSpareArea == 0) ? 0 : 1);
return GetUseSpareArea(fbt);
}
#if !NAND_CODE
UINT_T GetSpareAreaSize(FlashBootType_T fbt)
{
return GetFlashProperties(fbt)->FlashSettings.SASize;
}
#endif
UINT_T SetSpareAreaSize(UINT_T SASize, FlashBootType_T fbt)
{
P_FlashProperties_T pFlashProps = GetFlashProperties(fbt);
pFlashProps->FlashSettings.SASize = SASize;
return GetSpareAreaSize(fbt);
}
UINT_T GetUseHwEcc(FlashBootType_T fbt)
{
return GetFlashProperties(fbt)->FlashSettings.UseHwEcc;
}
UINT_T SetUseHwEcc(UINT_T bUseHwEcc, FlashBootType_T fbt)
{
P_FlashProperties_T pFlashProps = GetFlashProperties(fbt);
pFlashProps->FlashSettings.UseHwEcc = ((bUseHwEcc == 0) ? 0 : 1);
#if NAND_CODE
xdfc_enable_ecc( bUseHwEcc );
#endif
return GetUseHwEcc(fbt);
}
#endif
UINT_T ConvertToLogicalAddr(UINT_T FlashLocation, FlashBootType_T fbt)
{
ConvertToLogicalAddr_F logaddr = GetFlashProperties(fbt)->pConvertToLogicalAddr;
if(logaddr == NULL)
return FlashLocation;
else
return logaddr(FlashLocation, fbt);
}
#define SPARSE_HEADER_MAJOR_VER 1
UINT_T HandleSparseImage(UINT_T source, UINT_T start_address, UINT_T image_length, FlashBootType_T fbt)
{
sparse_header_t *header = (sparse_header_t *)source;
UINT_T i;
UINT64 logic_length = 0, outlen = 0, write_len = 0;
UINT_T sparse_header_length, chunk_header_length;
UINT_T r;
UINT64 len = 0;
chunk_header_t *chunk;
UINT64 tmp_total_blks, tmp_blk_sz;
if (header->magic != SPARSE_HEADER_MAGIC)
{
return Sparse_BadMagic;
}
if ((header->major_version != SPARSE_HEADER_MAJOR_VER) ||
(header->file_hdr_sz != sizeof(sparse_header_t)) ||
(header->chunk_hdr_sz != sizeof(chunk_header_t)))
{
return Sparse_IncompatibleFormat;
}
tmp_total_blks = header->total_blks;
tmp_blk_sz = header->blk_sz;
logic_length = tmp_total_blks * tmp_blk_sz;
sparse_header_length = sizeof(sparse_header_t);
chunk_header_length = sizeof(chunk_header_t);
source += sparse_header_length; // skip the sparse header
for (i = 0; i < header->total_chunks; i++)
{
chunk = (chunk_header_t *)source;
source += chunk_header_length; // skip the chunk header
switch (chunk->chunk_type)
{
case CHUNK_TYPE_RAW:
{
len = chunk->chunk_sz * header->blk_sz;
write_len += len;
if (chunk->total_sz != (len + chunk_header_length))
{
return Sparse_BadChunkSize;
}
outlen += len;
if (outlen > logic_length)
{
return Sparse_ImageLengthLimitExceeded;
}
r = WriteFlash(start_address, source, len, fbt); // write real data to flash
if (r != NoError)
{
return r;
}
start_address += len / 512; // use sector address as default
source += len;
break;
}
case CHUNK_TYPE_DONT_CARE:
{
if (chunk->total_sz != chunk_header_length)
{
return Sparse_BogusDontCareChunk;
}
len = chunk->chunk_sz * header->blk_sz;
outlen += len;
if (outlen > logic_length)
{
return Sparse_ImageLengthLimitExceeded;
}
start_address += len / 512; // use sector address as default
break;
}
default:
return Sparse_UnknownChunkId;
}
}
if (outlen != logic_length)
return Sparse_IncompatibleFormat;
if (write_len + sparse_header_length + header->total_chunks * chunk_header_length != image_length)
return Sparse_WriteError;
return NoError;
}