#include "Typedef.h" #include "Errors.h" #include "bsp.h" #include "PlatformConfig.h" #include "osa.h" #include #include "UART.h" #include "qspi_host.h" #include "qspi_nor.h" #include "qspi_dma.h" #include "crane_ds_mpu.h" #include "qspi_nor_bp.h" #if defined(FLASH_SEND_IPC) #include "WS_CmdMsg.h" #define SEND_IPC_FLAG 1 OS_HISR send_ipc_hisr; OSFlagRef send_ipc_flag=NULL; unsigned char spi_nor_test_leval=0; static void spi_nor_send_ipc(void); static void spi_nor_loop_delay(UINT32 n); static int spi_nor_delay(void); extern void L1aSendEcphyFlashDspReq(unsigned short eraseStartFlag, unsigned int cpmaxDelayTime, unsigned int cp32kTimer); typedef unsigned char Boolean; extern Boolean LteMacSendEcphyFlashDspReq(Boolean isForce, Int16 eraseStartFlag, Int32 cpmaxDelayTime, Int32 cp32kTimer); extern UINT32 get_current_TStimer_tick(void); extern unsigned char L1aCheckHasRxModeReport(void); #endif #ifdef SW_HANDLE_XIP extern void crane_ds_mpu_xip_cache_enable(void); extern void crane_ds_mpu_xip_cache_disable(void); #endif static struct spi_nor_info spi_nor_table[] = { #if (defined(LTEONLY_THIN) || defined(LTEGSM_THIN)) #ifdef LTEONLY_THIN_SINGLE_SIM_2MFLASH /* Wuhan XinXin */ SPI_NOR_INFO("XM25QU16C", 0x20, 0x5015, 256, 256, 2*1024*1024, 0, 0), /* GigaDeivce */ SPI_NOR_INFO("GD25LE16E", 0xC8, 0x6015, 256, 256, 2*1024*1024, 0, 0), /* Silicon Kaiser */ SPI_NOR_INFO("SK25LE016", 0x25, 0x7015, 256, 256, 2*1024*1024, 0, 0), #else /* GigaDeivce */ SPI_NOR_INFO("GD25LE128E", 0xC8, 0x6018, 256, 256, 16*1024*1024, 0, 0), SPI_NOR_INFO("GD25LE32E", 0xC8, 0x6016, 256, 256, 4*1024*1024, 0, 0), SPI_NOR_INFO("GD25LE64E", 0xC8, 0x6017, 256, 256, 8*1024*1024, 0, 0), /* Wuhan XinXin */ SPI_NOR_INFO("XM25LU32C", 0x20, 0x5016, 256, 256, 4*1024*1024, 0, 0), SPI_NOR_INFO("XM25QU64B", 0x20, 0x5017, 256, 256, 8*1024*1024, SPINOR_QE_USE_BIT6 | SPINOR_WRITE_STATUS1_1BYTE, 0), SPI_NOR_INFO("XM25QU64C", 0x20, 0x4117, 256, 256, 8*1024*1024, 0, 0), SPI_NOR_INFO("XM25QU128C", 0x20, 0x4118, 256, 256, 16*1024*1024, 0, 0), #endif #else /* Macronix */ SPI_NOR_INFO("MX25U12835", 0xC2, 0x2538, 256, 256, 16*1024*1024, SPINOR_QE_USE_BIT6 | SPINOR_WRITE_STATUS1_1BYTE, 0), SPI_NOR_INFO("MX25U3273", 0xC2, 0x2536, 256, 256, 4*1024*1024, SPINOR_QE_USE_BIT6 | SPINOR_WRITE_STATUS1_1BYTE, 0), /* GigaDeivce */ SPI_NOR_INFO("GD25LQ256C", 0xC8, 0x6019, 256, 256, 32*1024*1024, 0, 0), SPI_NOR_INFO("GD25LE128E", 0xC8, 0x6018, 256, 256, 16*1024*1024, 0, 0), SPI_NOR_INFO("GD25LE64E", 0xC8, 0x6017, 256, 256, 8*1024*1024, 0, 0), SPI_NOR_INFO("GD25LE32E", 0xC8, 0x6016, 256, 256, 4*1024*1024, 0, 0), /* Winbond */ SPI_NOR_INFO("W25Q256JW", 0xEF, 0x6019, 256, 256, 32*1024*1024, 0, 0), SPI_NOR_INFO("W25Q256JW-IM*", 0xEF, 0x8019, 256, 256, 32*1024*1024, 0, 0), SPI_NOR_INFO("W25Q128JW", 0xEF, 0x6018, 256, 256, 16*1024*1024, 0, 0), SPI_NOR_INFO("W25Q64FW", 0xEF, 0x6017, 256, 256, 8*1024*1024, 0, 0), /* Dosilicon */ SPI_NOR_INFO("FM25M4AA", 0xF8, 0x4218, 256, 256, 16*1024*1024, 0, 0), /* DouQi */ SPI_NOR_INFO("DQ25Q128AL", 0x54, 0x6018, 256, 256, 16*1024*1024, SPINOR_HAVE_WRITE_STATUS2, 0), /* Puya */ SPI_NOR_INFO("P25Q128L", 0x85, 0x6018, 256, 256, 16*1024*1024, SPINOR_HAVE_WRITE_STATUS2, 78), SPI_NOR_INFO("P25Q64LE", 0x85, 0x6017, 256, 256, 8*1024*1024, SPINOR_HAVE_WRITE_STATUS2, 0), SPI_NOR_INFO("P25Q32SL", 0x85, 0x6016, 256, 256, 4*1024*1024, SPINOR_HAVE_WRITE_STATUS2, 0), /* ZettaDevice */ SPI_NOR_INFO("ZD25Q128", 0xBA, 0x4218, 256, 256, 16*1024*1024, 0, 0), /* Wuhan XinXin */ SPI_NOR_INFO("XM25LU32C", 0x20, 0x5016, 256, 256, 4*1024*1024, 0, 0), SPI_NOR_INFO("XM25QU64B", 0x20, 0x5017, 256, 256, 8*1024*1024, SPINOR_QE_USE_BIT6 | SPINOR_WRITE_STATUS1_1BYTE, 0), SPI_NOR_INFO("XM25QU64C", 0x20, 0x4117, 256, 256, 8*1024*1024, 0, 0), SPI_NOR_INFO("XM25QU128B", 0x20, 0x5018, 256, 256, 16*1024*1024, SPINOR_QE_USE_BIT6 | SPINOR_WRITE_STATUS1_1BYTE, 0), SPI_NOR_INFO("XM25QU128C", 0x20, 0x4118, 256, 256, 16*1024*1024, 0, 0), SPI_NOR_INFO("XM25QU256B", 0x20, 0x7019, 256, 256, 32*1024*1024, SPINOR_QE_USE_BIT6 | SPINOR_WRITE_STATUS1_1BYTE, 0), /* Fudan Microelectronics */ SPI_NOR_INFO("FM25W128", 0xA1, 0x2818, 256, 256, 16*1024*1024, SPINOR_HAVE_WRITE_STATUS2, 52), /* Zbit Semiconductor */ SPI_NOR_INFO("ZB25LQ64A", 0x5E, 0x7017, 256, 256, 8*1024*1024, 0, 0), SPI_NOR_INFO("ZB25LQ128A", 0x5E, 0x5018, 256, 256, 16*1024*1024, 0, 0), #endif {.name = NULL}, }; /** * spi_nor_scan_id_table - scan chip info in id table * @chip: SPI-NOR device structure * Description: * If found in id table, config chip with table information. */ static int spi_nor_scan_id_table(struct spi_flash_chip *chip) { struct spi_nor_info *type = spi_nor_table; for (; type->name; type++) { if (chip->mfr_id == type->mfr_id && chip->dev_id == type->dev_id) { chip->name = type->name; chip->size = type->total_size; chip->block_size = type->page_size * type->pages_per_blk; chip->page_size = type->page_size; chip->options = type->options; chip->max_mhz = type->max_mhz; #if (!defined(LTEONLY_8M8M) && !defined(CRANEL_4MRAM) && !defined(LTEGSM_THIN)) CPUartLogPrintf("SPI-NOR: %s is found in table",type->name); #endif return TRUE; } } return FALSE; } enum normal_cmd { ENABLE_4BYTE, DISABLE_4BYTE, READ_STATUS1, READ_STATUS2, READ_STATUS3, WRITE_STATUS, WRITE_STATUS2, READ_SLOW, READ_FAST, READ_FAST_X2, READ_FAST_X4, READ_FAST_DUAL, READ_FAST_QUAD, SECTOR_ERASE_4K, BLK_ERASE_32K, BLK_ERASE_64K, CHIP_ERASE, PROG, PROG_X4, WR_ENABLE, WR_DISABLE, READ_ID, READ_UID, ENABLE_QPI, PGM_ERS_SUSPEND, PGM_ERS_RESUME, EN_RST, RESET, READ_STATUS2_MXIC, PROG_X4_MXIC, ENABLE_QPI_MXIC, PGM_ERS_SUSPEND_MXIC, PGM_ERS_RESUME_MXIC, #ifdef SUPPORT_FBP WR_EN_VSR, #endif READ_SFDP, MAX_CMD, }; enum qspi_cmd { ENABLE_4BYTE_QPI, DISABLE_4BYTE_QPI, READ_STATUS1_QPI, READ_STATUS2_QPI, READ_STATUS3_QPI, READ_STATUS2_MXIC_QPI, WRITE_STATUS_QPI, WRITE_STATUS2_QPI, READ_FAST_QPI, READ_FAST_QUAD_QPI, SECTOR_ERASE_4K_QPI, BLK_ERASE_32K_QPI, BLK_ERASE_64K_QPI, CHIP_ERASE_QPI, PROG_QPI, WR_ENABLE_QPI, WR_DISABLE_QPI, READ_ID_QPI, READ_QPIID, DISABLE_QPI, DISABLE_QPI_MXIC, SET_READ_PARA_QPI, PGM_ERS_SUSPEND_QPI, PGM_ERS_RESUME_QPI, PGM_ERS_SUSPEND_MXIC_QPI, PGM_ERS_RESUME_MXIC_QPI, #ifdef SUPPORT_FBP WR_EN_VSR_QPI, #endif EN_RST_QPI, RESET_QPI, MAX_CMD_QPI, }; /* Standard SPI-NOR flash normal commands */ static struct spi_flash_cmd_cfg cmd_table[] = { /*opcode addr_bytes addr_pins mode_bits mode_pins dummy_cycles dummy_pins data_pins seq_id cmd_type */ {0xb7, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [ENABLE_4BYTE] = SPI_CMD(0xb7, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0xe9, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [DISABLE_4BYTE] = SPI_CMD(0xe9, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x05, 0, 0, 0, 0, 0, 0, 1, 2, 1},// [READ_STATUS1] = SPI_CMD(0x05, 0, 0, 0, 0, 0, 0, 1, 2, 1), {0x35, 0, 0, 0, 0, 0, 0, 1, -1, 1},// [READ_STATUS2] = SPI_CMD(0x35, 0, 0, 0, 0, 0, 0, 1, -1, 1), {0x15, 0, 0, 0, 0, 0, 0, 1, -1, 1},// [READ_STATUS3] = SPI_CMD(0x15, 0, 0, 0, 0, 0, 0, 1, -1, 1), {0x01, 0, 0, 0, 0, 0, 0, 1, -1, 2},// [WRITE_STATUS] = SPI_CMD(0x01, 0, 0, 0, 0, 0, 0, 1, -1, 2), {0x31, 0, 0, 0, 0, 0, 0, 1, -1, 2},// [WRITE_STATUS2] = SPI_CMD(0x31, 0, 0, 0, 0, 0, 0, 1, -1, 2), {0x03, 3, 1, 0, 0, 0, 0, 1, -1, 1},// [READ_SLOW] = SPI_CMD(0x03, 3, 1, 0, 0, 0, 0, 1, -1, 1), {0x0b, 3, 1, 0, 0, 8, 1, 1, 3, 1},// [READ_FAST] = SPI_CMD(0x0b, 3, 1, 0, 0, 8, 1, 1, 3, 1), {0x3b, 3, 1, 0, 0, 8, 1, 2, -1, 1},// [READ_FAST_X2] = SPI_CMD(0x3b, 3, 1, 0, 0, 8, 1, 2, -1, 1), {0x6b, 3, 1, 0, 0, 8, 1, 4, 4, 1},// [READ_FAST_X4] = SPI_CMD(0x6b, 3, 1, 0, 0, 8, 1, 4, 4, 1), {0xbb, 3, 2, 8, 2, 0, 0, 2, -1, 1},// [READ_FAST_DUAL] = SPI_CMD(0xbb, 3, 2, 8, 2, 0, 0, 2, -1, 1), {0xeb, 3, 4, 8, 4, 4, 4, 4, 5, 1},// [READ_FAST_QUAD] = SPI_CMD(0xeb, 3, 4, 8, 4, 4, 4, 4, 5, 1), {0x20, 3, 1, 0, 0, 0, 0, 0, -1, 0},// [SECTOR_ERASE_4K] = SPI_CMD(0x20, 3, 1, 0, 0, 0, 0, 0, -1, 0), {0x52, 3, 1, 0, 0, 0, 0, 0, -1, 0},// [BLK_ERASE_32K] = SPI_CMD(0x52, 3, 1, 0, 0, 0, 0, 0, -1, 0), {0xd8, 3, 1, 0, 0, 0, 0, 0, -1, 0},// [BLK_ERASE_64K] = SPI_CMD(0xd8, 3, 1, 0, 0, 0, 0, 0, -1, 0), {0xc7, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [CHIP_ERASE] = SPI_CMD(0xc7, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x02, 3, 1, 0, 0, 0, 0, 1, 6, 2},// [PROG] = SPI_CMD(0x02, 3, 1, 0, 0, 0, 0, 1, 6, 2), {0x32, 3, 1, 0, 0, 0, 0, 4, 7, 2},// [PROG_X4] = SPI_CMD(0x32, 3, 1, 0, 0, 0, 0, 4, 7, 2), {0x06, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [WR_ENABLE] = SPI_CMD(0x06, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x04, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [WR_DISABLE] = SPI_CMD(0x04, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x9f, 0, 0, 0, 0, 0, 0, 1, -1, 1},// [READ_ID] = SPI_CMD(0x9f, 0, 0, 0, 0, 0, 0, 1, -1, 1), {0x4b, 0, 0, 0, 0,32, 1, 1, -1, 1},// [READ_UID] = SPI_CMD(0x4b, 0, 0, 0, 0,32, 1, 1, -1, 1), {0x38, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [ENABLE_QPI] = SPI_CMD(0x38, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x75, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [PGM_ERS_SUSPEND] = SPI_CMD(0x75, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x7a, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [PGM_ERS_RESUME] = SPI_CMD(0x7a, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x66, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [EN_RST] = SPI_CMD(0x66, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x99, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [RESET] = SPI_CMD(0x99, 0, 0, 0, 0, 0, 0, 0, -1, 0), /* Vendor specific command */ {0x15, 0, 0, 0, 0, 0, 0, 1, -1, 1},// [READ_STATUS2_MXIC] = SPI_CMD(0x15, 0, 0, 0, 0, 0, 0, 1, -1, 1), {0x38, 3, 4, 0, 0, 0, 0, 4, 8, 2},// [PROG_X4_MXIC] = SPI_CMD(0x38, 3, 4, 0, 0, 0, 0, 4, 8, 2), {0x35, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [ENABLE_QPI_MXIC] = SPI_CMD(0x35, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0xb0, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [PGM_ERS_SUSPEND_MXIC] = SPI_CMD(0xb0, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x30, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [PGM_ERS_RESUME_MXIC] = SPI_CMD(0x30, 0, 0, 0, 0, 0, 0, 0, -1, 0), #ifdef SUPPORT_FBP {0x50, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [WR_EN_VSR] = SPI_CMD(0x99, 0, 0, 0, 0, 0, 0, 0, -1, 0), #endif {0x5a, 3, 1, 0, 0, 8, 1, 1, -1, 1},// [READ_SFDP] = SPI_CMD(0x5a, 3, 1, 0, 0, 8, 1, 1, -1, 1), /* END Mark */ {0x00, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [MAX_CMD] = SPI_CMD(0x00, 0, 0, 0, 0, 0, 0, 0, -1, 0), }; /* Standard SPI-NOR flash QPI commands */ static struct spi_flash_cmd_cfg cmd_table_qpi[] = { /*opcode addr_bytes addr_pins mode_bits mode_pins dummy_cycles dummy_pins data_pins seq_id cmd_type */ {0xb7, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [ENABLE_4BYTE_QPI] = SPI_CMD(0xb7, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0xe9, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [DISABLE_4BYTE_QPI] = SPI_CMD(0xe9, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x05, 0, 0, 0, 0, 0, 0, 4, -1, 1},// [READ_STATUS1_QPI] = SPI_CMD(0x05, 0, 0, 0, 0, 0, 0, 4, 2, 1), {0x35, 0, 0, 0, 0, 0, 0, 4, -1, 1},// [READ_STATUS2_QPI] = SPI_CMD(0x35, 0, 0, 0, 0, 0, 0, 4, -1, 1), {0x11, 0, 0, 0, 0, 0, 0, 4, -1, 1},// [READ_STATUS3_QPI] = SPI_CMD(0x11, 0, 0, 0, 0, 0, 0, 4, -1, 1), {0x15, 0, 0, 0, 0, 0, 0, 4, -1, 1},// [READ_STATUS2_MXIC_QPI] = SPI_CMD(0x15, 0, 0, 0, 0, 0, 0, 4, -1, 1), {0x01, 0, 0, 0, 0, 0, 0, 4, -1, 2},// [WRITE_STATUS_QPI] = SPI_CMD(0x01, 0, 0, 0, 0, 0, 0, 4, -1, 2), {0x31, 0, 0, 0, 0, 0, 0, 4, -1, 2},// [WRITE_STATUS2_QPI] = SPI_CMD(0x31, 0, 0, 0, 0, 0, 0, 4, -1, 2), {0x0b, 3, 4, 0, 0, 8, 4, 4, -1, 1},// [READ_FAST_QPI] = SPI_CMD(0x0b, 3, 4, 0, 0, 8, 4, 4, 3, 1), {0xeb, 3, 4, 0, 0, 8, 4, 4, -1, 1},// [READ_FAST_QUAD_QPI] = SPI_CMD(0xeb, 3, 4, 0, 0, 8, 4, 4, 4, 1), {0x20, 3, 4, 0, 0, 0, 0, 0, -1, 0},// [SECTOR_ERASE_4K_QPI] = SPI_CMD(0x20, 3, 4, 0, 0, 0, 0, 0, -1, 0), {0x52, 3, 4, 0, 0, 0, 0, 0, -1, 0},// [BLK_ERASE_32K_QPI] = SPI_CMD(0x52, 3, 4, 0, 0, 0, 0, 0, -1, 0), {0xd8, 3, 4, 0, 0, 0, 0, 0, -1, 0},// [BLK_ERASE_64K_QPI] = SPI_CMD(0xd8, 3, 4, 0, 0, 0, 0, 0, -1, 0), {0xc7, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [CHIP_ERASE_QPI] = SPI_CMD(0xc7, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x02, 3, 4, 0, 0, 0, 0, 4, -1, 2},// [PROG_QPI] = SPI_CMD(0x02, 3, 4, 0, 0, 0, 0, 4, 5, 2), {0x06, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [WR_ENABLE_QPI] = SPI_CMD(0x06, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x04, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [WR_DISABLE_QPI] = SPI_CMD(0x04, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x9f, 0, 0, 0, 0, 0, 0, 4, -1, 1},// [READ_ID_QPI] = SPI_CMD(0x9f, 0, 0, 0, 0, 0, 0, 4, -1, 1), {0xaf, 0, 0, 0, 0, 0, 0, 4, -1, 1},// [READ_QPIID] = SPI_CMD(0xaf, 0, 0, 0, 0, 0, 0, 4, -1, 1), {0xff, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [DISABLE_QPI] = SPI_CMD(0xff, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0xf5, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [DISABLE_QPI_MXIC] = SPI_CMD(0xf5, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0xc0, 0, 0, 0, 0, 0, 0, 4, -1, 2},// [SET_READ_PARA_QPI] = SPI_CMD(0xc0, 0, 0, 0, 0, 0, 0, 4, -1, 2), {0x75, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [PGM_ERS_SUSPEND_QPI] = SPI_CMD(0x75, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x7a, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [PGM_ERS_RESUME_QPI] = SPI_CMD(0x7a, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0xb0, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [PGM_ERS_SUSPEND_MXIC_QPI]= SPI_CMD(0xb0, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x30, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [PGM_ERS_RESUME_MXIC_QPI]= SPI_CMD(0x30, 0, 0, 0, 0, 0, 0, 0, -1, 0), #ifdef SUPPORT_FBP {0x50, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [WR_EN_VSR_QPI] = SPI_CMD(0x99, 0, 0, 0, 0, 0, 0, 0, -1, 0), #endif {0x66, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [EN_RST_QPI] = SPI_CMD(0x66, 0, 0, 0, 0, 0, 0, 0, -1, 0), {0x99, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [RESET_QPI] = SPI_CMD(0x99, 0, 0, 0, 0, 0, 0, 0, -1, 0), /* END Mark */ {0x00, 0, 0, 0, 0, 0, 0, 0, -1, 0},// [MAX_CMD_QPI] = SPI_CMD(0x00, 0, 0, 0, 0, 0, 0, 0, -1, 0), }; #pragma arm section zidata="SPI_NOR_CHIP" static struct spi_flash_chip nor_chip; #pragma arm section zidata static uint8_t ilog2(unsigned int v) { uint8_t l = 0; while ((1UL << l) < v) l++; return l; } void *qspi_memset(void *str, int c, unsigned int count) { void *s = str; while (count --) { *(char *) s = (char) c; s = (char *) s + 1; } return str; } static TaskSuspendCB XipTaskSuspendCB[XIP_MAX_TASK_ID] = {NULL}; static TaskResumeCB TaskTaskResumeCB[XIP_MAX_TASK_ID] = {NULL}; void spi_nor_register_xip_task_cb(XipTaskID TaskId, TaskSuspendCB suspend, TaskResumeCB resume) { ASSERT(TaskId < XIP_MAX_TASK_ID); XipTaskSuspendCB[TaskId] = suspend; TaskTaskResumeCB[TaskId] = resume; } void spi_nor_suspend_task_xip(void) { int i = 0; if(!SysIsAssert()) { for(i = 0; i < XIP_MAX_TASK_ID; i++) { if(XipTaskSuspendCB[i] != NULL) { XipTaskSuspendCB[i](); } } crane_ds_mpu_xip_enable(FALSE); } } void spi_nor_resume_task_xip(void) { int i = 0; if(!SysIsAssert()) { crane_ds_mpu_xip_enable(TRUE); for(i = 0; i < XIP_MAX_TASK_ID; i++) { if(TaskTaskResumeCB[i] != NULL) { TaskTaskResumeCB[i](); } } } } /** * spi_nor_read_id - send 9Fh command to get ID * @chip: SPI_FLASH device structure * @buf: buffer to store id */ static int spi_nor_read_id(struct spi_flash_chip *chip, uint8_t *buf) { struct spi_flash_cmd cmd; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + READ_ID_QPI; else cmd.cmd_cfg = chip->table + READ_ID; cmd.n_rx = 3; cmd.rx_buf = buf; return qspi_start_cmd(chip, &cmd); } static int spi_nor_read_uid(struct spi_flash_chip *chip, uint8_t *buf) { struct spi_flash_cmd cmd; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); cmd.cmd_cfg = chip->table + READ_UID; cmd.n_rx = 8; cmd.rx_buf = buf; return qspi_start_cmd(chip, &cmd); } static int spi_nor_read_qpiid(struct spi_flash_chip *chip, uint8_t *buf) { struct spi_flash_cmd cmd; if (!chip->qpi_enabled) { uart_printf("err: not in qpi mode\r\n"); return -1; } qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); cmd.cmd_cfg = chip->table + READ_QPIID; cmd.n_rx = 3; cmd.rx_buf = buf; return qspi_start_cmd(chip, &cmd); } /** * spi_nor_reset - send command to reset chip. * @chip: SPI_FLASH device structure */ static int spi_nor_reset(struct spi_flash_chip *chip) { struct spi_flash_cmd cmd; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + EN_RST_QPI; else cmd.cmd_cfg = chip->table + EN_RST; if (qspi_start_cmd(chip, &cmd) != 0) uart_printf("spi_nor enable reset failed!\n"); if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + RESET_QPI; else cmd.cmd_cfg = chip->table + RESET; if (qspi_start_cmd(chip, &cmd) != 0) uart_printf("spi_nor reset failed!\n"); /* elapse 2ms before issuing any other command */ udelay(2000); return 0; } /** * spi_nor_write_enable - send command 06h to enable write or erase the * Nand cells * @chip: SPI_FLASH device structure * Description: * Before write and erase the Nand cells, the write enable has to be set. * After the write or erase, the write enable bit is automatically * cleared (status register bit 2) * Set the bit 2 of the status register has the same effect */ int spi_nor_write_enable(struct spi_flash_chip *chip) { struct spi_flash_cmd cmd; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + WR_ENABLE_QPI; else cmd.cmd_cfg = chip->table + WR_ENABLE; return qspi_start_cmd(chip, &cmd); } #ifdef SUPPORT_FBP int spi_nor_write_volatile_status_register_enable(struct spi_flash_chip *chip) { struct spi_flash_cmd cmd; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + WR_EN_VSR_QPI; else cmd.cmd_cfg = chip->table + WR_EN_VSR; return qspi_start_cmd(chip, &cmd); } #endif #ifdef SW_HANDLE_XIP #ifdef DEBUG_XIP_SUSPEND UINT32 spi_suspend_cnt=0; static UINT32 spi_resume_cnt=0; static UINT32 spi_suspend_start_tick=0; static UINT32 spi_suspend_total_tick=0; static UINT32 spi_erase_start_tick = 0; static UINT32 spi_erase_end_tick = 0; UINT32 spi_suspend_PC[64]={0}; #endif int spi_nor_suspend_resume(struct spi_flash_chip *chip, int cmd_index, int flag) { struct spi_flash_cmd cmd; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); cmd.cmd_cfg = chip->table + cmd_index; cmd.flag = flag; return qspi_start_cmd(chip, &cmd); } extern int T32kCountInitialized; extern int fota_donwloading; static unsigned long resume_stratTick=0,resume_stopTick=0; /*[Resume to another suspend time]tRS > 100us*/ #define QSPI_TRS_TICK 5 //120us ~ 150us UINT32 RESUME_SUSPEND_TRS = 0;//XM25QU16C tRS > 1000us /*[Suspend to read ready]tSUS > 20us*/ #define QSPI_TSUS_TICK 2 UINT32 SUSPEND_READY_TSUS = 0;//XM25LU16C tSUS > 120us int spi_nor_suspend(struct spi_flash_chip *chip) { int ret , cmd_index; unsigned long stratTick,stopTick,consumeTick; unsigned long tRS_timewait = QSPI_TRS_TICK; uint8_t status; if (chip->mfr_id == SPIFLASH_MFR_MXIC) cmd_index = PGM_ERS_SUSPEND_MXIC; else cmd_index = PGM_ERS_SUSPEND; if(fota_donwloading && RESUME_SUSPEND_TRS){ tRS_timewait = RESUME_SUSPEND_TRS; } /*[Resume to another suspend time]tRS > 100us*/ if(T32kCountInitialized && resume_stratTick!=0){ resume_stopTick = get_current_TStimer_tick(); if(resume_stopTick < resume_stratTick){ consumeTick = (0xFFFFFFFF - resume_stratTick) + resume_stopTick; }else{ consumeTick = resume_stopTick - resume_stratTick; } while(consumeTick < tRS_timewait) { //udelay(10); resume_stopTick = get_current_TStimer_tick(); if(resume_stopTick < resume_stratTick){ consumeTick = (0xFFFFFFFF - resume_stratTick) + resume_stopTick; }else{ consumeTick = resume_stopTick - resume_stratTick; } } }else{ udelay(3000); } #ifdef DEBUG_XIP_SUSPEND spi_suspend_start_tick = get_current_TStimer_tick(); spi_suspend_cnt++; #endif ret = spi_nor_suspend_resume(chip, cmd_index, SUSPEND_CMD); if(SUSPEND_READY_TSUS){ //XM25LU16C tSUS sometimes need more than 120us,using status busy to check stratTick = 0; stopTick = 0; if(T32kCountInitialized) stratTick = get_current_TStimer_tick(); while(1){ spi_nor_read_status1(chip, &status); if ((status & STATUS_OIP_MASK) == STATUS_READY) { break; } } if(T32kCountInitialized && stratTick){ stopTick = get_current_TStimer_tick(); if(stopTick < stratTick){ consumeTick = (0xFFFFFFFF - stratTick) + stopTick; }else{ consumeTick = stopTick - stratTick; } if(consumeTick > SUSPEND_READY_TSUS) { SUSPEND_READY_TSUS = consumeTick; } } }else{ /*[Suspend to read ready]tSUS > 20us*/ if(T32kCountInitialized){ stratTick = get_current_TStimer_tick(); stopTick = get_current_TStimer_tick(); if(stopTick < stratTick){ consumeTick = (0xFFFFFFFF - stratTick) + stopTick; }else{ consumeTick = stopTick - stratTick; } while(consumeTick < QSPI_TSUS_TICK) { udelay(10); stopTick = get_current_TStimer_tick(); if(stopTick < stratTick){ consumeTick = (0xFFFFFFFF - stratTick) + stopTick; }else{ consumeTick = stopTick - stratTick; } } }else{ udelay(1000);//30us } } crane_ds_mpu_xip_cache_enable(); //uart_printf("spi_nor_suspend delay %08x\r\n",used_time); return ret; } int spi_nor_resume(struct spi_flash_chip *chip) { int cmd_index; int res; if (chip->mfr_id == SPIFLASH_MFR_MXIC) cmd_index = PGM_ERS_RESUME_MXIC; else cmd_index = PGM_ERS_RESUME; #ifdef DEBUG_XIP_SUSPEND spi_resume_cnt++; #endif crane_ds_mpu_xip_cache_disable(); res = spi_nor_suspend_resume(chip, cmd_index, RESUME_CMD); #ifdef DEBUG_XIP_SUSPEND spi_suspend_total_tick += get_current_TStimer_tick() - spi_suspend_start_tick; #endif if(T32kCountInitialized){ resume_stratTick = get_current_TStimer_tick(); } return res; } #endif /** * spi_nor_read_status - get status register value * @chip: SPI_FLASH device structure * @status: buffer to store value * Description: * After read, write, or erase, the Nand device is expected to set the * busy status. * This function is to allow reading the status of the command: read, * write, and erase. * Once the status turns to be ready, the other status bits also are * valid status bits. */ static int spi_nor_read_status(struct spi_flash_chip *chip, uint8_t index, uint8_t *status) { struct spi_flash_cmd cmd; int ret; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); cmd.cmd_cfg = chip->table + index; cmd.n_rx = 1; cmd.rx_buf = status; ret = qspi_start_cmd(chip, &cmd); if (ret != 0) uart_printf("err: read register %d\n", ret); return ret; } int spi_nor_read_status1(struct spi_flash_chip *chip, uint8_t *status) { uint8_t cmd_index; if (chip->qpi_enabled) cmd_index = READ_STATUS1_QPI; else cmd_index = READ_STATUS1; return spi_nor_read_status(chip, cmd_index, status); } int spi_nor_read_status2(struct spi_flash_chip *chip, uint8_t *status) { uint8_t cmd_index; if (chip->mfr_id == SPIFLASH_MFR_MXIC) { /* Not support SPINOR_CMD_READ_STATUS2 for 32MB spi-nor */ if (chip->dev_id == 0x2536) return 0; if (chip->qpi_enabled) cmd_index = READ_STATUS2_MXIC_QPI; else cmd_index = READ_STATUS2_MXIC; } else { if (chip->qpi_enabled) cmd_index = READ_STATUS2_QPI; else cmd_index = READ_STATUS2; } return spi_nor_read_status(chip, cmd_index, status); } static int spi_nor_read_status3(struct spi_flash_chip *chip, uint8_t *status) { uint8_t cmd_index; if (chip->qpi_enabled) cmd_index = READ_STATUS3_QPI; else cmd_index = READ_STATUS3; return spi_nor_read_status(chip, cmd_index, status); } /** * spi_nor_write_reg - send command 1Fh to write register * @chip: SPI_FLASH device structure * @reg; register to write * @buf: buffer stored value */ int spi_nor_write_status1(struct spi_flash_chip *chip, uint8_t *buf, uint8_t count) { struct spi_flash_cmd cmd; int ret; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + WRITE_STATUS_QPI; else cmd.cmd_cfg = chip->table + WRITE_STATUS; cmd.n_tx = count; cmd.tx_buf = buf; ret = qspi_start_cmd(chip, &cmd); if (ret != 0) uart_printf("err: %d write status1\n", ret); return ret; } int spi_nor_write_status2(struct spi_flash_chip *chip, uint8_t *buf) { struct spi_flash_cmd cmd; int ret; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + WRITE_STATUS2_QPI; else cmd.cmd_cfg = chip->table + WRITE_STATUS2; cmd.n_tx = 1; cmd.tx_buf = buf; ret = qspi_start_cmd(chip, &cmd); if (ret != 0) uart_printf("err: %d write status2\n", ret); return ret; } /** * spi_nor_wait - wait until the command is done * @chip: SPI_FLASH device structure * @s: buffer to store status register(can be NULL) */ #ifdef SW_HANDLE_XIP int spi_nor_wait(struct spi_flash_chip *chip, uint8_t *s, int pe, unsigned int *p_cpsr) { uint8_t status; int ret = -ETIMEDOUT; unsigned int cpsr; while (1) { if (qspi_need_send_resume()) { cpsr=disable_interupt_for_qspi(); spi_nor_resume(chip); enable_interupt_for_qspi(cpsr); } if (pe) cpsr=disable_interupt_for_qspi(); spi_nor_read_status1(chip, &status); if ((status & STATUS_OIP_MASK) == STATUS_READY) { /* * Re-enable interrupt in erase/program after * clear QSPI_MCR_SW_HANDLE_XIP */ if (!qspi_need_send_resume()) { ret = 0; if (pe) *p_cpsr=cpsr; goto out; } } if (pe) enable_interupt_for_qspi(cpsr); } out: if (s) *s = status; return ret; } #else int spi_nor_wait(struct spi_flash_chip *chip, uint8_t *s) { uint8_t status; uint32_t sr, fr; unsigned long ret = ETIMEDOUT; unsigned int cpsr; while (1) { #ifndef CRANE_MCU_DONGLE cpsr=disableInterrupts(); //need protect if use SW to send SUSPEND/RESUME #endif do { sr = _readl(QSPI0_SR); fr = _readl(QSPI0_FR); if (!(sr & QSPI0_SR_BUSY) && !(fr & QSPI0_FR_XIP_ON)) break; } while(1); spi_nor_read_status1(chip, &status); #ifndef CRANE_MCU_DONGLE restoreInterrupts(cpsr); #endif if ((status & STATUS_OIP_MASK) == STATUS_READY) { ret = 0; goto out; } } out: if (s) *s = status; return ret; } #endif /** * spi_nor_erase_block_erase - send command D8h to erase a block * @chip: SPI_FLASH device structure * @addr: the flash addr to erase. * Description: * Need to wait for tERS. */ static int spi_nor_erase_sector(struct spi_flash_chip *chip, uint32_t addr) { struct spi_flash_cmd cmd; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + SECTOR_ERASE_4K_QPI; else cmd.cmd_cfg = chip->table + SECTOR_ERASE_4K; if (chip->en_addr_4byte) { cmd.n_addr = 4; cmd.addr[0] = (uint8_t)(addr >> 24); cmd.addr[1] = (uint8_t)(addr >> 16); cmd.addr[2] = (uint8_t)(addr >> 8); cmd.addr[3] = (uint8_t)addr; } else { cmd.n_addr = 3; cmd.addr[0] = (uint8_t)(addr >> 16); cmd.addr[1] = (uint8_t)(addr >> 8); cmd.addr[2] = (uint8_t)addr; } cmd.flag = RST_AHB_DOMAIN; return qspi_start_cmd(chip, &cmd); } /** * spi_nor_erase_block_erase - send command D8h to erase a block * @chip: SPI_FLASH device structure * @addr: the flash addr to erase. * Description: * Need to wait for tERS. */ static int spi_nor_erase_block(struct spi_flash_chip *chip, uint32_t addr) { struct spi_flash_cmd cmd; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->block_size < 64*1024) { if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + BLK_ERASE_32K_QPI; else cmd.cmd_cfg = chip->table + BLK_ERASE_32K; } else { if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + BLK_ERASE_64K_QPI; else cmd.cmd_cfg = chip->table + BLK_ERASE_64K; } if (chip->en_addr_4byte) { cmd.n_addr = 4; cmd.addr[0] = (uint8_t)(addr >> 24); cmd.addr[1] = (uint8_t)(addr >> 16); cmd.addr[2] = (uint8_t)(addr >> 8); cmd.addr[3] = (uint8_t)addr; } else { cmd.n_addr = 3; cmd.addr[0] = (uint8_t)(addr >> 16); cmd.addr[1] = (uint8_t)(addr >> 8); cmd.addr[2] = (uint8_t)addr; } cmd.flag = RST_AHB_DOMAIN | SW_PROG_ERASE; return qspi_start_cmd(chip, &cmd); } static int spi_nor_erase_chip(struct spi_flash_chip *chip) { struct spi_flash_cmd cmd; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + CHIP_ERASE_QPI; else cmd.cmd_cfg = chip->table + CHIP_ERASE; cmd.flag = RST_AHB_DOMAIN; return qspi_start_cmd(chip, &cmd); } static int spi_nor_erase_all(struct spi_flash_chip *chip) { uint8_t status; int ret = 0; #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) unsigned int cpsr=0; unsigned long CurrentTick; unsigned long flag_value = 0; Boolean flush_flash = TRUE; #endif spi_nor_write_enable(chip); spi_nor_erase_chip(chip); #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) CPUartLogPrintf("spi_nor_erase_all"); CurrentTick = get_current_TStimer_tick(); if(L1aCheckHasRxModeReport()==TRUE){ do{ flush_flash = LteMacSendEcphyFlashDspReq(0, 1, 4600*512, CurrentTick); if(flush_flash ) break; spi_nor_delay(); }while(1); flag_value = 1; CPUartLogPrintf("LteMacSendEcphyFlashDspReq done\r\n"); } cpsr=disableInterrupts(); #elif (defined(CRANE_MCU_DONGLE) && !defined(SW_HANDLE_XIP)) spi_nor_suspend_task_xip(); #endif #ifdef SW_HANDLE_XIP ret = spi_nor_wait(chip, &status,0, NULL); #else ret = spi_nor_wait(chip, &status); #endif #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) if(flag_value) OS_Activate_HISR(&send_ipc_hisr); restoreInterrupts(cpsr); if(flag_value) OSAFlagWait(send_ipc_flag, SEND_IPC_FLAG,OSA_FLAG_OR_CLEAR,&flag_value,OSA_SUSPEND); CPUartLogPrintf("spi_nor_erase_all done"); #elif (defined(CRANE_MCU_DONGLE) && !defined(SW_HANDLE_XIP)) spi_nor_resume_task_xip(); #endif if (ret != 0) { uart_printf("chip erase command wait failed\n"); return ret; } return 0; } static int spi_nor_enable_4byte_mode(struct spi_flash_chip *chip) { struct spi_flash_cmd cmd; uint8_t data[3]; uint8_t status, en4b_shift; uint32_t sdata; int ret; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + ENABLE_4BYTE_QPI; else cmd.cmd_cfg = chip->table + ENABLE_4BYTE; ret = qspi_start_cmd(chip, &cmd); if (ret != 0) { uart_printf("enable_4byte mode failed\r\n"); return ret; } chip->en_addr_4byte = 1; /* * Macronix use status register bit S13 for EN4B * Gigadevice use status register bit S11 * WinBond use status register bit S17 */ if (chip->mfr_id == SPIFLASH_MFR_MXIC) en4b_shift = 13; else if (chip->mfr_id == SPIFLASH_MFR_GIGADEVICE) en4b_shift = 11; else if (chip->mfr_id == SPIFLASH_MFR_WINBOND) en4b_shift = 16; else { uart_printf("EN4B: lack vendor status bit info\r\n"); return 0; } if (en4b_shift >= 16) spi_nor_read_status3(chip, &data[2]); else if (en4b_shift >= 8) spi_nor_read_status2(chip, &data[1]); else spi_nor_read_status1(chip, &data[0]); sdata = data[2] << 16 | data[1] << 8 | data[0]; if (!(sdata & (1 << en4b_shift))) { uart_printf("Failed to enable 4byte mode: bit%d\r\n", en4b_shift); chip->en_addr_4byte = 0; return -1; } uart_printf("Enter 4byte address mode, bit%d\r\n", en4b_shift); return 0; } static int spi_nor_disable_4byte_mode(struct spi_flash_chip *chip) { struct spi_flash_cmd cmd; int ret; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->qpi_enabled) cmd.cmd_cfg = chip->table + DISABLE_4BYTE_QPI; else cmd.cmd_cfg = chip->table + DISABLE_4BYTE; ret = qspi_start_cmd(chip, &cmd); if (ret != 0) { uart_printf("Failed to disable 4byte_mode\r\n"); return ret; } chip->en_addr_4byte = 0; return 0; } /** * spi_nor_erase - [Interface] erase block(s) * @chip: spi flash device structure * @addr: address that erase start with, should be blocksize aligned * @len: length that want to be erased, should be blocksize aligned * Description: * Erase one ore more blocks * The command sequence for the BLOCK ERASE operation is as follows: * 06h (WRITE ENBALE command) * D8h (BLOCK ERASE command) * 0Fh (GET FEATURES command to read the status register) */ int spi_nor_erase(struct spi_flash_chip *chip, uint32_t addr, int len) { uint8_t status; int erase_len; int ret = 0; unsigned long CurrentTick; unsigned int cpsr; uint32_t sr, fr; #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) unsigned long flag_value = 0; Boolean flush_flash = TRUE; #endif /* reset AHB buffer */ { int dummy, start_page, end_page, dummy_addr; start_page = addr & ~chip->page_mask; if (start_page >= chip->page_size) { dummy_addr = start_page - chip->page_size; } else { end_page = (addr + len -1) & ~chip->page_mask; end_page += chip->page_size; if (end_page < chip->size){ /* * Add extra 128 Byte to make sure dummy_addr * is out of AHB buffer range */ dummy_addr = end_page + 128; } else dummy_addr = 0; } if (dummy_addr != addr) { dummy_addr += chip->host->cs_addr[chip->cs]; dcache_invalidate_range(dummy_addr, chip->page_size); qspi_memcpy(&dummy, (void *)dummy_addr, 4); } } erase_len = chip->block_size; #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) CPUartLogPrintf("spi_nor_erase,len[%08x]",len); CurrentTick = get_current_TStimer_tick(); if(L1aCheckHasRxModeReport()==TRUE){ do{ flush_flash==LteMacSendEcphyFlashDspReq(0, 1, 4600*16, CurrentTick); if(flush_flash) break; spi_nor_delay(); }while(1); flag_value = 1; CPUartLogPrintf("LteMacSendEcphyFlashDspReq done\r\n"); } cpsr=disableInterrupts(); #elif (defined(CRANE_MCU_DONGLE) && !defined(SW_HANDLE_XIP)) spi_nor_suspend_task_xip(); #endif while (len > 0) { spi_nor_write_enable(chip); #ifdef SW_HANDLE_XIP cpsr=disable_interupt_for_qspi(); #endif qspi_enable_ahb_preempt(1); spi_nor_erase_block(chip, addr); #ifdef SW_HANDLE_XIP crane_ds_mpu_xip_cache_disable(); enable_interupt_for_qspi(cpsr); ret = spi_nor_wait(chip, &status, 1, &cpsr); #else ret = spi_nor_wait(chip, &status); #endif qspi_enable_ahb_preempt(0); #ifdef SW_HANDLE_XIP crane_ds_mpu_xip_cache_enable(); enable_interupt_for_qspi(cpsr); #endif len -= erase_len; addr += erase_len; if (addr >= chip->size) break; } #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) if(flag_value) OS_Activate_HISR(&send_ipc_hisr); restoreInterrupts(cpsr); if(flag_value) OSAFlagWait(send_ipc_flag, SEND_IPC_FLAG,OSA_FLAG_OR_CLEAR,&flag_value,OSA_SUSPEND); CPUartLogPrintf("spi_nor_erase done"); #elif (defined(CRANE_MCU_DONGLE) && !defined(SW_HANDLE_XIP)) spi_nor_resume_task_xip(); #endif return ret; } #define CHIP_SECTOR_SIZE 0x1000 int spi_nor_erase_4k(struct spi_flash_chip *chip, uint32_t addr, int len) { uint8_t status; int ret = 0; unsigned int cpsr; char lab; unsigned long CurrentTick; #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) unsigned long flag_value = 0; Boolean flush_flash = TRUE; #endif #ifdef SW_HANDLE_XIP #ifdef DEBUG_XIP_SUSPEND unsigned int resume_us=0; CPUartLogPrintf("spi_nor_erase_4k,addr[%08x], len[%08x]",addr, len); unsigned int start_tick=get_current_TStimer_tick(); #endif #endif /* reset AHB buffer */ { int dummy, start_page, end_page, dummy_addr; start_page = addr & ~chip->page_mask; if (start_page >= chip->page_size) { dummy_addr = start_page - chip->page_size; } else { end_page = (addr + len -1) & ~chip->page_mask; end_page += chip->page_size; if (end_page < chip->size){ /* * Add extra 128 Byte to make sure dummy_addr * is out of AHB buffer range */ dummy_addr = end_page + 128; } else dummy_addr = 0; } if (dummy_addr != addr) { dummy_addr += chip->host->cs_addr[chip->cs]; dcache_invalidate_range(dummy_addr, chip->page_size); qspi_memcpy(&dummy, (void *)dummy_addr, 4); } } #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) CPUartLogPrintf("spi_nor_erase_4k,len[%08x]\r\n",len); CurrentTick = get_current_TStimer_tick(); if(L1aCheckHasRxModeReport()==TRUE){ do{ flush_flash=LteMacSendEcphyFlashDspReq(0, 1, 4600, CurrentTick); if(flush_flash) break; spi_nor_delay(); }while(1); flag_value = 1; CPUartLogPrintf("LteMacSendEcphyFlashDspReq done\r\n"); } cpsr=disableInterrupts(); #elif (defined(CRANE_MCU_DONGLE) && !defined(SW_HANDLE_XIP)) spi_nor_suspend_task_xip(); #endif while (len) { spi_nor_write_enable(chip); #ifdef SW_HANDLE_XIP cpsr=disable_interupt_for_qspi(); #endif qspi_enable_ahb_preempt(1); spi_nor_erase_sector(chip, addr); #ifdef SW_HANDLE_XIP crane_ds_mpu_xip_cache_disable(); #ifdef DEBUG_XIP_SUSPEND spi_erase_start_tick = get_current_TStimer_tick(); #endif enable_interupt_for_qspi(cpsr); #ifdef DEBUG_XIP_SUSPEND CPUartLogPrintf("spi_nor_wait start"); spi_suspend_cnt = 0; spi_resume_cnt = 0; spi_suspend_total_tick = 0; memset(spi_suspend_PC, 0,sizeof(spi_suspend_PC)); #endif ret = spi_nor_wait(chip, &status, 1, &cpsr); #ifdef DEBUG_XIP_SUSPEND spi_erase_end_tick = get_current_TStimer_tick(); CPUartLogPrintf("spi_nor_wait end,suspend:resume[%d][%d], total[%d ms], resume[%d ms]\r\n",spi_suspend_cnt,spi_resume_cnt, (((spi_erase_end_tick - spi_erase_start_tick)*1000)/32768),(((spi_erase_end_tick - spi_erase_start_tick - spi_suspend_total_tick)*1000)/32768)); #endif #else ret = spi_nor_wait(chip, &status); #endif qspi_enable_ahb_preempt(0); #ifdef SW_HANDLE_XIP crane_ds_mpu_xip_cache_enable(); enable_interupt_for_qspi(cpsr); #endif len -= CHIP_SECTOR_SIZE; addr += CHIP_SECTOR_SIZE; } #if 0 #ifdef SW_HANDLE_XIP #ifdef DEBUG_XIP_SUSPEND if(spi_suspend_cnt){ resume_us = (spi_erase_end_tick - spi_erase_start_tick - spi_suspend_total_tick)*30; //tRS + tSUS = 120us //if((spi_suspend_cnt > 1500) && ((resume_us/spi_suspend_cnt) < 120)) if(spi_suspend_cnt > 1500) { int k; RTI_LOG("spi_nor_wait end,suspend:resume[%d][%d], total[%d ms], resume[%d ms],cycle[%d us]\r\n",spi_suspend_cnt,spi_resume_cnt, (((spi_erase_end_tick - spi_erase_start_tick)*1000)/32768),(((spi_erase_end_tick - spi_erase_start_tick - spi_suspend_total_tick)*1000)/32768), ((resume_us/spi_suspend_cnt) < 120)); for(k=0; k<(sizeof(spi_suspend_PC)/16); k++) RTI_LOG("suspendPC:[%d-%d]0x%x,0x%x,0x%x,0x%x\r\n",4*k,4*k+3, spi_suspend_PC[4*k],spi_suspend_PC[4*k+1],spi_suspend_PC[4*k+2],spi_suspend_PC[4*k+3]); ASSERT(0); } } #endif #endif #endif #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) if(spi_nor_test_leval==1){ spi_nor_loop_delay(160*1000*100); }else if(spi_nor_test_leval==2){ spi_nor_loop_delay(200*1000*100); } if(flag_value) OS_Activate_HISR(&send_ipc_hisr); restoreInterrupts(cpsr); if(flag_value) OSAFlagWait(send_ipc_flag, SEND_IPC_FLAG,OSA_FLAG_OR_CLEAR,&flag_value,OSA_SUSPEND); CPUartLogPrintf("spi_nor_erase_4k done\r\n"); #elif (defined(CRANE_MCU_DONGLE) && !defined(SW_HANDLE_XIP)) spi_nor_resume_task_xip(); #endif return ret; } static int spi_nor_read(struct spi_flash_chip *chip, int addr, int size, uint8_t *rbuf) { struct spi_flash_cmd cmd; if (chip->host->xip_read) { addr += chip->host->cs_addr[chip->cs]; qspi_memcpy(rbuf, (void *)addr, size); return 0; } qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); cmd.cmd_cfg = chip->table + chip->read_op; if (chip->en_addr_4byte) { cmd.n_addr = 4; cmd.addr[0] = (uint8_t)((addr >> 24) & 0xff); cmd.addr[1] = (uint8_t)((addr >> 16) & 0xff); cmd.addr[2] = (uint8_t)((addr >> 8) & 0xff); cmd.addr[3] = (uint8_t)(addr & 0xff); } else { cmd.n_addr = 3; cmd.addr[0] = (uint8_t)((addr >> 16) & 0xff); cmd.addr[1] = (uint8_t)((addr >> 8) & 0xff); cmd.addr[2] = (uint8_t)(addr & 0xff); } cmd.n_rx = size; cmd.rx_buf = rbuf; cmd.mode = 0xff; return qspi_start_cmd(chip, &cmd); } /** * spi_nor_program_data_to_cache - write data to cache register * @chip: SPI_FLASH device structure * @page_addr: page to write * @column: the location to write to the cache * @len: number of bytes to write * @wrbuf: buffer held @len bytes * @clr_cache: clear cache register or not * Description: * Command can be 02h, 32h, 84h, 34h * 02h and 32h will clear the cache with 0xff value first * Since it is writing the data to cache, there is no tPROG time. */ static int spi_nor_program_data(struct spi_flash_chip *chip, uint32_t addr, int len, const uint8_t *wbuf) { struct spi_flash_cmd cmd; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); cmd.cmd_cfg = chip->table + chip->write_op; if (chip->en_addr_4byte) { cmd.n_addr = 4; cmd.addr[0] = (uint8_t)((addr >> 24) & 0xff); cmd.addr[1] = (uint8_t)((addr >> 16) & 0xff); cmd.addr[2] = (uint8_t)((addr >> 8) & 0xff); cmd.addr[3] = (uint8_t)(addr & 0xff); } else { cmd.n_addr = 3; cmd.addr[0] = (uint8_t)((addr >> 16) & 0xff); cmd.addr[1] = (uint8_t)((addr >> 8) & 0xff); cmd.addr[2] = (uint8_t)(addr & 0xff); } cmd.n_tx = len; cmd.tx_buf = wbuf; cmd.flag = RST_AHB_DOMAIN | SW_PROG_ERASE; return qspi_start_cmd(chip, &cmd); } static int spi_nor_write_page(struct spi_flash_chip *chip, int addr, int size, uint8_t *buf) { uint8_t status; int ret = 0; unsigned int cpsr; uint32_t sr, fr; #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) cpsr=disableInterrupts(); #elif (defined(CRANE_MCU_DONGLE) && !defined(SW_HANDLE_XIP)) spi_nor_suspend_task_xip(); #endif spi_nor_write_enable(chip); #ifdef SW_HANDLE_XIP cpsr=disable_interupt_for_qspi(); #endif qspi_enable_ahb_preempt(1); spi_nor_program_data(chip, addr, size, buf); #ifdef SW_HANDLE_XIP crane_ds_mpu_xip_cache_disable(); enable_interupt_for_qspi(cpsr); ret = spi_nor_wait(chip, &status, 1, &cpsr); #else ret = spi_nor_wait(chip, &status); #endif qspi_enable_ahb_preempt(0); #ifdef SW_HANDLE_XIP crane_ds_mpu_xip_cache_enable(); enable_interupt_for_qspi(cpsr); #endif #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) restoreInterrupts(cpsr); #elif (defined(CRANE_MCU_DONGLE) && !defined(SW_HANDLE_XIP)) spi_nor_resume_task_xip(); #endif if (ret != 0) { uart_printf("error %d reading page 0x%x from cache\n",ret, addr); return ret; } return ret; } int spi_nor_write(struct spi_flash_chip *chip, int addr, int size, uint8_t *buf) { int len, ret; unsigned int cpsr; unsigned long CurrentTick; #ifdef SW_HANDLE_XIP #ifdef DEBUG_XIP_SUSPEND CPUartLogPrintf("spi_nor_write,addr[%08x],size[%08x]\r\n",addr,size); #endif #endif // uart_printf("spi_nor_write 0x%x 0x%x\r\n", addr, size); #if defined(FLASH_SEND_IPC) unsigned long flag_value = 0; Boolean flush_flash = TRUE; int num=1; if(size & (CHIP_SECTOR_SIZE-1)){ num = size/CHIP_SECTOR_SIZE + 1; }else{ num = size/CHIP_SECTOR_SIZE; } CPUartLogPrintf("spi_nor_write,size[%08x]\r\n",size); CurrentTick = get_current_TStimer_tick(); if(L1aCheckHasRxModeReport()==TRUE){ do{ flush_flash=LteMacSendEcphyFlashDspReq(0, 1, num*1000, CurrentTick); if(flush_flash) break; spi_nor_delay(); }while(1); flag_value = 1; CPUartLogPrintf("LteMacSendEcphyFlashDspReq done\r\n"); } #endif /* reset ahb buffer */ { int dummy, start_page, end_page, dummy_addr; start_page = addr & ~chip->page_mask; if (start_page >= chip->page_size) { dummy_addr = start_page - chip->page_size; } else { end_page = (addr + size -1) & ~chip->page_mask; end_page += chip->page_size; if (end_page < chip->size){ /* * Add extra 128 Byte to make sure dummy_addr * is out of AHB buffer range */ dummy_addr = end_page + 128; } else dummy_addr = 0; } if (dummy_addr != addr) { dummy_addr += chip->host->cs_addr[chip->cs]; dcache_invalidate_range(dummy_addr, chip->page_size); qspi_memcpy(&dummy, (void *)dummy_addr, 4); } } while (size) { len = chip->page_size - (addr & chip->page_mask); len = min(min(len, size), chip->tx_max_len); ret = spi_nor_write_page(chip, addr, len, buf); if (ret != 0) { uart_printf("page program failed\n"); break; } /* Increment page address and decrement length */ size -= len; addr += len; buf += len; } #if defined(FLASH_SEND_IPC) if(spi_nor_test_leval==1){ spi_nor_loop_delay(10*1000*100); }else if(spi_nor_test_leval==2){ spi_nor_loop_delay(30*1000*100); } if(flag_value){ OS_Activate_HISR(&send_ipc_hisr); OSAFlagWait(send_ipc_flag, SEND_IPC_FLAG,OSA_FLAG_OR_CLEAR,&flag_value,OSA_SUSPEND); } CPUartLogPrintf("spi_nor_write done\r\n"); #endif // uart_printf("spi_nor_write done\r\n"); #ifdef SW_HANDLE_XIP #ifdef DEBUG_XIP_SUSPEND CPUartLogPrintf("spi_nor_write done,addr[%08x],ret[%08x]\r\n",addr,ret); #endif #endif return ret; } static void spi_nor_set_rd_wr_op(struct spi_flash_chip *chip, uint32_t op_mode_rx, uint32_t op_mode_tx) { if (op_mode_rx & SPI_OPM_RX_QUAD) { if (chip->qpi_enabled) { chip->read_op = READ_FAST_QPI; } else { if (chip->mfr_id == SPIFLASH_MFR_GIGADEVICE || chip->mfr_id == SPIFLASH_MFR_ZETTADEVICE || chip->mfr_id == SPIFLASH_MFR_WINBOND || chip->mfr_id == SPIFLASH_MFR_PUYA || chip->mfr_id == SPIFLASH_MFR_ZBIT) { chip->read_op = READ_FAST_QUAD; } else { chip->read_op = READ_FAST_X4; } } } else if (op_mode_rx & SPI_OPM_RX_DUAL) { chip->read_op = READ_FAST_DUAL; } else { chip->read_op = READ_FAST; } if (op_mode_tx & SPI_OPM_TX_QUAD) { if (chip->qpi_enabled) { chip->write_op = PROG_QPI; } else { if (chip->mfr_id == SPIFLASH_MFR_MXIC) chip->write_op = PROG_X4_MXIC; else chip->write_op = PROG_X4; } } else { chip->write_op = PROG; } uart_printf("Set rx_pins: %d tx_pins: %d\r\n", op_mode_rx, op_mode_tx); } static int spi_set_read_parameters(struct spi_flash_chip *chip, uint8_t *buf) { struct spi_flash_cmd cmd; int ret = 0; if (!chip->qpi_enabled) return 0; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); cmd.cmd_cfg = chip->table + SET_READ_PARA_QPI; cmd.n_tx = 1; cmd.tx_buf = buf; ret = qspi_start_cmd(chip, &cmd); if (ret != 0) uart_printf("err: %d set_read_parameters\n", ret); return ret; } static int spi_nor_enable_quad(struct spi_flash_chip *chip) { uint8_t data[2]; uint8_t status, qe_shift; uint16_t sdata; int ret; /* * Macronix use status register bit s6 for QE enable * Winbond/Gigadevice use status register bit S9 */ if (chip->options & SPINOR_QE_USE_BIT6) qe_shift = 6; else qe_shift = 9; spi_nor_read_status1(chip, &data[0]); spi_nor_read_status2(chip, &data[1]); sdata = data[1] << 8 | data[0]; if (sdata & (1 << qe_shift)) { uart_printf("QE already set: bit%d\r\n", qe_shift); return 0; } sdata |= 1 << qe_shift; data[0] = sdata & 0xff; data[1] = sdata >> 8; spi_nor_write_enable(chip); if (qe_shift > 7) { if (chip->options & SPINOR_HAVE_WRITE_STATUS2) spi_nor_write_status2(chip, &data[1]); else spi_nor_write_status1(chip, data, 2); } else { if (chip->options & SPINOR_WRITE_STATUS1_1BYTE) spi_nor_write_status1(chip, data, 1); else spi_nor_write_status1(chip, data, 2); } #ifdef SW_HANDLE_XIP ret = spi_nor_wait(chip, &status, 0, NULL); #else ret = spi_nor_wait(chip, &status); #endif if (ret != 0) { uart_printf("error %d write status register\n", ret); return ret; } spi_nor_read_status1(chip, &data[0]); spi_nor_read_status2(chip, &data[1]); sdata = data[1] << 8 | data[0]; if (!(sdata & (1 << qe_shift))) { uart_printf("Failed to enable quad, maybe not supported\r\n"); return -1; } return 0; } static int spi_nor_disable_qpi(struct spi_flash_chip *chip) { struct spi_flash_cmd cmd; int ret = 0; if (!chip->qpi_enabled) return 0; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->mfr_id == SPIFLASH_MFR_MXIC) cmd.cmd_cfg = chip->table + DISABLE_QPI_MXIC; else cmd.cmd_cfg = chip->table + DISABLE_QPI; ret = qspi_start_cmd(chip, &cmd); if (ret != 0) return ret; chip->qpi_enabled = 0; chip->table = cmd_table; uart_printf("QPI Disabled\r\n"); return 0; } /* * QPI dummy clock depend on bus frequency * * Giga: {4, 6, 8, 8}, Winbond: {2, 4, 6, 8} * Macronix use a different way to set dummy clock */ static uint8_t qpi_dummy_wb[4][2] = { {2, 26}, {4, 50}, {6, 80}, {8, 104} }; static uint8_t qpi_dummy_gd[4][2] = { {4, 80}, {4, 80}, {6, 100}, {8, 133} }; static int spi_nor_enable_qpi(struct spi_flash_chip *chip) { struct spi_flash_cmd cmd; int ret = 0, i = 0; uint8_t cfg; uint8_t (*qpi_dummy)[2]; if (chip->qpi_enabled) return 0; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); if (chip->mfr_id == SPIFLASH_MFR_MXIC) cmd.cmd_cfg = chip->table + ENABLE_QPI_MXIC; else cmd.cmd_cfg = chip->table + ENABLE_QPI; ret = qspi_start_cmd(chip, &cmd); if (ret != 0) return ret; chip->qpi_enabled = 1; chip->table = cmd_table_qpi; if(chip->mfr_id == SPIFLASH_MFR_MXIC) { chip->qpi_dummy = 6; } else { if (chip->mfr_id == SPIFLASH_MFR_GIGADEVICE) qpi_dummy = qpi_dummy_gd; else qpi_dummy = qpi_dummy_wb; for (i = 0; i < 4; i++) { if(chip->host->bus_clk <= qpi_dummy[i][1]) { cfg = i << 4; chip->qpi_dummy = qpi_dummy[i][0]; break; } } ret = spi_set_read_parameters(chip, &cfg); if (ret != 0) return ret; } spi_nor_set_rd_wr_op(chip, SPI_OPM_RX_QUAD, SPI_OPM_TX_QUAD); uart_printf("QPI Enabled, P5-4:%d dummy_cycles:%d\r\n", i, chip->qpi_dummy); return 0; } static const struct spi_flash_ops qspi_ops = { spi_nor_reset, spi_nor_read_id, spi_nor_read_uid, spi_nor_read, spi_nor_write, spi_nor_erase, spi_nor_erase_4k, }; #if defined(FLASH_SEND_IPC) static void spi_nor_send_ipc(void) { unsigned long exit_CurrentTick; exit_CurrentTick = get_current_TStimer_tick(); if(L1aCheckHasRxModeReport()==TRUE) LteMacSendEcphyFlashDspReq(0, 0, 0, exit_CurrentTick); OSAFlagSet(send_ipc_flag,SEND_IPC_FLAG,OSA_FLAG_OR); } static void spi_nor_loop_delay(UINT32 n) { UINT32 i; for(i=0;i=BSP_INIT_TASK_FINISH){ OSATaskSleep(2); }else{ spi_nor_loop_delay(10*1000*100); } return 0; } #endif /** * spi_nor_init - [Interface] Init SPI_FLASH device driver * @spi: spi device structure * @chip_ptr: pointer point to spi nand device structure pointer */ struct spi_flash_chip *spi_nor_init(struct qspi_host *host, int cs, int rx_mode, int tx_mode, int qpi) { struct spi_flash_chip *chip = &nor_chip; uint8_t id[SPINOR_MAX_ID_LEN] = {0}; uint8_t DTR=0; #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) unsigned int cpsr = 0; OSAFlagCreate(&send_ipc_flag); Os_Create_HISR(&send_ipc_hisr, "SPIIPCHR", spi_nor_send_ipc, 2); #endif if (chip->qpi_enabled) spi_nor_disable_qpi(chip); qspi_memset(chip, 0, sizeof(struct spi_flash_chip)); chip->cs = cs >= QSPI_CS_MAX ? QSPI_CS_A1 : cs; chip->ops = (void *)&qspi_ops; chip->table = cmd_table; chip->host = host; chip->size = 16*1024*1024; chip->block_size = 1 << 16; chip->page_size = 1 << 7; #ifndef RUN_XIP_MODE spi_nor_reset(chip); #endif #if 0 //uses as it is, for whichever size. spi_nor_disable_4byte_mode(chip); //disable 4-byte mode, just use 16M flash even if it's 32M size. #endif spi_nor_read_id(chip, id); chip->mfr_id = id[0]; chip->dev_id = id[1] << 8 | id[2]; spi_nor_scan_id_table(chip); chip->page_size = 1 << 7; chip->block_shift = ilog2(chip->block_size); chip->page_shift = ilog2(chip->page_size); chip->page_mask = chip->page_size - 1; #if (!defined(LTEONLY_8M8M) && !defined(CRANEL_4MRAM) && !defined(LTEGSM_THIN)) CPUartLogPrintf("SPI-NOR: mfr_id: 0x%x, dev_id: 0x%x", chip->mfr_id, chip->dev_id); #endif #ifdef SW_HANDLE_XIP if(chip->mfr_id == SPIFLASH_MFR_XM &&(chip->dev_id == 0x5015)) //XM25QU16C or XM25LU16C { spi_nor_read_sfdp(chip,0x32,1,&DTR); if((DTR & BIT_3)){ //XM25LU16C bit3 support DTR SUSPEND_READY_TSUS = 5;// 122us ~ 152us, XM25LU16C [Suspend to read ready]tSUS > 120us }else{ RESUME_SUSPEND_TRS = 34;// 1006us ~ 1037us, XM25QU16C [Resume to another suspend time]tRS > 1000us } } else if(chip->mfr_id == SPIFLASH_MFR_XM &&(chip->dev_id == 0x4117)) //XM25QU64C { RESUME_SUSPEND_TRS = 34;// 1006us ~ 1037us, XM25QU64C [Resume to another suspend time]tRS > 1000us } #endif #if 0 if (chip->max_mhz && mhz > chip->max_mhz) { bbu_printf("warn: device max supported frequency is %d MHz!!!\r\n", chip->max_mhz); mhz = chip->max_mhz; } qspi_set_func_clk(host, mhz); #endif /* * The Enter 4-Byte Address Mode instruction will allow 32-bit address * (A31-A0) to be used to access the memory array beyond 128Mb */ if (chip->size > 16*1024*1024) spi_nor_enable_4byte_mode(chip); #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) cpsr=disableInterrupts(); #elif (defined(CRANE_MCU_DONGLE) && !defined(SW_HANDLE_XIP)) spi_nor_suspend_task_xip(); #endif spi_nor_enable_quad(chip); #if defined(RUN_XIP_MODE) && defined(FLASH_SEND_IPC) restoreInterrupts(cpsr); #elif (defined(CRANE_MCU_DONGLE) && !defined(SW_HANDLE_XIP)) spi_nor_resume_task_xip(); #endif if (qpi) spi_nor_enable_qpi(chip); spi_nor_set_rd_wr_op(chip, rx_mode, tx_mode); /* * TODO: * Maybe change due to different vendor */ if (chip->mfr_id == SPIFLASH_MFR_MXIC) { qspi_config_lookup_tbl(chip, chip->table + PGM_ERS_SUSPEND_MXIC, 0x0, QSPI_LUT_SEQID14); qspi_config_lookup_tbl(chip, chip->table + PGM_ERS_RESUME_MXIC, 0x0, QSPI_LUT_SEQID15); } else { qspi_config_lookup_tbl(chip, chip->table + PGM_ERS_SUSPEND, 0x0, QSPI_LUT_SEQID14); qspi_config_lookup_tbl(chip, chip->table + PGM_ERS_RESUME, 0x0, QSPI_LUT_SEQID15); } qspi_enable_xip(chip, chip->table + chip->read_op); if (qspi_preinit_lookup_tbl(chip) != 0) { fatal_printf("preinit_lookup_tbl failed, check cmd table\r\n"); return NULL; } if (!host->en_tx_dma) chip->tx_max_len = QSPI_TX_BUFF_MAX << 2; else chip->tx_max_len = chip->page_size; return chip; } #ifdef SW_HANDLE_XIP int qspi_abort_handle(void) { struct spi_flash_chip *chip = &nor_chip; int fr; unsigned int cpsr; uint32_t mcr; unsigned int need_resume=0; uint8_t status; unsigned long stratTick,stopTick; fr = _readl(QSPI0_FR); if (fr & BIT_9) { _writel(fr, QSPI0_FR); spi_nor_suspend(chip); return 1; } if (qspi_need_send_resume()) { stratTick = get_current_TStimer_tick(); need_resume = 1; cpsr=disable_interupt_for_qspi(); spi_nor_resume(chip); while(1){ spi_nor_read_status1(chip, &status); if ((status & STATUS_OIP_MASK) == STATUS_READY) { break; } } qspi_enable_ahb_preempt(0); crane_ds_mpu_xip_cache_enable(); enable_interupt_for_qspi(cpsr); stopTick = get_current_TStimer_tick(); } mcr = _readl(QSPI0_MCR); if(need_resume){ RTI_LOG("abort need resume,stratT[0x%08x],stopT[0x%08x],mcr[0x%08x]\r\n",stratTick,stopTick,mcr); } RTI_LOG("== mcr==0x%x\r\n",mcr); return 0; } #endif #if 0 extern struct spi_flash_chip *chip; int spi_nor_suspend_resume(struct spi_flash_chip *chip, int cmd_index) { struct spi_flash_cmd cmd; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); cmd.cmd_cfg = chip->table + cmd_index; return qspi_start_cmd(chip, &cmd); } int spi_nor_suspend(void) { int ret=1; if (chip) { ret = spi_nor_suspend_resume(chip, PGM_ERS_SUSPEND); } return ret; } int spi_nor_resume(void) { int ret=1; if (chip) { ret = spi_nor_suspend_resume(chip, PGM_ERS_RESUME); } return ret; } #endif struct spi_flash_chip *get_spi_flash_chip(unsigned char num) { if(num==1){ return &nor_chip; }else{ return NULL; } } int spi_nor_read_sfdp(struct spi_flash_chip *chip, int addr, int size, uint8_t *rbuf) { struct spi_flash_cmd cmd; qspi_memset(&cmd, 0, sizeof(struct spi_flash_cmd)); cmd.cmd_cfg = chip->table + READ_SFDP; if (chip->en_addr_4byte) { cmd.n_addr = 4; cmd.addr[0] = (uint8_t)((addr >> 24) & 0xff); cmd.addr[1] = (uint8_t)((addr >> 16) & 0xff); cmd.addr[2] = (uint8_t)((addr >> 8) & 0xff); cmd.addr[3] = (uint8_t)(addr & 0xff); } else { cmd.n_addr = 3; cmd.addr[0] = (uint8_t)((addr >> 16) & 0xff); cmd.addr[1] = (uint8_t)((addr >> 8) & 0xff); cmd.addr[2] = (uint8_t)(addr & 0xff); } cmd.n_rx = size; cmd.rx_buf = rbuf; cmd.mode = 0xff; return qspi_start_cmd(chip, &cmd); }