Files
banban/ql-kernel/threadx/quec_minsys/qspi_core.c
T

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