📄 fmd.cpp
字号:
BOOLEAN SetBlockLock(BLOCK_ID blockID, ULONG NumBlocks, BOOL bLock)
{
volatile ULONG ulBlockAddress = 0;
BOOL bLastMode = SetKMode(TRUE);
FMDHAL_ASMInterruptDisable();
while (NumBlocks--)
{
// Compute the block address.
ulBlockAddress = g_FMDInfo.BaseAddress + (blockID * g_FMDInfo.BlockSize);
// Clear the status register.
WRITE_COMMAND(ulBlockAddress, CLEAR_STATUS_CMD);
// Set or Clear the block lock bit and confirm.
WRITE_COMMAND(ulBlockAddress, BLOCK_LOCK_CMD);
if (bLock)
{
WRITE_COMMAND(ulBlockAddress, BLOCK_SETLOCK_CMD);
}
else
{
WRITE_COMMAND(ulBlockAddress, BLOCK_PROCEED_CMD);
}
ULONG status = READ_FLASH(ulBlockAddress);
while ((status & 0x0080) != 0x0080)
{
status = READ_FLASH(ulBlockAddress);
}
if ((status & 0x0008) == 0x0008)
RETAILMSG(SANKA_DBG,(_T("ERROR: SetBlockLock: voltage range error ... .\r\n")));
if ((status & 0x0030) == 0x0030)
RETAILMSG(SANKA_DBG,(_T("ERROR: SetBlockLock: command sequence error ... .\r\n")));
if ((status & 0x0020) == 0x0020)
RETAILMSG(SANKA_DBG,(_T("ERROR: SetBlockLock: clear lock bits error ... .\r\n")));
if (status != 0x0080)
{
RETAILMSG(SANKA_DBG,(_T("ERROR: SetBlockLock: status register returned 0x%X\r\n"), status));
FMDHAL_ASMInterruptEnable();
SetKMode(bLastMode);
return FALSE;
}
++blockID;
}
FMDHAL_ASMInterruptEnable();
SetKMode(bLastMode);
return(TRUE);
}
VOID GetPhysicalSectorAddress (DWORD dwSector, PSECTOR_ADDR pStartSectorAddr, PSECTOR_ADDR pStartSectorInfoAddr)
{
// Determine the block this physical sector resides in
DWORD dwBlockID = dwSector / g_FMDInfo.SectorsPerBlock;
DWORD dwSectorOffset = dwSector % g_FMDInfo.SectorsPerBlock;
SECTOR_ADDR BlockAddr = g_FMDInfo.BaseAddress + (dwBlockID * g_FMDInfo.BlockSize);
*pStartSectorAddr = BlockAddr + (dwSectorOffset * g_FMDInfo.SectorSize);
if (pStartSectorInfoAddr && !g_bXIPEntire) {
*pStartSectorInfoAddr = BlockAddr + g_FMDInfo.SectorInfoOffset + (dwSectorOffset * sizeof(SectorInfo));
}
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: FMD_GetPhysSectorAddr()
Description: Returns the physical address for the physical sector passed in.
Returns: None
------------------------------------------------------------------------------*/
VOID FMD_GetPhysSectorAddr (DWORD dwSector, PSECTOR_ADDR pStartSectorAddr)
{
GetPhysicalSectorAddress (dwSector, pStartSectorAddr, NULL);
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: FMD_ReadSector()
Description: Reads the requested sector data and/or sector metadata from the
Flash media.
Notes: Notice that although each byte of a NOR Flash block is individually
addressable, the media is still logically broken up into sectors.
Thus, for each sector request, we must determine where this data
resides in the respective Flash block (see note above).
By default, the NOR Flash is configured in READ ARRAY MODE so there
is no need to set any control lines to access the media. The data
can just be read directly from the media (like RAM).
Returns: Boolean indicating success.
------------------------------------------------------------------------------*/
BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
{
volatile SECTOR_ADDR physicalSectorAddr = 0;
volatile SECTOR_ADDR physicalSectorInfoAddr = 0;
BLOCK_ID blockID = 0;
DWORD i = 0;
BOOL bLastMode;
RETAILMSG(SANKA_DBG,(_T("FMD_ReadSector +\r\n")));
//----- 1. Check the input parameters -----
// NOTE: The FAL insures that the starting sector address is in the allowable range.
if((dwNumSectors == 0) || ((pSectorBuff == NULL) && (pSectorInfoBuff == NULL)))
{
return(FALSE);
}
//----- 2. Process the read request(s)... -----
bLastMode = SetKMode(TRUE);
for(i = startSectorAddr ; i < (startSectorAddr + dwNumSectors) ; i++)
{
//----- Compute the physical address for the requested -----
GetPhysicalSectorAddress(i, (PSECTOR_ADDR)&physicalSectorAddr, (PSECTOR_ADDR)&physicalSectorInfoAddr);
//----- Read the necessary sector data -----
if(pSectorBuff)
{
memcpy(pSectorBuff, (UCHAR*)physicalSectorAddr, g_FMDInfo.SectorSize);
pSectorBuff += g_FMDInfo.SectorSize;
}
//----- Read the necessary SectorInfo data (metadata) -----
if(pSectorInfoBuff)
{
if (g_bXIPEntire)
{
// For XIP, fill the SectorInfo with 1:1 log/phys mapping and read-only status
memset (pSectorInfoBuff, 0xff, sizeof(SectorInfo));
pSectorInfoBuff->dwReserved1 = startSectorAddr;
}
else
{
// For non-XIP, The metadata bytes are read directly into the SectorInfo structure...
memcpy(pSectorInfoBuff, (CONST PVOID)physicalSectorInfoAddr, sizeof(SectorInfo));
}
pSectorInfoBuff++;
}
}
SetKMode(bLastMode);
return(TRUE);
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: FMD_WriteSector()
Description: Writes the requested sector data and/or sector metadata to the
Flash media.
Notes: Notice that although each byte of a NOR Flash block is individually
addressable, the media is still logically broken up into sectors.
Thus, for each sector request, we must determine where to put the
data in each respective Flash block (see note above).
By default, the NOR Flash is configured in READ ARRAY MODE we need
to set some control lines to prepare for the WRITE operation.
Returns: Boolean indicating success.
------------------------------------------------------------------------------*/
BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
{
volatile SECTOR_ADDR physicalSectorAddr = 0;
volatile SECTOR_ADDR physicalSectorInfoAddr = 0;
BLOCK_ID blockID = 0;
DWORD i = 0;
DWORD j = 0;
DWORD k = 0;
volatile ULONG ulBlockAddress = 0;
BOOL bLastMode;
DWORD dwBusWidth = g_bPairedFlash ? sizeof(ULONG) : sizeof(USHORT);
LPBYTE pBuffer = pSectorBuff;
BOOL fRet = FALSE;
LPBYTE pTempBuffer = NULL;
RETAILMSG(SANKA_DBG,(_T("FMD_WriteSector +\r\n")));
//----- 1. Check the input parameters -----
// NOTE: The FAL insures that the starting sector address is in the allowable range.
if((dwNumSectors == 0) || ((pSectorBuff == NULL) && (pSectorInfoBuff == NULL)))
{
return(FALSE);
}
//----- 2. Process the write request(s)... -----
bLastMode = SetKMode(TRUE);
for(i = startSectorAddr; i < (startSectorAddr + dwNumSectors); i++)
{
//----- Compute the physical address for the requested -----
GetPhysicalSectorAddress(i, (PSECTOR_ADDR)&physicalSectorAddr, (PSECTOR_ADDR)&physicalSectorInfoAddr);
// Compute the block address for this sector write.
//
ulBlockAddress = (ULONG)(physicalSectorAddr - (physicalSectorAddr % g_FMDInfo.BlockSize));
//----- Write the necessary sector data -----
if(pSectorBuff)
{
#ifdef READ_FROM_REGISTRY
// Check for unaligned pointer. Only need to do this if the FMD is being used as
// a block driver (and therefore READ_FROM_REGISTRY is set)
if ((DWORD)pSectorBuff & (dwBusWidth - 1))
{
if (!pTempBuffer) {
if (!(pTempBuffer = (LPBYTE)LocalAlloc (LMEM_FIXED, g_FMDInfo.SectorSize))) {
RETAILMSG(1, (TEXT("FMD_WriteSector: Memory allocation failed.\r\n")));
goto exit;
}
}
RETAILMSG(1, (TEXT("FMD_WriteSector: Unaligned pointer - using internal buffer\r\n")));
memcpy(pTempBuffer, pSectorBuff, g_FMDInfo.SectorSize);
pBuffer = pTempBuffer;
}
else
#endif
{
pBuffer = pSectorBuff;
}
// from Intel: if the sector is not aligned modulo write buffer size -
// performance can be enhanced my doing a partial write to align the buffer
// for the rest of the writes to complete the sector. If you are doing
// partial writes to align the buffer address, and a single word
// (or DWORD of x32) is being written, it is faster to use the flash's WORD
// write command instead of the buffered write.
for (j = 0, k = 0 ; (j < g_FMDInfo.SectorSize) ; j += k)
{
// Since we're using the StrataFlash write buffer to accelerate the write operation, we need to determine how many words should be written
// to the part(s). The value will be the minimum of either the sector bytes remaining or the write buffer size itself (including the number
// of flash parts/banks in the design). Since we write the data in longword form, we assume 2 banks in our design.
//
USHORT NumWriteBytes = (USHORT)MIN((g_FMDInfo.SectorSize - j), g_dwWriteBufferSize);
k = DoBufferedWrite(ulBlockAddress, physicalSectorAddr + j, pBuffer + j, NumWriteBytes);
if (!k)
goto exit;
}
pSectorBuff += g_FMDInfo.SectorSize;
}
//----- Write the necessary sector info data (metadata) -----
if (!g_bXIPEntire && pSectorInfoBuff)
{
if (!DoBufferedWrite(ulBlockAddress, physicalSectorInfoAddr, (PUCHAR)pSectorInfoBuff, sizeof(SectorInfo)))
goto exit;
pSectorInfoBuff++;
}
}
fRet = TRUE;
exit:
#ifdef READ_FROM_REGISTRY
if (pTempBuffer)
LocalFree (pTempBuffer);
#endif
//----- 3. Put the Flash back into READ ARRAY mode -----
WRITE_COMMAND(ulBlockAddress, READ_ARRAY_CMD);
SetKMode(bLastMode);
return fRet;
}
DWORD DoBufferedWrite(volatile ULONG ulBlockAddress,
volatile SECTOR_ADDR physicalSectorAddr,
PUCHAR pBuffer,
USHORT NumWriteBytes)
{
DWORD k = 0;
DWORD status;
DWORD dwBusWidth = g_bPairedFlash ? sizeof(ULONG) : sizeof(USHORT);
// Let the flash know the size of the buffer we plan to send (note that this is a 0-based word count and we simulatenously
// write it to both flash parts (upper and lower).
DWORD dwWordCount = (NumWriteBytes / dwBusWidth) - 1;
FMDHAL_ASMInterruptDisable();
RETAILMSG(SANKA_DBG,(_T("First unlock \r\n")));
WRITE_COMMAND(ulBlockAddress, BLOCK_LOCK_CMD);
WRITE_COMMAND(ulBlockAddress, BLOCK_PROCEED_CMD);
status = READ_FLASH(ulBlockAddress);
while ((status & 0x0080) != 0x0080)
{
status = READ_FLASH(ulBlockAddress);
}
if ((status & 0x0008) == 0x0008)
RETAILMSG(SANKA_DBG,(_T("ERROR: Flashwrite: voltage range error ... .\r\n")));
if ((status & 0x0030) == 0x0030)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -