📄 amd.c
字号:
g_FlashProgInfo.bUnlockBypassSupport? L"TRUE" : L"FALSE"));
#endif
// TODO: If CPU is not little endian, need to take care of endianess in
// the structures.
// Check for at least 1 erase region
if(pFlashDesc->Geometry.NumEraseBlockRegions == 0)
{
ERRORMSG(ZONE_ERROR, (TEXT("ERROR: NORInit32: invalid geometry info!\r\n")));
bSuccess = FALSE;
goto _exit;
}
// Check for device with supported interface
if(pFlashDesc->Geometry.DevInterface != CFI_DEV_INTF_x8x16_ASYNC &&
pFlashDesc->Geometry.DevInterface != CFI_DEV_INTF_x16_ASYNC &&
pFlashDesc->Geometry.DevInterface != CFI_DEV_INTF_x16x32_ASYNC )
{
DEBUGMSG(ZONE_HAL_INFO, (TEXT("INFO: Unsupported device interface 0x%x\r\n"),
pFlashDesc->Geometry.DevInterface));
bSuccess = FALSE;
goto _exit;
}
// Check for supported command set.
if(pFlashDesc->QryIDStr.PriOEMCmdSetID != AMD_CMD_SET_ID)
{
DEBUGMSG(ZONE_HAL_INFO, (TEXT("Unsupported Pri Cmd Set: 0x%x\r\n"),
pFlashDesc->QryIDStr.PriOEMCmdSetID));
bSuccess = FALSE;
goto _exit;
}
#ifdef VIRTIO_FIXME
// Virtio is not returning correct CFI data for S29WSxxxN
// Force correct values according to specs, especially write buffer size
if(pFlashDesc->FlashID.DeviceID[1] == 0x2230)
{
pFlashDesc->SysInt.Typical.SnglWordProgTO_us = 6;
pFlashDesc->SysInt.Typical.BlockEraseTO_ms = 0x0A;
pFlashDesc->SysInt.Max.BlockEraseTO_ms = 2;
#if S29WSxxxN_BUFFER_PROG_SUPPORT
pFlashDesc->Geometry.WriteBuffSize = 6;
#else
// Force non buffer write
pFlashDesc->Geometry.WriteBuffSize = 0;
#endif
}
if(pFlashDesc->FlashID.DeviceID[1] == 0x2231 || pFlashDesc->FlashID.DeviceID[1] == 0x2232)
{
pFlashDesc->SysInt.Typical.SnglWordProgTO_us = 6;
pFlashDesc->SysInt.Typical.BlockEraseTO_ms = 0x0A;
pFlashDesc->SysInt.Max.SnglWordProgTO_us = 4;
pFlashDesc->SysInt.Max.WriteBuffTO_us = 4;
#if S29WSxxxN_BUFFER_PROG_SUPPORT
pFlashDesc->Geometry.WriteBuffSize = 6;
#else
// Force non buffer write
pFlashDesc->Geometry.WriteBuffSize = 0;
#endif
}
#endif
// Get device unique silicon ID
pusSiID = (USHORT *)(pFlashDesc->FlashID.SiliconID);
dwBusWidth = bIsPaired? sizeof(ULONG): sizeof(USHORT);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_1_ADDR_UNLOCK_x16, CYCLE_1_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_2_ADDR_UNLOCK_x16, CYCLE_2_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_2_ADDR_UNLOCK_x16, CYCLE_3_DATA_ENTER_SECSI);
for(i = 0; i < 8; i++)
{
*(pusSiID + i) = (USHORT)(RD_FLASH_INDEXED16(bIsPaired, ulFlashBase, i) & 0xFFFF);
}
// Exit Sec Si area
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_1_ADDR_UNLOCK_x16, CYCLE_1_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_2_ADDR_UNLOCK_x16, CYCLE_2_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_2_ADDR_UNLOCK_x16, CYCLE_3_DATA_EXIT_SECSI);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_4_ADDR_EXIT_SECSI, CYCLE_4_DATA_EXIT_SECSI);
// Get driver prog info & store for easy access.
// Single datum timeouts
if(pFlashDesc->SysInt.Typical.SnglWordProgTO_us)
g_FlashProgInfo.ulDatumProgTO_us = (1 << pFlashDesc->SysInt.Typical.SnglWordProgTO_us);
else
g_FlashProgInfo.ulDatumProgTO_us = POLLING_WRBYPASS_LIFETIME_US;
if(pFlashDesc->SysInt.Max.SnglWordProgTO_us)
g_FlashProgInfo.ulMaxDatumProgTOFactor = 1 << pFlashDesc->SysInt.Max.SnglWordProgTO_us;
else
g_FlashProgInfo.ulMaxDatumProgTOFactor = POLLING_WRBYPASS_LIFETIME_FACTOR;
// Write buffer timeouts.
if(pFlashDesc->SysInt.Typical.WriteBuffTO_us)
g_FlashProgInfo.ulBufferProgTO_us = (1 << (pFlashDesc->SysInt.Typical.WriteBuffTO_us));
else
g_FlashProgInfo.ulBufferProgTO_us = POLLING_WRBUFR_LIFETIME_US;
if(pFlashDesc->SysInt.Max.WriteBuffTO_us)
g_FlashProgInfo.ulMaxBufferProgTOFactor = 1 << pFlashDesc->SysInt.Max.WriteBuffTO_us;
else
g_FlashProgInfo.ulMaxBufferProgTOFactor = POLLING_WRBUFR_LIFETIME_FACTOR;
// Sector erase timeouts
if(pFlashDesc->SysInt.Typical.BlockEraseTO_ms)
g_FlashProgInfo.ulSectorEraseTO_ms = (1 << pFlashDesc->SysInt.Typical.BlockEraseTO_ms);
else
g_FlashProgInfo.ulSectorEraseTO_ms = ERASE_BLOCK_TIMEOUT_MS;
if(pFlashDesc->SysInt.Max.BlockEraseTO_ms)
g_FlashProgInfo.ulMaxSectorEraseTOFactor = 1 << pFlashDesc->SysInt.Max.BlockEraseTO_ms;
else
g_FlashProgInfo.ulMaxSectorEraseTOFactor = ERASE_BLOCK_TIMEOUT_FACTOR;
// Chip erase timeouts
if(pFlashDesc->SysInt.Typical.ChipEraseTO_ms)
g_FlashProgInfo.ulChipEraseTO_ms = (1 << pFlashDesc->SysInt.Typical.ChipEraseTO_ms);
else
g_FlashProgInfo.ulChipEraseTO_ms = ERASE_CHIP_TIMEOUT_MS;
if(pFlashDesc->SysInt.Max.ChipEraseTO_ms)
g_FlashProgInfo.ulMaxChipEraseTOFactor = 1 << pFlashDesc->SysInt.Max.ChipEraseTO_ms;
else
g_FlashProgInfo.ulMaxChipEraseTOFactor = ERASE_CHIP_TIMEOUT_FACTOR;
PrintFlashProgInfo(&g_FlashProgInfo);
// Set device width
pFlashDesc->DeviceWidth = 16;
pFlashDesc->PairedFlash = bIsPaired;
#ifdef USE_OS_SERVICES
// Calibrate CEDDK's counter for the StallExecution() API
CalibrateStallCounter();
#endif
_exit:
// exit CFI query mode by issuing a soft reset
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_1_ADDR_RESET, CYCLE_1_DATA_RESET);
DEBUGMSG(ZONE_HAL_FUNCTION, (TEXT("AMD_IsFlashSupported-\r\n")));
return bSuccess;
}
//-----------------------------------------------------------------------------
//
// Function: AMDx16_Program
//
// Function performs programming of AMD 16bit mode flash devices.
//
// Programming Notes:
// DQ7 indicates the programming is complete however this does not
// guarantee the value that was programmed to the device is correct
// Test to make sure the data programmed is the data that is being
// read from the device.
// ****************************************************************
// Note:
// Just prior to the completion of an Embedded Program or Erase
// operation, DQ7 may change asynchronously with DQ0朌Q6 while
// Output Enable (OE#) is asserted low. That is, the device may
// change from providing status information to valid data on DQ7.
// Depending on when the system samples the DQ7 output, it may read
// the status or valid data. Even if the device has completed
// the program or erase operation and DQ7 has valid data, the data
// outputs on DQ0朌Q6 may be still invalid. Valid data on DQ0朌Q7
// will appear on successive read cycles.
// ****************************************************************
// If DQ5 is a 1, it may not necessarily be true that a time out has
// occurred and the value should be checked once more to see if it
// was successfully programmed.
// In addition the value that was programmed may have this bit set
// in which case the check for the proper value is also required.
// *****************************************************************
//
// Parameters:
// pFlashDesc
// [in] pointer to NOR flash descriptor
//
// ulStartAddress
// [in] start address to start programming
//
// pData
// [in] ptr to data buffer
//
// ulLen
// [in] length of data
//
// Returns:
// FALSE if programming failed
//
//-----------------------------------------------------------------------------
BOOL AMDx16_Program(NOR_FLASH_DESC *pFlashDesc, ULONG ulProgramAddress, UCHAR *pData, ULONG ulLen, BOOL bIgnore0to1)
{
ULONG ulFlashBase;
BOOL bIsPaired;
ULONG *pulData;
ULONG i;
ULONG j;
ULONG retry;
DWORD dwBusWidth;
ULONG ulWriteBufferSize;
ULONG ulBufAlignBytes;
ULONG dwNumPages;
ULONG ulProgBytes;
ULONG ulDataToWrite;
ULONG ulDataWritten;
ULONG ulBufDatumSize;
ULONG ulFlashSectorAddr;
ULONG ulSectorSize;
ULONG ulCurRegion;
ULONG ulCurBlock;
ULONG ulNumRegionBlocks;
BOOL bDone;
BOOL bSuccess;
ULONG ulIgnoreBuffer[AMD_BUF_PROG_MAX_DATUM];
#ifdef DEBUG
ULONG ulPageStart;
#endif
DEBUGMSG(ZONE_HAL_FUNCTION, (TEXT("AMDx16_Program+: 0x%x 0x%x 0x%x\r\n"),
ulProgramAddress, pData, ulLen));
if(!pFlashDesc && !pData)
{
DEBUGMSG(ZONE_HAL_ERROR, (TEXT("AMDx16_Program: null param\r\n")));
return FALSE;
}
bIsPaired = pFlashDesc->PairedFlash;
ulFlashBase = pFlashDesc->FlashBase;
// 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).
ulWriteBufferSize = (pFlashDesc->Geometry.WriteBuffSize)?
(bIsPaired?
((1 << pFlashDesc->Geometry.WriteBuffSize) * 2) :
(1 << pFlashDesc->Geometry.WriteBuffSize)) :
0;
dwNumPages = (ulWriteBufferSize)? (ulLen / ulWriteBufferSize) : 0;
ulBufAlignBytes = (ulWriteBufferSize)? ulProgramAddress % ulWriteBufferSize : 0;
pulData = (ULONG *)pData;
bSuccess = TRUE;
DEBUGMSG(ZONE_HAL_INFO, (TEXT("ulWriteBufferSize 0x%x\r\n"), ulWriteBufferSize));
// Use bypass mode single datum non-buffered program method for
// 1. no write buffer support or data < 1 page.
// 2. Align program address to write buffer page
// Refer to single word program operation in flash specification
// for more details
dwBusWidth = bIsPaired? sizeof(ULONG) : sizeof(USHORT);
if(ulBufAlignBytes != 0 || dwNumPages == 0)
{
ulProgBytes = (ulWriteBufferSize)? ulBufAlignBytes : ulLen;
DEBUGMSG(ZONE_HAL_FUNCTION, (TEXT("dwBufAlignBytes 0x%x dwNumPages 0x%x ulProgBytes 0x%x\r\n"),
ulBufAlignBytes, dwNumPages, ulProgBytes));
for(i = 0; i < ulProgBytes; i += dwBusWidth)
{
bDone = FALSE;
ulDataToWrite = bIsPaired? *(ULONG *)pulData : *(USHORT *)pulData;
if(bIgnore0to1)
{
ulDataWritten = bIsPaired? *(volatile ULONG *)ulProgramAddress : *(volatile USHORT *)ulProgramAddress;
ulDataToWrite &= ulDataWritten;
}
DEBUGMSG(ZONE_HAL_FUNCTION, (TEXT("Before: [0x%x] 0x%x\r\n"),
ulProgramAddress, bIsPaired? *((volatile ULONG *)(ulProgramAddress)) :
*((volatile USHORT *)(ulProgramAddress)) ));
if(g_FlashProgInfo.bUnlockBypassSupport)
{
// Send unlock bypass enter command for first datum
if(i == 0)
{
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_1_ADDR_UNLOCK_x16, CYCLE_1_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_2_ADDR_UNLOCK_x16, CYCLE_2_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_3_ADDR_CMD_x16, CYCLE_3_DATA_UNLOCK_BYPASS);
}
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_1_ADDR_PROGRAM_BYPASS, CYCLE_1_DATA_PROGRAM_BYPASS);
WR_FLASH_16(bIsPaired, ulProgramAddress, ulDataToWrite);
}
else
{
// 4 cycle per datum program
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_1_ADDR_UNLOCK_x16, CYCLE_1_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, CYCLE_2_ADDR_UNLOCK_x16, CYCLE_2_DATA_UNLOCK);
WR_FLASH_REG_INDEXED16(bIsPaired, ulFlashBase, UNLOCK_ADDR1_x16, CYCLE_3_DATA_PROGRAM);
WR_FLASH_16(bIsPaired, ulProgramAddress, ulDataToWrite);
}
j = 0;
while(!bDone && bSuccess && j++ < CHECK_STATUS_TIMEOUT)
{
ulDataWritten = bIsPaired? *((volatile ULONG *)(ulProgramAddress)) :
*((volatile USHORT *)(ulProgramAddress));
DEBUGMSG(ZONE_HAL_FUNCTION, (TEXT("[0x%x] 0x%x : expect 0x%x\r\n"),
ulProgramAddress, ulDataWritten, ulDataToWrite));
// D7 will be driven to complement of D7 written to the FLASH.
// When it is driven to the value just written,
// the program operation is complete.
if((ulDataWritten & CREATE_MASK_16(bIsPaired, AMD_FLASH_DQ7_X16)) == (ulDataToWrite & CREATE_MASK_16(bIsPaired, AMD_FLASH_DQ7_X16)))
{
// Spec indiates that D7 may be valid while other data lines are still invalid.
if(ulDataWritten != ulDataToWrite)
{
// Try reading again before we report an error. We want to avoid
// reporting an error here because EBOOT has no recovery and
// will terminate the flashing procedure.
for (retry = 10; retry > 0 && !bDone; retry--)
{
ulDataWritten = bIsPaired? *((volatile ULONG *)(ulProgramAddress)) : *((volatile USHORT *)(ulProgramAddress));
if(ulDataWritten == ulDataToWrite)
{
// page is programmed properly
bDone = TRUE;
}
}
// Now report an error if the value we wanted did not get programmed
if (!bDone)
{
// programming failure
ERRORMSG(ZONE_HAL_ERROR, (TEXT("Program failure [0x%x] 0x%x : expect 0x%x\r\n"),
ulProgramAddress, ulDataWritten, ulDataToWrite));
bSuccess = FALSE;
}
}
else
{
// datum is programmed properly
bDone = TRUE;
}
}
else
{
if((ulDataWritten & CREATE_MASK_16(bIsPaired, AMD_FLASH_DQ5_X16)) == CREATE_MASK_16(bIsPaired, AMD_FLASH_DQ5_X16))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -