/*******************************************************************************
 * 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 <remap.h>
#include <mem_io.h>
#include <rst_register.h>
#include <cpg_register.h>
#include <cpg.h>
#include <rpc_register.h>
#include <rpcqspidrv.h>
#include <rpc.h>
#include <image_load_flash.h>
#include <pfc.h>
#include <log.h>

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

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];

/* The number of Flash vendor */
#if USER_ADDED_QSPI == 0
#define VENDOR_NUM                  (1U)
#endif /* USER_ADDED_QSPI == 0 */
/* Command for S25FS512S */
#define MT25QU01GB_READ_FAST             (0x0CU) /* 4FAST_READ, read_fast */
#define MT25QU01GB_SEC_ER_4BYTE_ADDR     (0xDCU) /* 4SE, sector_erase_4byte_addr */
#define MT25QU01GB_PARA_4KBYTE_ER        (0x21U) /* 4P4E, parameter_4kbyte_erase */
#define MT25QU01GB_PP_4BYTE_ADDR         (0x12U) /* 4PP, pp_4byte_addr */
#define MT25QU01GB_READ_ANY_REG          (0x05U) /* READ STATUS, read_any_register */
#define MT25QU01GB_READ_STATUS           (0x70U) /* READ FLAG STATUS, read_stts_register */
#define MT25QU01GB_WRITE_ENABLE          (0x06U) /* WREN, write_enable */
#define S25FS512S_READ_32BIT_ADDR                   (0x13U) /* read 32bit address */
#define S25FS512S_DDR_QUAD_IO_READ_32BIT_ADDR       (0xEEU) /* DDR quad I/O read 32bit address */

#if USER_ADDED_QSPI == 1
/* User can customize for another vendor's QSPI Flash. */
#define VENDOR_NUM                  (2U)
/* Command for XXXXXXXXX */
#define XXXXXXXXX_READ_FAST             (0x0CU) /* 4-byte read_fast */
#define XXXXXXXXX_SEC_ER_4BYTE_ADDR     (0xDCU) /* sector_erase_4byte_addr */
#define XXXXXXXXX_PARA_4KBYTE_ER        (0x21U) /* parameter_4kbyte_erase */
#define XXXXXXXXX_PP_4BYTE_ADDR         (0x12U) /* page_program_4byte_addr */
#define XXXXXXXXX_READ_ANY_REG          (0x05U) /* READ STATUS, read_any_register */
#define XXXXXXXXX_READ_STATUS           (0x2BU) /* RDSCUR, read_stts_register */
#define XXXXXXXXX_WRITE_ENABLE          (0x06U) /* WREN, write_enable */
#define XXXXXXXXX_READ_32BIT_ADDR                   (0x13U) /* read 32bit address */
#define XXXXXXXXX_DDR_QUAD_IO_READ_32BIT_ADDR       (0xEEU) /* DDR quad I/O read 32bit address */
#endif /* USER_ADDED_QSPI == 1 */

static const st_qspi_cmd_tbl_t qspi_cmd_tbls[VENDOR_NUM] =
{
    /* Command table for MT25QU01GB */
    {
        MT25QU01GB_READ_FAST,            /* read_fast */
        MT25QU01GB_SEC_ER_4BYTE_ADDR,    /* sector_erase_4byte_addr */
        MT25QU01GB_PARA_4KBYTE_ER,       /* parameter_4kbyte_erase */
        MT25QU01GB_PP_4BYTE_ADDR,        /* pp_4byte_addr */
        MT25QU01GB_READ_ANY_REG,         /* read_any_register */
        MT25QU01GB_READ_STATUS,          /* read_status */
        MT25QU01GB_WRITE_ENABLE,         /* write_enable */
        S25FS512S_READ_32BIT_ADDR,                /* read 32bit address */
        S25FS512S_DDR_QUAD_IO_READ_32BIT_ADDR     /* DDR quad I/O read 32bit address */
    },
#if USER_ADDED_QSPI == 1
    /* Command table for XXXXXXXXX */
    /* User can customize for another vendor's QSPI Flash. */
    {
        XXXXXXXXX_READ_FAST,            /* read_fast */
        XXXXXXXXX_SEC_ER_4BYTE_ADDR,    /* sector_erase_4byte_addr */
        XXXXXXXXX_PARA_4KBYTE_ER,       /* parameter_4kbyte_erase */
        XXXXXXXXX_PP_4BYTE_ADDR,        /* pp_4byte_addr */
        XXXXXXXXX_READ_ANY_REG,         /* read_any_register */
        XXXXXXXXX_READ_STATUS,          /* read_status */
        XXXXXXXXX_WRITE_ENABLE,         /* write_enable */
        XXXXXXXXX_READ_32BIT_ADDR,               /* read 32bit address */
        XXXXXXXXX_DDR_QUAD_IO_READ_32BIT_ADDR    /* DDR quad I/O read 32bit address */
    }
#endif /* USER_ADDED_QSPI == 1 */
};

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

const st_qspi_cmd_tbl_t* gp_qspi_cmd_tbl;

static void rpc_save_hw_init_val(void);
static uint32_t init_qspi_cmd(uint32_t device_id);

void rpc_init(void)
{
    /* Save HW initial value of RPC registers */
    rpc_save_hw_init_val();
}

void qspi_flash_rw_init(void)
{
    uint32_t reg;
    uint32_t qspi_flash_id;
    uint32_t rtn_val;
    static bool qspi_flash_id_checked = false;

    if (qspi_flash_id_checked == true)
    {
        NOTICE("QSPI Flash ID has been checked.\n");
        return;
    }
    qspi_flash_id_checked = true;

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

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

        /* Initialize command for QSPI Flash. */
        read_qspi_flash_id(&qspi_flash_id);
        qspi_flash_id = (qspi_flash_id & DEVICE_ID_MASK);
        NOTICE("QSPI Flash ID = 0x%08x\n", qspi_flash_id);
        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);
    }
}

uint8_t prk3_rev = 3;
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];
            if (device_id == DEVID_XXXXXXXXX)
                prk3_rev = 4;
            rtn_val = QSPI_CMD_INIT_SUCCESS;
            break;
        }
    }
    return rtn_val;
}

int check_Erase_Fail(uint32_t status) {
    if (prk3_rev <= 3)
        return (status & BIT5);
    return (status & BIT6);
}
/* End of function init_qspi_cmd(uint32_t device_id) */
