/*******************************************************************************
 * DISCLAIMER
 * This software is supplied by Renesas Electronics Corporation and is only
 * intended for use with Renesas products. No other uses are authorized. This
 * software is owned by Renesas Electronics Corporation and is protected under
 * all applicable laws, including copyright laws.
 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
 * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
 * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
 * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
 * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
 * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
 * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * Renesas reserves the right, without notice, to make changes to this software
 * and to discontinue the availability of this software. By using this software,
 * you agree to the additional terms and conditions found by accessing the
 * following link:
 * http://www.renesas.com/disclaimer
 * Copyright 2021-2024 Renesas Electronics Corporation All rights reserved.
 *******************************************************************************/

/*******************************************************************************
 * DESCRIPTION   : RPC driver
 ******************************************************************************/
/******************************************************************************
 * @file          rpc.c
 * - Version      : 0.08
 * @brief         Initial setting process of RPC.
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 28.07.2021 0.01     First Release
 *         : 03.09.2021 0.02     Add rpc_release function.
 *         : 27.07.2022 0.03     Add QSPI Flash vendor ID check and QSPI Flash
 *         :                     command initialization.
 *         : 22.08.2022 0.04     Add DDR mode for QSPI Flash.
 *         : 21.09.2022 0.05     Fix comparison of test data
 *         :                     in adjust_strobe_timing function.
 *         : 12.01.2023 0.06     Add PFC setting to qspi_ddr_transfer_mode()
 *         :                     function.
 *         : 04.04.2023 0.07     Removed stdio.h.
 *         : 17.06.2024 0.08     Fix PUEN register setting when QSPI DDR mode.
 *****************************************************************************/

#include <stdint.h>
#include <stddef.h>
#include <rpc.h>
#include <mem_io.h>
#include <rst_register.h>
#include <image_load_flash.h>
#include <cpg_register.h>
#include <cpg.h>
#include <remap.h>
#include <log.h>
#include <pfc.h>

#define RPC_PHYCNT_CAL                  ((uint32_t)1U   << 31U)
#define RPC_PHYCNT_DDRCAL               ((uint32_t)1U   << 19U)
#define RPC_PHYCNT_PHYMEM_SPI_DDR       ((uint32_t)1U   << 0U)
#define RPC_PHYCNT_HS                   (0x00040000U)
#define RPC_PHYCNT_WBUF2                (0x00000010U)
#define RPC_PHYCNT_WBUF                 (0x00000004U)
#define RPC_PHYCNT_PHYMEM_MASK          (0x00000003U)
#define RPC_DRCR_RCF                    ((uint32_t)1U   << 9U)
#define RPC_DRCR_SSLN_NEGATE            (0x01000000U)
#define RPC_DRCR_RBE_RBURST_MASK        (0x001F0000U)
#define RPC_DRCR_RBE_RBURST_1DATA       (0x00000000U) /* Smallest data unit (8byte) */
#define RPC_DRCR_RBE_RBURST_32DATA      (0x001F0000U) /* biggest data unit (256byte) */
#define RPC_DRCR_RBE_ENABLE             (0x00000100U)
#define RPC_DRCMR_CMD_SHIFT             (16U)
#define RPC_DRCMR_CMD_MASK              ((uint32_t)0xFFU << RPC_DRCMR_CMD_SHIFT)
#define RPC_DRCMR_OCMD_MASK             ((uint32_t)0xFFU << 0U)
#define RPC_DRCMR_HW_INIT               (0x00030000U)
#define RPC_DREAR_EAV_MASK              ((uint32_t)0xFFU << 16U)
#define RPC_DREAR_EAC_MASK              ((uint32_t)0x7U << 0U)
#define RPC_DREAR_EAC_EXT_ADDR_25BIT    ((uint32_t)0x1U << 0U)
#define RPC_DREAR_HW_INIT               (0x00000000U)
#define RPC_DRENR_CDB_MASK              (0xC0000000U)
#define RPC_DRENR_CDB_1BIT              (0x00000000U)
#define RPC_DRENR_ADB_MASK              (0x03000000U)
#define RPC_DRENR_ADB_4BIT              (0x02000000U)
#define RPC_DRENR_DRDB_MASK             (0x00030000U)
#define RPC_DRENR_DRDB_4BIT             (0x00020000U)
#define RPC_DRENR_DME_MASK              (0x00008000U)
#define RPC_DRENR_DME_ENABLE            (0x00008000U)
#define RPC_DRENR_CDE_ENABLE            ((uint32_t)0x1U << 14U)
#define RPC_DRENR_ADE_MASK              (0x00000F00U)
#define RPC_DRENR_ADE_32BIT_ADDR        ((uint32_t)0xFU << 8U)
#define RPC_DRENR_HW_INIT               (0x00004700U)
#define RPC_DRENR_TRANS_DISABLE         (0x00000000U)
#define RPC_SMCMR_CMD_SHIFT             (16U)
#define RPC_SMCMR_CMD_MASK              (0x00FF0000U)
#define RPC_SMCMR_OCMD_MASK             (0x000000FFU)
#define RPC_SMDRENR_HYPE_MASK           (0x00007000U)
#define RPC_SMDRENR_ADDRE               (0x00000100U)
#define RPC_SMDRENR_OPDRE               (0x00000010U)
#define RPC_SMDRENR_SPIDRE              (0x00000001U)
#define RPC_SMENR_CDB_MASK              (0xC0000000U)
#define RPC_SMENR_OCDB_MASK             (0x30000000U)
#define RPC_SMENR_ADB_MASK              (0x03000000U)
#define RPC_SMENR_OPDB_MASK             (0x00300000U)
#define RPC_SMENR_SPIDB_MASK            (0x00030000U)
#define RPC_SMENR_DME_EN                (0x00008000U)
#define RPC_SMENR_CDE_EN                (0x00004000U)
#define RPC_SMENR_OCDE_EN               (0x00001000U)
#define RPC_SMENR_ADE_MASK              (0x00000F00U)
#define RPC_SMENR_OPDE_MASK             (0x000000F0U)
#define RPC_SMENR_SPIDE_MASK            (0x0000000FU)
#define RPC_SMENR_SPIDE_SPI_32          (0x0000000FU)
#define RPC_SMCR_SSLKP                  (0x00000100U)
#define RPC_SMCR_SPIRE                  (0x00000004U)
#define RPC_SMCR_SPIWE                  (0x00000002U)
#define RPC_SMCR_SPIE                   (0x00000001U)
#define RPC_CMNCR_MD                    (0x80000000U)    /* bit[31]:Operating Mode Switch -> Manual mode */
#define RPC_CMNCR_MOIIO_MASK            (0x00FF0000U)
#define RPC_CMNCR_MOIIO3_HI_Z           (0x00C00000U)
#define RPC_CMNCR_MOIIO2_HI_Z           (0x00300000U)
#define RPC_CMNCR_MOIIO1_HI_Z           (0x000C0000U)
#define RPC_CMNCR_MOIIO0_HI_Z           (0x00030000U)
#define RPC_CMNCR_BSZ_MASK              (0x00000003U)
#define RPC_DRDRENR_DRDRE               (0x00000001U)
#define RPC_DRDRENR_ADDRE               (0x00000100U)
#define RPC_PHYOFFSET1_DDRTMG_MSK       (0x30000000U)
#define RPC_PHYOFFSET1_DDRTMG_DDR       (0x20000000U)
#define CMNSR_TEND                      (0x00000001U)

#define STRTIM_SMALLEST                 (0x0000000FU)
#define STRTIM_MASK_3                   (0x00000008U)
#define STRTIM_MASK                     (0x00000007U)
#define STRTIM_MATCH_ERROR              (0xFFFFFFFFU)

#define RST_MODEMR0_BOOTMODE            (0xFU << 1U)
#define BOOTMODE_QSPI_SINGLE_40MHZ      (0x4U)

/* QSPI Flash device ID */
#define DEVID_S25FS512S         (0x00200201U)       /* S25FS512S */
#if USER_ADDED_QSPI == 1
#define DEVID_XXXXXXXXX         (0xFFFFFFFFU)
#endif /* USER_ADDED_QSPI == 1 */

/* For return value */
#define QSPI_CMD_INIT_SUCCESS   (0x00000000U)
#define QSPI_CMD_INIT_ERROR     (0xFFFFFFFFU)
/* Common command for QSPI Flash */
#define FLASH_CMD_READ_ID       (0x9FU)
/* Device ID mask for QSPI Flash */
#define DEVICE_ID_MASK          (0x00FFFFFFU)

/* For PFC register */
#define PFC_PUEN3_QSPI0_IO3     (0x00010000U)       /* bit16 */
#define PFC_PUEN3_QSPI0_IO2     (0x00020000U)       /* bit17 */

typedef struct{
    uint32_t reg_addr;  /* registers address. */
    uint32_t value;     /* setting value. */
} st_register_table_t;


#define RPC_TBL_MAX   (13U)

static st_register_table_t g_rpc_reg_hwinit_val_tbl[RPC_TBL_MAX];

static const uint32_t dev_id_index[VENDOR_NUM] =
{
    /* QSPI Flash device ID */
        DEVID_S25FS512S,     /* S25FS512S */
#if USER_ADDED_QSPI == 1
    /* User can customize for another vendor's QSPI Flash. */
        DEVID_XXXXXXXXX
#endif /* USER_ADDED_QSPI == 1 */
};

static const st_qspi_cmd_tbl_t* gp_qspi_cmd_tbl;


/* verification data for strobe timing adjustment  */
#define QSPI_TESTDATA               (0x5A5AA5A5U)
#define QSPI_TESTDATA_OFFSET        (0x00000400U)
#define QSPI_TESTDATA_FLASH_ADDR    (FLASH_CONTENT_CERT_ADDR + QSPI_TESTDATA_OFFSET)    /* Offset 0x00240400 */

static void rpc_save_hw_init_val(void);
static uint32_t read_qspi_flash_id(void);
static uint32_t init_qspi_cmd(uint32_t device_id);
static inline void set_strtim(uint32_t strobe_timing);
#if (QSPI_DDR_MODE==1)
static void adjust_strobe_timing(void);
#endif


void rpc_init(void)
{
    uint32_t reg;
    uint32_t qspi_flash_id;
    uint32_t rtn_val;

    /* Save HW initial value of RPC registers */
    rpc_save_hw_init_val();

    /* judge boot device */
    reg = (mem_read32(RST_MODEMR0) & RST_MODEMR0_BOOTMODE) >> 1U;

    if(reg == BOOTMODE_QSPI_SINGLE_40MHZ)
    {
        /* check the transfer end flag */
        rpc_end_state_check();

        /* Initialize command for QSPI Flash. */
        rtn_val = read_qspi_flash_id();
        qspi_flash_id = (rtn_val & DEVICE_ID_MASK);
        rtn_val       = init_qspi_cmd(qspi_flash_id);
        if(rtn_val != QSPI_CMD_INIT_SUCCESS)
        {
            /* unknown QSPI Flash ID */
            ERROR("QSPI Flash command initialization error!!\n");
            panic;
        }

#if (QSPI_DDR_MODE==1)
        /* Initialize for QSPI DDR transfer mode */
        qspi_ddr_transfer_mode(gp_qspi_cmd_tbl->ddr_quad_io_read_32bit_addr);
#else
        /* Initialize for QSPI SDR transfer mode */
        qspi_sdr_transfer_mode(gp_qspi_cmd_tbl->read_32bit_addr);
#endif
    }
}
/* End of function rpc_init(void) */

void rpc_release(void)
{
    uint32_t loop;

    /* Set HW initial value to RPC registers */
    for(loop = 0; loop < RPC_TBL_MAX; loop++)
    {
         mem_write32(g_rpc_reg_hwinit_val_tbl[loop].reg_addr, g_rpc_reg_hwinit_val_tbl[loop].value);
    }
}
/* End of function rpc_release(void) */

void rpc_end_state_check(void)
{
    /* Wait until RPC data transfer is completed */
    while ((mem_read32(RPC_CMNSR) & CMNSR_TEND) != 1U)
    {
        ;
    }
}
/* End of function rpc_end_state_check(void) */


static void rpc_save_hw_init_val(void)
{
    uint32_t loop;

    g_rpc_reg_hwinit_val_tbl[0].reg_addr  = RPC_CMNCR;
    g_rpc_reg_hwinit_val_tbl[1].reg_addr  = RPC_DRCR;
    g_rpc_reg_hwinit_val_tbl[2].reg_addr  = RPC_DRCMR;
    g_rpc_reg_hwinit_val_tbl[3].reg_addr  = RPC_DREAR;
    g_rpc_reg_hwinit_val_tbl[4].reg_addr  = RPC_DRENR;
    g_rpc_reg_hwinit_val_tbl[5].reg_addr  = RPC_SMCR;
    g_rpc_reg_hwinit_val_tbl[6].reg_addr  = RPC_SMCMR;
    g_rpc_reg_hwinit_val_tbl[7].reg_addr  = RPC_SMENR;
    /* RPC_SMRDR0 is Read only */
    /* RPC_CMNSR is Read only */
    g_rpc_reg_hwinit_val_tbl[8].reg_addr  = RPC_DRDMCR;
    g_rpc_reg_hwinit_val_tbl[9].reg_addr  = RPC_DRDRENR;
    g_rpc_reg_hwinit_val_tbl[10].reg_addr = RPC_SMDRENR;
    g_rpc_reg_hwinit_val_tbl[11].reg_addr = RPC_PHYCNT;
    g_rpc_reg_hwinit_val_tbl[12].reg_addr = RPC_PHYOFFSET1;

    /* Save RPC register initial value */
    for(loop = 0; loop < RPC_TBL_MAX; loop++)
    {
        g_rpc_reg_hwinit_val_tbl[loop].value = mem_read32(g_rpc_reg_hwinit_val_tbl[loop].reg_addr);
    }
}

#if (QSPI_DDR_MODE==0)
void qspi_sdr_transfer_mode(uint32_t command)
{
    uint32_t reg;
    /* check the transfer end flag */
    rpc_end_state_check();

    /* For the initial setting flow of RPC, see Figure 112.12 in    */
    /* "R-Car Series, S4 Series User's Manual" and                  */
    /* "R-Car Series, V4H Series User's Manual".                    */
    /* This RPC setting is for S25FS512S device                     */
    /* A register that does not set a value expects                 */
    /* the initial value of HW.                                     */

    /* PHY calibration */
    set_strtim(STRTIM_SMALLEST);
    reg = mem_read32(RPC_PHYCNT);
    reg |= RPC_PHYCNT_CAL;
    mem_write32(RPC_PHYCNT, reg);
    /* External Address Space Read Mode */
    reg = mem_read32(RPC_CMNCR);
    reg &= ~(RPC_CMNCR_MD);
    mem_write32(RPC_CMNCR, reg);
    /* Read cache Flash */
    reg = mem_read32(RPC_DRCR);
    mem_write32(RPC_DRCR, (reg | RPC_DRCR_RCF));
    /* 32bit address read command*/
    reg = mem_read32(RPC_DRCMR);
    reg &= ~(RPC_DRCMR_CMD_MASK | RPC_DRCMR_OCMD_MASK);
    reg |= (command << RPC_SMCMR_CMD_SHIFT);
    mem_write32(RPC_DRCMR, reg);
    /* Extended external address valid range is [25:0]*/
    reg = mem_read32(RPC_DREAR);
    reg &= ~(RPC_DREAR_EAV_MASK | RPC_DREAR_EAC_MASK);
    reg |= RPC_DREAR_EAC_EXT_ADDR_25BIT;
    mem_write32(RPC_DREAR, reg);
    /* output command is 32bit width */
    reg = mem_read32(RPC_DRENR);
    reg &= ~(RPC_DRENR_CDE_ENABLE | RPC_DRENR_ADE_MASK);
    reg |= (RPC_DRENR_CDE_ENABLE | RPC_DRENR_ADE_32BIT_ADDR);
    mem_write32(RPC_DRENR, reg);
}
/* End of function rpc_init(void) */

#else
void qspi_ddr_transfer_mode(uint32_t command)
{
    uint32_t reg;

    /* check the transfer end flag */
    rpc_end_state_check();

    cpg_reg_write(CPG_RPCCKCR, CPG_RPCCKCR, RPC_CLK_160MHZ);    /* RPCD2 = 80MHz */

    /* Disable pull-up/down function of QSPI0_IO2/QSPI0_IO3 when QSPI DDR transfer mode. */
    reg  = mem_read32(PFC_PUEN3_RW);
    reg &= ~(PFC_PUEN3_QSPI0_IO3 | PFC_PUEN3_QSPI0_IO2);
    pfc_reg_write(PFC_PUEN3_RW, reg);

    /* For the initial setting flow of RPC, see Figure 112.12 in    */
    /* "R-Car Series, S4 Series User's Manual" and                  */
    /* "R-Car Series, V4H Series User's Manual".                    */
    /* This RPC setting is for S25FS512S device                     */
    /* A register that does not set a value expects                 */
    /* the initial value of HW.                                     */

    /* PHY calibration */
    set_strtim(STRTIM_SMALLEST);
    reg = mem_read32(RPC_PHYCNT);
    reg |= RPC_PHYCNT_DDRCAL;
    reg |= RPC_PHYCNT_PHYMEM_SPI_DDR;
    mem_write32(RPC_PHYCNT, reg);
    /* External Address Space Read Mode */
    reg = mem_read32(RPC_CMNCR);
    reg &= ~(RPC_CMNCR_MD | RPC_CMNCR_MOIIO_MASK | RPC_CMNCR_BSZ_MASK);
    reg |= (RPC_CMNCR_MOIIO0_HI_Z | RPC_CMNCR_MOIIO1_HI_Z | RPC_CMNCR_MOIIO2_HI_Z | RPC_CMNCR_MOIIO3_HI_Z);
    mem_write32(RPC_CMNCR, reg);
  /* Read cache Flash */
    reg = mem_read32(RPC_DRCR);
    reg &= ~(RPC_DRCR_RBE_RBURST_MASK);
    reg |= (RPC_DRCR_SSLN_NEGATE | RPC_DRCR_RBE_RBURST_1DATA | RPC_DRCR_RCF | RPC_DRCR_RBE_ENABLE);
    mem_write32(RPC_DRCR, (reg | RPC_DRCR_RCF));
    /* 32bit address read command*/
    reg = mem_read32(RPC_DRCMR);
    reg &= ~(RPC_DRCMR_CMD_MASK | RPC_DRCMR_OCMD_MASK);
    reg |= (command << RPC_SMCMR_CMD_SHIFT);
    mem_write32(RPC_DRCMR, reg);
    /* Extended external address valid range is [25:0]*/
    reg = mem_read32(RPC_DREAR);
    reg &= ~(RPC_DREAR_EAV_MASK | RPC_DREAR_EAC_MASK);
    reg |= RPC_DREAR_EAC_EXT_ADDR_25BIT;
    mem_write32(RPC_DREAR, reg);
    /* output command is 32bit width */
    reg = mem_read32(RPC_DRENR);
    reg &= ~(RPC_DRENR_CDB_MASK | RPC_DRENR_ADB_MASK   | RPC_DRENR_DRDB_MASK
        |    RPC_DRENR_DME_MASK | RPC_DRENR_CDE_ENABLE | RPC_DRENR_ADE_MASK);
    reg |= (RPC_DRENR_CDB_1BIT   | RPC_DRENR_ADB_4BIT   | RPC_DRENR_DRDB_4BIT
        |   RPC_DRENR_DME_ENABLE | RPC_DRENR_CDE_ENABLE | RPC_DRENR_ADE_32BIT_ADDR);
    mem_write32(RPC_DRENR, reg);
    /* Set Dummy Cycle */
    mem_write32(RPC_DRDMCR, (uint32_t)RCAR_QSPI_DDR_DUMMY_CYCLE - 1U);
    /* Specifies DDR transfer of the data read. */
    reg = mem_read32(RPC_DRDRENR);
    reg |= RPC_DRDRENR_DRDRE | RPC_DRDRENR_ADDRE;
    mem_write32(RPC_DRDRENR, reg);
    /* timing adjustment in DDR read operation. */
    reg = mem_read32(RPC_PHYOFFSET1);
    reg &= ~(RPC_PHYOFFSET1_DDRTMG_MSK);
    reg |= RPC_PHYOFFSET1_DDRTMG_DDR;
    mem_write32(RPC_PHYOFFSET1, reg);

    /* Change PHYCNT.DDRCAL */
    reg = mem_read32(RPC_PHYCNT);
    reg |=  RPC_PHYCNT_PHYMEM_SPI_DDR;
    reg &=  ~RPC_PHYCNT_CAL;
    reg |=  RPC_PHYCNT_DDRCAL;
    mem_write32(RPC_PHYCNT, reg);

    adjust_strobe_timing();

    /* Set data burst length to 256 byte */
    reg = mem_read32(RPC_DRCR);
    reg |= RPC_DRCR_RBE_RBURST_32DATA;
    mem_write32(RPC_DRCR, reg);
}

static void adjust_strobe_timing(void)
{
    uint32_t reg;
    uint32_t flash_data;
    uint32_t remap_flash_addr;
    uint32_t strobe_timing = STRTIM_SMALLEST;
    uint32_t first_match = STRTIM_MATCH_ERROR;
    uint32_t match_count = 0U;
    uint32_t loop;

    /* Convert verification data to logical addresses. */
    remap_register(QSPI_TESTDATA_FLASH_ADDR, &remap_flash_addr);

    INFO("Adjust strobe timing\n");

    INFO("QSPI_TESTDATA_FLASH_ADDR = 0x%08x\n",remap_flash_addr);

    for(loop = 0U; loop <= STRTIM_SMALLEST; loop++)
    {
        /* RPC Transfer Disable */
        mem_write32(RPC_DRENR, RPC_DRENR_TRANS_DISABLE);

        /* Read cache Flash */
        reg = mem_read32(RPC_DRCR);
        mem_write32(RPC_DRCR, (reg | RPC_DRCR_RCF));

        /* set strobe timing */
        set_strtim(strobe_timing);

        /* RPC Transfer Enable */
        reg = mem_read32(RPC_DRENR);
        reg &= ~(RPC_DRENR_CDB_MASK | RPC_DRENR_ADB_MASK   | RPC_DRENR_DRDB_MASK
            |    RPC_DRENR_DME_MASK | RPC_DRENR_CDE_ENABLE | RPC_DRENR_ADE_MASK);
        reg |= (RPC_DRENR_CDB_1BIT   | RPC_DRENR_ADB_4BIT   | RPC_DRENR_DRDB_4BIT
            |   RPC_DRENR_DME_ENABLE | RPC_DRENR_CDE_ENABLE | RPC_DRENR_ADE_32BIT_ADDR);
        mem_write32(RPC_DRENR, reg);

        /* Read verification Data on QSPIFlash */
        flash_data = mem_read32(remap_flash_addr);

        /* check the transfer end flag */
        rpc_end_state_check();

        INFO("strobe timing:0x%x\tflash_data:0x%x\ttest_data:0x%x\n", strobe_timing, flash_data, QSPI_TESTDATA);

        /* Comparison of Verification Data */
        if(flash_data == QSPI_TESTDATA)
        {
            /* First match of validation data. */
            if(first_match == STRTIM_MATCH_ERROR)
            {
                first_match = strobe_timing;
            }
            match_count++;
        }
        else
        {
            /* If out of timing to match */
            if(first_match != STRTIM_MATCH_ERROR)
            {
                /* Terminate the exploration of Strobe timing. */
                break;
            }
        }
        strobe_timing--;
    }

    /* Verification Data is not matched */
    if(first_match == STRTIM_MATCH_ERROR)
    {
        ERROR("Failed Strobe timing adjustment of DDR transfer mode.\n");
        panic;
    }

    INFO("first_match:0x%x\tmatch_count:0x%x\n", first_match, match_count);
    remap_unregister(remap_flash_addr);

    /* strobe timing value adjustment */
    strobe_timing = first_match - (match_count / 2U);

    /* set strobe timing */
    set_strtim(strobe_timing);
    INFO("RPC_PHYCNT\t = 0x%08x\n",mem_read32(RPC_PHYCNT));
}
#endif

static inline void set_strtim(uint32_t strobe_timing)
{
    uint32_t reg;
    reg = mem_read32(RPC_PHYCNT);
    reg &= ~((STRTIM_MASK_3 << 24U) | (STRTIM_MASK << 15U));
    reg |= ((strobe_timing & STRTIM_MASK_3) << 24U);    /* bit[27] */
       reg |= ((strobe_timing & STRTIM_MASK) << 15U);   /* bit[17:15] */
    mem_write32(RPC_PHYCNT, reg);
}


static uint32_t read_qspi_flash_id(void)
{
    uint32_t reg;
    uint32_t device_id;

    reg = mem_read32(RPC_PHYCNT);
    reg &= ~( RPC_PHYCNT_HS
            | RPC_PHYCNT_WBUF2
            | RPC_PHYCNT_WBUF
            | RPC_PHYCNT_PHYMEM_MASK);
    mem_write32(RPC_PHYCNT, reg);
    set_strtim(STRTIM_SMALLEST);
    reg |= RPC_PHYCNT_CAL;
    mem_write32(RPC_PHYCNT, reg);
        /* bit31  CAL         =  1 : PHY calibration */
        /* bit1-0 PHYMEM[1:0] = 00 : QSPI-SDR */

    reg  =  mem_read32(RPC_CMNCR);
    reg &= ~(RPC_CMNCR_BSZ_MASK);
    reg |=  (RPC_CMNCR_MD);
    mem_write32(RPC_CMNCR, reg);
        /* bit31  MD       =  1 : Manual mode */
        /* bit1-0 BSZ[1:0] = 00 : QSPI Flash x 1 */

    reg =  mem_read32(RPC_SMCMR);
    reg &= ~( RPC_SMCMR_CMD_MASK
            | RPC_SMCMR_OCMD_MASK);
    reg |= (FLASH_CMD_READ_ID << RPC_SMCMR_CMD_SHIFT);
    mem_write32(RPC_SMCMR, reg);
        /* bit23-16 CMD[7:0] = 0x9F : Read ID command (for Palladium QSPI model) */

    reg =  mem_read32(RPC_SMDRENR);
    reg &= ~( RPC_SMDRENR_HYPE_MASK
            | RPC_SMDRENR_ADDRE
            | RPC_SMDRENR_OPDRE
            | RPC_SMDRENR_SPIDRE);
    mem_write32(RPC_SMDRENR, reg);
        /* bit8 ADDRE  = 0 : Address SDR transfer */
        /* bit0 SPIDRE = 0 : DATA SDR transfer */

    reg =  mem_read32(RPC_SMENR);
    reg &= ~( RPC_SMENR_CDB_MASK
            | RPC_SMENR_OCDB_MASK
            | RPC_SMENR_ADB_MASK
            | RPC_SMENR_OPDB_MASK
            | RPC_SMENR_SPIDB_MASK
            | RPC_SMENR_DME_EN
            | RPC_SMENR_OCDE_EN
            | RPC_SMENR_ADE_MASK
            | RPC_SMENR_OPDE_MASK
            | RPC_SMENR_SPIDE_MASK);
    reg |=  ( RPC_SMENR_CDE_EN
            | RPC_SMENR_SPIDE_SPI_32);
    mem_write32(RPC_SMENR, reg);
        /* bit31-30 CDB[1:0]   =   00 : 1bit width command (QSPI0_MOSI) */
        /* bit25-24 ADB[1:0]   =   00 : 1bit width address (QSPI0_MOSI) */
        /* bit17-16 SPIDB[1:0] =   00 : 1bit width transfer data (QSPI0_MISO) */
        /* bit15    DME        =    0 : No dummy cycle */
        /* bit14    CDE        =    1 : Command enable */
        /* bit11-8  ADE[3:0]   = 0000 : Address output disable */
        /* bit3-0   SPIDE[3:0] = 1111 : 32bit transfer */

    reg =  mem_read32(RPC_SMCR);
    reg &= ~( RPC_SMCR_SSLKP
            | RPC_SMCR_SPIWE);
    reg |=  ( RPC_SMCR_SPIRE
            | RPC_SMCR_SPIE);
    mem_write32(RPC_SMCR, reg);
        /* bit2     SPIRE      = 1 : Data read enable */
        /* bit1     SPIWE      = 0 : Data write disable */
        /* bit0     SPIE       = 1 : SPI transfer start */

    rpc_end_state_check();

    device_id = mem_read32(RPC_SMRDR0);

    return device_id;
}
/* End of function read_qspi_flash_id(void) */

static uint32_t init_qspi_cmd(uint32_t device_id)
{
    uint32_t    i = 0U;
    uint32_t    rtn_val = QSPI_CMD_INIT_ERROR;

    gp_qspi_cmd_tbl = NULL;

    for (i = 0U; i < VENDOR_NUM; i++)
    {
        if (device_id == dev_id_index[i])
        {
            gp_qspi_cmd_tbl = &qspi_cmd_tbls[i];
            rtn_val = QSPI_CMD_INIT_SUCCESS;
            break;
        }
    }
    return rtn_val;
}
/* End of function init_qspi_cmd(uint32_t device_id) */
