📄 fmd.cpp
字号:
// Furthemore, we see that this NOR Flash memory can map (504*256)==>129,024
// physical sectors.
//
// Note:
// Unlike NAND, the sector meta info is groups together at the end of the
// flash block,
// -------
//
// Two other points are worth mentioning:
//
// 1) NOR Flash memory is guaranteed by manufacturing to ship with no bad Flash blocks.
// 2) NOR Flash memory doesn't suffer from electrical leakage currents (like NAND Flash) and
// does not require error-correction codes (ECC) to insure data integrity.
//
// Environment:
// As noted, this media driver works on behalf of the FAL to directly
// access the underlying FLASH hardware. Consquently, this module
// needs to be linked with FAL.LIB to produce the device driver
// named FLASHDRV.DLL.
//
// -----------------------------------------------------------------------------*/
// Function defines the virtual layout of logical sectors in flash given the
// flash geometry.
//
// Parameters:
// pGeometry
// [in] pointer to flash geometry information
//
// pLayout
// [out] pointer to virtual layout infomation.
//
// Returns:
// None
//
//-----------------------------------------------------------------------------
static BOOL DefineLayout(BOOL bIsPaired, CFI_FLASH_GEOMETRY_INFO *pGeometry, NOR_FMD_FLASH_INFO *pInfo)
{
ULONG FMDBase;
ULONG FMDLength;
ULONG FlashWalkAddr;
ULONG EraseBlockSize;
ULONG MaxEraseBlockSize;
BOOL bFMDStartAligned;
ULONG i;
ULONG j;
DWORD NumBlocks;
ULONG LogicalBlockSize;
DEBUGMSG(ZONE_FUNCTION, (TEXT("DefineLayout+\r\n")));
// Currently CE only supported sector size of 512.
FMDBase = pInfo->BaseAddress + pInfo->FMDBaseOffset;
FMDLength = pInfo->FlashLength - pInfo->FMDBaseOffset;
DEBUGMSG(ZONE_FUNCTION, (TEXT("FMDBase 0x%08X FMDLength 0x%08X+\r\n"), FMDBase, FMDLength));
// Get max block size and check FMD allocation is aligned.
MaxEraseBlockSize = 0;
FlashWalkAddr = pInfo->BaseAddress;
bFMDStartAligned = FALSE;
for(i = 0; i < pGeometry->NumEraseBlockRegions; i++)
{
EraseBlockSize = pGeometry->EraseBlockInfo[i].EraseBlockSize * CFI_ERASE_BLOCK_SIZE_MULTP;
EraseBlockSize += bIsPaired? EraseBlockSize : 0;
for(j = 0; j < (ULONG)(pGeometry->EraseBlockInfo[i].NumIdentEraseBlocks + 1); j++)
{
// Don't care sectors before FMD allocation
if(FlashWalkAddr < FMDBase)
{
FlashWalkAddr += EraseBlockSize;
continue;
}
// Check for FMD allocation start alignment with physical NOR sectors.
// Shift FMD allocation if not aligned.
if(bFMDStartAligned == FALSE)
{
if(FlashWalkAddr > FMDBase)
{
// Align FMDBase to physical sector and adjust allocated
// FMD flash accordingly.
DEBUGMSG(ZONE_INFO, (TEXT("INFO: 0x%08x not NOR sector aligned! Shifted to 0x%08x\r\n"),
FMDBase, FlashWalkAddr));
FMDLength -= (FlashWalkAddr - FMDBase);
FMDBase = FlashWalkAddr;
}
bFMDStartAligned = TRUE;
}
else
{
// Get max erase block size within FMD reserved region.
MaxEraseBlockSize = MAX(MaxEraseBlockSize, EraseBlockSize);
}
// Increment walk address
FlashWalkAddr += EraseBlockSize;
}
}
DEBUGMSG(ZONE_INFO, (TEXT("INFO: MaxEraseBlockSize 0x%08x\r\n"), MaxEraseBlockSize));
DEBUGMSG(ZONE_INFO, (TEXT("INFO: Sector aligned FMDBase 0x%08x FMDLength 0x%08x\r\n"),
FMDBase, FMDLength));
// Check for blocks of < max size and combine them if possible to get
// uniform blocks.
// Assumptions:
// 1. Blocks that are less than the basis block size are grouped sequentially.
// 2. Such a grouping of lesser blocks will amount to one basis block.
// 3. Such groupings can only occur at the beginning or end of flash device
FlashWalkAddr = pInfo->BaseAddress;
NumBlocks = 0;
LogicalBlockSize = 0;
for(i = 0; i < pGeometry->NumEraseBlockRegions; i++)
{
EraseBlockSize = pGeometry->EraseBlockInfo[i].EraseBlockSize * CFI_ERASE_BLOCK_SIZE_MULTP;
EraseBlockSize += bIsPaired? EraseBlockSize : 0;
for(j = 0; j < (ULONG)(pGeometry->EraseBlockInfo[i].NumIdentEraseBlocks + 1); j++)
{
if(FlashWalkAddr >= FMDBase)
{
if(EraseBlockSize < MaxEraseBlockSize)
{
// Combine all smaller blocks into single larger logical block
DEBUGMSG(ZONE_FUNCTION, (TEXT("INFO: EraseBlockSize 0x%08x CombineBlockSize 0x%08x\r\n"),
EraseBlockSize, LogicalBlockSize));
LogicalBlockSize += EraseBlockSize;
if(LogicalBlockSize == MaxEraseBlockSize)
{
LogicalBlockSize = 0;
NumBlocks++;
DEBUGMSG(ZONE_FUNCTION, (TEXT("INFO: Combine blocks success! NumLogicalBlocks 0x%08X\r\n"),
NumBlocks));
}
}
else
{
// Trap combine blocks at start of flash error condition
if(LogicalBlockSize != 0 && LogicalBlockSize < MaxEraseBlockSize)
{
// Combination of blocks is insufficient to form a basis block!
// Shift the FMD allocation base in this case
ERRORMSG(ZONE_ERROR, (TEXT("ERROR: unable to combine blocks! Shifted FMD start to 0x%08x\r\n"),
FlashWalkAddr));
FMDBase = FlashWalkAddr;
FMDLength -= LogicalBlockSize;
LogicalBlockSize = 0;
NumBlocks = 0;
}
NumBlocks++;
DEBUGMSG(ZONE_FUNCTION, (TEXT("INFO: Found blocks %d FlashWalkAddr 0x%08X\r\n"), NumBlocks, FlashWalkAddr));
DEBUGMSG(ZONE_FUNCTION, (TEXT("INFO: i %d j %d\r\n"), i, j));
}
}
DEBUGMSG(ZONE_FUNCTION, (TEXT("INFO: FlashWalkAddr 0x%08X\r\n"), FlashWalkAddr));
FlashWalkAddr += EraseBlockSize;
}
}
// Trap combine blocks at end of flash error condition
if(LogicalBlockSize != 0 && LogicalBlockSize < MaxEraseBlockSize)
{
// Should never be here!
ERRORMSG(ZONE_ERROR, (TEXT("ERROR: unable to combine blocks at flash end!\r\n")));
return FALSE;
}
// Return values
pInfo->FMDBaseOffset = FMDBase - pInfo->BaseAddress;
pInfo->BytesPerSector = SECTOR_SIZE;
if(!g_bXIPMode)
{
pInfo->SectorsPerBlock = (WORD)(MaxEraseBlockSize / (pInfo->BytesPerSector + sizeof(SectorInfo)));
pInfo->SectorInfoOffset = SECTOR_SIZE * pInfo->SectorsPerBlock;
}
else
{
pInfo->SectorsPerBlock = (WORD)(MaxEraseBlockSize / pInfo->BytesPerSector);
pInfo->SectorInfoOffset = 0;
}
pInfo->NumBlocks = NumBlocks;
pInfo->EraseBlockSize = MaxEraseBlockSize;
DEBUGMSG(ZONE_FUNCTION, (TEXT("DefineLayout-\r\n")));
return TRUE;
}
//-----------------------------------------------------------------------------
//
// Function: GetPhysicalSectorAddress
//
// Function returns the actual physical address for start of the sector passed in.
//
// Parameters:
// dwSector
// [in] sector number
//
// pStartSectorAddr
// [out] physical address.
//
// Returns:
// None
//
//-----------------------------------------------------------------------------
static void GetPhysicalSectorAddress(DWORD dwSector, PSECTOR_ADDR pStartSectorAddr, PSECTOR_ADDR pStartSectorInfoAddr)
{
DEBUGMSG(ZONE_FUNCTION, (TEXT("GetPhysicalSectorAddress+\r\n")));
// Determine the block this sector resides in
DWORD dwBlockID = dwSector / g_FMDInfo.SectorsPerBlock;
DWORD dwSectorOffset = dwSector % g_FMDInfo.SectorsPerBlock;
SECTOR_ADDR BlockAddr;
BlockAddr = g_FMDInfo.BaseAddress + g_FMDInfo.FMDBaseOffset + (dwBlockID * g_FMDInfo.EraseBlockSize);
*pStartSectorAddr = BlockAddr + (dwSectorOffset * g_FMDInfo.BytesPerSector);
if(pStartSectorInfoAddr && !g_bXIPMode)
{
*pStartSectorInfoAddr = BlockAddr + g_FMDInfo.SectorInfoOffset + (dwSectorOffset * sizeof(SectorInfo));
}
DEBUGMSG(ZONE_FUNCTION, (TEXT("GetPhysicalSectorAddress-\r\n")));
}
//-----------------------------------------------------------------------------
//
// Function: GetMappedSectorAddress
//
// Function returns the mapped address for start of the sector passed in.
//
// Parameters:
// dwSector
// [in] sector number
//
// pStartSectorAddr
// [out] mapped sector address.
//
// pStartSectorInfoAddr
// [out] mapped sector info address.
//
// Returns:
// None
//
//-----------------------------------------------------------------------------
static void GetMappedSectorAddress(DWORD dwSector, PSECTOR_ADDR pStartSectorAddr, PSECTOR_ADDR pStartSectorInfoAddr)
{
DEBUGMSG(ZONE_FUNCTION, (TEXT("GetMappedSectorAddress+, 0x%08X\r\n"), dwSector));
// Determine the block this sector resides in
DWORD dwBlockID = dwSector / g_FMDInfo.SectorsPerBlock;
DWORD dwSectorOffset = dwSector % g_FMDInfo.SectorsPerBlock;
SECTOR_ADDR BlockAddr;
DEBUGMSG(ZONE_FUNCTION, (TEXT("dwBlockID 0x%08X dwSectorOffset 0x%08X\r\n"),
dwBlockID, dwSectorOffset));
BlockAddr = (ULONG)g_pNORFlashBase + g_FMDInfo.FMDBaseOffset + (dwBlockID * g_FMDInfo.EraseBlockSize);
*pStartSectorAddr = BlockAddr + (dwSectorOffset * g_FMDInfo.BytesPerSector);
if(pStartSectorInfoAddr && !g_bXIPMode)
{
*pStartSectorInfoAddr = BlockAddr + g_FMDInfo.SectorInfoOffset + (dwSectorOffset * sizeof(SectorInfo));
}
DEBUGMSG(ZONE_FUNCTION, (TEXT("GetMappedSectorAddress-\r\n")));
}
//-----------------------------------------------------------------------------
//
// Function: SetBlockLock
//
// Function locks given number of blocks.
//
// Parameters:
// blockID
// [in] start block ID
//
// NumBlocks
// [in] number of blocks to lock.
//
// bLock
// [in] TRUE to lock blocks
//
// Returns:
// FALSE on failure
//
//-----------------------------------------------------------------------------
static BOOL SetBlockLock(BLOCK_ID blockID, ULONG NumBlocks, BOOL bLock)
{
ULONG ulBlockAddress = 0;
DEBUGMSG(ZONE_FUNCTION, (TEXT("SetBlockLock+\r\n")));
while(NumBlocks--)
{
// Compute the block address.
ulBlockAddress = (ULONG)g_pNORFlashBase + g_FMDInfo.FMDBaseOffset + (blockID * g_FMDInfo.EraseBlockSize);
if(bLock)
{
if(!NORLockSector(ulBlockAddress))
{
ERRORMSG(ZONE_ERROR, (TEXT("ERROR: Cannot lock block 0x%08X\r\n"), ulBlockAddress));
return FALSE;
}
}
else
{
if(!NORUnlockSector(ulBlockAddress))
{
ERRORMSG(ZONE_ERROR, (TEXT("ERROR: Cannot unlock block 0x%08X\r\n"), ulBlockAddress));
return FALSE;
}
}
}
DEBUGMSG(ZONE_FUNCTION, (TEXT("SetBlockLock-\r\n")));
return TRUE;
}
//-----------------------------------------------------------------------------
// END OF FILE
//-----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -