1172 lines
29 KiB
C
1172 lines
29 KiB
C
|
|
#include "Typedef.h"
|
|
#include "Errors.h"
|
|
//#include "PlatformConfig.h"
|
|
#include "qspi_common.h"
|
|
#include "qspi_host.h"
|
|
#include "qspi_flash.h"
|
|
//#include "utils.h"
|
|
//#include "spi_nand.h"
|
|
#include "qspi_nor.h"
|
|
#include "spi_nor.h"
|
|
#include "watchdog.h"
|
|
#include "string.h"
|
|
#include "bsp.h"
|
|
#include "osa.h"
|
|
#include "utils.h"
|
|
#include "UART.h"
|
|
#include "ptable.h"
|
|
#include "firmware.h"
|
|
#include "crane_ds_mpu.h"
|
|
#include "loadTable.h"
|
|
|
|
#include "quec_cust_feature.h"
|
|
#include "quec_flash.h"
|
|
|
|
extern BOOL IsMiniSystem(void);
|
|
|
|
#define RW_BUF_LEN 2048
|
|
|
|
struct spi_flash_chip *chip=NULL;
|
|
struct spi_flash_chip *chip2=NULL;
|
|
struct spinor_chip_info *spichip=NULL;
|
|
static float rd_speed, wr_speed;
|
|
|
|
struct qspi_mode qspi_tx_mode[] = {
|
|
{SPI_OPM_TX, "write_x1"},
|
|
{SPI_OPM_TX_QUAD, "write_x4"},
|
|
};
|
|
|
|
struct qspi_mode qspi_rx_mode[] = {
|
|
{SPI_OPM_RX, "read_x1"},
|
|
{SPI_OPM_RX_DUAL, "read_x2"},
|
|
{SPI_OPM_RX_QUAD, "read_x4"},
|
|
};
|
|
|
|
char *qspi_tx_mode_name(int mode)
|
|
{
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
if (qspi_tx_mode[i].mode == mode)
|
|
return qspi_tx_mode[i].name;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
char *qspi_rx_mode_name(int mode)
|
|
{
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
if (qspi_rx_mode[i].mode == mode)
|
|
return qspi_rx_mode[i].name;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
char log_buf[1024*3+1];
|
|
|
|
#if QUEC_OPTIMIZE_SOFT_POWER_DOWN
|
|
#define QUEC_WAIT_FLASH_DONE_TIMEOUT (400) //400*5ms=2000ms
|
|
#define QUEC_FLASH_WRITE_ERASE_FLAG (0x55AA)
|
|
|
|
static UINT32 g_cur_flash_tick = 0; //save current flash tick
|
|
static UINT32 g_cur_flash_flag = QUEC_FLASH_WRITE_ERASE_FLAG; //0-Disable erase/write flash, 0x55AA-Enable
|
|
|
|
char quec_soft_power_is_flash_flag_enable(void);
|
|
void quec_soft_power_update_flash_tick(void);
|
|
#endif
|
|
|
|
|
|
void buf_dump(unsigned char* buf, unsigned int len)
|
|
{
|
|
unsigned int i;
|
|
|
|
uart_printf("\r\n");
|
|
|
|
for(i=0;i<len;i++)
|
|
uart_printf("%02x ", buf[i]);
|
|
|
|
uart_printf("\r\n");
|
|
|
|
}
|
|
static OSSemaRef QspiSemaRef = NULL;
|
|
extern UINT32 EEHandlerFlag;
|
|
|
|
void QSPI_MutexInit(void)
|
|
{
|
|
OSA_STATUS status;
|
|
|
|
if (QspiSemaRef == NULL)
|
|
{
|
|
status = OSASemaphoreCreate (&QspiSemaRef, 1, OSA_FIFO);
|
|
ASSERT(status == OS_SUCCESS);
|
|
}
|
|
}
|
|
void QSPI_MutexLock(void)
|
|
{
|
|
OSA_STATUS status;
|
|
if (EEHandlerFlag == 1)
|
|
return;
|
|
status = OSASemaphoreAcquire(QspiSemaRef, OS_SUSPEND);
|
|
ASSERT(status == OS_SUCCESS);
|
|
}
|
|
void QSPI_MutexUnlock(void)
|
|
{
|
|
OSA_STATUS status;
|
|
if (EEHandlerFlag == 1)
|
|
return;
|
|
status = OSASemaphoreRelease(QspiSemaRef);
|
|
ASSERT(status == OS_SUCCESS);
|
|
|
|
}
|
|
|
|
#ifdef QUEC_NORFLASH_ERASE_OPTIMIZE
|
|
extern void Quec_FlashEraseRecord_step1(UINT32 flash_addr,quec_Record_type_enum type);
|
|
extern void Quec_FlashEraseRecord_step2(UINT32 flash_addr,quec_Record_type_enum type);
|
|
extern UINT32 FLASH_ERASE_RECORD_ALLOW_AREA(UINT32 flash_addr,UINT32 size);
|
|
extern UINT32 get_erase_rd_start_address(void);
|
|
extern UINT32 get_erase_rd_bin_size(void);
|
|
unsigned int Quec_EraseFlashExt(unsigned int addr, unsigned int size, unsigned char flashType)
|
|
{
|
|
int ret = 0;
|
|
#ifdef RUN_XIP_MODE
|
|
watchdogKick();
|
|
#endif
|
|
if(flashType == 0)
|
|
ret = chip->ops->erase_4k(chip, addr, size);//tomas@20260224,fix FAE-212010,Fix the issue where the erase interface was used as a block based erase interface, causing the factory partition to be erased.
|
|
else if (flashType == 1 && chip2)
|
|
ret = chip2->ops->erase_4k(chip2, addr, size);
|
|
else if (flashType == 2 && spichip)
|
|
ret = spichip->ops->erase_sector(spichip, addr, size);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int Quec_ReadFlashExt(unsigned int addr, unsigned int buf_addr, unsigned int size, unsigned char flashType)
|
|
{
|
|
int ret = 0;
|
|
#ifdef RUN_XIP_MODE
|
|
watchdogKick();
|
|
#endif
|
|
if(flashType == 0)
|
|
ret = chip->ops->read(chip, addr, size, (uint8_t *)buf_addr);
|
|
else if (flashType == 1 && chip2)
|
|
ret = chip2->ops->read(chip2, addr, size, (uint8_t *)buf_addr);
|
|
else if (flashType == 2 && spichip)
|
|
ret = spichip->ops->read(spichip, addr, size, (uint32_t)buf_addr);
|
|
return ret;
|
|
}
|
|
|
|
unsigned int Quec_WriteFlashExt(unsigned int addr, unsigned int buf_addr,unsigned int size, unsigned char flashType)
|
|
{
|
|
int ret = 0;
|
|
#ifdef RUN_XIP_MODE
|
|
watchdogKick();
|
|
#endif
|
|
if(flashType==0)
|
|
ret = chip->ops->write(chip, addr, size, (uint8_t *)buf_addr);
|
|
else if (flashType == 1 && chip2)
|
|
ret = chip2->ops->write(chip2, addr, size, (uint8_t *)buf_addr);
|
|
else if (flashType == 2 && spichip)
|
|
ret = spichip->ops->write(spichip, addr, size, (uint32_t)buf_addr);
|
|
return ret;
|
|
}
|
|
|
|
#endif
|
|
|
|
extern void qspi_enter_mode(uint32_t mode);
|
|
extern UINT32 RESUME_SUSPEND_TRS;
|
|
extern UINT32 SUSPEND_READY_TSUS;
|
|
#pragma arm section code="QSPI_INIT"
|
|
|
|
#ifdef QUECTEL_PROJECT_CUST //Get flash id
|
|
unsigned int nor_flash_id = 0;
|
|
#endif
|
|
|
|
int bbu_qspi_init(void)
|
|
{
|
|
struct qspi_host *host;
|
|
int cs = QSPI_CS_A1;
|
|
int mhz = (PLATFORM_IS_ASIC)? 104: 26;
|
|
int nand = 0;
|
|
int use_xip = 1;
|
|
int rx_mode = SPI_OPM_RX_QUAD;
|
|
int tx_mode = SPI_OPM_TX_QUAD;
|
|
int qpi = 0;
|
|
int chip_is_craneLR = CHIP_IS_CRANELR || CHIP_IS_CRANELG || CHIP_IS_CRANELRH;
|
|
|
|
QSPI_MutexInit();
|
|
|
|
#if (defined(LTEONLY_8M8M) || defined(CRANEL_4MRAM) || defined(LTEGSM_THIN))
|
|
crane_ds_mpu_xip_enable(FALSE);
|
|
#endif
|
|
host = qspi_host_init(cs, mhz, use_xip);
|
|
|
|
chip = spi_nor_init(host, cs, rx_mode, tx_mode, qpi);
|
|
|
|
#ifdef QUECTEL_PROJECT_CUST //Get flash id
|
|
nor_flash_id = (unsigned int)chip->mfr_id << 16;
|
|
nor_flash_id |= chip->dev_id;
|
|
#endif
|
|
|
|
if (mhz == 104)
|
|
{
|
|
switch (chip->mfr_id)
|
|
{
|
|
case SPIFLASH_MFR_XM:
|
|
case SPIFLASH_MFR_WINBOND:
|
|
case SPIFLASH_MFR_ZBIT:
|
|
if(chip->mfr_id == SPIFLASH_MFR_XM){
|
|
if(chip->dev_id == 0x5016){
|
|
break;//XM25LU32C no need set SMPR
|
|
}
|
|
|
|
if(chip_is_craneLR && (chip->dev_id == 0x5015)){
|
|
break;//XM25QU16C ,craneLR no need set SMPR
|
|
}
|
|
}
|
|
qspi_enter_mode(QSPI_DISABLE_MODE);
|
|
*(volatile unsigned int*)(QSPI0_SMPR) = (0x1<<5);
|
|
qspi_enter_mode(QSPI_NORMAL_MODE);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if (defined(LTEONLY_8M8M) || defined(CRANEL_4MRAM) || defined(LTEGSM_THIN))
|
|
crane_ds_mpu_xip_enable(TRUE);
|
|
#endif
|
|
#ifdef SW_HANDLE_XIP
|
|
if(RESUME_SUSPEND_TRS || SUSPEND_READY_TSUS){
|
|
CPUartLogPrintf("set nor flash tRS[%d], tSUS[%d]",RESUME_SUSPEND_TRS,SUSPEND_READY_TSUS);
|
|
}
|
|
#endif
|
|
|
|
#ifdef QUEC_LIMIT_FLASH_ERASE
|
|
#ifndef MIN_SYS
|
|
if (!IsMiniSystem())
|
|
{
|
|
CHECK_FLASH_AREA_ADDR_CONFIG();
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
CPUartLogPrintf("SPI Nor/NAND flash init %s\r\n",chip? "success" : "failed");
|
|
|
|
return 0;
|
|
}
|
|
#pragma arm section code
|
|
|
|
#if 0
|
|
|
|
int bbu_qspi_test(void)
|
|
{
|
|
|
|
unsigned int flash_addr;
|
|
unsigned int mem_addr;
|
|
unsigned int size;
|
|
int ret = 0;
|
|
unsigned int i,j;
|
|
|
|
unsigned char *qspi_test_buf;
|
|
|
|
qspi_test_buf=(unsigned char *)malloc(64*1024);
|
|
|
|
for(j=0;j<4;j++)
|
|
{
|
|
mem_addr=(unsigned int)qspi_test_buf;
|
|
size=1024*64;
|
|
|
|
flash_addr=j*1024*64;
|
|
|
|
uart_printf("bbu_qspi_test 0x%08x\r\n", flash_addr);
|
|
|
|
for(i=0;i<sizeof(qspi_test_buf);i++)
|
|
qspi_test_buf[i]=i&0xFF;
|
|
|
|
ret = chip->ops->erase(chip, flash_addr, 64*1024);
|
|
ret = chip->ops->write(chip, flash_addr, size, (uint8_t *)mem_addr);
|
|
memset(qspi_test_buf,0,sizeof(qspi_test_buf));
|
|
ret = chip->ops->read(chip, flash_addr, size, (uint8_t *)mem_addr);
|
|
|
|
|
|
for(i=0;i<sizeof(qspi_test_buf);i++)
|
|
{
|
|
if(qspi_test_buf[i]!=(i&0xFF))
|
|
{
|
|
uart_printf("bbu_qspi_test 0x%08x Fail\r\n", flash_addr);
|
|
return 0;
|
|
}
|
|
}
|
|
uart_printf("bbu_qspi_test 0x%08x Pass\r\n", flash_addr);
|
|
|
|
// buf_dump(qspi_test_buf,1024);
|
|
}
|
|
|
|
free(qspi_test_buf);
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
unsigned int spi_nor_do_erase(unsigned int addr, unsigned int size, BOOL flashType) //flashType:0, qspi flash;,1,spi flash
|
|
{
|
|
int ret = 0;
|
|
#ifndef MIN_SYS
|
|
if (!IsMiniSystem())
|
|
{//MiniSystem
|
|
#ifdef QUEC_LIMIT_FLASH_ERASE
|
|
//检查此地址是否可以被擦除
|
|
if(!FLASH_LIMIT_ALLOW_AREA(addr,size,1))
|
|
{
|
|
uart_printf("not allow erase!!");
|
|
return 0;
|
|
}
|
|
#endif
|
|
#ifdef QUEC_AT_FLASH_ERASE_COUNT_CMD
|
|
//记录被擦除的地址次数
|
|
Flash_erase_count_Set(addr,size);
|
|
#endif
|
|
#if QUEC_OPTIMIZE_SOFT_POWER_DOWN
|
|
quec_soft_power_update_flash_tick();
|
|
if (!quec_soft_power_is_flash_flag_enable())
|
|
{
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifdef QUEC_NORFLASH_ERASE_OPTIMIZE
|
|
UINT32 pagenum;
|
|
UINT32 QUEC_RECORD_BLOCKREASE_AREA_ADD = get_erase_rd_start_address();
|
|
pagenum = size / CHIP_BLOCK_SIZE;
|
|
pagenum += (size % CHIP_BLOCK_SIZE) ? 1 : 0;
|
|
uart_printf("do_erase_1 %d\r\n", pagenum);
|
|
if (FLASH_ERASE_RECORD_ALLOW_AREA(addr, size))
|
|
{
|
|
while (pagenum--)
|
|
{
|
|
QSPI_MutexLock();
|
|
if (QUEC_RECORD_BLOCKREASE_AREA_ADD != addr) // QUEC_RECORD_BLOCKREASE_AREA_ADD this block not record ,
|
|
{
|
|
fatal_printf("step1_block 0x%x 0x%x\r\n", addr, pagenum);
|
|
Quec_FlashEraseRecord_step1(addr, Record_type_Block);
|
|
#ifdef QUEC_FLASH_TEST_REPAIR_ERASE
|
|
if (flashType == QUEC_FLASH_TEST_REPAIR_ERASE)
|
|
{
|
|
//增加记录类型,用于补擦URC上报
|
|
Quec_FlashEraseRecord_step1(addr, (quec_Record_type_enum)QUEC_FLASH_TEST_REPAIR_ERASE);
|
|
return 0;
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef RUN_XIP_MODE
|
|
watchdogKick();
|
|
#endif
|
|
if (flashType == 0)
|
|
ret = chip->ops->erase(chip, addr, size);
|
|
else if (flashType == 1 && chip2)
|
|
ret = chip2->ops->erase(chip2, addr, size);
|
|
else if (flashType == 2 && spichip)
|
|
#ifdef QUEC_NVM_IN_EXT_FLASH
|
|
ret = spichip->ops->erase(spichip, addr, size);
|
|
#else
|
|
ret = spichip->ops->erase_sector(spichip, addr, size);
|
|
#endif
|
|
|
|
if(QUEC_RECORD_BLOCKREASE_AREA_ADD != addr )
|
|
{
|
|
Quec_FlashEraseRecord_step2(addr,Record_type_Block);
|
|
}
|
|
addr+=CHIP_BLOCK_SIZE;
|
|
QSPI_MutexUnlock();
|
|
}
|
|
return ret;
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
QSPI_MutexLock();
|
|
#ifdef RUN_XIP_MODE
|
|
watchdogKick();
|
|
#endif
|
|
if(flashType == 0)
|
|
ret = chip->ops->erase(chip, addr, size);
|
|
else if (flashType == 1 && chip2)
|
|
ret = chip2->ops->erase(chip2, addr, size);
|
|
else if (flashType == 2 && spichip)
|
|
#ifdef QUEC_NVM_IN_EXT_FLASH
|
|
ret = spichip->ops->erase(spichip, addr, size);
|
|
#else
|
|
ret = spichip->ops->erase_sector(spichip, addr, size);
|
|
#endif
|
|
|
|
QSPI_MutexUnlock();
|
|
return 0;
|
|
|
|
}
|
|
int spi_nor_do_erase_4k(unsigned int addr, unsigned int size, BOOL flashType)
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
#ifndef MIN_SYS
|
|
if (!IsMiniSystem())
|
|
{//MiniSystem
|
|
uart_printf("do_erase 0x%x 0x%x\r\n",addr,size);
|
|
#ifdef QUEC_LIMIT_FLASH_ERASE
|
|
//检查此地址是否可以被擦除
|
|
if(!FLASH_LIMIT_ALLOW_AREA(addr,size,1))
|
|
{
|
|
uart_printf("not allow erase!!");
|
|
return 0;
|
|
}
|
|
#endif
|
|
#ifdef QUEC_AT_FLASH_ERASE_COUNT_CMD
|
|
//记录被擦除的地址次数
|
|
Flash_erase_count_Set(addr,size);
|
|
#endif
|
|
|
|
#if QUEC_OPTIMIZE_SOFT_POWER_DOWN
|
|
quec_soft_power_update_flash_tick();
|
|
if (!quec_soft_power_is_flash_flag_enable())
|
|
{
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifdef QUEC_NORFLASH_ERASE_OPTIMIZE
|
|
UINT32 pagenum;
|
|
UINT32 QUEC_RECORD_BLOCKREASE_AREA_ADD = get_erase_rd_start_address();
|
|
pagenum = size / CHIP_BLOCK_SIZE;
|
|
pagenum += (size % CHIP_BLOCK_SIZE) ? 1 : 0;
|
|
uart_printf("do_erase_1 %d\r\n", pagenum);
|
|
if (FLASH_ERASE_RECORD_ALLOW_AREA(addr, size))
|
|
{
|
|
while (pagenum--)
|
|
{
|
|
QSPI_MutexLock();
|
|
if (QUEC_RECORD_BLOCKREASE_AREA_ADD != addr) // QUEC_RECORD_BLOCKREASE_AREA_ADD this block not record ,
|
|
{
|
|
fatal_printf("step1_block 0x%x 0x%x\r\n", addr, pagenum);
|
|
Quec_FlashEraseRecord_step1(addr, Record_type_Page);
|
|
#ifdef QUEC_FLASH_TEST_REPAIR_ERASE
|
|
if (flashType == QUEC_FLASH_TEST_REPAIR_ERASE)
|
|
{
|
|
//增加记录类型,用于补擦URC上报
|
|
Quec_FlashEraseRecord_step1(addr, (quec_Record_type_enum)QUEC_FLASH_TEST_REPAIR_ERASE);
|
|
return 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef RUN_XIP_MODE
|
|
watchdogKick();
|
|
#endif
|
|
if (flashType == 0)
|
|
ret = chip->ops->erase_4k(chip, addr, size);
|
|
else if (flashType == 1 && chip2)
|
|
ret = chip2->ops->erase_4k(chip2, addr, size);
|
|
else if (flashType == 2 && spichip)
|
|
ret = spichip->ops->erase_sector(spichip, addr, size);
|
|
|
|
if(QUEC_RECORD_BLOCKREASE_AREA_ADD != addr )
|
|
{
|
|
Quec_FlashEraseRecord_step2(addr,Record_type_Page);
|
|
}
|
|
addr+=CHIP_SECTOR_SIZE;
|
|
QSPI_MutexUnlock();
|
|
}
|
|
return ret;
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
QSPI_MutexLock();
|
|
|
|
#ifdef RUN_XIP_MODE
|
|
watchdogKick();
|
|
#endif
|
|
if(flashType==0)
|
|
ret = chip->ops->erase_4k(chip, addr, size);
|
|
else if (flashType == 1 && chip2)
|
|
ret = chip2->ops->erase_4k(chip2, addr, size);
|
|
else if (flashType == 2 && spichip)
|
|
ret = spichip->ops->erase_sector(spichip, addr, size);
|
|
|
|
QSPI_MutexUnlock();
|
|
return ret;
|
|
|
|
}
|
|
|
|
unsigned int spi_nor_do_read(unsigned int addr, unsigned int buf_addr, unsigned int size, BOOL flashType)
|
|
{
|
|
|
|
int ret = 0;
|
|
QSPI_MutexLock();
|
|
|
|
if(flashType == 0)
|
|
ret = chip->ops->read(chip, addr, size, (uint8_t *)buf_addr);
|
|
else if (flashType == 1 && chip2)
|
|
ret = chip2->ops->read(chip2, addr, size, (uint8_t *)buf_addr);
|
|
else if (flashType == 2 && spichip)
|
|
ret = spichip->ops->read(spichip, addr, size, (uint32_t)buf_addr);
|
|
|
|
QSPI_MutexUnlock();
|
|
return ret;
|
|
}
|
|
|
|
unsigned int spi_nor_do_write(unsigned int addr, unsigned int buf_addr,unsigned int size, BOOL flashType)
|
|
{
|
|
int ret = 0;
|
|
#ifndef MIN_SYS
|
|
if (!IsMiniSystem())
|
|
{//MiniSystem
|
|
#ifdef QUEC_LIMIT_FLASH_ERASE
|
|
if(!FLASH_LIMIT_ALLOW_AREA(addr,size,1))
|
|
{
|
|
uart_printf("not allow write!!");
|
|
return 0;
|
|
}
|
|
#endif
|
|
#if QUEC_OPTIMIZE_SOFT_POWER_DOWN
|
|
quec_soft_power_update_flash_tick();
|
|
if (!quec_soft_power_is_flash_flag_enable())
|
|
{
|
|
return ret;
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
QSPI_MutexLock();
|
|
#ifdef RUN_XIP_MODE
|
|
watchdogKick();
|
|
#endif
|
|
if(flashType==0)
|
|
ret = chip->ops->write(chip, addr, size, (uint8_t *)buf_addr);
|
|
else if (flashType == 1 && chip2)
|
|
ret = chip2->ops->write(chip2, addr, size, (uint8_t *)buf_addr);
|
|
else if (flashType == 2 && spichip)
|
|
ret = spichip->ops->write(spichip, addr, size, (uint32_t)buf_addr);
|
|
|
|
QSPI_MutexUnlock();
|
|
return 0;
|
|
|
|
}
|
|
|
|
#define CRANE_QSPI_BASE_ADD 0x80000000
|
|
#define CRANE_SPI_BASE_ADD 0x90000000
|
|
|
|
BOOL apn_is_internal=FALSE;
|
|
UINT32 apn_flash_start_addr = 0;
|
|
UINT32 apn_bin_size = 0;
|
|
|
|
// BT_SUPPORT
|
|
#ifdef BT_SUPPORT
|
|
BOOL btbin_is_internal = FALSE;
|
|
UINT32 btbin_flash_start_addr = 0;
|
|
UINT32 btbin_bin_size = 0;
|
|
|
|
BOOL btlst_is_internal = FALSE;
|
|
UINT32 btlst_flash_start_addr = 0;
|
|
UINT32 btlst_bin_size = 0;
|
|
#endif
|
|
|
|
BOOL nvm_is_internal=FALSE;
|
|
UINT32 nvm_flash_start_addr = 0;
|
|
UINT32 nvm_bin_size = 0;
|
|
BOOL nvm_flash_type = FALSE; //flash type 0:external,1:internal;
|
|
BOOL factoryA_is_internal = FALSE;
|
|
//UINT32 factoryA_flash_start_addr = 0;
|
|
//UINT32 factoryA_bin_size = 0;
|
|
BOOL factory_flash_type = FALSE;
|
|
BOOL fota_is_internal = FALSE;
|
|
BOOL fota_flash_type = FALSE;
|
|
|
|
/* GPS Support.Add JoshuaWang. @07/29/2021*/
|
|
BOOL gpsfw_is_internal = FALSE;
|
|
UINT32 gpsfw_flash_start_addr = 0;
|
|
UINT32 gpsfw_bin_size = 0;
|
|
|
|
BOOL gpspvt_is_internal = FALSE;
|
|
UINT32 gpspvt_flash_start_addr = 0;
|
|
UINT32 gpspvt_bin_size = 0;
|
|
|
|
BOOL apn_ex_is_internal = FALSE;
|
|
UINT32 apn_ex_flash_start_addr = 0;
|
|
UINT32 apn_ex_bin_size = 0;
|
|
|
|
|
|
//BT_SUPPORT
|
|
#ifdef BT_SUPPORT
|
|
void flash_init_btbin(void)
|
|
{
|
|
if(ptable_find_entry("btbin") != NULL)
|
|
{
|
|
btbin_is_internal = is_partition_internal_flash("btbin");
|
|
btbin_flash_start_addr = get_btbin_begin_address();
|
|
btbin_bin_size = get_btbin_bin_size();
|
|
}
|
|
else
|
|
{
|
|
int ret = 0;
|
|
firmware_load_info_t fw_info = {0};
|
|
_ptentry * WCN_Entry = NULL;
|
|
|
|
/* WCN partitiion is valid, Get BT firmware info from it! */
|
|
ret = firmware_get_load_info(FIRMWARE_WCN_BT_BTBIN, &fw_info);
|
|
if(ret == 0)
|
|
{
|
|
btbin_is_internal = is_partition_internal_flash(fw_info.partition_name);
|
|
|
|
WCN_Entry = ptable_find_entry(fw_info.partition_name);
|
|
|
|
btbin_flash_start_addr = WCN_Entry->vstart + fw_info.offset;
|
|
btbin_bin_size = fw_info.size;
|
|
}
|
|
}
|
|
CPUartLogPrintf("[BTAPP]btbin: internal %d, addr 0x%x, size %lu",
|
|
btbin_is_internal, btbin_flash_start_addr, btbin_bin_size);
|
|
}
|
|
|
|
void flash_init_btlst(void)
|
|
{
|
|
if(ptable_find_entry("btlst") != NULL)
|
|
{
|
|
btlst_is_internal = is_partition_internal_flash("btlst");
|
|
btlst_flash_start_addr = get_btlst_begin_address();
|
|
btlst_bin_size = get_btlst_bin_size();
|
|
}
|
|
else
|
|
{
|
|
int ret = 0;
|
|
firmware_load_info_t fw_info = {0};
|
|
_ptentry * WCN_Entry = NULL;
|
|
|
|
/* WCN partitiion is valid, Get BT firmware info from it! */
|
|
ret = firmware_get_load_info(FIRMWARE_WCN_BT_BTLST, &fw_info);
|
|
if(ret == 0)
|
|
{
|
|
btlst_is_internal = is_partition_internal_flash(fw_info.partition_name);
|
|
|
|
WCN_Entry = ptable_find_entry(fw_info.partition_name);
|
|
|
|
btlst_flash_start_addr = WCN_Entry->vstart + fw_info.offset;
|
|
btlst_bin_size = fw_info.size;
|
|
}
|
|
}
|
|
CPUartLogPrintf("[BTAPP]btlst: internal %d, addr 0x%x, size %lu",
|
|
btlst_is_internal, btlst_flash_start_addr, btlst_bin_size);
|
|
}
|
|
#endif
|
|
|
|
void flash_init_apn(void)
|
|
{
|
|
apn_is_internal = is_partition_internal_flash("apn");
|
|
apn_flash_start_addr= get_apn_begin_address();
|
|
apn_bin_size=get_apn_bin_size();
|
|
}
|
|
|
|
// void flash_init_apn_ex(void)
|
|
// {
|
|
// apn_ex_is_internal = is_partition_internal_flash("apn_ex");
|
|
// apn_ex_flash_start_addr = get_apn_ex_begin_address();
|
|
// apn_ex_bin_size = get_apn_ex_bin_size();
|
|
// }
|
|
|
|
void flash_init_nvm(void)
|
|
{
|
|
nvm_is_internal = is_partition_internal_flash("nvm");
|
|
nvm_flash_start_addr= get_nvm_start_address();
|
|
nvm_bin_size=get_nvm_bin_size();
|
|
if(nvm_is_internal)
|
|
nvm_flash_type = TRUE; //0:external,1:internal;
|
|
else
|
|
nvm_flash_type = FALSE;
|
|
}
|
|
void flash_init_factory(void)
|
|
{
|
|
factoryA_is_internal= is_partition_internal_flash("factory_a");
|
|
if(factoryA_is_internal)
|
|
factory_flash_type = TRUE;
|
|
else
|
|
factory_flash_type = FALSE;
|
|
// factoryA_flash_start_addr= get_factory_a_start_address();
|
|
// factoryA_bin_size=get_factory_a_bin_size();
|
|
}
|
|
void flash_init_fota(void)
|
|
{
|
|
fota_is_internal= is_partition_internal_flash("fota_param");
|
|
if(fota_is_internal)
|
|
fota_flash_type = TRUE;
|
|
else
|
|
fota_flash_type = FALSE;
|
|
}
|
|
|
|
|
|
void flash_partion_init(void)
|
|
{
|
|
flash_init_apn();
|
|
// flash_init_apn_ex();
|
|
flash_init_nvm();
|
|
flash_init_factory();
|
|
flash_init_fota();
|
|
|
|
CPUartLogPrintf("Flash type: nvm %d, factory %d, fota %d", nvm_flash_type, factory_flash_type, fota_flash_type);
|
|
}
|
|
|
|
// BT_SUPPORT
|
|
#ifdef BT_SUPPORT
|
|
int flash_read_btbin(unsigned int offset,unsigned int buf_addr, unsigned int size)
|
|
{
|
|
int ret = 0;
|
|
|
|
QSPI_MutexLock();
|
|
|
|
if(offset > btbin_bin_size)
|
|
{
|
|
QSPI_MutexUnlock();
|
|
return -1;
|
|
}
|
|
|
|
if(btbin_is_internal)
|
|
{
|
|
ret = spichip->ops->read(spichip, btbin_flash_start_addr - CRANE_SPI_BASE_ADD + offset, size, (uint32_t)buf_addr);
|
|
}
|
|
else
|
|
{
|
|
ret = chip->ops->read(chip, btbin_flash_start_addr - CRANE_QSPI_BASE_ADD + offset, size, (uint8_t *)buf_addr);
|
|
}
|
|
QSPI_MutexUnlock();
|
|
return ret;
|
|
}
|
|
|
|
int flash_read_btbin_rom_version(unsigned int offset,unsigned int buf_addr, unsigned int size)
|
|
{
|
|
int ret = 0;
|
|
|
|
QSPI_MutexLock();
|
|
|
|
if(offset > btbin_bin_size)
|
|
{
|
|
QSPI_MutexUnlock();
|
|
return -1;
|
|
}
|
|
|
|
if(btbin_is_internal)
|
|
{
|
|
ret = spichip->ops->read(spichip, btbin_flash_start_addr - CRANE_SPI_BASE_ADD + offset, size, (uint32_t)buf_addr);
|
|
}
|
|
else
|
|
{
|
|
ret = chip->ops->read(chip, btbin_flash_start_addr - CRANE_QSPI_BASE_ADD + offset, size, (uint8_t *)buf_addr);
|
|
}
|
|
QSPI_MutexUnlock();
|
|
return ret;
|
|
}
|
|
|
|
|
|
int flash_read_btlst(unsigned int offset, unsigned int buf_addr, unsigned int size)
|
|
{
|
|
int ret = 0;
|
|
|
|
QSPI_MutexLock();
|
|
|
|
if(offset > btlst_bin_size)
|
|
{
|
|
QSPI_MutexUnlock();
|
|
return -1;
|
|
}
|
|
|
|
if(btlst_is_internal)
|
|
{
|
|
btlst_flash_start_addr -= CRANE_SPI_BASE_ADD;
|
|
ret = spichip->ops->read(spichip, btlst_flash_start_addr+offset, size, (uint32_t)buf_addr);
|
|
}
|
|
else
|
|
{
|
|
btlst_flash_start_addr -= CRANE_QSPI_BASE_ADD;
|
|
|
|
ret = chip->ops->read(chip, btlst_flash_start_addr+offset, size, (uint8_t *)buf_addr);
|
|
}
|
|
QSPI_MutexUnlock();
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
int flash_read_apn(unsigned int offset,unsigned int buf_addr, unsigned int size)
|
|
{
|
|
int ret = 0;
|
|
|
|
QSPI_MutexLock();
|
|
|
|
if(offset>apn_bin_size)
|
|
{
|
|
fatal_printf("flash_read_apn offset too long!\r\n ");
|
|
QSPI_MutexUnlock();
|
|
return -1;
|
|
}
|
|
|
|
if (apn_flash_start_addr == 0 || apn_bin_size == 0)
|
|
{
|
|
fatal_printf("flash_read_apn partition not init or not exist!\r\n ");
|
|
QSPI_MutexUnlock();
|
|
return -1;
|
|
}
|
|
|
|
if(apn_is_internal)
|
|
ret = spichip->ops->read(spichip, apn_flash_start_addr-CRANE_SPI_BASE_ADD+offset, size, (uint32_t)buf_addr);
|
|
else
|
|
ret = chip->ops->read(chip, apn_flash_start_addr-CRANE_QSPI_BASE_ADD+offset, size, (uint8_t *)buf_addr);
|
|
|
|
QSPI_MutexUnlock();
|
|
return ret;
|
|
}
|
|
|
|
int flash_read_apn_ex(unsigned int offset,unsigned int buf_addr, unsigned int size)
|
|
{
|
|
int ret = 0;
|
|
|
|
QSPI_MutexLock();
|
|
|
|
if (offset>apn_ex_bin_size)
|
|
{
|
|
fatal_printf("flash_read_apn_ex offset too long!\r\n ");
|
|
QSPI_MutexUnlock();
|
|
return -1;
|
|
}
|
|
|
|
if (apn_ex_flash_start_addr == 0 || apn_ex_bin_size == 0)
|
|
{
|
|
fatal_printf("flash_read_apn_ex partition not init or not exist!\r\n ");
|
|
QSPI_MutexUnlock();
|
|
return -1;
|
|
}
|
|
|
|
if(apn_ex_is_internal)
|
|
ret = spichip->ops->read(spichip, apn_ex_flash_start_addr-CRANE_SPI_BASE_ADD+offset, size, (uint32_t)buf_addr);
|
|
else
|
|
ret = chip->ops->read(chip, apn_ex_flash_start_addr-CRANE_QSPI_BASE_ADD+offset, size, (uint8_t *)buf_addr);
|
|
|
|
QSPI_MutexUnlock();
|
|
return ret;
|
|
}
|
|
|
|
int flash_read_nvm(unsigned int offset,unsigned int buf_addr, unsigned int size)
|
|
{
|
|
int ret = 0;
|
|
|
|
QSPI_MutexLock();
|
|
|
|
if(offset+size>nvm_bin_size)
|
|
{
|
|
fatal_printf("flash_read_nvm read exceeds!\r\n ");
|
|
QSPI_MutexUnlock();
|
|
return -1;
|
|
}
|
|
|
|
if(nvm_is_internal)
|
|
ret = spichip->ops->read(spichip, nvm_flash_start_addr+offset, size, (uint32_t)buf_addr);
|
|
else
|
|
ret = chip->ops->read(chip, nvm_flash_start_addr-CRANE_QSPI_BASE_ADD+offset, size, (uint8_t *)buf_addr);
|
|
|
|
QSPI_MutexUnlock();
|
|
return ret;
|
|
}
|
|
|
|
int flash_write_nvm(unsigned int offset,unsigned int buf_addr, unsigned int size)
|
|
{
|
|
int ret = 0;
|
|
|
|
QSPI_MutexLock();
|
|
|
|
if(offset+size>nvm_bin_size)
|
|
{
|
|
fatal_printf("flash_read_nvm write exceeds!\r\n ");
|
|
QSPI_MutexUnlock();
|
|
return -1;
|
|
}
|
|
|
|
if(nvm_is_internal)
|
|
ret = spichip->ops->write(spichip, nvm_flash_start_addr+offset, size, (uint32_t)buf_addr);
|
|
else
|
|
ret = chip->ops->write(chip, nvm_flash_start_addr-CRANE_QSPI_BASE_ADD+offset, size, (uint8_t *)buf_addr);
|
|
|
|
QSPI_MutexUnlock();
|
|
return ret;
|
|
}
|
|
|
|
int flash_erase_nvm(unsigned int offset,unsigned int buf_addr, unsigned int size)
|
|
{
|
|
int ret = 0;
|
|
|
|
QSPI_MutexLock();
|
|
|
|
if(offset+size>nvm_bin_size)
|
|
{
|
|
fatal_printf("flash_read_nvm erase exceeds!\r\n ");
|
|
QSPI_MutexUnlock();
|
|
return -1;
|
|
}
|
|
|
|
if(nvm_is_internal)
|
|
ret = spichip->ops->erase_sector(spichip, nvm_flash_start_addr+offset, size);
|
|
else
|
|
ret = chip->ops->erase(chip, nvm_flash_start_addr-CRANE_QSPI_BASE_ADD+offset, size);
|
|
|
|
QSPI_MutexUnlock();
|
|
return ret;
|
|
}
|
|
|
|
|
|
UINT64 spi_nor_do_read_uid(void)
|
|
{
|
|
int ret = 0;
|
|
uint8_t uid[8] = {0};
|
|
UINT64 flash_uid = 0;
|
|
|
|
QSPI_MutexLock();
|
|
ret = chip->ops->read_uid(chip, (uint8_t *)uid);
|
|
QSPI_MutexUnlock();
|
|
if (ret != 0) return 0;
|
|
|
|
memcpy((unsigned char*)&flash_uid, uid, 8);
|
|
return flash_uid;
|
|
}
|
|
|
|
void spi_nor_do_read_id(void)
|
|
{
|
|
int ret = 0;
|
|
uint8_t id[3]={0};
|
|
|
|
fatal_printf("spi_nor_do_read_id\r\n");
|
|
QSPI_MutexLock();
|
|
ret = spichip->ops->read_id(spichip, id);
|
|
QSPI_MutexUnlock();
|
|
if (ret != 0) return;
|
|
|
|
fatal_printf("Manufacture ID: 0x%x, Device ID: 0x%x\n\r", id[1], id[2]);
|
|
fatal_printf("flash_density: 8M\r\n");
|
|
return;
|
|
}
|
|
void qspi_nor_erase_all()
|
|
{
|
|
|
|
spi_nor_do_erase(0,0x1000000, 0);
|
|
}
|
|
|
|
#ifdef QUEC_NVM_IN_EXT_FLASH
|
|
#include "SPI.h"
|
|
|
|
struct spinor_chip_info spinor_chip = {0};
|
|
|
|
static int spinor_reset(struct spinor_chip_info *chip)
|
|
{
|
|
int ret = 0;
|
|
int port = SPINOR_getSSPPort();
|
|
|
|
SPINOR_SW_Reset(port);
|
|
return ret;
|
|
}
|
|
|
|
static int spinor_read_id(struct spinor_chip_info *chip, uint8_t *buf)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int spinor_read_uid(struct spinor_chip_info *chip, uint8_t *buf)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int spinor_erase(struct spinor_chip_info *chip, int addr, int len)
|
|
{
|
|
int ret = 0;
|
|
int port = SPINOR_getSSPPort();
|
|
|
|
ret = SPINOR_EraseByBlock(port, addr, len);
|
|
|
|
return ret;
|
|
}
|
|
static int spinor_erase_sector(struct spinor_chip_info *chip, int addr, int len)
|
|
{
|
|
int ret = 0;
|
|
int port = SPINOR_getSSPPort();
|
|
|
|
ret = SPINOR_EraseBySector(port, addr, len);
|
|
return ret;
|
|
}
|
|
|
|
static int spinor_write(struct spinor_chip_info *chip, unsigned int addr, int size, unsigned int wbuf)
|
|
{
|
|
int ret = 0;
|
|
int port = SPINOR_getSSPPort();
|
|
|
|
ret = SPINOR_Write(port, addr,wbuf, size);
|
|
return ret;
|
|
}
|
|
|
|
static int spinor_read(struct spinor_chip_info *chip, unsigned int addr, int size, unsigned int rbuf)
|
|
{
|
|
int ret = 0;
|
|
int port = SPINOR_getSSPPort();
|
|
|
|
ret = SPINOR_Read(port, addr, rbuf, size);
|
|
return ret;
|
|
}
|
|
|
|
static const struct spinor_ops ext_nor_ops = {
|
|
.reset = spinor_reset,
|
|
.read_id = NULL,
|
|
.read = spinor_read,
|
|
.write = spinor_write,
|
|
.erase = spinor_erase,
|
|
.erase_sector = spinor_erase_sector
|
|
};
|
|
|
|
extern int quec_spi_pin_selflag;
|
|
|
|
#define quec_app_log(msg , ...) RTI_LOG("[QUEC APP]"msg"", ##__VA_ARGS__)
|
|
extern unsigned int quec_spi_pin_select(int port);
|
|
extern int quec_get_extflash_select_port(void);
|
|
|
|
int external_spi_init(void)
|
|
{
|
|
int ret = 0;
|
|
int pin_flag =quec_get_extflash_select_port();//port0 default
|
|
int port = 0;
|
|
struct spinor_chip_info *chip = &spinor_chip;
|
|
spichip = chip;
|
|
// quec_spi_pin_selflag = 1;//pinmux config: gpio33~36 must be compatible with hardware!!!
|
|
if(pin_flag == 1)//33~36 ssp0
|
|
{
|
|
port = 0;
|
|
}
|
|
else if((pin_flag == 0)||(pin_flag == 2))
|
|
{
|
|
port = pin_flag;
|
|
}
|
|
else if(pin_flag == 4)
|
|
{
|
|
port = 1;
|
|
}
|
|
else//12~15 for SSP2
|
|
{
|
|
port = 2;
|
|
}
|
|
|
|
|
|
InitializeSPIDevice(port,SSP_CLOCK_26M); //SSP_CLOCK_52M
|
|
|
|
chip->ops = (void *)&ext_nor_ops;
|
|
if(!chip->ops->reset)
|
|
return NULL;
|
|
ret = chip->ops->reset(chip);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
#ifndef CRANE_MCU_DONGLE
|
|
int bbu_spi_init(void)
|
|
{
|
|
int ret;
|
|
|
|
QSPI_MutexInit();
|
|
|
|
spichip=spinor_init(NULL,2);
|
|
|
|
if (!spichip) {
|
|
fatal_printf("SPI Nor flash init failed\r\n");
|
|
|
|
}
|
|
|
|
// spinor_rw_test(spichip, 0x100000, 0x100);
|
|
// spinor_rw_test(spichip, 0x100000, 0x1000);
|
|
|
|
// ret = spinor_erase(spichip);
|
|
// fatal_printf("spinor_erase done, ret = 0x%x\n\r", ret);
|
|
|
|
// nvm_spi_time_test();
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if QUEC_OPTIMIZE_SOFT_POWER_DOWN
|
|
void quec_soft_power_wait_flash_idle(void)
|
|
{
|
|
UINT32 wait_flash_cnt = 0;
|
|
|
|
CPUartLogPrintf("%s, cur_tick=%d,flash_tick=%d", __func__, OSAGetTicks(), g_cur_flash_tick);
|
|
|
|
if ((OSAGetTicks() > g_cur_flash_tick) &&
|
|
((OSAGetTicks() - g_cur_flash_tick) < QUEC_WAIT_FLASH_DONE_TIMEOUT))
|
|
{
|
|
//Maybe erase or write flash is ongoing,
|
|
//so we wait 2S here to make flash operation done.
|
|
|
|
wait_flash_cnt = QUEC_WAIT_FLASH_DONE_TIMEOUT;
|
|
while(wait_flash_cnt > 0)
|
|
{
|
|
OSATaskSleep(1);
|
|
wait_flash_cnt--;
|
|
}
|
|
}
|
|
}
|
|
|
|
void quec_soft_power_disable_flash_write_erase(void)
|
|
{
|
|
/*
|
|
GD25LQ128D
|
|
Fast Program/Erase Speed:
|
|
-Page Program time: 0.5ms typical
|
|
-Sector Erase time: 70ms typical
|
|
-Block Erase time: 0.16/0.3s typical
|
|
-Chip Erase time: 50s typical
|
|
|
|
Program/Erase Speed
|
|
-Page Program time: 0.7ms typical
|
|
-Sector Erase time: 60ms typical
|
|
-Block Erase time: 0.3/0.5s typical
|
|
-Chip Erase time: 60s typical
|
|
*/
|
|
|
|
g_cur_flash_flag = 0;
|
|
|
|
//According to flash datasheet, we sleep 500ms if block erase exist.
|
|
OSATaskSleep(100);
|
|
}
|
|
|
|
char quec_soft_power_is_flash_flag_enable(void)
|
|
{
|
|
if (g_cur_flash_flag == QUEC_FLASH_WRITE_ERASE_FLAG)
|
|
{
|
|
//Enable erase or write flash
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
//Diasble erase or write flash
|
|
return 0;
|
|
}
|
|
}
|
|
//记录擦或者写的时间
|
|
void quec_soft_power_update_flash_tick(void)
|
|
{
|
|
g_cur_flash_tick = OSAGetTicks();
|
|
}
|
|
#endif
|
|
|