/*
 * Copyright (c) 2018-2023 Renesas Electronics Corporation. All rights reserved.
 */

#include <stdio.h>
#include <rcar_def.h>
#include <scif.h>
#include <timer.h>
#include <log.h>
#include "d_armasm.h"

#include <image_load.h>
#include <loader_main.h>
#include <loader_main_common.h>
#include <cpu_on.h>
#include <emmc_def.h>
#include <emmc_boot.h>
#if (BOOT_MODE == SECURE)
#include "secure_boot.h"
#endif /* BOOT_MODE == SECURE */
/* Time analysis */
#if (1 == (MEASURE_TIME))
	#include <scmt.h>
	#include <scmt_checkpoint.h>
#else
  #define scmt_wait_ticks(x)
  #define store_time_checkpoint(x,y)
  #define print_time_checkpoints(x)
#endif
#include <android_ab.h>

#define _SECURE_BOOT_MARK	(0x41DFFFF8U)
#define IS_SECURE_BOOT		NORMAL_BOOT
#define OS_LOAD_FAIL		(0xBAADF00DU)

extern const uint8_t __RO_START__[1];
extern const uint8_t __STACKS_END__[1];
extern const char build_message[];

void Main(void)
{
    uint32_t ca_load_num; /* number of load for CA program */
    uint32_t loop;
    uint32_t reg;       /* store register value */
    int slot = 0;
    __attribute__((unused))const char *str;
#if (BOOT_MODE == SECURE)
    uint32_t bootmode;       /* store boot mode */
#endif /* BOOT_MODE == SECURE */
    LOAD_INFO li[MAX_PLACED];

#if (RCAR_LSI != RCAR_V4H)
#error "RCAR_V4H only"
#endif
#if (1 == (MEASURE_TIME))
    scmt_module_start();
    store_time_checkpoint("loader_main", 0);
#endif
/*****************************************************************************
 *  Initialize Hardware
 *****************************************************************************/
	/* ip_control/ip_init() */
	scif_init();
	import_mmc_drv_obj();
	store_time_checkpoint("emmc_initialize", 0);

/*****************************************************************************
 *  Output boot message
 *****************************************************************************/
    NOTICE("CA76 Loader Program Rev.%s\n", IPL_VERSION);
    NOTICE("%s\n", build_message);

    /* Get PRR */
    reg = mem_read32(PRR);
    switch (reg & PRR_PRODUCT_MASK) {
        case PRR_PRODUCT_V4H:
            str = "V4H";
            break;
        default:
            str = "unknown";
            break;
    }
    NOTICE("PRR is R-Car %s Ver.%d.%d\n", str,
        ((int)(reg & PRR_MAJOR_MASK) >> PRR_MAJOR_SHIFT)
        + PRR_MAJOR_OFFSET, (int)(reg & PRR_MINOR_MASK));
    store_time_checkpoint("init_done", 0);

/*****************************************************************************
 *  Load Certficate
 *****************************************************************************/

	/* Load content certificate */
    ca_load_num = mem_read32(CONTENT_CERT_DEST_ADDR);

    /* Get load information */
    load_init(li, ca_load_num);

#if (BOOT_MODE == SECURE)
    secureboot_init();

    /* LCS judgement for secure boot */
    bootmode = judge_bootmode();

    if (NORMAL_BOOT != bootmode)
    {
        /* Content cert certification */
        secureboot_verify(li, CA_OPTIONAL_ID, CA_OPTIONAL_ID + ca_load_num);
        store_time_checkpoint("verify_cert_done", 0);
#ifdef MOBIS_PRK3
        /* because of SECURE_BOOT == 0x0,
           we use NORMAL_BOOT as secure boot flag */
        mem_write32(_SECURE_BOOT_MARK, IS_SECURE_BOOT);
#endif
    }
#endif /* BOOT_MODE == SECURE */

/*****************************************************************************
 *  Load CA Program#2--#8
 *****************************************************************************/
    reg = mem_read32(AB_INFO_FLAG_ADDR);
    if (reg & AB_INFO_SELECT_2nd)
        slot = 1;
    NOTICE("slot: %d\n", slot);

    load_update_part_num(li, ca_load_num, slot);

    /* Start loading CA Program#n image */
    for (loop = 0U; loop < ca_load_num; loop++)
    {
#ifdef MOBIS_PRK3
        if (loop == (CA_BL2_ID - CA_OPTIONAL_ID))
            continue;
#endif
		/* Loading start */
        load_image(&li[CA_OPTIONAL_ID + loop]);
        store_time_checkpoint("load_CA_#_done", li[CA_OPTIONAL_ID + loop].image_size);

#if (BOOT_MODE == SECURE)
        /* Decryption image and Image certification  */
        if (NORMAL_BOOT != bootmode)
        {
#ifdef MOBIS_PRK3
            if (loop == (CA_QNX_OS_ID - CA_OPTIONAL_ID)) {
                int ret = secureboot_image(&li[CA_OPTIONAL_ID + loop], 0);
                if (ret != 0) {
                    ERROR("secureboot_image failed for %s\n", li[CA_OPTIONAL_ID + loop].name);
                    mem_write32(_SECURE_BOOT_MARK, OS_LOAD_FAIL);
                }
            } else
#endif
            secureboot_image(&li[CA_OPTIONAL_ID + loop], 1);
            store_time_checkpoint("verify_CA_#_done", 0);
        }
#endif /* BOOT_MODE == SECURE */
    }

    /* Set Secure Monitor parameter */
    smoni_set_param(li[CA_OPTIONAL_ID].boot_addr,        /* BL31 */
                    li[CA_OPTIONAL_ID + 1U].boot_addr,   /* U-Boot */
                    li[CA_OPTIONAL_ID + 2U].boot_addr);  /* TEE-OS */

/*****************************************************************************
 *  Exit Hardware
 *****************************************************************************/
    EMMC_ERROR_CODE result = EMMC_ERR;

    result = emmc_terminate();
    if(EMMC_SUCCESS != result)
    {
        ERROR("ip_release error (emmc_terminate).\n");
        panic;
    }

    NOTICE("Load finish.(CA76 Loader)\n");
/*****************************************************************************
 *  Jump to BL31
 *****************************************************************************/
    void (*bl31_func)(void);

    bl31_func = (void (*)(void))(uintptr_t)li[CA_OPTIONAL_ID].boot_addr;
    store_time_checkpoint("Jump to BL31", 0);
    print_time_checkpoints();
#if !defined(BE_QUIET) && (LOG_LEVEL < LOG_NOTICE)
    log_printf("%s\n", build_message);
#if (BOOT_MODE == SECURE)
    if (NORMAL_BOOT != bootmode) {
        log_printf("Secure boot(CA76 Loader)\n");
    } else {
        log_printf("Normal boot(CA76 Loader)\n");
    }
#else
    log_printf("Boot(CA76 Loader)\n");
#endif
#endif
    bl31_func();  /* Jump to BL31 */
}
