blob: e60fe07e7bb1852ffa97e283e650d16a6b3e88b7 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Implementation of norflash common flash interface functions.
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "memories.h"
#include <string.h>
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
#define DUMP_CFI
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
/**
* \brief Dump the Common Flash Interface Definition Table.
*
* \param pNorFlashCFI Pointer to an NorFlashCFI instance.
*/
static void NorFlash_CFI_DumpConfiguration( NorFlashCFI *pNorFlashCFI )
{
uint8_t i ;
TRACE_DEBUG("Common Flash Interface Definition Table\n\r");
TRACE_DEBUG("Addr. Data Description \n\r");
TRACE_DEBUG("0x10 %04Xh Query Unique ASCII string\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.queryUniqueString[0]);
TRACE_DEBUG("0x11 %04Xh \n\r",
pNorFlashCFI->norFlashCfiQueryInfo.queryUniqueString[1]);
TRACE_DEBUG("0x12 %04Xh \n\r",
pNorFlashCFI->norFlashCfiQueryInfo.queryUniqueString[2]);
TRACE_DEBUG("0x13 %04Xh Primary OEM Command Set\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.primaryCode);
TRACE_DEBUG("0x15 %04Xh Address for Primary Extended Table\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.primaryAddr);
TRACE_DEBUG("0x17 %04Xh Alternate OEM Command Set\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.alternateCode);
TRACE_DEBUG("0x19 %04Xh Address for Alternate OEM Extended Table\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.alternateAddr);
TRACE_DEBUG("0x1B %04Xh VCC min write/erase\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.minVcc);
TRACE_DEBUG("0x1C %04Xh VCC max write/erase\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.maxVcc);
TRACE_DEBUG("0x1D %04Xh VPP min voltage\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.minVpp);
TRACE_DEBUG("0x1E %04Xh VPP max voltage\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.maxVpp);
TRACE_DEBUG("0x1F %04Xh Typical timeout per single word write\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.minTimeOutWrite);
TRACE_DEBUG("0x20 %04Xh Typical timeout for Min. size buffer write\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.minTimeOutBuffer);
TRACE_DEBUG("0x21 %04Xh Typical timeout per individual block erase\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.minTimeOutBlockErase);
TRACE_DEBUG("0x22 %04Xh Typical timeout for full chip erase\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.minTimeOutChipErase);
TRACE_DEBUG("0x23 %04Xh Max. timeout for word write\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.maxTimeOutWrite);
TRACE_DEBUG("0x24 %04Xh Max. timeout for buffer write\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.maxTimeOutBuffer);
TRACE_DEBUG("0x25 %04Xh Max. timeout per individual block erase\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.maxTimeOutBlockErase);
TRACE_DEBUG("0x26 %04Xh Max. timeout for full chip erase\n\r",
pNorFlashCFI->norFlashCfiQueryInfo.maxTimeOutChipErase);
TRACE_DEBUG("0x27 %04Xh Device Size = 2N byte\n\r",
pNorFlashCFI->norFlashCfiDeviceGeometry.deviceSize);
TRACE_DEBUG("0x28 %04Xh Flash Device Interface description\n\r",
pNorFlashCFI->norFlashCfiDeviceGeometry.deviceInterface);
TRACE_DEBUG("0x2A %04Xh Max. number of byte in multi-byte write\n\r",
pNorFlashCFI->norFlashCfiDeviceGeometry.numMultiWrite);
TRACE_DEBUG("0x2C %04Xh Number of Erase Block Regions within device\n\r",
pNorFlashCFI->norFlashCfiDeviceGeometry.numEraseRegion);
for(i = 0; i < pNorFlashCFI->norFlashCfiDeviceGeometry.numEraseRegion; i++)
{
TRACE_DEBUG("0x%2X %04Xh Number of Erase Blocks of identical size within region %x \n\r",
0x2D + i * 4, pNorFlashCFI->norFlashCfiDeviceGeometry.eraseRegionInfo[i].Y, i );
TRACE_DEBUG("0x%2X %04Xh (z) times 256 bytes within region %x \n\r",
0x2E + i * 4, pNorFlashCFI->norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z, i );
}
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Returns the numbers of block in all Norflash regions.
*
* \param pNorFlashInfo Pointer to a NorFlashInfo instance.
*/
uint32_t NorFlash_GetDeviceNumOfBlocks( NorFlashInfo *pNorFlashInfo )
{
uint8_t i;
uint32_t blocks = 0;
uint16_t numBlockRegion;
numBlockRegion = pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.numEraseRegion;
for (i = 0; i < numBlockRegion; i++)
{
blocks += (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i]).Y + 1;
}
return blocks;
}
/**
* \brief Returns the minimun block size in all Norflash regions.
*
* \param pNorFlashInfo Pointer to a NorFlashInfo instance.
*/
uint32_t NorFlash_GetDeviceMinBlockSize( NorFlashInfo *pNorFlashInfo )
{
uint8_t i;
uint16_t numBlockRegion;
uint32_t size ;
uint32_t dwTemp ;
numBlockRegion = pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.numEraseRegion;
size = (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[0].Z) * 256;
for ( i = 1; i < numBlockRegion; i++ )
{
dwTemp=(pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z) * 256 ;
if (size > dwTemp )
{
size = dwTemp ;
}
}
return size;
}
/**
* \brief Returns the maximun block size in all Norflash regions.
*
* \param pNorFlashInfo Pointer to a NorFlashInfo instance.
*/
uint32_t NorFlash_GetDeviceMaxBlockSize( NorFlashInfo* pNorFlashInfo )
{
uint8_t i;
uint16_t numBlockRegion;
uint32_t size ;
uint32_t dwTemp ;
numBlockRegion = pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.numEraseRegion;
size = (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[0].Z) * 256;
for (i = 1; i < numBlockRegion; i++)
{
dwTemp=(pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z) * 256 ;
if (size < dwTemp )
{
size = dwTemp ;
}
}
return size;
}
/**
* \brief Returns the block size in giving block number.
*
* \param pNorFlashInfo Pointer to a NorFlashInfo instance.
* \param sector Sector number.
*/
uint32_t NorFlash_GetDeviceBlockSize( NorFlashInfo* pNorFlashInfo, uint32_t sector )
{
uint16_t i;
uint16_t j;
uint16_t numBlockRegion ;
uint16_t numBlockPerRegion ;
uint32_t block = 0;
numBlockRegion = pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.numEraseRegion;
for (i = 0; i < numBlockRegion; i++)
{
numBlockPerRegion = (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i]).Y + 1;
for (j = 0; j < numBlockPerRegion; j++)
{
if (block == sector)
{
return (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z) * 256 ;
}
block++;
}
}
return 0;
}
/**
* \brief Returns secort number on specified memory offset.
*
* \param pNorFlashInfo Pointer to a NorFlashInfo instance.
* \param memoryOffset Memory offset.
*/
uint16_t NorFlash_GetDeviceSectorInRegion( NorFlashInfo *pNorFlashInfo, uint32_t memoryOffset )
{
uint16_t numBlockRegion,numBlockPerRegion;
uint16_t sectorId = 0;
uint32_t size = 0;
uint8_t done = 0;
uint16_t i , j;
numBlockRegion = pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.numEraseRegion;
for ( i=0 ; (i < numBlockRegion) && (done == 0) ; i++ )
{
numBlockPerRegion = (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i]).Y + 1;
for (j = 0; j < numBlockPerRegion; j++)
{
size+= (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z) * 256 ;
if ( size > memoryOffset )
{
done = 1;
break;
}
sectorId++;
}
}
return sectorId;
}
/**
* \brief Returns start address of specified sector number.
*
* \param pNorFlashInfo Pointer to a NorFlashInfo instance.
* \param sector Sector number.
*/
uint32_t NorFlash_GetDeviceSectorAddress( NorFlashInfo *pNorFlashInfo, uint32_t sector )
{
uint16_t numBlockRegion,numBlockPerRegion;
uint16_t sectorId = 0;
uint32_t address = 0;
uint8_t done = 0;
uint16_t i , j;
numBlockRegion = pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.numEraseRegion;
for ( i = 0 ; (i < numBlockRegion) && (done == 0) ; i++ )
{
numBlockPerRegion = (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i]).Y + 1;
for ( j = 0; j < numBlockPerRegion; j++ )
{
if (sector == sectorId)
{
done = 1;
break;
}
address+= (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z) * 256 ;
sectorId++;
}
}
return address;
}
/**
* \brief Convert address to byte addressing.
*
* \param pNorFlashInfo Pointer to a NorFlashInfo instance.
* \Param offset Address offset
*/
uint32_t NorFlash_GetByteAddress( NorFlashInfo *pNorFlashInfo, uint32_t offset )
{
return (offset * pNorFlashInfo-> deviceChipWidth);
}
/**
* \brief Convert address to byte addressing and return the address in chip.
*
* \param pNorFlashInfo Pointer to a NorFlashInfo instance.
* \Param offset Address offset
*/
uint32_t NorFlash_GetByteAddressInChip( NorFlashInfo *pNorFlashInfo, uint32_t offset )
{
return (pNorFlashInfo->baseAddress + (offset * pNorFlashInfo-> deviceChipWidth));
}
/**
* \brief Returns the address in chip.
*
* \param pNorFlashInfo Pointer to a NorFlashInfo instance.
* \Param offset Address offset
*/
uint32_t NorFlash_GetAddressInChip( NorFlashInfo *pNorFlashInfo, uint32_t offset )
{
return (pNorFlashInfo->baseAddress + offset);
}
/**
* \brief Returns bus width in bits of giving device.
*
* \param pNorFlashInfo Pointer to a NorFlashInfo instance.
*/
uint8_t NorFlash_GetDataBusWidth( NorFlashInfo *pNorFlashInfo )
{
return (pNorFlashInfo->deviceChipWidth * 8);
}
/**
* \brief Returns the size of the whole device in bytes.
*
* \param pNorFlashInfo Pointer to a NorFlashInfo instance.
*/
uint32_t NorFlash_GetDeviceSizeInBytes( NorFlashInfo *pNorFlashInfo )
{
return ((uint32_t) 2 << ((pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.deviceSize) - 1));
}
/**
* \brief Looks for query struct in Norflash common flash interface.
* If found, the model variable is filled with the correct values.
* This function returns 0 if a matching model has been found; otherwise it
* returns NorCommon_ERROR_UNKNOWNMODEL.
*/
uint8_t NorFlash_CFI_Detect( NorFlash *pNorFlash, uint8_t hardwareBusWidth )
{
uint8_t i;
uint8_t *pCfi = (uint8_t*)(&(pNorFlash->norFlashInfo.cfiDescription));
uint32_t address;
pNorFlash->norFlashInfo.cfiCompatible = 0;
pNorFlash->norFlashInfo.deviceChipWidth = hardwareBusWidth;
address = CFI_QUERY_OFFSET;
for ( i = 0; i< sizeof( NorFlashInfo) ; i++)
{
WriteCommand(8, NorFlash_GetByteAddressInChip(&(pNorFlash->norFlashInfo), CFI_QUERY_ADDRESS), CFI_QUERY_COMMAND);
ReadRawData(8, NorFlash_GetByteAddressInChip(&(pNorFlash->norFlashInfo), address), pCfi);
address++;
pCfi++;
}
/* Check the query-unique ASCII string "QRY" */
if ( (pNorFlash->norFlashInfo.cfiDescription.norFlashCfiQueryInfo.queryUniqueString[0] != 'Q' )
|| (pNorFlash->norFlashInfo.cfiDescription.norFlashCfiQueryInfo.queryUniqueString[1] != 'R')
|| (pNorFlash->norFlashInfo.cfiDescription.norFlashCfiQueryInfo.queryUniqueString[2] != 'Y') )
{
return NorCommon_ERROR_UNKNOWNMODEL;
}
#ifdef DUMP_CFI
NorFlash_CFI_DumpConfiguration( &(pNorFlash->norFlashInfo.cfiDescription) ) ;
#endif
if (pNorFlash->norFlashInfo.cfiDescription.norFlashCfiQueryInfo.primaryCode == CMD_SET_AMD)
{
pNorFlash->pOperations = &amdOperations;
}
else if ((pNorFlash->norFlashInfo.cfiDescription.norFlashCfiQueryInfo.primaryCode == CMD_SET_INTEL_EXT)
|| (pNorFlash->norFlashInfo.cfiDescription.norFlashCfiQueryInfo.primaryCode == CMD_SET_INTEL))
{
pNorFlash->pOperations = &intelOperations;
}
else
{
return NorCommon_ERROR_UNKNOWNMODEL;
}
pNorFlash->norFlashInfo.cfiCompatible = 1;
NORFLASH_Reset(pNorFlash, 0);
return 0;
}