781 lines
25 KiB
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
|
|
|
|
|