#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;iops->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;iops->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;iops->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