2177 lines
59 KiB
C
2177 lines
59 KiB
C
|
|
#include "Typedef.h"
|
|
#include "Errors.h"
|
|
#include "bsp.h"
|
|
#include "PlatformConfig.h"
|
|
#include "osa.h"
|
|
|
|
#include <string.h>
|
|
#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<n;i++)
|
|
;
|
|
|
|
}
|
|
|
|
void spi_nor_set_test_leval(UINT32 leval)
|
|
{
|
|
spi_nor_test_leval = leval;
|
|
|
|
|
|
}
|
|
|
|
static int spi_nor_delay(void)
|
|
{
|
|
extern UINT32 initState;
|
|
if(initState>=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);
|
|
|
|
}
|
|
|