/*******************************************************************************
 * 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 2022-2023 Renesas Electronics Corporation All rights reserved.
 *******************************************************************************/

/*******************************************************************************
 * DESCRIPTION   : MCU power management driver
 ******************************************************************************/
 /******************************************************************************
 * @file          cpu_on.c
 * - Version      : 0.02
 * @brief         1. Boot process of MCU CPU core.
 *                2. Set Option Byte to OPBT.
 *                3. Disable the Bus Guard.
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 21.06.2022 0.01     First Release
 *         : 02.02.2023 0.02     Moved definitions to header file.
 *****************************************************************************/

#include <stdint.h>
#include <types.h>
#include <mem_io.h>
#include <mcu_register.h>
#include <remap.h>
#include <cpu_on_for_mcu.h>

/* MCU */
#define MCU_OPBT_MAX         (12U)
#define MCU_ICUM_OPBT_MAX    (7U)
#define MCU_PBG_MAX          (7U)
#define MCU_HBG_MAX          (9U)
#define LOCAL_FLASH_BUS_MODE (0x12B9B0A1U)

#define MCU_RESET_READY     (0x00000001U)
#define MCU_RCT_RUNNING     (0x00000001U)

#define CODESRAM_ROUND_MASK     (0x000FFFFFU)

#define OPBT_EMPTY_VALUE         (0xFFFFFFFFU)

static void csrm_n_csifcode_protect(uint32_t bit_shift);

void mcu_cpu_on(uint32_t target)
{
    uint32_t boot_ctrl = 0U;
    uint32_t ret;

    if(MCU_PWR_TARGET_G4MH == target)
    {
#if ((BOOT_MCU & MCU_BOOT_G4MH) != 0U)
        boot_ctrl = MCU_G4MH_BOOT_CTLR;
#endif /* ((BOOT_MCU & MCU_BOOT_G4MH) != 0U) */
    }
    else if(MCU_PWR_TARGET_ICUMH == target)
    {
#if ((BOOT_MCU & MCU_BOOT_ICUMH) != 0U)
        boot_ctrl = MCU_ICUMH_BOOT_CTLR;
#endif /* ((BOOT_MCU & MCU_BOOT_ICUMH) != 0) */
    }
    else
    {
        /* No Process */
    }

    /* Execute the reset process of MCU core.        *
     * If the register address is not set in "A",    *
     * exit the function without executing anything. */
    if(boot_ctrl != 0U)
    {
        /* Release write protection of SCDS0 */
        mem_write32(MCUAXI_PBG_ERRSLV_PBGKCPROT,  MCU_HBG_REL_CODE);

        /* MCU core reset */
        ret = mem_read32(boot_ctrl);
        ret |= MCU_RESET_READY;
        mem_write32(boot_ctrl, ret);
        ret = mem_read32(MCU_OPBT_CTRL);
        ret |= MCU_RESET_READY;
        mem_write32(MCU_OPBT_CTRL, ret);

        /* Wait until the MCU status is set to start. */
        do
        {
            ret = mem_read32(MCU_OPBT_STAT);
            ret &= MCU_RCT_RUNNING;
        } while (ret != MCU_RCT_RUNNING);

        /* write protection of SCDS0 */
        mem_write32(MCUAXI_PBG_ERRSLV_PBGKCPROT,  MCU_HBG_PROT_CODE);
    }
}
/* End of function mcu_cpu_on(uint32_t target) */

void mcu_set_opbt(void)
{
    uint32_t loop;
    const uint32_t opbt_reg[MCU_OPBT_MAX] =
    { MCU_RESET_VECTOR_PE0,
      MCU_RESET_VECTOR_PE1,
      MCU_OPBT0,
      MCU_OPBT1,
      MCU_OPBT2,
      MCU_OPBT3,
      MCU_OPBT4,
      MCU_OPBT6,
      MCU_OPBT7,
      MCU_OPBT8,
      MCU_OPBT9,
      MCU_OPBT96
    };

    uint32_t opbt_val[MCU_OPBT_MAX] =
    { 0x00000400U,
      0x00000400U,
      0x3D810010U,
      0x00700000U,
      0x707FFFFFU,
      0x00000000U,
      0x0C0C0C0FU,
      0x00000F00U,
      0x00000FFFU,
      0x02000000U,
      0x03000300U,
      0x00000000U
    };

    for (loop = 0U; loop < MCU_OPBT_MAX; loop++)
    {
        mem_write32(opbt_reg[loop], opbt_val[loop]);
        opbt_val[loop] = OPBT_EMPTY_VALUE;
    }
}
/* End of function mcu_set_opbt(uint32_t g4mh_addr) */

void mcu_set_icum_opbt(void)
{
    uint32_t loop;
    const uint32_t opbt_reg[MCU_ICUM_OPBT_MAX] =
    { MCU_ICUM_OPBT0,
      MCU_ICUM_OPBT1,
      MCU_ICUM_OPBT2,
      MCU_ICUM_OPBT4,
      MCU_ICUM_OPBT5,
      MCU_ICUM_OPBT6,
      MCU_ICUM_OPBT7
    };

#if (BOOT_MCU  == MCU_BOOT_G4MH_ICUMH)
    uint32_t opbt_val[MCU_ICUM_OPBT_MAX] =
    { 0x0FFFFFFFU,
      0x00500000U,
      0x00500000U,
      0xFFFFFFEFU,
      0x00600000U,
      0xFFFFFFFFU,
      0xFFFFFFFFU
    };
#else
    uint32_t opbt_val[MCU_ICUM_OPBT_MAX] =
    { OPBT_EMPTY_VALUE,
      OPBT_EMPTY_VALUE,
      OPBT_EMPTY_VALUE,
      OPBT_EMPTY_VALUE,
      OPBT_EMPTY_VALUE,
      OPBT_EMPTY_VALUE,
      OPBT_EMPTY_VALUE
    };
#endif

    for (loop = 0U; loop < MCU_ICUM_OPBT_MAX; loop++)
    {
        mem_write32(opbt_reg[loop], opbt_val[loop]);
        opbt_val[loop] = OPBT_EMPTY_VALUE;
    }
}
/* End of function mcu_set_icum_opbt(uint32_t icumh_addr) */

void mcu_set_hbg(void)
{
    uint32_t loop;
    const uint32_t pbg_reg[MCU_PBG_MAX][2U] =
    {    /* register address     setting value */
        {MCUAXI_PBG_PBGPROT0_0,  0x00000000U},
        {MCUAXI_PBG_PBGPROT0_1,  0x00000000U},
        {MCUAXI_PBG_PBGPROT0_2,  0x00000000U},
        {MCUAXI_PBG_PBGPROT0_3,  0x00000000U},
        {MCUAXI_PBG_PBGPROT0_4,  0x00000000U},
        {MCUAXI_PBG_PBGPROT0_5,  0x00000000U},
        {MCUAXI_PBG_PBGPROT0_6,  0x00000000U}
    };

    const uint32_t hbg_reg[MCU_HBG_MAX][2U] =
    {    /* register address    setting value */
        {MCU_HBG_CS0_HBGPROT0,  0x00000000U},
        {MCU_HBG_CS1_HBGPROT0,  0x00000000U},
        {MCU_HBG_CS2_HBGPROT0,  0x00000000U},
        {MCU_HBG_CS3_HBGPROT0,  0x00000000U},
        {MCU_HBG_CS4_HBGPROT0,  0x00000000U},
        {MCU_HBG_CS5_HBGPROT0,  0x00000000U},
        {MCU_HBG_DS_HBGPROT0,   0x00000000U},
        {MCU_HBG_SOCM_HBGPROT0, 0x00000000U},
        {MCU_HBG_SOCS_HBGPROT0, 0x00000000U}
    };

    const uint32_t hbg_prot_reg[MCU_HBG_MAX] =
    {
        MCU_HBGSLVER_CS0_HBGKCPROT,
        MCU_HBGSLVER_CS1_HBGKCPROT,
        MCU_HBGSLVER_CS2_HBGKCPROT,
        MCU_HBGSLVER_CS3_HBGKCPROT,
        MCU_HBGSLVER_CS4_HBGKCPROT,
        MCU_HBGSLVER_CS5_HBGKCPROT,
        MCU_HBGSLVER_DS_HBGKCPROT,
        MCU_HBGSLVER_SOCM_HBGKCPROT,
        MCU_HBGSLVER_SOCS_HBGKCPROT
    };

    /* Release write protection of SCDS0 */
    mem_write32(MCUAXI_PBG_ERRSLV_PBGKCPROT,  MCU_HBG_REL_CODE);

    /* Set PBG register */
    for (loop = 0U; loop < MCU_PBG_MAX; loop++)
    {
        mem_write32(pbg_reg[loop][0U], pbg_reg[loop][1U]);
    }

    /* write protection of SCDS0 */
    mem_write32(MCUAXI_PBG_ERRSLV_PBGKCPROT,  MCU_HBG_PROT_CODE);

    /* Set HBG register */
    for (loop = 0U; loop < MCU_HBG_MAX; loop++)
    {
        hbg_reg_write(hbg_prot_reg[loop], hbg_reg[loop][0U], hbg_reg[loop][1U]);
    }
}
/* End of function mcu_set_hbg(void) */

void mcu_set_csrm(uint32_t boot_addr, uint32_t size)
{
    uint32_t loop;
    uint32_t bus_num;
    uint32_t set_num;
    const uint32_t csrm_reg[MCU_CSRM_MAX] =
    { MCU_CSRM0CSIFCODE,
      MCU_CSRM1CSIFCODE,
      MCU_CSRM2CSIFCODE,
      MCU_CSRM3CSIFCODE,
      MCU_CSRM4CSIFCODE,
      MCU_CSRM5CSIFCODE,
    };

    /* Calculate the area used by Code SRAM. */
    bus_num = ((boot_addr  & CODESRAM_BUS_NUM_MASK) >> 20U);
    set_num = ((size & CODESRAM_BUS_NUM_MASK) >> 20U);

    /* Set CSRM register */
    for (loop = 0U; loop < set_num; loop++)
    {
        mem_write32(csrm_reg[bus_num + loop], LOCAL_FLASH_BUS_MODE);

        /* Write protection of CSRMnCSIFCODE registers */
        csrm_n_csifcode_protect((bus_num + loop));
    }
}
/* End of function mcu_set_csrm(void) */

void hbg_reg_write(uint32_t prot_reg_addr, uint32_t reg_addr, uint32_t val)
{
    mem_write32(prot_reg_addr, MCU_HBG_REL_CODE);
    mem_write32(reg_addr, val);
    mem_write32(prot_reg_addr, MCU_HBG_PROT_CODE);
}
/* End of function hbg_reg_write(uint32_t prot_reg_addr, uint32_t reg_addr, uint32_t val) */

static void csrm_n_csifcode_protect(uint32_t bit_shift)
{
    /* Control CSIFCODE_LOCK to protect writing to CSRMnCSIFCODE during product mass production. */
}
/* End of function csrm_n_csifcode_protect(uint32_t bit_shift) */
