📄 flash_drv_amd.c
字号:
{
{ 0x00000000, 31, 0x40000 }
,{ 0x007C0000, 4, 0x10000 }
,{ 0, 0, 0 }
,{ 0, 0, 0 }
}
};
// MirrorBit Top/Bottom Boot
const NOR_Die_Layout_S AMD_MB_TB_128 = {
0x01000000,
{
{ 0x00000000, 4, 0x10000 }
,{ 0x00040000, 62, 0x40000 }
,{ 0x00FC0000, 4, 0x10000 }
,{ 0, 0, 0 }
}
};
const NOR_Die_Layout_S AMD_MB_TB_256 = {
0x02000000,
{
{ 0x00000000, 4, 0x10000 }
,{ 0x00040000, 126, 0x40000 }
,{ 0x01FC0000, 4, 0x10000 }
,{ 0, 0, 0 }
}
};
//------------------------------------------------------------------------------
// Check Device ID Callback Function
//------------------------------------------------------------------------------
bool AMD_CheckDevID(const uint16 dev, volatile uint16 *die1_addr, volatile uint16 *die2_addr) {
//
// Some 128Mb flash devices were assembled by two the same 64Mb flash devices.
// The worse thing is that the 128Mb flash share the same manufacture id and device
// code with 64Mb flash !!!
//
// For example:
// AM50DL128CG(128Mb) was assembled by two AM29DL640D(64Mb) devices.
// S71JL128HXX(128Mb) was assembled by two S29JL064HXX(64Mb) devices.
// ST_M74DW66500B(128Mb) was assembled by two ST_M29DW640D(64Mb) devices.
//
// This function has ability to tell from those flashes that share the same id.
//
uint16 manufacture_code;
uint16 dev_code;
uint16 ext_dev_code1;
uint16 ext_dev_code2;
uint16 die_count = 0;
uint16 ADDR_LEFT_SHIFT_BIT = 0;
uint16 boot_sector_flag;
uint16 cfi_bank_a_region_info;
NOR_DeviceID_E flash_enum_id=g_FlashDevTbl[dev].m_device_id;
// check if AM29PDL128G
if( NOR_AM29PDL128G == flash_enum_id ) {
ADDR_LEFT_SHIFT_BIT = 1;
}
// reset die1 to read mode
die1_addr[AMD_SA_ADDR<<ADDR_LEFT_SHIFT_BIT] = AMD_RESET_TO_READ_MODE_DATA1;
// identify AM49DL3208GT or S29PL032J by reading CFI boot sector flag, because these two flashes has the same ID
if( (NOR_AM49DL3208GT == flash_enum_id) ||
(NOR_S29PL032J == flash_enum_id)
) {
// enter CFI mode
die1_addr[AMD_ENTER_CFI_ADDR<<ADDR_LEFT_SHIFT_BIT] = AMD_ENTER_CFI_DATA;
// read Top/Bottom Boot Sector Flag
boot_sector_flag = die1_addr[AMD_CFI_BOOT_SECTOR_FLAG_ADDR<<ADDR_LEFT_SHIFT_BIT];
// reset die1 to read mode
die1_addr[AMD_SA_ADDR<<ADDR_LEFT_SHIFT_BIT] = AMD_RESET_TO_READ_MODE_DATA1;
// check if boot sector is matched
if( ((&AMD_T_32)==FLASH_DIE_LAYOUT(dev, 0) && AMD_CFI_TOP_DEV!=boot_sector_flag) ||
((&AMD_B_32)==FLASH_DIE_LAYOUT(dev, 0) && AMD_CFI_BOTTOM_DEV!=boot_sector_flag)
) {
return FALSE;
}
}
// identify S71PLXXXJ and S71PLXXXN(MirrorBit) by reading CFI Bank A region info, because those devices have the same ID
switch(flash_enum_id) {
case NOR_AM49PDL127BH:
case NOR_S71PL254J:
case NOR_AM49PDL129BH:
case NOR_S71PL127N:
case NOR_S71PL129N:
// enter CFI mode
die1_addr[AMD_ENTER_CFI_ADDR<<ADDR_LEFT_SHIFT_BIT] = AMD_ENTER_CFI_DATA;
// read bank A region info
cfi_bank_a_region_info = die1_addr[AMD_CFI_BANK_A_REGION_INFO_ADDR<<ADDR_LEFT_SHIFT_BIT];
// reset die1 to read mode
die1_addr[AMD_SA_ADDR<<ADDR_LEFT_SHIFT_BIT] = AMD_RESET_TO_READ_MODE_DATA1;
// check if region info match
if( ( (NOR_S71PL127N==flash_enum_id || NOR_S71PL129N==flash_enum_id) && 0x000B!=cfi_bank_a_region_info) ||
(!(NOR_S71PL127N==flash_enum_id || NOR_S71PL129N==flash_enum_id) && 0x000B==cfi_bank_a_region_info)
) {
return FALSE;
}
break;
default:
break;
}
// enter auto-select mode on die1
die1_addr[AMD_CMD_ADDR1<<ADDR_LEFT_SHIFT_BIT] = AMD_ENTER_AUTOSELECT_MODE_DATA1;
die1_addr[AMD_CMD_ADDR2<<ADDR_LEFT_SHIFT_BIT] = AMD_ENTER_AUTOSELECT_MODE_DATA2;
die1_addr[AMD_CMD_ADDR1<<ADDR_LEFT_SHIFT_BIT] = AMD_ENTER_AUTOSELECT_MODE_DATA3;
// read manufacture id and device code from die1
manufacture_code = (die1_addr[AMD_MANUFACTURE_ID_ADDR<<ADDR_LEFT_SHIFT_BIT]&0x00FF); dev_code = die1_addr[AMD_DEVICE_CODE_ADDR<<ADDR_LEFT_SHIFT_BIT];
ext_dev_code1 = die1_addr[AMD_EXT_DEVICE_CODE1_ADDR<<ADDR_LEFT_SHIFT_BIT];
ext_dev_code2 = die1_addr[AMD_EXT_DEVICE_CODE2_ADDR<<ADDR_LEFT_SHIFT_BIT];
// compare id
if( g_FlashDevTbl[dev].m_hw_info.m_manufacture_code != manufacture_code )
goto not_match;
// if manufacture code exist, temporarily record flash id to g_HW_DetectionResult
g_HW_DetectionResult.m_flash_dev_code_1 = manufacture_code;
g_HW_DetectionResult.m_flash_dev_code_2 = dev_code;
g_HW_DetectionResult.m_flash_dev_code_3 = ext_dev_code1;
g_HW_DetectionResult.m_flash_dev_code_4 = ext_dev_code2;
if( g_FlashDevTbl[dev].m_hw_info.m_dev_code != dev_code )
goto not_match;
if( 0!=g_FlashDevTbl[dev].m_hw_info.m_ext_dev_code1 && (g_FlashDevTbl[dev].m_hw_info.m_ext_dev_code1!=ext_dev_code1) )
goto not_match;
if( 0!=g_FlashDevTbl[dev].m_hw_info.m_ext_dev_code2 && (g_FlashDevTbl[dev].m_hw_info.m_ext_dev_code2!=ext_dev_code2) )
goto not_match;
// die1 id matched, continue to check if this flash is dual stack
if( 0 != memcmp((void *)die1_addr, (void *)die2_addr, 64) ) {
// if it's dual stack, the 2nd die baseaddr won't enter auto-select mode,
// the data locate in die1 and die2 address won't be the same.
die_count = 2;
}
else {
// otherwise the 2nd baseaddr will enter auto-select mode due to address wrap,
// the data locate in die1 and die2 address will be the same.
die_count = 1;
}
// reset die1 to read mode
die1_addr[AMD_SA_ADDR<<ADDR_LEFT_SHIFT_BIT] = AMD_RESET_TO_READ_MODE_DATA1;
// if die count matched, return true
if( die_count == FLASH_DIE_COUNT(dev) ) {
return TRUE;
}
not_match:
// reset die1 to read mode
die1_addr[AMD_SA_ADDR<<ADDR_LEFT_SHIFT_BIT] = AMD_RESET_TO_READ_MODE_DATA1;
return FALSE;
}
//------------------------------------------------------------------------------
// Check If Device Is Idle Callback Function
//------------------------------------------------------------------------------
bool AMD_CheckDevIdle(const uint32 addr)
{
volatile uint16 stat_data1;
volatile uint16 stat_data2;
stat_data1 = *(volatile uint16*)addr;
stat_data2 = *(volatile uint16*)addr;
if( (stat_data1&AMD_DQ6_TOGGLE_BIT) == (stat_data2&AMD_DQ6_TOGGLE_BIT) )
{
return TRUE;
}
else
{
return FALSE;
}
}
//------------------------------------------------------------------------------
// Erase Related Callback Function
//------------------------------------------------------------------------------
void AMD_Erase_CMD(const uint32 blockaddr)
{
volatile uint16 *ba = (volatile uint16 *)blockaddr;
ba[AMD_CMD_ADDR1] = AMD_SECTOR_ERASE_DATA1;
ba[AMD_CMD_ADDR2] = AMD_SECTOR_ERASE_DATA2;
ba[AMD_CMD_ADDR1] = AMD_SECTOR_ERASE_DATA3;
ba[AMD_CMD_ADDR1] = AMD_SECTOR_ERASE_DATA4;
ba[AMD_CMD_ADDR2] = AMD_SECTOR_ERASE_DATA5;
ba[AMD_SA_ADDR] = AMD_SECTOR_ERASE_DATA6;
}
STATUS_E AMD_Erase_CheckDone_By_Polling(const uint32 blockaddr)
{
// use POLL_BIT instead of TOGGLE_BIT to wait for erase complete,
// because in some device using TOGGLE_BIT to wait for erase complete will fail.
volatile uint16 status;
status = *(volatile uint16 *)blockaddr;
if( (status&AMD_DQ7_POLL_BIT) ) {
return S_DONE;
}
else if( (status&AMD_DQ5_TIMEOUT_ERR_BIT) ) {
status = *(volatile uint16 *)blockaddr;
if( (status&AMD_DQ7_POLL_BIT) ) {
return S_DONE;
}
else {
return S_TIMEOUT;
}
}
else {
return S_IN_PROGRESS;
}
}
//------------------------------------------------------------------------------
// Program Related Callback Function
//------------------------------------------------------------------------------
void AMD_PreProcess(const uint16 dev) {
#ifdef AMD_PROTECTION_ENABLED
AMD_UnprotectChip(dev);
#endif
}
void AMD_UnlockBypass_Enter_CMD(const uint32 blockaddr)
{
volatile uint16 *ba = (volatile uint16 *)blockaddr;
ba[AMD_CMD_ADDR1] = AMD_ENTER_UNLOCK_BYPASS_DATA1;
ba[AMD_CMD_ADDR2] = AMD_ENTER_UNLOCK_BYPASS_DATA2;
ba[AMD_CMD_ADDR1] = AMD_ENTER_UNLOCK_BYPASS_DATA3;
}
void AMD_UnlockBypass_Exit_CMD(const uint32 blockaddr)
{
volatile uint16 *ba = (volatile uint16 *)blockaddr;
ba[AMD_CMD_ADDR1] = AMD_EXIT_UNLOCK_BYPASS_DATA1;
ba[AMD_CMD_ADDR2] = AMD_EXIT_UNLOCK_BYPASS_DATA2;
}
void AMD_UnlockBypass_Program_CMD(const uint32 blockaddr, const uint32 prog_addr, const uint16 data)
{
volatile uint16 *ba = (volatile uint16 *)blockaddr;
ba[AMD_CMD_ADDR1] = AMD_UNLOCK_BYPASS_PGM_DATA1;
*(volatile uint16*)prog_addr = data;
}
void AMD_Word_Program_CMD(const uint32 blockaddr, const uint32 prog_addr, const uint16 data)
{
volatile uint16 *ba = (volatile uint16 *)blockaddr;
ba[AMD_CMD_ADDR1] = AMD_WORD_PGM_DATA1;
ba[AMD_CMD_ADDR2] = AMD_WORD_PGM_DATA2;
ba[AMD_CMD_ADDR1] = AMD_WORD_PGM_DATA3;
*(volatile uint16*)prog_addr = data;
}
STATUS_E AMD_Program_CheckDone_By_Toggle(const uint32 prog_addr)
{
volatile uint16 stat_data1;
volatile uint16 stat_data2;
stat_data1 = *(volatile uint16*)prog_addr;
stat_data2 = *(volatile uint16*)prog_addr;
if( (stat_data1&AMD_DQ6_TOGGLE_BIT) == (stat_data2&AMD_DQ6_TOGGLE_BIT) )
{
return S_DONE;
}
if( (stat_data1&AMD_DQ5_TIMEOUT_ERR_BIT) )
{
stat_data1 = *(volatile uint16*)prog_addr;
stat_data2 = *(volatile uint16*)prog_addr;
if( (stat_data1&AMD_DQ6_TOGGLE_BIT) == (stat_data2&AMD_DQ6_TOGGLE_BIT) )
{
return S_DONE;
}
else
{
return S_PGM_FAILED;
}
}
return S_IN_PROGRESS;
}
//------------------------------------------------------------------------------
// MirrorBit Related Callback Function
//------------------------------------------------------------------------------
void AMD_MirrorBit_Erase_CMD(const uint32 blockaddr)
{
volatile uint32 i;
AMD_Erase_CMD(blockaddr);
//final step, wait for 10us
for (i=0;i<1000;i++);
}
void AMD_MirrorBit_PreProcess(const uint16 dev)
{
g_FLASH_MAX_BUFPGM_SIZE_IN_BYTE = 64;
}
void AMD_MirrorBit_Buf_Program_CMD(const uint32 blockaddr, const uint32 prog_addr, const uint16 *data, const uint32 length_in_word)
{
volatile uint32 i;
volatile uint16 *ba = (volatile uint16 *)blockaddr;
volatile uint16 *prog_word_addr = (volatile uint16*)prog_addr;
volatile uint16 *data_word_addr = (volatile uint16*)data;
ba[AMD_CMD_ADDR1] = AMD_BUF_PGM_DATA1;
ba[AMD_CMD_ADDR2] = AMD_BUF_PGM_DATA2;
ba[0] = AMD_BUF_PGM_DATA3;
ba[0] = (uint16)(length_in_word - 1);
for(i=0;i<length_in_word;i++)
{
*prog_word_addr++ = *data_word_addr++;
}
ba[0] = AMD_BUF_PGM_LAST;
//final step, wait for 10us
for (i=0;i<1000;i++);
}
//------------------------------------------------------------------------------
// Protection Related Callback Function
//------------------------------------------------------------------------------
#ifdef AMD_PROTECTION_ENABLED
void AMD_UnprotectChip(const uint16 dev) {
uint32 die;
uint32 die_baseaddr;
uint32 addr;
uint32 die_size;
uint32 blk_size;
// charge all PPBs to 1
for(die=0; die<FLASH_DIE_COUNT(dev); die++) {
die_size = FLASH_DIE_SIZE(dev, die);
addr = die_baseaddr = FUTL_GetFlashDieBaseAddr(die);
while( addr < (die_baseaddr+die_size) ) {
// set PPB to 1
if(!AMD_Protection_PPB_Program_CMD(addr)) {
while(1);
}
// current sector size
FUTL_SearchBaseAddr(addr, NULL, &blk_size);
// next sector address
addr += blk_size;
}
}
// issue erase all PPBs command
if(!AMD_Protection_Erase_All_PPBs_CMD(FUTL_GetFlashDieBaseAddr(0))) {
while(1);
}
}
bool AMD_Protection_PPB_Program_CMD(uint32 blockaddr)
{
volatile uint16 *ba = (volatile uint16 *)blockaddr;
volatile bool ok_flag = FALSE;
volatile uint32 i;
ba[AMD_CMD_ADDR1] = AMD_PROTECT_PPB_PGM_DATA1;
ba[AMD_CMD_ADDR2] = AMD_PROTECT_PPB_PGM_DATA2;
ba[AMD_CMD_ADDR1] = AMD_PROTECT_PPB_PGM_DATA3;
ba[AMD_PROTECT_WP_ADDR] = AMD_PROTECT_PPB_PGM_DATA4;
// delay 100us
for(i=0; i<10000; i++);
ba[AMD_PROTECT_WP_ADDR] = AMD_PROTECT_PPB_PGM_DATA5;
if(!(ba[AMD_PROTECT_WP_ADDR]&AMD_PROTECT_PPB_SET)) {
ok_flag = FALSE;
}
else {
ok_flag = TRUE;
}
// enter auto-select mode
ba[AMD_CMD_ADDR1] = AMD_ENTER_AUTOSELECT_MODE_DATA1;
ba[AMD_CMD_ADDR2] = AMD_ENTER_AUTOSELECT_MODE_DATA2;
ba[AMD_CMD_ADDR1] = AMD_ENTER_AUTOSELECT_MODE_DATA3;
// reset to read mode
ba[AMD_SA_ADDR] = AMD_RESET_TO_READ_MODE_DATA1;
return ok_flag;
}
bool AMD_Protection_PPB_Status_CMD(uint32 blockaddr)
{
volatile uint16 *ba = (volatile uint16 *)blockaddr;
volatile bool ok_flag = FALSE;
ba[AMD_CMD_ADDR1] = AMD_PROTECT_PPB_STATUS_DATA1;
ba[AMD_CMD_ADDR2] = AMD_PROTECT_PPB_STATUS_DATA2;
ba[AMD_CMD_ADDR1] = AMD_PROTECT_PPB_STATUS_DATA3;
ba[AMD_PROTECT_WP_ADDR] = AMD_PROTECT_PPB_STATUS_DATA4;
if(!(ba[AMD_PROTECT_WP_ADDR]&AMD_PROTECT_PPB_SET)) {
ok_flag = FALSE;
}
else {
ok_flag = TRUE;
}
// reset to read mode
ba[AMD_SA_ADDR] = AMD_RESET_TO_READ_MODE_DATA1;
return ok_flag;
}
bool AMD_Protection_Erase_All_PPBs_CMD(uint32 blockaddr)
{
volatile uint16 *ba = (volatile uint16 *)blockaddr;
volatile uint32 i;
volatile bool ok_flag=FALSE;
ba[AMD_CMD_ADDR1] = AMD_PROTECT_PPB_ERASE_DATA1;
ba[AMD_CMD_ADDR2] = AMD_PROTECT_PPB_ERASE_DATA2;
ba[AMD_CMD_ADDR1] = AMD_PROTECT_PPB_ERASE_DATA3;
ba[AMD_PROTECT_WP_ADDR] = AMD_PROTECT_PPB_ERASE_DATA4;
// delay 1.2ms
for(i=0; i<0x30000; i++);
ba[AMD_SA_ADDR] = AMD_PROTECT_PPB_ERASE_DATA5;
if(ba[AMD_PROTECT_WP_ADDR]&AMD_PROTECT_PPB_SET) {
ok_flag = TRUE;
}
else {
ok_flag = FALSE;
}
// reset to read mode
ba[AMD_SA_ADDR] = AMD_RESET_TO_READ_MODE_DATA1;
return ok_flag;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -