/*!
    \file    flash.c
    \brief   the flash api file

*/

#include "lisoc_test.h"
#include "flash.h"
#include "qspi.h"
#include "gpio.h"
#include "uart.h"
#include "uart_stdout.h"

/********************************************************************************************
* Forbid debug print in this file (UART uploader<->flash interaction is time-sensitive)
********************************************************************************************/
#undef debug
#define debug(...)

#define TEST_FAST_IO

#define FLASH_ADDRESS_START     0x1F000000u
#define FLASH_ADDRESS_END       0x20000000u   // Default flash area size = 16MB
#define SPI_USR_CFG_AREA_SZ     0x100u        // Config area @ (flash_addr_end - SPI_USR_CFG_AREA_SZ)
#define SRAM_ADDRESS_START      0x20000000u
#define SRAM_ADDRESS_END        0x20060000u
#define SRAM0_ADDRESS           0x20000000u
#define SRAM1_ADDRESS           0x20020000u
#define SRAM2_ADDRESS           0x20040000u
#define SRAM_SIZE               0x00020000u   // sram area size = 128KB
#define SRAM_COPY_SIZ           0x00008000u   // qflash -> sram copy area size = 32KB



/* ------- ToDo try different 4 line formats */

#ifndef TEST_FAST_IO
/*******************************************************************************************
* User config default parameter set.
*
* Allows slow access to flash in standard SPI format (1-1-1) for maximum compatibility
*
* We use this parameter to obtain user config table from flash.
* Once a valid config table is retrieved, we switch to using the
*   parameter from the new valid config table.
*******************************************************************************************/
const ST_SpiUsrCfg spi_def_cfg = {
  SPI_USR_CFG_SIGNATURE,        // #0 signature
  SPI_DEFAULT_BOOT,             // #2 mod_override
  24u,                          // #3 addr_len (plain number)

  SPIF_READ_DATA,               // #4 fast_rd_inst
  SPIR0_INS_STD_ADR_STD,        // #5 trans_typ
  SPI_SPI_FRF_STD,              //    spi_frf
  SPIR0_WAIT_CYC_0_CYC,         // #6 fastrd_dmycyc (plain number)
  SPIR0_WAIT_CYC_8_CYC,         // #7 xip_dmycyc (plain number)

  SPIF_XIP_MODE_BITS,           // #8 xip_mod_bits
  0u,                           // #10 xip_MBL_bitcnt (plain number)
  SPIF_XIP_CNT_TIME_OUT,        // #11 xip_cnt_tmo

  FLASH_ADDRESS_START,          // #12 src_addr
  SRAM1_ADDRESS,                // #16 dest_addr
  SRAM_COPY_SIZ,                // #20 copy_len
  0u,                           // #24 read QE status inst
  0u,                           // #25 write QE status inst
  0u,                           // #26 QE bit postion
  0u,                           // #27 rsvd

  SPIF_PAGE_PROGRAM,            // #28 write_inst
  SPIF_FAST_READ_QUAD_OUT,      // #29 xip_inst
  SPIR0_INS_STD_ADR_STD,        // #30 xip_trans_typ
  SPI_SPI_FRF_QUAD,             //     xip_spi_frf
  SPI_DEF_BAUDR_DIV,            // #31 qspi_baud_div

  0x0u,                         // #32 chksum
};

#else
/*******************************************************************************************
* For debug purpose: contains high speed access parameter for N25Q128
*******************************************************************************************/
#ifndef TEST_FAST_DUAL_READ
const ST_SpiUsrCfg spi_def_cfg = {
  SPI_USR_CFG_SIGNATURE,        // #0 signature
  SPI_DEFAULT_BOOT,             // #2 mod_override
  24u,                          // #3 addr_len (plain number)

  SPIF_FAST_READ_QUAD_OUT,      // #4 fast_rd_inst
  SPIR0_INS_STD_ADR_STD,        // #5 trans_typ
  SPI_SPI_FRF_QUAD,             //    spi_frf
  SPIR0_WAIT_CYC_8_CYC,         // #6 fastrd_dmycyc (plain number)
  SPIR0_WAIT_CYC_8_CYC,         // #7 xip_dmycyc (plain number)

  SPIF_XIP_MODE_BITS,           // #8 xip_mod_bits
  0u,                           // #10 xip_MBL_bitcnt (plain number)
  SPIF_XIP_CNT_TIME_OUT,        // #11 xip_cnt_tmo

  FLASH_ADDRESS_START,          // #12 src_addr
  SRAM1_ADDRESS,                // #16 dest_addr
  SRAM_COPY_SIZ,                // #20 copy_len
  0u,                           // #24 read QE status inst
  0u,                           // #25 write QE status inst
  0u,                           // #26 QE bit postion
  0u,                           // #27 rsvd

  SPIF_PAGE_PROG_QUAD_IN,       // #28 write_inst
  SPIF_FAST_READ_QUAD_OUT,      // #29 xip_inst
  SPIR0_INS_STD_ADR_STD,        // #30 xip_trans_typ
  SPI_SPI_FRF_QUAD,             //     xip_spi_frf
  SPI_FAST_BAUDR_DIV,           // #31 qspi_baud_div

  0x0u,                         // #32 chksum
};
#else
const ST_SpiUsrCfg spi_def_cfg = {
  SPI_USR_CFG_SIGNATURE,        // #0 signature
  SPI_DEFAULT_BOOT,             // #2 mod_override
  24u,                          // #3 addr_len (plain number)

  SPIF_FAST_READ_DUAL_OUT,      // #4 fast_rd_inst
  SPIR0_INS_STD_ADR_STD,        // #5 trans_typ
  SPI_SPI_FRF_DUAL,             //    spi_frf
  SPIR0_WAIT_CYC_8_CYC,         // #6 fastrd_dmycyc (plain number)
  SPIR0_WAIT_CYC_8_CYC,         // #7 xip_dmycyc (plain number)

  SPIF_XIP_MODE_BITS,           // #8 xip_mod_bits
  0u,                           // #10 xip_MBL_bitcnt (plain number)
  SPIF_XIP_CNT_TIME_OUT,        // #11 xip_cnt_tmo

  FLASH_ADDRESS_START,          // #12 src_addr
  SRAM1_ADDRESS,                // #16 dest_addr
  SRAM_COPY_SIZ,                // #20 copy_len
  0u,                           // #24 read QE status inst
  0u,                           // #25 write QE status inst
  0u,                           // #26 QE bit postion
  0u,                           // #27 rsvd

  SPIF_PAGE_PROG_QUAD_IN,       // #28 write_inst
  SPIF_FAST_READ_QUAD_OUT,      // #29 xip_inst
  SPIR0_INS_STD_ADR_STD,        // #30 xip_trans_typ
  SPI_SPI_FRF_QUAD,             //     xip_spi_frf
  SPI_FAST_BAUDR_DIV,           // #31 qspi_baud_div

  0x0u,                         // #32 chksum
};

#endif
#endif

const uint8_t flash_jedec_capacity_tab[] =
{
  0x18u,            /* 16MB = 128Mbit */
  0x17u,            /*  8MB = 64Mbit */
  0x16u,            /*  4MB = 32Mbit */
  0x15u,            /*  2MB = 16Mbit */
  0x14u,            /*  1MB = 8Mbit */
};

ST_SpiUsrCfg spi_cfg;

uint32_t aligned_flash_buff[64u];
uint8_t *flash_buff = (uint8_t *)aligned_flash_buff;
uint32_t flash_addr_end;


/*!
    \brief      checksum32
    \param[in]  none
    \param[out] none
    \retval     none
*/
uint32_t checksum32(uint32_t *data, uint32_t len)
{
  uint32_t i;
  uint32_t cs;

  cs = (uint32_t)0u;
  for (i = 0u; i < len / 4u; i ++) {
    cs ^= data[i];
  }
  cs = ~cs;

  return cs;
}


/*****************************************************************************************
*spi flash select,pgio poarta 1
******************************************************************************************/
void SPIF_CS(uint8_t en)
{
  if (en)
  {
    /* QSPI CS = active low */
    gpiob_out(GPIOB_QSPI_CS_OUT, OFF);
  }
  else
  {
    gpiob_out(GPIOB_QSPI_CS_OUT, ON);
  }
}

/*****************************************************************************************
*spi flash init
******************************************************************************************/
void SPIF_init(void)
{
  /*Set PB1 output.*/
  gpiob_setPinDreict(PB1, GPIO_OUT);

  SPIF_CS(OFF);
  SPIM_Disable();
  SSI0_CTRLR0 = (SPI_FRM_FMT_SPI << SPI_FRF_BITOFS)
              | (SPI_CLOCK_POLARITY_HIGH << SPI_SCPOL_BITOFS)
              | (SPI_CLOCK_PHASE_START << SPI_SCPH_BITOFS);
  SSI0_SPI_CTRLR0 = 0u;

  SPIM_SelectSlave(SPI_CS0);
  SPIM_MaskInt(SPI_INT_DISABLE);

  /*************************************************************************
  * Use default config params to get user config'ed params from flash
  *************************************************************************/
  SPIF_GetFlashCfg();
  /* Enable Flash quand output */
  SPIF_QuadInstEn();
}

/*******************************************************************************************
* Description: Standard SPI Tx and Rx (fifo access bitwidth = 8bit)
*
* max supported Tx length = 256 bytes
* max supported Rx length = 32 bytes!!
*******************************************************************************************/
void SPIM_TxRx(uint8_t inst, uint32_t addr, uint8_t *buf, uint32_t tlen, uint32_t rlen)
{
  uint32_t tcnt;          /* Tx count */
  uint32_t rcnt;          /* Rx count */
  uint32_t tmp;

  SPIM_SetBaudrate(spi_cfg.qspi_baud_div);
  SPIM_SetDataWidth(SPI_DAT_FRM_SIZ_8bit);
  SPIM_SetSlaveSlectToggleEn(SPI_TOGGLE_ENABLE);
  SPIM_SetSpiFrmFormat(SPI_SPI_FRF_STD);

  if (rlen == 0u)
  {
    SPIM_SetMode(SPI_TMOD_TX);
  }
  else
  {
    SPIM_SetMode(SPI_TMOD_E2PROM);
    SSI0_CTRLR1 = rlen - 1u;
  }
  SPIM_SetTransType(SPIR0_INS_STD_ADR_STD);
  SPIM_SetInsLen(SPIR0_INST_L_0bit);
  SPIM_SetAddrLen(SPIR0_ADDR_L_0bit);
  SPIM_SetWaitCycle(SPIR0_WAIT_CYC_0_CYC);
  SPIM_SetClkStretEnable();

  SPIM_Enable();
  SPIF_CS(ON);

  /* Prefill instruction, address, and Tx bytes triggering Rx */
  SSI0_DR0 = (uint32_t)inst;
  if (addr != (uint32_t)-1)
  {
    if (spi_cfg.addr_len > 24u)
    {
      SSI0_DR0 = (uint8_t)(addr >> 24u);
    }
    SSI0_DR0 = (uint8_t)(addr >> 16u);
    SSI0_DR0 = (uint8_t)(addr >> 8u);
    SSI0_DR0 = (uint8_t)(addr >> 0u);
  }
  tcnt = 0u;
  while ((tcnt < tlen) && (tcnt < SSI0_TX_PREFILL_THRES))
  {
    SSI0_DR0 = (uint32_t)buf[tcnt];
    tcnt ++;
  }

  /* Polling */
  do
  {
    tmp = SSI0_TXFLR;
    while ((tcnt < tlen) && (tmp < SSI0_TXFIFO_DEPTH))
    {
      SSI0_DR0 = (uint32_t)buf[tcnt];
      tcnt ++;
      tmp ++;
    }
  } while (SSI0_SR & SSI0_SR_BUSY);

  rcnt = 0u;
  while ((rcnt < rlen) && (SSI0_RXFLR > 0u))
  {
    buf[rcnt] = SSI0_DR0;
    rcnt ++;
  }
  SPIF_CS(OFF);
  SPIM_Disable();
}

/*******************************************************************************************
* Description: Standard SPI Tx and Rx (fifo access bitwidth = 32bit)
*              Only support flash program / flash read
*              Onnly support address of 24bit length!
*
* max supported Tx length = 256 bytes
* max supported Rx length = 32 bytes!!
*******************************************************************************************/
void SPIM_TxRx32(uint8_t inst, uint32_t addr, uint8_t *buf, uint32_t tlen, uint32_t rlen)
{
  uint32_t tcnt;          /* Tx count */
  uint32_t rcnt;          /* Rx count */
  uint32_t tmp;

  SPIM_SetBaudrate(spi_cfg.qspi_baud_div);
  SPIM_SetDataWidth(SPI_DAT_FRM_SIZ_32bit);
  SPIM_SetSlaveSlectToggleEn(SPI_TOGGLE_ENABLE);
  SPIM_SetSpiFrmFormat(SPI_SPI_FRF_STD);

  SPIM_SetMode(SPI_TMOD_TX);
  SPIM_SetTransType(SPIR0_INS_STD_ADR_STD);
  SPIM_SetInsLen(SPIR0_INST_L_0bit);
  SPIM_SetAddrLen(SPIR0_ADDR_L_0bit);
  SPIM_SetWaitCycle(SPIR0_WAIT_CYC_0_CYC);
  SPIM_SetClkStretEnable();

  SPIM_Enable();
  SPIF_CS(ON);

  /* Prefill instruction, address, and Tx bytes triggering Rx */
  SSI0_DR0 = ((uint32_t)inst << 24u) | (addr & 0xFFFFFFu);
  tcnt = 0u;
  while ((tcnt < tlen) && (tcnt < SSI0_TX_PREFILL_THRES))
  {
    SSI0_DR0 = ((uint32_t*)buf) [tcnt / 4u];
    tcnt += 4u;
  }

  /* Polling */
  do
  {
    tmp = SSI0_TXFLR;
    while ((tcnt < tlen) && (tmp < SSI0_TXFIFO_DEPTH))
    {
      SSI0_DR0 = ((uint32_t*)buf) [tcnt / 4u];
      tcnt += 4u;
      tmp ++;
    }
  } while (SSI0_SR & SSI0_SR_BUSY);

  if(rlen != 0u)
  {
    SPIM_Disable();
    SPIM_SetMode(SPI_TMOD_RX);
    SSI0_CTRLR1 = (rlen / 4u) - 1u;
    SPIM_Enable();

    /* receive start. */
    SSI0_DR0 = 0u;

    rcnt = 0u;
    while ((rcnt < rlen))
    {
      if((SSI0_RXFLR > 0u))
      {
        ((uint32_t*)buf) [rcnt / 4u] = SSI0_DR0;
        rcnt += 4u;
      }
    }
  }

  SPIF_CS(OFF);
  SPIM_Disable();
}

/*******************************************************************************************
* Description: Enhanced SPI Tx and Rx (fifo access bitwidth = 32bit)
*
* max supported Tx length = 256 bytes
* max supported Rx length = 32 bytes!!
*******************************************************************************************/
void SPIM_EnhTxRx32(uint8_t inst, uint32_t addr, uint8_t *buf, uint32_t tlen, uint32_t rlen)
{
  uint32_t tcnt;          /* Tx count */
  uint32_t rcnt;          /* Rx count */
  uint32_t tmp;

  SPIM_SetBaudrate(spi_cfg.qspi_baud_div);
  SPIM_SetDataWidth(SPI_DAT_FRM_SIZ_32bit);
  SPIM_SetSlaveSlectToggleEn(SPI_TOGGLE_ENABLE);

  if (rlen == 0u)
  {
    SPIM_SetMode(SPI_TMOD_TX);
    SPIM_SetTransType(SPIR0_INS_STD_ADR_STD);
    SPIM_SetSpiFrmFormat(SPIF_DEF_PAGE_PRG_SPI_FRF);
    SPIM_SetWaitCycle(SPIR0_WAIT_CYC_0_CYC);
  }
  else
  {
    SPIM_SetMode(SPI_TMOD_RX);
    SPIM_SetTransType(spi_cfg.trans_typ);
    SPIM_SetSpiFrmFormat(spi_cfg.spi_frf);
    SPIM_SetWaitCycle(spi_cfg.fastrd_dmycyc);
    SSI0_CTRLR1 = (rlen / 4u) - 1u;
  }
  SPIM_SetClkStretEnable();
  SPIM_SetInsLen(SPIR0_INST_L_8bit);
  SPIM_SetAddrLen((spi_cfg.addr_len == 20u) ? SPIR0_ADDR_L_20bit
    : (spi_cfg.addr_len == 24u) ? SPIR0_ADDR_L_24bit
    : (spi_cfg.addr_len == 28u) ? SPIR0_ADDR_L_28bit : SPIR0_ADDR_L_32bit);

  SPIM_Enable();
  SPIF_CS(ON);

  /* Prefill instruction, address, and Tx bytes triggering Rx */
  SSI0_DR0 = (uint32_t)inst;
  SSI0_DR0 = addr;
  tcnt = 0u;
  while ((tcnt < tlen) && (tcnt < SSI0_TX_PREFILL_THRES))
  {
    SSI0_DR0 = ((uint32_t*)buf) [tcnt / 4u];
    tcnt += 4u;
  }

  /* Polling */
  if (rlen == 0u)
  {
    /* Tx */
    do
    {
      tmp = SSI0_TXFLR;
      while ((tcnt < tlen) && (tmp < SSI0_TXFIFO_DEPTH))
      {
        SSI0_DR0 = ((uint32_t*)buf) [tcnt / 4u];
        tcnt += 4u;
        tmp ++;
      }
    } while ((tcnt < tlen) || (tmp > 0u));
  }
  else
  {
    /* Rx */
    rcnt = 0u;
    while (rcnt < rlen)
    {
      if (SSI0_RXFLR > 0u)
      {
        ((uint32_t*)buf) [rcnt / 4u] = SSI0_DR0;
        rcnt += 4u;
      }
    }
  }
  SPIF_CS(OFF);
  SPIM_Disable();
}

/****************************************************************************************
*spi flash write enable
*****************************************************************************************/
uint8_t SPIF_WriteEN(void)
{
  uint8_t status;

  debug("write enable\n");
  SPIM_TxRx(SPIF_WRITE_EN, -1u, NULL, 0u, 0u);

  do
  {
    SPIM_TxRx(SPIF_READ_SR, -1u, &status, 0u, 1u);
  } while (!(status & SPIFLASH_IS_WEL));

  return SUCCESS;
}

/***************************************************************************************
*waiting spi progress is end
****************************************************************************************/
uint8_t SPIF_WaitReady(void)
{
  uint8_t status;

  debug("wait ready\n");
  do
  {
    SPIM_TxRx(SPIF_READ_SR, -1u, &status, 0u, 1u);
  } while (status & SPIFLASH_IS_BUSY);

  return SUCCESS;
}

/****************************************************************************************
*get spi flash manufacturer and device id
****************************************************************************************/
void SPIF_GetDevID(uint8_t *id_buff, uint32_t len)
{
  SPIM_TxRx(SPIF_READ_MF_DEVID, -1u, id_buff, 0u, len);
}

/***************************************************************************************
*erase spi flash sector(4K)
****************************************************************************************/
uint8_t SPIF_SectorErase(uint8_t cmd, uint32_t sector)
{
  uint8_t status;

  debug("erase sect #%d\n", sector);
  status = SPIF_WriteEN();

  SPIM_TxRx(cmd, sector << 12u, NULL, 0u, 0u);

  status = SPIF_WaitReady();

  return status;
}

uint8_t SPIF_BlockErase4K(uint32_t block)
{
  return SPIF_SectorErase(SPIF_SECTOR_ERASE, block);
}


/***************************************************************************************
*erase spi flash block 32K
****************************************************************************************/
uint8_t  SPIF_BlockErase32K(uint32_t block)
{
  return SPIF_SectorErase(SPIF_BLOCK_ERASE_32, block << 3u);
}

/***************************************************************************************
*erase spi flash block 64K
****************************************************************************************/
uint8_t  SPIF_BlockErase64K(uint32_t block)
{
  return SPIF_SectorErase(SPIF_BLOCK_ERASE_64, block << 4u);
}

/****************************************************************************************
*erase spi flash chip
****************************************************************************************/
uint8_t SPIF_ChipErase(void)
{
  uint8_t status;

  debug("erase chip\n");
  status = SPIF_WriteEN();

  SPIM_TxRx(SPIF_CHIP_ERASE, -1u, NULL, 0u, 0u);

  status = SPIF_WaitReady();

  return status;
}

/****************************************************************************************
*program spi flash page,page is 256 Bytes, so data len <= 256
*****************************************************************************************/
uint8_t SPIF_PageProgram(uint32_t page, uint8_t *data, uint32_t len)
{
  uint8_t status;

  debug("flash program page #%ld (cmd 0x%x)\n", page, spi_cfg.write_inst);
  status = SPIF_WriteEN();

  if (spi_cfg.write_inst == (uint8_t)SPIF_PAGE_PROGRAM)
  {
    SPIM_TxRx32(SPIF_PAGE_PROGRAM, page << 8u, data, len, 0u);
  }
  else
  {
    SPIM_EnhTxRx32(SPIF_PAGE_PROG_QUAD_IN, page << 8u, data, len, 0u);
  }

  status = SPIF_WaitReady();

  return status;
}

/**************************************************************************************
*spi flash data read
***************************************************************************************/
uint8_t SPIF_ReadData(uint32_t addr, uint8_t *data, uint32_t len)
{
  uint32_t rdcnt;
  uint32_t rdlen;

  debug("flash read 0x%x (cmd 0x%x)\n", addr, spi_cfg.fast_rd_inst);

  for (rdcnt = 0u; rdcnt < len; rdcnt += SPI_RD_LEN)
  {
    rdlen = (rdcnt + SPI_RD_LEN > len) ? len - rdcnt : SPI_RD_LEN;
    if (spi_cfg.fast_rd_inst == (uint8_t)SPIF_READ_DATA)
    {
      SPIM_TxRx32(spi_cfg.fast_rd_inst, addr + rdcnt, &data[rdcnt], 0, rdlen);
    }
    else
    {
      SPIM_EnhTxRx32(spi_cfg.fast_rd_inst, addr + rdcnt, &data[rdcnt], 0, rdlen);
    }
  }


  return SUCCESS;
}

/**************************************************************************************
*program spi flash
*page: the base page number;
*data: the data base addr that will be write
*len:  the data len
***************************************************************************************/
uint8_t SPIF_Program(uint32_t page, uint8_t *data, uint32_t len)
{
  uint32_t ofs, pglen;
  uint8_t  status;

  for (ofs = 0u; ofs < len; ofs += SPIF_PAGE_SIZE)
  {
    pglen = (ofs + SPIF_PAGE_SIZE > len) ? len - ofs : SPIF_PAGE_SIZE;
    status = SPIF_PageProgram(page + ofs / SPIF_PAGE_SIZE, &data[ofs], pglen);
  }

  return status;
}

void SPIF_XIP_Init(void)
{
  uint32_t mbl;

  /* Set PB1 pin mode */
  PB1_SetToSSICsMode();
  /* XIP disable */
  SPIM_SysXIPDisable();
  /* SSIENR   disable  dwc_ssi */
  SPIM_Disable();

  /* Set to master
   * QSPI format
   * tmode--rx_only
   */
  //SPIM_SetSpiIsMaster();
  SPIM_SetMode(SPI_TMOD_RX);
  SPIM_SetSpiFrmFormat(spi_cfg.xip_spi_frf);
  SPIM_SetDataWidth(SPI_DAT_FRM_SIZ_32bit);
  SPIM_SetBaudrate(spi_cfg.qspi_baud_div);

  /* XIP_MBL_8
   * XIP_CONT_XFER_EN
   * XIP_INST_EN
   * XIP_DFS_HC
   * WAIT_CYCLES_4
   * INST_L_8
   * XIP_MD_BIT_EN
   * ADDR_L_24
   * TRANS_TYPE_1
   */
  SPIM_SetClkStretDisable();
  if(spi_cfg.xip_MBL_bitcnt == 0u)
  {
    SPIM_SetXIPModeBitDis();
  }
  else
  {
    if (spi_cfg.xip_MBL_bitcnt == 2u) {
      mbl = SPIR0_XIP_MBL_2bit;
    }
    else if (spi_cfg.xip_MBL_bitcnt == 4u) {
      mbl = SPIR0_XIP_MBL_4bit;
    }
    else if (spi_cfg.xip_MBL_bitcnt == 8u) {
      mbl = SPIR0_XIP_MBL_8bit;
    }
    else {
      mbl = SPIR0_XIP_MBL_16bit;
    }
    SPIM_SetXIPModeBitsLen(mbl);
    /* XIP_MODE_BITS */
    SPIM_SetXIPModeBits(spi_cfg.xip_mod_bits);
    SPIM_SetXIPModeBitEn();
  }

  SPIM_XIPContTransEnable();
  SPIM_XIPInsEnable();
  SPIM_SetWaitCycle(spi_cfg.xip_dmycyc);
  SPIM_SetInsLen(SPIR0_INST_L_8bit);
  SPIM_SetAddrLen((spi_cfg.addr_len == 20u) ? SPIR0_ADDR_L_20bit
    : (spi_cfg.addr_len == 24u) ? SPIR0_ADDR_L_24bit
    : (spi_cfg.addr_len == 28u) ? SPIR0_ADDR_L_28bit : SPIR0_ADDR_L_32bit);
  SPIM_SetTransType(spi_cfg.xip_trans_typ);
  SPIM_SetXIPFixedDFSTrans();

  /* XIP_INCR_INST */
  SPIM_SetXIPIncrIns(spi_cfg.xip_inst);
  /* XIP_WRAP_INST */
  SPIM_SetXIPWrapIns(spi_cfg.xip_inst);
  /* XIP_CNT_TIME_OUT */
  SPIM_SetXIPCntTimeOut(spi_cfg.xip_cnt_tmo);
  /* XIP_SER */
  SPIM_XIPSelectSlave(SPI_CS0);
  /* XIP Prefetch enable*/
  //SPIM_SetXIPPreFetchEn();
  /* SSIENR   enable  dwc_ssi */
  SPIM_Enable();

  /* XIP enable */
  SPIM_SysXIPEnable();
}

void SPIF_GetFlashCfg(void)
{
  uint32_t usr_cfg_addr;
  ST_SpiUsrCfg *usr_cfg;
  uint32_t cs;
  uint32_t i;

  /* Use default flash config at this moment */
  memcpy(&spi_cfg, &spi_def_cfg, sizeof(ST_SpiUsrCfg));

  /* Default flash address size is 16MB */
  flash_addr_end = FLASH_ADDRESS_END;

  /* Read flash JEDEC ID to determine its capacity */
  SPIF_GetDevID(flash_buff, 3u);
  debug("idbuff:0x%02x, 0x%02x 0x%02x\n", flash_buff[0u], flash_buff[1u], flash_buff[2u]);
  for(i = 0u; i < sizeof(flash_jedec_capacity_tab); i ++)
  {
    if(flash_buff[2u] == flash_jedec_capacity_tab[i])
    {
      flash_addr_end = FLASH_ADDRESS_START + (1u << flash_jedec_capacity_tab[i]);
      break;
    }
  }

  /* Read flash user config table using default config parameters */
  usr_cfg_addr = flash_addr_end - FLASH_ADDRESS_START - SPI_USR_CFG_AREA_SZ;
  SPIF_ReadData(usr_cfg_addr, flash_buff, sizeof(ST_SpiUsrCfg));
  debug("flash usr config:\n");
  for(i = 0u; i < sizeof(ST_SpiUsrCfg); i ++)
  {
    debug("%x ", flash_buff[i]);
    if((i + 1u) % 16u == 0u)
    {
      debug("\n");
    }
  }
  cs = checksum32((uint32_t *)flash_buff, sizeof(ST_SpiUsrCfg) - 4u);
  debug("\n chksum = %x\n", cs);

  /* Use this user config table if it is valid */
  usr_cfg = (ST_SpiUsrCfg *)flash_buff;
  if((usr_cfg->signature == (uint16_t)SPI_USR_CFG_SIGNATURE) && (cs == usr_cfg->chksum))
  {
    memcpy(&spi_cfg, usr_cfg, sizeof(ST_SpiUsrCfg));
  }
}

uint8_t SPIF_QuadInstEn(void)
{
  uint8_t status;

  if(spi_cfg.qe_rd_inst != 0x0u)
  {
    SPIM_TxRx(spi_cfg.qe_rd_inst, -1u, &status, 0u, 1u);

    debug("status register:%x\n",status);

    if(!((status >> spi_cfg.qe_bit_pos) & 1u))
    {
      SPIF_WriteEN();

      status |= (1u << spi_cfg.qe_bit_pos);

      SPIM_TxRx(spi_cfg.qe_wt_inst, -1u, &status, 1u, 0u);

      do{
        SPIM_TxRx(spi_cfg.qe_rd_inst, -1u, &status, 0u, 1u);
        debug("status register:%x\n",status);
      } while (!((status >> spi_cfg.qe_bit_pos) & 1u));
    }
    else
    {
      /* Do Nothing. */
    }
  }
  else
  {
    /* Do Nothing. */
  }

  return SUCCESS;

}


