Files
banban/ql-kernel/threadx/quec/quec_flash.c

781 lines
25 KiB
C

/*==========================================================================================================
Copyright (c) 2021, Quectel Wireless Solutions Co., Ltd. All rights reserved.
Quectel Wireless Solutions Proprietary and Confidential.
===========================================================================================================*/
/*==========================================================================================================
EDIT HISTORY FOR MODULE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
WHEN WHO WHAT, WHERE, WHY
------------ ------- -------------------------------------------------------------------------------
10/04/2022 Sharon.li 此文件是操作内部Nor Flash的(QSPI)的接口INTERNAL_NORFLASH
===========================================================================================================*/
#include "loadTable.h"
#include "quec_debug.h"
#include <string.h>
#include "loadTable.h"
#include "quec_flash.h"
#include "UART.h"
#include "qspi_nor.h"
#include <lfs_cache.h>
#include "Flash_wk.h"
#define quec_flash_printf(msg, ...) custom_log("Flash_LOG", msg, ##__VA_ARGS__)
#ifdef QUEC_LIMIT_FLASH_ERASE //分区擦除保护功能,用于实现当前分区是否可以被擦除
typedef struct
{
UINT32 start_addr; //addr not 0x80000000
UINT32 end_addr;
}QUEC_PART_ADDR_S;
typedef struct
{
char name[16];//分区名称
char erase_flag;//分区是否能被擦除 1,可以被擦除;0,不能被擦除
QUEC_PART_ADDR_S AddrInfo;//分区的结束地址和起始地址
}QUEC_PART_ADDR_TYPE_S;
QUEC_PART_ADDR_TYPE_S QUEC_PART_ADDR_TYPE_AERA[]={
{"nvm",1,NULL},
{"quec_cfg",1,NULL},
{"fota_param",1,NULL},
{"factory_a",1,NULL},
{"factory_b",1,NULL},
{"erase_rd",1,NULL},
{"bootloader",NULL},
{"ptable",0,NULL},
{"fwcerts",0,NULL},
{"rd",0,NULL},
{"cp",0,NULL},
{"dsp",0,NULL},
{"rfbin",0,NULL},
{"customer_app",1,NULL},
{"reserved",0,NULL},
{"logo",0,NULL},
};
#define QFTEST_PARTITION_COUNT_MAX (sizeof(QUEC_PART_ADDR_TYPE_AERA)/sizeof(QUEC_PART_ADDR_TYPE_AERA[0]))
UINT32 G_QftestEraseCount[QFTEST_PARTITION_COUNT_MAX] = {0};
//初始化分区信息
UINT32 CHECK_FLASH_AREA_ADDR_CONFIG(void)
{
int len = QFTEST_PARTITION_COUNT_MAX;
_ptentry *pnt;
int i;
for(i=0;i<len;i++)
{
pnt=ptable_find_entry(QUEC_PART_ADDR_TYPE_AERA[i].name);
if(pnt==NULL)
{
uart_printf("Egan_check flash not found name=%s\r\n",QUEC_PART_ADDR_TYPE_AERA[i].name);
continue;
}
QUEC_PART_ADDR_TYPE_AERA[i].AddrInfo.start_addr=pnt->start;
QUEC_PART_ADDR_TYPE_AERA[i].AddrInfo.end_addr=pnt->start + pnt->size;
// uart_printf("Egan_flash_name=%s flash_addr=0x%x flash_end=0x%x \r\n",QUEC_PART_ADDR_TYPE_AERA[i].name,QUEC_PART_ADDR_TYPE_AERA[i].AddrInfo.start_addr,QUEC_PART_ADDR_TYPE_AERA[i].AddrInfo.end_addr);
}
return 0;
}
//检查指定的Flash地址和大小是否可以被擦除
//flash_addr:要擦除Flash地址
//flash_size:擦除的大小
//rw_flag:是否记录此次擦除,0,不记录;1,记录
UINT32 FLASH_LIMIT_ALLOW_AREA(UINT32 flash_addr,UINT32 flash_size,BOOL rw_flag)
{
int len = QFTEST_PARTITION_COUNT_MAX;
int i;
QUEC_PART_ADDR_TYPE_S *ptr=QUEC_PART_ADDR_TYPE_AERA;
for(i=0;i<len;i++)
{
if((flash_addr>=ptr[i].AddrInfo.start_addr)&&((flash_addr + flash_size) <= ptr[i].AddrInfo.end_addr))
{
if((ptr[i].erase_flag==1)&&(flash_size!=NULL))
{
if(rw_flag)
G_QftestEraseCount[i]++;
break;
}
else{
return NULL;
}
}
}
return 1;
}
/*****************************************************************
* Function: QUEC_PART_ADDR_TYPE_AERA_GET_CNT
*
* Description:
* 获取数组QUEC_PART_ADDR_TYPE_AERA的下标值
* Parameters:
* name [in] partition name
*
* Return:
* -1 failure
*****************************************************************/
int QUEC_PART_ADDR_TYPE_AERA_GET_CNT(const char *name)
{
int len = QFTEST_PARTITION_COUNT_MAX;
int i;
for(i=0;i<len;i++)
{
if(!strcmp(name, QUEC_PART_ADDR_TYPE_AERA[i].name))
return i;
}
return -1;
}
#endif
#define CHIP_SECTOR_SIZE 0x1000 //erase 4k each times
UINT16 g_FlashBlkEraseCnt[1024]; //4M for nvm erea
UINT16 g_FlashBlkEraseTotal = 0;
extern UINT32 nvm_flash_start_addr;
#ifdef QUEC_FS_WEAR_BALANCE_VERIFY //QuecOpen 记录文件系统均衡的次数
UINT32 customer_fs_flash_start_addr = 0;
UINT32 gFsRWBkTotalCnt = 0; //存储文件系统擦写的总次数
UINT32 *gFsPerBkRWCnt = NULL; //存储每块block的擦写次数
UINT32 gFsTotalBkCnt = 0; //存储文件系统block的数量
#endif
//检查指定的Flash地址是否在某个分区内
//0:Flash地址不在指定的分区内;1:Flash地址在指定的分区内部
UINT32 CHECK_FLASH_AREA(const char *name,UINT32 flash_addr,UINT32 flash_size)
{
_ptentry *pnt;
pnt=ptable_find_entry(name);
if(pnt==NULL)
{
return 0;
}
if(flash_addr>=pnt->start)
{
if((flash_addr+ flash_size)<= (pnt->start + pnt->size))
{
return 1;
}
}
return 0;
}
#define CRANE_NVM_ON_FLASH_BASE_ADD (nvm_flash_start_addr&0xF0000000)
#define CRANE_COUSTOMER_FS_ON_FLASH_BASE_ADD (customer_fs_flash_start_addr&0XF0000000)
//记录flash_addr所在分区的第几个block,被擦除的次数
UINT32 Flash_erase_count_Set(UINT32 flash_addr,UINT32 size)
{
int i=0;
UINT32 nvm_block_id=(CRANE_NVM_ON_FLASH_BASE_ADD+flash_addr-nvm_flash_start_addr)/CHIP_SECTOR_SIZE;
if(g_FlashBlkEraseCnt == NULL)
return 0;
if(CHECK_FLASH_AREA("nvm",flash_addr,size))
{
for(i=0;i*CHIP_SECTOR_SIZE<size;i++)
{
g_FlashBlkEraseCnt[nvm_block_id+i]++;
g_FlashBlkEraseTotal++;
}
}
#ifdef QUEC_FS_WEAR_BALANCE_VERIFY //QuecOpen 记录文件系统均衡的次数
if(CHECK_FLASH_AREA("customer_fs",flash_addr,size))
{
UINT32 customer_fs_block_id=(CRANE_COUSTOMER_FS_ON_FLASH_BASE_ADD+flash_addr-customer_fs_flash_start_addr)/CHIP_SECTOR_SIZE;
//RTI_LOG("flash_addr(0x%x),size(0x%x),customer_fs_block_id(0x%x)\r\n",flash_addr,size,customer_fs_block_id);
if(NULL != gFsPerBkRWCnt)
{
for(i=0;i*CHIP_SECTOR_SIZE<size;i++)
{
gFsPerBkRWCnt[customer_fs_block_id+i]++;
gFsRWBkTotalCnt++;
}
}
}
#endif
return 0;
}
void quec_norflash_get_addr(unsigned char *patition_name, unsigned int *start_addr, unsigned int *size)
{
unsigned int end_addr=0;
*start_addr=quec_get_patition_start_address((const char *)patition_name);
end_addr=quec_get_patition_end_address((const char *)patition_name);
*size=end_addr-*start_addr;
}
unsigned int quec_norflash_do_read(unsigned char *patition_name, unsigned int addr, unsigned int buf_addr, unsigned int size)
{
unsigned int ret=FLASH_RW_ERROR;
unsigned int start_address=0;
unsigned int end_address=0;
unsigned int free_size=0;
unsigned int relative_addr = 0;
relative_addr = addr&0x7FFFFFFF;
start_address=quec_get_patition_start_address((const char *)patition_name);
end_address=quec_get_patition_end_address((const char *)patition_name);
if(addr<start_address || addr>end_address)
{
uart_printf("error address param \n");
return FLASH_RW_ERROR;
}
free_size=end_address-addr;
if(size<=free_size)
{
ret = spi_nor_do_read(relative_addr, buf_addr, size, 0);
}
else
{
uart_printf("no enough free space \n");
ret = FLASH_RW_ERROR;
}
return ret;
}
unsigned int quec_norflash_do_write(unsigned char *patition_name, unsigned int addr, unsigned int buf_addr, unsigned int size)
{
unsigned int ret=FLASH_RW_ERROR;
unsigned int start_address=0;
unsigned int end_address=0;
unsigned int free_size=0;
unsigned int relative_addr = 0;
unsigned char buf[10] = {0};
relative_addr = addr&0x7FFFFFFF;
start_address=quec_get_patition_start_address((const char *)patition_name);
end_address=quec_get_patition_end_address((const char *)patition_name);
if(addr<start_address || addr>end_address)
{
uart_printf("error address param \n");
return FLASH_RW_ERROR;
}
free_size=end_address-addr;
if(size<=free_size)
{
if(size >= 8)
{
ret = spi_nor_do_write(relative_addr, buf_addr, size, 0);
}
else
{
memset(buf, 0xFF, 10);
memcpy(buf,(const void *)buf_addr, size);
ret = spi_nor_do_write(relative_addr, (unsigned int)&buf, 8, 0);
}
}
else
{
uart_printf("no enough free space \n");
ret = FLASH_RW_ERROR;
}
return ret;
}
//erase a block for internal test
int quec_erase_block(int blk_index, unsigned int disable_protect)
{
int flash_err = 0;
lfsBlockInfo * p_blk_prop = NULL;
p_blk_prop = GetLfsBlkInfo(0);
//fatal_printf("EraseFlash_4k 0x%x 0x%x\r\n", flash_addr, size);
if(blk_index*p_blk_prop->FlashBlockSize > quec_get_patition_end_address("all"))
{
return -1;
}
return spi_nor_do_erase_4k(blk_index*p_blk_prop->FlashBlockSize,p_blk_prop->FlashBlockSize, BOOT_FLASH);
}
//擦除,实现了非4K对齐的擦除
int quec_norflash_do_erase(unsigned char *patition_name, unsigned int addr, unsigned int size)
{
unsigned int ret = 0;
unsigned int sector_size = 4*1024;//4K
unsigned int back_recovery_size=0;
unsigned int start_address = 0;
unsigned int end_address = 0;
unsigned int free_size = 0;
unsigned int erase_size = 0;
volatile unsigned int sector_size_num = 0;
volatile unsigned int sector_addr_num = 0;
unsigned int relative_addr = 0;
unsigned char *recovery_buf1 = NULL;
unsigned char *recovery_buf2 = NULL;
relative_addr = addr&0x7FFFFFFF;
start_address = quec_get_patition_start_address((const char *)patition_name);
end_address = quec_get_patition_end_address((const char *)patition_name);
if(addr<start_address || addr>end_address)
{
uart_printf("error address param \n");
return FLASH_RW_ERROR;
}
free_size=end_address-addr;
if(size <= free_size)
{
if(relative_addr%sector_size == 0)
{
if((size%sector_size == 0))
{
ret = spi_nor_do_erase_4k(relative_addr, size, 0);
}
else
{
recovery_buf1 = malloc(sector_size);
sector_size_num = (relative_addr+size)/sector_size;
back_recovery_size = size%sector_size;
spi_nor_do_read((sector_size_num*sector_size),(unsigned int)recovery_buf1, sector_size, 0);
ret = spi_nor_do_erase_4k(relative_addr, (size - (size%sector_size) + sector_size), 0);
spi_nor_do_write((relative_addr+size),(unsigned int)(recovery_buf1+back_recovery_size), (sector_size-back_recovery_size), 0);
free(recovery_buf1);
}
}
else
{
if((relative_addr+size)%sector_size ==0)
{
recovery_buf1 = malloc(sector_size);
sector_addr_num = relative_addr/sector_size;
spi_nor_do_read((sector_addr_num*sector_size), (unsigned int)recovery_buf1, sector_size, 0);
ret = spi_nor_do_erase_4k((sector_addr_num*sector_size), (size + (relative_addr%sector_size)), 0);
spi_nor_do_write((sector_addr_num*sector_size), (unsigned int)recovery_buf1, (relative_addr%sector_size), 0);
free(recovery_buf1);
}
else
{
recovery_buf1 = malloc(sector_size);
recovery_buf2 = malloc(sector_size);
sector_size_num = (relative_addr+size)/sector_size;
sector_addr_num = relative_addr/sector_size;
back_recovery_size = (relative_addr+size)%sector_size;
erase_size = (size + relative_addr%sector_size);
spi_nor_do_read((sector_addr_num*sector_size), (unsigned int)recovery_buf1, sector_size, 0);
spi_nor_do_read((sector_size_num*sector_size), (unsigned int)recovery_buf2, sector_size, 0);
ret = spi_nor_do_erase_4k((sector_addr_num*sector_size), (erase_size - (erase_size%sector_size) +sector_size), 0);
spi_nor_do_write((sector_addr_num*sector_size), (unsigned int)recovery_buf1, (relative_addr%sector_size), 0);
spi_nor_do_write((relative_addr+size), (unsigned int)(recovery_buf2+back_recovery_size), (sector_size-back_recovery_size), 0);
free(recovery_buf1);
free(recovery_buf2);
}
}
}
else
{
uart_printf("no enough free space \n");
ret = FLASH_RW_ERROR;
}
return ret;
}
extern unsigned int nor_flash_id;
//获取内部QSPI Nor Flash的id
int quec_norflash_read_id(void)
{
return nor_flash_id;
}
UINT32 get_quec_cfg_start_address(void)
{
_ptentry * QUEC_CFG_Entry= ptable_find_entry("quec_cfg");
return QUEC_CFG_Entry->vstart;
}
#ifdef QUEC_NORFLASH_ERASE_OPTIMIZE //补擦的实现
unsigned int Quec_EraseFlashExt(unsigned int addr, unsigned int size, unsigned char flashType);
unsigned int Quec_ReadFlashExt(unsigned int addr, unsigned int buf_addr, unsigned int size, unsigned char flashType);
unsigned int Quec_WriteFlashExt(unsigned int addr, unsigned int buf_addr,unsigned int size, unsigned char flashType);
UINT32 get_erase_rd_start_address(void)
{
_ptentry * erase_rd_start_Entry= ptable_find_entry("erase_rd");
if(erase_rd_start_Entry==NULL)
return NULL;
return erase_rd_start_Entry->start;
}
UINT32 get_erase_rd_bin_size(void)
{
_ptentry * erase_rd_begin_Entry= ptable_find_entry("erase_rd");
if(erase_rd_begin_Entry==NULL)
return NULL;
return erase_rd_begin_Entry->vsize;
}
extern const char USER_ERASE_RECORD_AREA[2][16]; //user 补擦区域
char ERASE_RECORD_AREA[][16]={
"nvm",
};//此数组+USER_ERASE_RECORD_AREA需要与boot33同步
int quec_repair_erase_get_parti_name_valid(char* parti_name)
{
int len =sizeof(ERASE_RECORD_AREA)/sizeof(ERASE_RECORD_AREA[0]);
_ptentry *pnt = NULL;
int i = 0;
for(i=0;i<len;i++)
{
pnt=ptable_find_entry(ERASE_RECORD_AREA[i]);
//分区存在,且属于补擦区域,必须要是内部flash
if(pnt && !strcmp(ERASE_RECORD_AREA[i], parti_name) && ((pnt->vstart & 0xF0000000) == 0x80000000))
{
return 0;
}
}
len =sizeof(USER_ERASE_RECORD_AREA)/sizeof(USER_ERASE_RECORD_AREA[0]);
for(i=0;i<len;i++)
{
pnt=ptable_find_entry(USER_ERASE_RECORD_AREA[i]);
//分区存在,且属于补擦区域,必须要是内部flash
if(pnt && !strcmp(USER_ERASE_RECORD_AREA[i], parti_name) && ((pnt->vstart & 0xF0000000) == 0x80000000))
{
return 0;
}
}
return -1;
}
UINT32 FLASH_ERASE_RECORD_ALLOW_AREA(UINT32 flash_addr,UINT32 size)
{
int len =sizeof(ERASE_RECORD_AREA)/sizeof(ERASE_RECORD_AREA[0]);
_ptentry *pnt;
int i;
for(i=0;i<len;i++)
{
pnt=ptable_find_entry(ERASE_RECORD_AREA[i]);
//补擦的分区必须是内部分区才能判断地址范围
if(pnt && ((pnt->vstart & 0xF0000000) == 0x80000000))
{
if(flash_addr >= pnt->start)
{
if((flash_addr+size) <= (pnt->start + pnt->size))
{
return 1;
}
}
}
}
len =sizeof(USER_ERASE_RECORD_AREA)/sizeof(USER_ERASE_RECORD_AREA[0]);
for(i=0;i<len;i++)
{
pnt=ptable_find_entry(USER_ERASE_RECORD_AREA[i]);
//补擦的分区必须是内部分区才能判断地址范围
if(pnt && ((pnt->vstart & 0xF0000000) == 0x80000000))
{
if(flash_addr >= pnt->start)
{
if((flash_addr+size) <= (pnt->start + pnt->size))
{
return 1;
}
}
}
}
return NULL;
}
#define NoError 0x0
#define QUEC_RECORD_MAGIC1 (0x78E5D4C2)
#define QUEC_RECORD_MAGIC2 (0x54F7D60E) // only record cell 0 used , for mark record area is erase successed
#define CHIP_SECTOR_SIZE 0x1000 //erase 4k each times
#define CHIP_BLOCK_SIZE 0x10000 //erase 4k each times
typedef struct
{
UINT32 flag;// 0xAAA55AA55
UINT32 reserve;
}quec_Eraseflag_s;
typedef struct
{
UINT32 RecordMagic;
UINT32 PageId; // recored the eraseing block id ,
UINT32 Record_type; // recored the eraseing block or page
}quec_RecordInfo_s;
typedef struct
{
quec_RecordInfo_s ReInfo;
quec_Eraseflag_s Eflag;
}quec_flashErase_record_s;
UINT32 g_RecordCell = 0xffffffff;
UINT8 g_IsfirstTimeReadRecordblock = 1;
void Quec_FlashEraseRecord_step1(UINT32 flash_addr,quec_Record_type_enum type)
{
UINT32 Retval = NoError;
quec_flashErase_record_s *p_BlkEraseRecordCell = NULL;
quec_RecordInfo_s *p_BlkERCellInfo = NULL;
quec_Eraseflag_s *p_BlkERCellflag = NULL;
quec_RecordInfo_s BlkERecordCellInfo;
char *Record_buff = NULL;
int i=0, flash_BlkSize = 0;
UINT32 QUEC_RECORD_BLOCKREASE_AREA_SIZE=get_erase_rd_bin_size();
UINT32 QUEC_RECORD_BLOCKREASE_AREA_ADD=get_erase_rd_start_address();
//如果是AT补擦测试,把当前cell的reserve记录为0X12345678,需先正常记录,此次必须为第二次记录
#ifdef QUEC_FLASH_TEST_REPAIR_ERASE
if(type == QUEC_FLASH_TEST_REPAIR_ERASE)
{
quec_flashErase_record_s* now_record = (quec_flashErase_record_s*)(QUEC_RECORD_BLOCKREASE_AREA_ADD+g_RecordCell*(sizeof(quec_flashErase_record_s)));
uint32_t test_reserve_fg = 0X12345678;
Retval = Quec_WriteFlashExt((unsigned int)&now_record->Eflag.reserve, (unsigned int)&test_reserve_fg, sizeof(uint32_t), 0);
if(NoError != Retval)
{
RTI_LOG("WriteFlash failed, retval=%d, g_RecordCell=%d need Record EraseblockId=%d !!!!\r\n", Retval, g_RecordCell,BlkERecordCellInfo.PageId);
return;
}
return;
}
#endif
if((!QUEC_RECORD_BLOCKREASE_AREA_SIZE)||(!QUEC_RECORD_BLOCKREASE_AREA_ADD))
{
quec_flash_printf("not found erase_rd !!!");
return ;
}
flash_BlkSize=type?CHIP_SECTOR_SIZE:CHIP_BLOCK_SIZE;
if(0 == g_IsfirstTimeReadRecordblock)
{
g_RecordCell++;
}
else
{
Record_buff = malloc(QUEC_RECORD_BLOCKREASE_AREA_SIZE);
if(NULL == Record_buff)
{
quec_flash_printf("malloc failed !!!!!!!!");
return;
}
Retval = Quec_ReadFlashExt(QUEC_RECORD_BLOCKREASE_AREA_ADD,(unsigned int)Record_buff,QUEC_RECORD_BLOCKREASE_AREA_SIZE, 0);
if( NoError != Retval)
{
if( NULL !=Record_buff )
{
free(Record_buff);
Record_buff = NULL;
}
quec_flash_printf("Flash read failed !!");
return;
}
// check record block is erase successed
p_BlkEraseRecordCell = (quec_flashErase_record_s*)Record_buff; // check the 0 cell which is mark for record area not erase
p_BlkERCellInfo = (quec_RecordInfo_s*)Record_buff;
if(QUEC_RECORD_MAGIC2 == p_BlkERCellInfo->RecordMagic && 0x00 == p_BlkERCellInfo->PageId)
{
// scan for 1 . because cell 0 is a flag which mark the block is not erase
for( i=1; i*sizeof(quec_flashErase_record_s)<QUEC_RECORD_BLOCKREASE_AREA_SIZE; i++)
{
p_BlkEraseRecordCell = (quec_flashErase_record_s*)Record_buff+i;
p_BlkERCellInfo = (quec_RecordInfo_s *)p_BlkEraseRecordCell;//
p_BlkERCellflag = (quec_Eraseflag_s *)((char *)p_BlkEraseRecordCell + sizeof(p_BlkEraseRecordCell->ReInfo));
if(( 0xffffffff == p_BlkERCellInfo->PageId ) && ( 0xffffffff == p_BlkERCellflag->flag)) // this record cell is not used
{
break;
}
}
g_RecordCell = i;
quec_flash_printf("g_RecordCall =%d\r\n",g_RecordCell);
g_IsfirstTimeReadRecordblock = 0;
if( NULL !=Record_buff )
{
free(Record_buff);
Record_buff = NULL;
}
}
else
{
Retval = NoError;
if( 0xffffffff != p_BlkERCellInfo->RecordMagic )
{
Retval = Quec_EraseFlashExt(QUEC_RECORD_BLOCKREASE_AREA_ADD, QUEC_RECORD_BLOCKREASE_AREA_SIZE, 0);
}
if(NoError ==Retval)
{
BlkERecordCellInfo.RecordMagic = QUEC_RECORD_MAGIC2;
BlkERecordCellInfo.PageId = 0x00;
Retval = Quec_WriteFlashExt(QUEC_RECORD_BLOCKREASE_AREA_ADD, (unsigned int)&BlkERecordCellInfo, sizeof(BlkERecordCellInfo),0);
if(NoError !=Retval)
{
quec_flash_printf("[Ramos], write cell0 EraseRecord area erase flag faild !!!!!");
return ;
}
}
else
{
quec_flash_printf("[Ramos], erase record area fail !!!!!!");
return ;
}
g_RecordCell = 1; // record block erase cell form cell 1. because cell 0 used record RecordArea erase success flag
}
if( NULL !=Record_buff )
{
free(Record_buff);
Record_buff = NULL;
}
}
//quec_flashErase_record_s 20 Byte 最后一个cell不止要小于尾地址,而且范围也不能超过
if( (g_RecordCell*sizeof(quec_flashErase_record_s) >= QUEC_RECORD_BLOCKREASE_AREA_SIZE) ||
(g_RecordCell*sizeof(quec_flashErase_record_s)+sizeof(quec_flashErase_record_s) > QUEC_RECORD_BLOCKREASE_AREA_SIZE)
)
{
Retval = Quec_EraseFlashExt(QUEC_RECORD_BLOCKREASE_AREA_ADD, QUEC_RECORD_BLOCKREASE_AREA_SIZE, 0);
if(NoError ==Retval)
{
BlkERecordCellInfo.RecordMagic = QUEC_RECORD_MAGIC2;
BlkERecordCellInfo.PageId = 0x00;
Retval = Quec_WriteFlashExt(QUEC_RECORD_BLOCKREASE_AREA_ADD, (unsigned int)&BlkERecordCellInfo, sizeof(BlkERecordCellInfo),0);
if(NoError !=Retval)
{
quec_flash_printf("[Ramos], write cell0 EraseRecord area erase flag faild !!!!!");
return ;
}
}
else
{
quec_flash_printf("[Ramos], erase record area fail !!!!!!");
return ;
}
g_RecordCell = 1; // record block erase cell form cell 1. because cell 0 used record RecordArea erase success flag
}
BlkERecordCellInfo.RecordMagic = QUEC_RECORD_MAGIC1;
BlkERecordCellInfo.PageId = flash_addr/flash_BlkSize;
BlkERecordCellInfo.Record_type=type;
quec_flash_printf("addr %x type %d",flash_addr,type);
Retval = Quec_WriteFlashExt((QUEC_RECORD_BLOCKREASE_AREA_ADD+g_RecordCell*(sizeof(quec_flashErase_record_s))), (unsigned int)&(BlkERecordCellInfo), sizeof(BlkERecordCellInfo),0);
if(NoError != Retval)
{
quec_flash_printf("WriteFlash failed, retval=%d, g_RecordCell=%d need Record EraseblockId=%d !!!!", Retval, g_RecordCell,BlkERecordCellInfo.PageId);
}
memset(&BlkERecordCellInfo,0,sizeof(BlkERecordCellInfo));
Retval = Quec_ReadFlashExt((QUEC_RECORD_BLOCKREASE_AREA_ADD+g_RecordCell*(sizeof(quec_flashErase_record_s))), (unsigned int)&(BlkERecordCellInfo), sizeof(BlkERecordCellInfo),0);
if(NoError != Retval)
{
quec_flash_printf("readFlash failed, retval=%d, g_RecordCell=%d need Record EraseblockId=%d !!!!", Retval, g_RecordCell,BlkERecordCellInfo.PageId);
}
uint32_t read_record_addr = BlkERecordCellInfo.PageId * (flash_BlkSize=type?CHIP_SECTOR_SIZE:CHIP_BLOCK_SIZE);
if( (BlkERecordCellInfo.RecordMagic != QUEC_RECORD_MAGIC1) ||
(!FLASH_ERASE_RECORD_ALLOW_AREA(read_record_addr, flash_BlkSize)) ||
(BlkERecordCellInfo.Record_type != type))
{
quec_Eraseflag_s BlkERecordCellflag;
BlkERecordCellflag.flag=0xAAAA5555;
BlkERecordCellflag.reserve = 0xffffffff;
if(0xffffffff != g_RecordCell)
{
//quec_debug("[Ramos] write cell(%d) RecordEraseblock(%d) flag 0xAA55!!",g_RecordCell, flash_addr/flash_BlkSize);
Retval = Quec_WriteFlashExt((QUEC_RECORD_BLOCKREASE_AREA_ADD+g_RecordCell*sizeof(quec_flashErase_record_s)+sizeof(quec_RecordInfo_s)), (unsigned int)&BlkERecordCellflag, sizeof(BlkERecordCellflag),0);
if(NoError != Retval)
{
quec_flash_printf("WriteFlash failed, retval=%d, g_RecordCell=%d, need Record EraseblockId=%d !!", Retval,g_RecordCell, flash_addr/flash_BlkSize);
}
quec_flash_printf("magic %x addr %x type %x %x",BlkERecordCellInfo.RecordMagic,BlkERecordCellInfo.PageId * (flash_BlkSize=type?CHIP_SECTOR_SIZE:CHIP_BLOCK_SIZE),BlkERecordCellInfo.Record_type,type);
}
else
{
quec_flash_printf("g_RecordCall(0x%x) not found !! need Record EraseblockId=%d!", g_RecordCell, flash_addr/flash_BlkSize);
}
}
return;
}
void Quec_FlashEraseRecord_step2(UINT32 flash_addr,quec_Record_type_enum type)
{
UINT32 Retval = NoError, flash_BlkSize = 0;
quec_Eraseflag_s BlkERecordCellflag;
UINT32 QUEC_RECORD_BLOCKREASE_AREA_SIZE=get_erase_rd_bin_size();
UINT32 QUEC_RECORD_BLOCKREASE_AREA_ADD=get_erase_rd_start_address();
if((!QUEC_RECORD_BLOCKREASE_AREA_SIZE)||(!QUEC_RECORD_BLOCKREASE_AREA_ADD))
{
quec_flash_printf("not found erase_rd !!!");
return ;
}
flash_BlkSize=type?CHIP_SECTOR_SIZE:CHIP_BLOCK_SIZE;;
if(0xffffffff != g_RecordCell)
{
Retval = Quec_ReadFlashExt((QUEC_RECORD_BLOCKREASE_AREA_ADD+g_RecordCell*sizeof(quec_flashErase_record_s)+sizeof(quec_RecordInfo_s)), (unsigned int)&BlkERecordCellflag, sizeof(BlkERecordCellflag),0);
if(NoError != Retval)
{
quec_flash_printf("readFlash failed, retval=%d, g_RecordCell=%d!!!!", Retval, g_RecordCell);
}
if(BlkERecordCellflag.flag == 0xAAAA5555)
{
quec_flash_printf("flag is already write,jump it!!!");
} else {
BlkERecordCellflag.flag=0xAAAA5555;
BlkERecordCellflag.reserve = 0xffffffff;
//quec_debug("[Ramos] write cell(%d) RecordEraseblock(%d) flag 0xAA55!!",g_RecordCell, flash_addr/flash_BlkSize);
Retval = Quec_WriteFlashExt((QUEC_RECORD_BLOCKREASE_AREA_ADD+g_RecordCell*sizeof(quec_flashErase_record_s)+sizeof(quec_RecordInfo_s)), (unsigned int)&BlkERecordCellflag, sizeof(BlkERecordCellflag),0);
if(NoError != Retval)
{
quec_flash_printf("WriteFlash failed, retval=%d, g_RecordCell=%d, need Record EraseblockId=%d !!", Retval,g_RecordCell, flash_addr/flash_BlkSize);
}
}
}
else
{
quec_flash_printf("g_RecordCall(0x%x) not found !! need Record EraseblockId=%d!", g_RecordCell, flash_addr/flash_BlkSize);
}
}
#endif