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

/*******************************************************************************
 * DESCRIPTION   : Loader main common function
 ******************************************************************************/
/******************************************************************************
 * @file          loader_main_common.c
 * - Version      : 0.05
 * @brief         1.Set BL31 parameter.
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 15.11.2022 0.01     First Release
 *         : 04.04.2023 0.02     Removed stdio.h.
 *         : 13.09.2024 0.03     Updated smoni_ep_info->ulpc_high to 0x20,
 *                               smoni_ipl_param->pnonsecepinfo_high to 0x20.
 *         : 11.10.2024 0.04     Updated Region ID and RAM protection setting
 *                               for QNX for V4M.
 *         : 26.05.2025 0.05     Added optee_ep_info parameter.
 *****************************************************************************/

#include <stdint.h>
#include <mem_io.h>
#include <loader_main_common.h>
#include <image_load.h>
#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
#include "access_protection.h"
#endif /* ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) */

#define SMONI_IPL_PARAM_OFFSET  (0x00022200U)
#define SMONI_EP_INFO_OFFSET    (SMONI_IPL_PARAM_OFFSET + 0x0030U)
#define OPTEE_EP_INFO_OFFSET    (SMONI_IPL_PARAM_OFFSET + 0x0088U)
#define BL31_KIND_BOOT_ADDR     (SMONI_IPL_PARAM_OFFSET + 0x0D00U)
#define BL31_COLD_BOOT          (0x0000000000000000U)
#define BL31_WARM_BOOT          (0x0000000000000001U)
#define SMONI_KIND_BOOT_PARAM   (0xFFFFFFFFFFFFFFFFU)

/* struct */
typedef struct{
    uint8_t uctype;
    uint8_t ucversion;
    uint16_t ussize;
    uint32_t uiattr;
    uint32_t psecmonimageinfo_low;
    uint32_t psecmonimageinfo_high;
    uint32_t psecoptepinfo_low;
    uint32_t psecoptepinfo_high;
    uint32_t psecoptimageinfo_low;
    uint32_t psecoptimageinfo_high;
    uint32_t pnonsecepinfo_low;
    uint32_t pnonsecepinfo_high;
    uint32_t pnonsecimageinfo_low;
    uint32_t pnonsecimageinfo_high;
}st_smoni_iplparams_t;

typedef struct{
    uint8_t uctype;
    uint8_t ucversion;
    uint16_t ussize;
    uint32_t uiattr;
    uint32_t ulpc_low;
    uint32_t ulpc_high;
    uint32_t ulspsr_low;
    uint32_t ulspsr_high;
    uint32_t ularg0_low;
    uint32_t ularg0_high;
    uint32_t ularg1_low;
    uint32_t ularg1_high;
    uint32_t ularg2_low;
    uint32_t ularg2_high;
    uint32_t ularg3_low;
    uint32_t ularg3_high;
    uint32_t ularg4_low;
    uint32_t ularg4_high;
    uint32_t ularg5_low;
    uint32_t ularg5_high;
    uint32_t ularg6_low;
    uint32_t ularg6_high;
    uint32_t ularg7_low;
    uint32_t ularg7_high;
}st_smoni_entrypointinfo_t;

#if (OPTEE_LOAD_ENABLE == OPTEE_DISABLE)
 void smoni_set_param(uintptr_t smoni_entry_point,
                             uintptr_t uboot_entry_point)
#else
void smoni_set_param(uintptr_t smoni_entry_point,
                            uintptr_t uboot_entry_point,
                            uintptr_t tee_entry_point)
#endif /* OPTEE_LOAD_ENABLE == OPTEE_DISABLE */
{
    st_smoni_iplparams_t *smoni_ipl_param;
    st_smoni_entrypointinfo_t *smoni_ep_info;
#if (OPTEE_LOAD_ENABLE == OPTEE_ENABLE)
    st_smoni_entrypointinfo_t *optee_ep_info;
#endif /* OPTEE_LOAD_ENABLE == OPTEE_ENABLE */
#ifdef AARCH64
    union {
        uintptr_t ptr;
        struct {
            uint32_t low;
            uint32_t high;
        } u32;
    } _tmp;
#endif

    /* set struct address */
    smoni_ipl_param = (st_smoni_iplparams_t *)
                (smoni_entry_point + SMONI_IPL_PARAM_OFFSET);
    smoni_ep_info = (st_smoni_entrypointinfo_t *)
                (smoni_entry_point + SMONI_EP_INFO_OFFSET);
#if (OPTEE_LOAD_ENABLE == OPTEE_ENABLE)
    optee_ep_info = (st_smoni_entrypointinfo_t *)
                (smoni_entry_point + OPTEE_EP_INFO_OFFSET);
#endif /* OPTEE_LOAD_ENABLE == OPTEE_ENABLE */

    /* set parameter */
    smoni_ipl_param->uctype                 = 0x03U;
    smoni_ipl_param->ucversion              = 0x01U;
    smoni_ipl_param->ussize                 = 0x0030U;
    smoni_ipl_param->uiattr                 = 0x00000000U;
    smoni_ipl_param->psecmonimageinfo_low   = 0x00000000U;
    smoni_ipl_param->psecmonimageinfo_high  = 0x00000000U;
#if (OPTEE_LOAD_ENABLE == OPTEE_DISABLE)
    smoni_ipl_param->psecoptepinfo_low      = 0x00000000U;
#else
  #ifdef AARCH64
    _tmp.ptr = (uintptr_t)optee_ep_info;
    smoni_ipl_param->psecoptepinfo_low      = _tmp.u32.low;
  #else
    smoni_ipl_param->psecoptepinfo_low      = (uint32_t)optee_ep_info;
  #endif
#endif /* OPTEE_LOAD_ENABLE == OPTEE_DISABLE */
#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
#if (ACC_PROT_ENABLE == PROTECTION_ENABLE)
    smoni_ipl_param->psecoptepinfo_high     = 0x00000020U;  /* OP-TEE entry point information 0x20_46422288 */
#elif (ACC_PROT_ENABLE == PROTECTION_DISABLE)
    smoni_ipl_param->psecoptepinfo_high     = 0x00000000U;
#endif /* ACC_PROT_ENABLE == PROTECTION_ENABLE */
#else
    smoni_ipl_param->psecoptepinfo_high     = 0x00000000U;
#endif /* ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) */
    smoni_ipl_param->psecoptimageinfo_low   = 0x00000000U;
    smoni_ipl_param->psecoptimageinfo_high  = 0x00000000U;
#ifdef AARCH64
    _tmp.ptr = (uintptr_t)smoni_ep_info;
    smoni_ipl_param->pnonsecepinfo_low      = _tmp.u32.low;
#else
    smoni_ipl_param->pnonsecepinfo_low      = (uint32_t)smoni_ep_info;
#endif
#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
#if (ACC_PROT_ENABLE == PROTECTION_ENABLE)
    smoni_ipl_param->pnonsecepinfo_high     = 0x00000020U;  /* Secure monitor entry point 0x20_XXXXXXXX */
    smoni_ipl_param->pnonsecepinfo_high     = 0x00000020U;  /* Secure monitor entry point 0x20_46400000 */
#elif (ACC_PROT_ENABLE == PROTECTION_DISABLE)
    smoni_ipl_param->pnonsecepinfo_high     = 0x00000000U;
#endif /* ACC_PROT_ENABLE == PROTECTION_ENABLE */
#else
    smoni_ipl_param->pnonsecepinfo_high     = 0x00000000U;
#endif /* ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) */
    smoni_ipl_param->pnonsecimageinfo_low   = 0x00000000U;
    smoni_ipl_param->pnonsecimageinfo_high  = 0x00000000U;

    smoni_ep_info->uctype                   = 0x01U;
    smoni_ep_info->ucversion                = 0x01U;
    smoni_ep_info->ussize                   = 0x0058U;      /* structure size */
    smoni_ep_info->uiattr                   = 0x00000001U;  /* SECURE */
#ifdef AARCH64
    _tmp.ptr = (uintptr_t)uboot_entry_point;
    smoni_ep_info->ulpc_low                 = _tmp.u32.low;
#else
    smoni_ep_info->ulpc_low                 = uboot_entry_point;
#endif
#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
#if (ACC_PROT_ENABLE == PROTECTION_ENABLE)
    smoni_ep_info->ulpc_high                = 0x00000020U;  /* U-boot entry point 0x20_50000000 */
#elif (ACC_PROT_ENABLE == PROTECTION_DISABLE)
    smoni_ep_info->ulpc_high                = 0x00000000U;
#endif
#else
    smoni_ep_info->ulpc_high                = 0x00000000U;
#endif /* ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) */
    /* SPSR_EL3.E[9]   = b1    (BigEndian)      *
     *         .A[8]   = b1    (DataAbort MASK) *
     *         .I[7]   = b1    (IRQ MASK)       *
     *         .F[6]   = b1    (FIQ MASK)       *
     *         .M[4]   = b0    (AArcch64)       *
     *         .M[3:1] = b0101 (EL1h)           */
    smoni_ep_info->ulspsr_low               = 0x000003C5U;
    smoni_ep_info->ulspsr_high              = 0x00000000U;
    smoni_ep_info->ularg0_low               = 0x00000000U;
    smoni_ep_info->ularg0_high              = 0x00000000U;
    smoni_ep_info->ularg1_low               = 0x00000000U;
    smoni_ep_info->ularg1_high              = 0x00000000U;
    smoni_ep_info->ularg2_low               = 0x00000000U;
    smoni_ep_info->ularg2_high              = 0x00000000U;
    smoni_ep_info->ularg3_low               = 0x00000000U;
    smoni_ep_info->ularg3_high              = 0x00000000U;
    smoni_ep_info->ularg4_low               = 0x00000000U;
    smoni_ep_info->ularg4_high              = 0x00000000U;
    smoni_ep_info->ularg5_low               = 0x00000000U;
    smoni_ep_info->ularg5_high              = 0x00000000U;
    smoni_ep_info->ularg6_low               = 0x00000000U;
    smoni_ep_info->ularg6_high              = 0x00000000U;
    smoni_ep_info->ularg7_low               = 0x00000000U;
    smoni_ep_info->ularg7_high              = 0x00000000U;

#if (OPTEE_LOAD_ENABLE == OPTEE_ENABLE)
    optee_ep_info->uctype                   = 0x01U;
    optee_ep_info->ucversion                = 0x02U;
    optee_ep_info->ussize                   = 0x0058U;
    optee_ep_info->uiattr                   = 0x00000008U;
#ifdef AARCH64
    _tmp.ptr = (uintptr_t)tee_entry_point;
    optee_ep_info->ulpc_low                 = _tmp.u32.low;
#else
    optee_ep_info->ulpc_low                 = tee_entry_point;
#endif
#if ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M))
#if (ACC_PROT_ENABLE == PROTECTION_ENABLE)
    optee_ep_info->ulpc_high                = 0x00000020U;  /* OP-TEE entry point 0x20_44100000 */
#elif (ACC_PROT_ENABLE == PROTECTION_DISABLE)
    optee_ep_info->ulpc_high                = 0x00000000U;
#endif /* ACC_PROT_ENABLE == PROTECTION_ENABLE */
#else
    optee_ep_info->ulpc_high                = 0x00000000U;
#endif /* ((RCAR_LSI == RCAR_V4H) || (RCAR_LSI == RCAR_V4M)) */
    optee_ep_info->ulspsr_low               = 0x000003C5U;
    optee_ep_info->ulspsr_high              = 0x00000000U;
    optee_ep_info->ularg0_low               = 0x00000000U;
    optee_ep_info->ularg0_high              = 0x00000000U;
    optee_ep_info->ularg1_low               = 0x00000000U;
    optee_ep_info->ularg1_high              = 0x00000000U;
    optee_ep_info->ularg2_low               = 0x00000000U;
    optee_ep_info->ularg2_high              = 0x00000000U;
    optee_ep_info->ularg3_low               = 0x00000000U;
    optee_ep_info->ularg3_high              = 0x00000000U;
    optee_ep_info->ularg4_low               = 0x00000000U;
    optee_ep_info->ularg4_high              = 0x00000000U;
    optee_ep_info->ularg5_low               = 0x00000000U;
    optee_ep_info->ularg5_high              = 0x00000000U;
    optee_ep_info->ularg6_low               = 0x00000000U;
    optee_ep_info->ularg6_high              = 0x00000000U;
    optee_ep_info->ularg7_low               = 0x00000000U;
    optee_ep_info->ularg7_high              = 0x00000000U;
#endif /* OPTEE_LOAD_ENABLE == OPTEE_ENABLE */

    smoni_entry_point += BL31_KIND_BOOT_ADDR;
    mem_write32((smoni_entry_point), (uint32_t)((uint64_t)BL31_COLD_BOOT & 0xFFFFFFFFU));
    mem_write32(((smoni_entry_point) + 0x4U),
        (uint32_t)(((uint64_t)BL31_COLD_BOOT >> 32U) & 0xFFFFFFFFU));
}
/* End of function smoni_set_param(uint32_t smoni_entry_point) */
