📄 fmd.cpp
字号:
}
return NumWriteBytes;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: FMD_GetBlockStatus()
Description: Returns the status of a block. For read-only blocks, checks the sector
info data for the first sector of the block. Block is always good, so no need to check.
Returns: Block status.
------------------------------------------------------------------------------*/
DWORD FMD_GetBlockStatus(BLOCK_ID blockID)
{
SECTOR_ADDR Sector = blockID * g_FMDInfo.SectorsPerBlock;
SectorInfo SI;
DWORD dwResult = 0;
if (!FMD_ReadSector(Sector, NULL, &SI, 1))
return BLOCK_STATUS_UNKNOWN;
if (!(SI.bOEMReserved & OEM_BLOCK_READONLY))
dwResult |= BLOCK_STATUS_READONLY;
if (!(SI.bOEMReserved & OEM_BLOCK_RESERVED))
dwResult |= BLOCK_STATUS_RESERVED;
return dwResult;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: FMD_SetBlockStatus()
Description: Sets the status of a block.
Returns: TRUE if no errors in setting.
------------------------------------------------------------------------------*/
BOOL FMD_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)
{
if (dwStatus & (BLOCK_STATUS_READONLY | BLOCK_STATUS_RESERVED)) {
SECTOR_ADDR Sector = blockID * g_FMDInfo.SectorsPerBlock;
SectorInfo SI;
if (!FMD_ReadSector(Sector, NULL, &SI, 1)) {
return FALSE;
}
if (dwStatus & BLOCK_STATUS_READONLY) {
SI.bOEMReserved &= ~OEM_BLOCK_READONLY;
}
if (dwStatus & BLOCK_STATUS_RESERVED) {
SI.bOEMReserved &= ~OEM_BLOCK_RESERVED;
}
if (!FMD_WriteSector (Sector, NULL, &SI, 1)) {
return FALSE;
}
}
return TRUE;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: FMD_EraseBlock()
Description: Erases the specified Flash block.
Returns: Boolean indicating success.
------------------------------------------------------------------------------*/
BOOL FMD_EraseBlock(BLOCK_ID blockID)
{
volatile ULONG ulBlockAddress = 0;
ULONG ulStatus = 0;
BOOL bLastMode = SetKMode(TRUE);
// Determine the address for the specified block.
ulBlockAddress = g_FMDInfo.BaseAddress + (blockID * g_FMDInfo.BlockSize);
// Issue erase and confirm command.
// Note: eventually this should be changed to issue mass block erases, then loop to
// verify each completes.
WRITE_COMMAND(ulBlockAddress, BLOCK_ERASE_CMD);
WRITE_COMMAND(ulBlockAddress, BLOCK_PROCEED_CMD);
do
{
WRITE_COMMAND(ulBlockAddress, READ_STATUS_CMD);
}
while (!CHECK_STATUS(ulBlockAddress, STATUS_READY_MASK));
// TODO
#if 0
if ((ulStatus & 0x00200000) || (ulStatus & 0x00000020))
{
if (ulStatus & 0x00200000)
DEBUGMSG(1, (TEXT("\n\rBlock erase failure. Lock bit upper flash set!\r\n")));
if (ulStatus & 0x00000020)
DEBUGMSG(1, (TEXT("\n\rBlock erase failure. Lock bit lower flash set!\r\n")));
DEBUGMSG(1, (TEXT("Unrecoverable failure encountered while erasing flash.\r\n")));
return(FALSE);
}
#endif
// Set the block back to read array mode...
WRITE_COMMAND(ulBlockAddress, READ_ARRAY_CMD);
SetKMode(bLastMode);
return(TRUE);
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: FMD_PowerUp()
Description: Restores power to the Flash memory device (if applicable).
Returns: None.
------------------------------------------------------------------------------*/
VOID FMD_PowerUp(VOID)
{
return;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: FMD_PowerDown()
Description: Suspends power to the Flash memory device (if applicable).
Returns: None.
------------------------------------------------------------------------------*/
VOID FMD_PowerDown(VOID)
{
return;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: FMD_OEMIoControl()
Description: Implements user-defined (a.k.a. application specific) commands
for the Flash memory device
Returns: None.
------------------------------------------------------------------------------*/
BOOL FMD_OEMIoControl(DWORD dwIoControlCode, PBYTE pInBuf, DWORD nInBufSize,
PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned)
{
switch(dwIoControlCode)
{
case IOCTL_FMD_SET_XIPMODE:
// Select between XIP mode or non-XIP mode. The difference from the FMD's standpoint is whether or not
// sector information is stored along with each sector.
if (!pInBuf || nInBufSize < sizeof(BOOLEAN))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_SET_XIPMODE bad parameter(s).\r\n")));
return(FALSE);
}
g_bXIPMode = *(PBOOLEAN)pInBuf;
if (!g_bXIPMode) // Not XIP mode.
{
g_FMDInfo.UnusedBytesPerBlock = (USHORT)(g_FMDInfo.BlockSize % (SECTOR_SIZE + sizeof(SectorInfo)));
g_FMDInfo.SectorsPerBlock = (USHORT)(g_FMDInfo.BlockSize / (SECTOR_SIZE + sizeof(SectorInfo)));
}
else // XIP mode.
{
g_FMDInfo.UnusedBytesPerBlock = (USHORT)(g_FMDInfo.BlockSize % SECTOR_SIZE);
g_FMDInfo.SectorsPerBlock = (USHORT)(g_FMDInfo.BlockSize / SECTOR_SIZE);
}
break;
case IOCTL_FMD_LOCK_BLOCKS:
// Lock one of more blocks in a specified range.
if (!pInBuf || nInBufSize < sizeof(BlockLockInfo))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_LOCK_BLOCKS bad parameter(s).\r\n")));
return(FALSE);
}
if (!SetBlockLock(((PBlockLockInfo)pInBuf)->StartBlock, ((PBlockLockInfo)pInBuf)->NumBlocks, TRUE))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_LOCK_BLOCKS failed to lock blocks (start=0x%x, number=0x%x).\r\n"), ((PBlockLockInfo)pInBuf)->StartBlock, ((PBlockLockInfo)pInBuf)->NumBlocks));
return(FALSE);
}
break;
case IOCTL_FMD_UNLOCK_BLOCKS:
// Unlock one of more blocks in a specified range.
if (!pInBuf || nInBufSize < sizeof(BlockLockInfo))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_UNLOCK_BLOCKS bad parameter(s).\r\n")));
return(FALSE);
}
if (!SetBlockLock(((PBlockLockInfo)pInBuf)->StartBlock, ((PBlockLockInfo)pInBuf)->NumBlocks, FALSE))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_UNLOCK_BLOCKS failed to unlock blocks (start=0x%x, number=0x%x).\r\n"), ((PBlockLockInfo)pInBuf)->StartBlock, ((PBlockLockInfo)pInBuf)->NumBlocks));
return(FALSE);
}
break;
default:
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: unrecognized IOCTL (0x%x).\r\n"), dwIoControlCode));
return(FALSE);
}
return(TRUE);
}
BOOLEAN InitializeFlash(volatile PULONG pBaseAddress, ULONG FlashLength)
{
UCHAR nCount = 0;
ASSERT(pBaseAddress);
ASSERT(FlashLength);
if (!pBaseAddress || !FlashLength)
return(FALSE);
// Assume the flash part is an Intel Strataflash - first check the manufacturer code.
//
g_bPairedFlash = TRUE; // Assume flash is paired.
WRITE_COMMAND(pBaseAddress, READ_IDENT_CMD);
if (!CHECK_STATUS_INDEXED(pBaseAddress, QS_MFGCODE_OFFSET, MFGCODE_INTEL))
{
g_bPairedFlash = FALSE; // Maybe it's not paired?
WRITE_COMMAND(pBaseAddress, READ_IDENT_CMD);
if (!CHECK_STATUS_INDEXED(pBaseAddress, QS_MFGCODE_OFFSET, MFGCODE_INTEL))
{
// This isn't an Intel flash part.
DEBUGMSG(1, (TEXT("ERROR: InitializeFlash: invalid manufacturing code.\r\n")));
return(FALSE);
}
}
// Look for a Common Flash Interface (CFI).
//
WRITE_COMMAND(pBaseAddress, READ_QUERY_CMD);
if (!CHECK_STATUS_INDEXED(pBaseAddress, QS_IDSTRING_OFFSET, IDSTRING_Q) ||
!CHECK_STATUS_INDEXED(pBaseAddress, QS_IDSTRING_OFFSET + 1, IDSTRING_R) ||
!CHECK_STATUS_INDEXED(pBaseAddress, QS_IDSTRING_OFFSET + 2, IDSTRING_Y))
{
// This flash doesn't support CFI, so it's not a Strataflash.
DEBUGMSG(1, (TEXT("ERROR: InitializeFlash: didn't find StrataFlash CFI.\r\n")));
return(FALSE);
}
// We're pretty sure this is an Intel Strataflash part at this point - use the CFI to
// collect information on it (we're still in query mode). Also, we'll assume that both
// high and low word flash parts are the same from here on out (if paired).
//
g_FMDInfo.BaseAddress = (ULONG)pBaseAddress;
g_FMDInfo.FlashLength = (ULONG)FlashLength;
for (nCount = 0 ; nCount < sizeof(FLASH_SYSINTERFACE_INFO) ; nCount++)
{
*((PUCHAR)&g_FMDInfo.SysInt + nCount) = (UCHAR)(READ_FLASH_INDEXED(pBaseAddress, QS_SYSINTF_OFFSET + nCount) & 0xFF);
}
for (nCount = 0 ; nCount < sizeof(FLASH_GEOMETRY_INFO) ; nCount++)
{
*((PUCHAR)&g_FMDInfo.Geometry + nCount) = (UCHAR)(READ_FLASH_INDEXED(pBaseAddress, QS_DEVGEOM_OFFSET + nCount) & 0xFF);
}
// The block erase code assumes a single block per erase region - check for that here...
//
if (g_FMDInfo.Geometry.NumEraseBlocks != 1)
{
DEBUGMSG(1, (TEXT("ERROR: InitializeFlash: more than one block per erase region (%d).\r\n"), g_FMDInfo.Geometry.NumEraseBlocks));
return(FALSE);
}
// Compute block size and the total number of blocks here. Since we know an erase region contains
// only one block, the erase region size is equal to the block size.
// Note that the flash block size is 128KB, if paired, we have two of the 16-bit parts and the block size is effectively 256KB.
g_FMDInfo.BlockSize = (g_FMDInfo.Geometry.EraseRegionSize * REGION_SIZE_MULT);
if (g_bPairedFlash)
{
g_FMDInfo.BlockSize *= 2;
}
// In order for all the math to work out later, we require that the flash base address be block-aligned and that the flash length be
// an integral number of blocks.
if (!IS_BLOCK_ALIGNED(pBaseAddress) || !IS_BLOCK_ALIGNED(FlashLength))
{
DEBUGMSG(1, (TEXT("ERROR: InitializeFlash: base address and length must be block-aligned (Base=0x%x, Length=0x%x).\r\n"), (ULONG)pBaseAddress, FlashLength));
return(FALSE);
}
// Note that we need to adjust the total available blocks if the caller specified a non-zero flash offset value.
g_FMDInfo.TotalFlashBlocks = (FlashLength / g_FMDInfo.BlockSize);
// By default, we start out in *non-XIP* mode.
g_bXIPMode = FALSE;
// Default to NAND sector layout. If the caller wants to use this FMD for XIP-able code, they'll call the FMD_OEMIoControl
// and we'll change the number of UnusedBytesPerBlock.
g_FMDInfo.UnusedBytesPerBlock = (USHORT)(g_FMDInfo.BlockSize % (SECTOR_SIZE + sizeof(SectorInfo)));
g_FMDInfo.SectorsPerBlock = (USHORT)(g_FMDInfo.BlockSize / (SECTOR_SIZE + sizeof(SectorInfo)));
// Put the Flash into a known state (READ_ARRAY mode with WRITE-ENABLE disabled).
//
WRITE_COMMAND(pBaseAddress, READ_ARRAY_CMD);
return(TRUE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -