/**
 * @file   fcMain.c
 * @brief  Implements the entry point of the fastcall
 */

#include "drStd.h"
#include "DrApi/DrApiCommon.h"
#if defined(CONFIG_EXYNOS5422) || defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS3470) ||\
	defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS3472) || defined(CONFIG_EXYNOS3250) ||\
	defined(CONFIG_EXYNOS4415) || defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS5410) ||\
	defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) ||\
	defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) ||\
	defined(CONFIG_EXYNOS7570) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810) ||\
	defined(CONFIG_EXYNOS7885)
#include "DrApi/DrApiFastCall.h"
#endif

#include "fcMem.h"
#include "fcHDCP.h"
#include "fcTIMA.h"
#include "fcEfuse.h"
#include "fcdrv_hw_hal.h"
#include "fcUART.h"
#include "regs-cmu.h"
#include "regs-pmu.h"
#include "regs-media.h"
#if defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS7580)
#include "otp.h"
#include "trng.h"
#else
#include "efusewriter.h"
#if defined(CONFIG_EXYNOS3475)
#include "trng.h"
#endif

#endif

#if defined(TIMA_MST_DRV)
#include "gpio-mst.h"
#include "regs-gpio-mst.h"
#include "mstdrv.h"
extern uint8_t gpio_mst_md_pin;
extern uint8_t gpio_mst_pd_pin;
extern uint8_t gpio_mst_pwr_en_pin;
#endif

/* TIMA Trusted-boot region address */
extern uint32_t g_trusted_boot_addr;

#if defined(CONFIG_FP_TZ_CONTROL)
#include "gpio-fp.h"
#endif

#if defined(CONFIG_ESE_TZ_CONTROL)
#include "gpio-ese.h"
#endif

#if defined(CONFIG_SECURE_CAMERA)
#include "sec_cam_api.h"
#endif

#if TBASE_API_LEVEL >= 5
#include "DrApi/DrApiMm.h"
#include "DrApi/DrApiMmExt.h"
#endif

/* Return value */
#define MC_FC_RET_OK 0
#define MC_FC_RET_ERR_INVALID 1
#define MC_FC_RET_ERR_INVALID_OEM_FLAG	23	// equivalent with Qualcomm
#ifdef CONFIG_KNOX_GEARPAY
#define MC_FC_RET_ERR_INVALID_GEARPAY_FLAG	2	/* for invalid gearpay smc */
#endif

/* Fastcall Id */
#define MC_FC_HDCP_VALUE ((uint32_t)(0x83000000))
#if defined(CONFIG_EXYNOS5260)
#define MC_FC_MAKE_TIMA_HASH_TABLE ((uint32_t)(0x81000000))
#else
#define MC_FC_MAKE_TIMA_HASH_TABLE ((uint32_t)(0x83000001))
#endif
#if defined(CONFIG_EXYNOS5260)
#define MC_FC_EFUSE_WRITER ((uint32_t)(0x81000001))
#elif defined(CONFIG_EXYNOS4415)
#define MC_FC_EFUSE_WRITER ((uint32_t)(0x83000002))
#elif defined(CONFIG_EXYNOS5430)
#define MC_FC_EFUSE_WRITER ((uint32_t)(0x83000002))
#define MC_FC_DMVERITY ((uint32_t)0x83000006)
#elif defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) ||\
	  defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS7570) ||\
	  defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS8895) ||\
	  defined(CONFIG_EXYNOS9810)
#define MC_FC_OTP_CONTROL ((uint32_t)(0x83000002))
#define MC_FC_GET_RANDOM_VALUE ((uint32_t)(0x83000005))
#define MC_FC_DMVERITY ((uint32_t)0x83000006)
#elif defined(CONFIG_EXYNOS3475)
#define MC_FC_EFUSE_WRITER ((uint32_t)(0x83000002))
#define MC_FC_GET_RANDOM_VALUE ((uint32_t)(0x83000005))
#define MC_FC_DMVERITY ((uint32_t)0x83000006)
#endif

#define MC_FC_OEM_FLAG_READ ((uint32_t)(0x83000003))
#define MC_FC_OEM_FLAG_WRITE ((uint32_t)(0x83000004))


#ifdef CONFIG_KNOX_GEARPAY
#define MC_FC_GEARPAY_BOOL_WRITE ((uint32_t)(0x83000016))
#endif

/* ICCC */
#if defined(ICCC_SECURE_PARAMETERS_AREA)
#define SMC_CMD_DMV_WRITE_STATUS (uint32_t)(0x83000014)
#define MC_FC_SHARE_SECURE_INFO  (uint32_t)(0x83000013)
#define ICCC_DEBUG 0
#if defined(CONFIG_EXYNOS5422) || defined(CONFIG_EXYNOS3470) || defined(CONFIG_EXYNOS5420)
#define TIMA_MAX_SIZE 0x100000
#endif
int g_check_call_iccc;
int g_check_call_iccc_dmv;
#endif

/* Jenkins Build Info */
#define MC_FC_BUILD_INFO  (uint32_t)(0x83000017)

#if defined(TIMA_TBOOT_CTX) 
#if defined(TIMA_FEATURE_FOR_64BIT)
#define TIMA_MAX_SIZE 0x200000
#else
#define TIMA_MAX_SIZE 0x100000
#endif
#endif

#if defined(TIMA_SHARED_INFO)
#define MC_FC_TIMA_SHARED_INFO (0x83000007)
#define MC_FC_GET_TIMA_SHARED_INFO (0x83000008)
tima_info tima_info_data;
#if defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7570) || \
	defined(CONFIG_EXYNOS7880)
#define SDRAM_BASE_ADDR 0x40000000
#elif defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
#define SDRAM_BASE_ADDR 0x80000000
#else
#define SDRAM_BASE_ADDR 0x20000000
#endif
#endif

#if defined(TUI_MULTI_RESOLUTION_SUPPORT)
#define MC_FC_TUI_SET_RESOLUTION_INFO (0x8300004A)
#define MC_FC_TUI_GET_RESOLUTION_INFO (0x8300004B)
uint32_t current_screen_width = 1080;
uint32_t current_screen_height = 1920;
#endif

#if defined(TIMA_MST_DRV) || defined(CONFIG_FP_TZ_CONTROL)
#define MC_FC_SECURE_PIN ((uint32_t)(0x8300000e))
#define TZPC_ERROR_PREFIX	(0x46630000)
#define MST_RET_BIT		(0x1 << 1)
#define FP_RET_BIT		(0x1 << 2)
#define MST_NOT_SUPPORT		(0x1 << 3)
#endif

#if defined(TIMA_MST_DRV)
#define MC_FC_MST_CONTROL ((uint32_t)(0x8300000b))
#define MC_FC_MST_SUSPEND ((uint32_t)(0x8300000c))
#define MC_FC_MST_RESUME ((uint32_t)(0x8300000d))
#define MC_FC_MST_TEST_TRANSMIT ((uint32_t)(0x8300000f))
#define MC_FC_LPA_MODE ((uint32_t)(0x83000011))
#define MC_FC_NFC_ACTION ((uint32_t)(0x83000030))
#define MC_FC_SECURE_GPIO_RECOVERY ((uint32_t)(0x83000012))
#endif

#if defined(CONFIG_FP_TZ_CONTROL)
#define MC_FC_FP_PM_SUSPEND ((uint32_t)(0x83000021))
#define MC_FC_FP_PM_RESUME ((uint32_t)(0x83000022))
#define MC_FC_FP_BTP_OCP_HIGH ((uint32_t)(0x83000023))
#define MC_FC_FP_BTP_OCP_LOW ((uint32_t)(0x83000024))
#define MC_FC_FP_BTP_OCP_NONE ((uint32_t)(0x83000025))
#define MC_FC_FP_PM_SUSPEND_RETAIN ((uint32_t)(0x83000026))
#define MC_FC_FP_CS_SET ((uint32_t)(0x83000027))
#define MC_FC_FP_PM_SUSPEND_CS_HIGH ((uint32_t)(0x83000028))
#define MC_FC_FP_TEST_FASTCALL ((uint32_t)(0x84040001))
#endif

#if defined(CONFIG_ESE_TZ_CONTROL)
#define MC_ESE_SECURE_PIN	((uint32_t)(0x83000031))
#define MC_ESE_PM_SUSPEND	((uint32_t)(0x83000032))
#define MC_ESE_PM_RESUME	((uint32_t)(0x83000033))
#endif

#if defined(CONFIG_SECURE_CAMERA)
#define MC_SECURE_CAMERA_INIT	((uint32_t)(0x83000041))
#define MC_SECURE_CAMERA_CFW_ENABLE	((uint32_t)(0x83000042))
#define MC_SECURE_CAMERA_PREPARE	((uint32_t)(0x83000043))
#define MC_SECURE_CAMERA_UNPREPARE	((uint32_t)(0x83000044))
#define MC_SECURE_CAMERA_I2C_RECOVERY	((uint32_t)(0x83000045))
#define SECURE_CAMERA_ERROR	(0x53430000)
#endif

#define MC_FC_ICCC_SVB_RESULT			(0x83000046)
#define MC_FC_ICCC_DATA_LOCK			(0x83000047)

int g_check_call_tima;
#ifdef CONFIG_KNOX_GEARPAY
extern uint32_t g_touch_bool;
extern uint32_t g_strap_bool;
extern uint32_t g_physbutton_bool;
extern uint32_t g_userauth_bool;
typedef enum gearpay_bool_s {
	TOUCH = (uint32_t)0,
	PHYSBUTTON,
	STRAP
} gearpay_bool_t;
#endif
static uint32_t pin_conf = 0;
static uint8_t pin_conf_flag = 1;
static uint8_t system_rev = 0;

extern uint32_t g_oem_flag[NUM_OEM_FLAG];

#if TBASE_API_LEVEL >= 5
	extern addr_t hdmi_sfr_va, pmu_media_sfr_va, cmu_top_sfr_va;
	extern addr_t dram_hash_table_va, sram_hash_table_va, kernel_hash_value_va;
	extern addr_t good_measurement_va, iccc_secure_parameter_va, secure_boot_enable_va;
	extern addr_t dmverity_va;
#endif

#if defined(TIMA_MST_DRV)
uint32_t *pVirtBaseAddr[FCH_L1_MAX];

static unsigned char mst_test_track1[] =
	{0x00,0x01,0x01,0x2C,0x02,0x65,
	 0x00,0x00,0x00,0x02,0x8a,0x3a,0x85,0x52,0x95,0x8a,0x34,0x23,0x46,0x91,
	 0x7a,0x84,0xa8,0x34,0x6b,0x47,0xc2,0xeb,0xc3,0x77,0xcf,0xcd,0x27,0x73,
	 0xe1,0xbb,0xe6,0x04,0x08,0x10,0x20,0x40,0x81,0x02,0x04,0x08,0x10,0x2f,
	 0xa2,0xa5,0x8a,0x12,0x28,0x48,0xa1,0x02,0x04,0x08,0x10,0x22,0x5a,0x93,
	 0x02,0x45,0x08,0x10,0x20,0x40,0x81,0x32,0x0d,0xc8,0x10,0x20,0x40,0x81,
	 0x02,0x7c,0x62,0x00,0x00,0x00,0x00};

static unsigned char mst_test_track2[] = 
	{0x00,0x01,0x01,0x2C,0x01,0x04,
	 0x00,0x00,0x00,0x03,0x4d,0x0c,0x03,0x56,0xf0,0x59,0x6e,
	 0x66,0x89,0x88,0x56,0x45,0x43,0x00,0x84,0x35,0x08,0x42,
	 0x16,0x84,0x3c,0xcc,0xf2,0x1f,0xd8,0x00,0x00,0x00,0x00};
#endif

setL1Entry_func setL1Entry;

#if defined(CONFIG_EXYNOS5422) || defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS3470) ||\
	defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS3472) || defined(CONFIG_EXYNOS3250) ||\
	defined(CONFIG_EXYNOS4415) || defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS5410) ||\
	defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) ||\
	defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) ||\
	defined(CONFIG_EXYNOS7570) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810) ||\
	defined(CONFIG_EXYNOS7885)
uint32_t fcInit(struct fcContext *context);
uint32_t _fcMain(fastcall_registers_t *regs, struct fcContext *context);
#else
uint32_t fcInit(fcContext_ptr context);
uint32_t _fcMain(fastcall_registers_t *regs, fcContext_ptr context);
#endif

void *entryVector[2] = { &fcInit, &_fcMain };

#if defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) ||\
	defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS5430) ||\
	defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7570) ||\
	defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
#define  MC_FC_KAP_CALL             ((uint32_t)0x83000009)
#define  MC_FC_KAP_STATUS             ((uint32_t)0x8300000a)
#define  CMD_ID_KAP_STATUS          0x50
#define  CMD_ID_DISABLE_KAP         0x51
#define  CMD_ID_DISABLE_KAP_BL      0x52
#define  CMD_ID_BOOT_STS_KAP_ON     0x53
#define  CMD_ID_BOOT_KAP_VIO        0x54
#define  KAP_MAGIC              0x5afe0000
/*
 * System call to check the status of the Knox Active Protection (KAP) mode
 * The possible return values:
 *              0x5afe0011 -> KAP ON
 *              0x5afe0001 -> KAP ON, A security violation occured
 *              0x5afe0000 -> KAP OFF
 */
volatile uint32_t KAP_STATUS_FUSE = 0; //This fuse defines the status of RP mode 1: OFF 0:ON
volatile uint32_t KAP_VIOLATION_FUSE = 0; //This fuse records RP violation 1: at lease 1 violation occured 0: None
volatile uint32_t KAP_BOOT_STATUS_FUSE = 0; //This fuse defines the RP mode status on booting up 1: it was ON while booting 0:it was OFF while booting


#define FC_KAP_ON       0x11
#define FC_KAP_VIOL     0x01
#define FC_KAP_OFF      0x00

/*
 * Check the KAP (KAP mode) fuse and return the status in the passed arg
 */
inline uint32_t fcKapStatus()
{
	    uint32_t kap_status;
        if (KAP_VIOLATION_FUSE) {
                kap_status = 3; //RKP and/or DMVerity says device is tampered
        } else if (KAP_STATUS_FUSE) {
                kap_status = 0; //KAP OFF
        } else {
                kap_status = 1; //KAP ON - No tamper
        }
        kap_status |= 0x5afe0000; //Add the magic to verify the return value
        return kap_status;
}

#if TBASE_API_LEVEL < 5
uint32_t *kap_status_flag = (uint32_t *)KAP_STATUS_VA;
#endif

uint32_t fcKAPsyscall(
    fastcall_registers_t regs
    ) {
    uint32_t cmd_id = regs[1];
    uint32_t arg1 = regs[2];
#if TBASE_API_LEVEL >= 5
    addr_t kap_status_va;
#if defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS7870) ||defined(CONFIG_EXYNOS7880) || \
    defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
    kap_status_va = dmverity_va + KAP_OFFSET;
#else
	kap_status_va = dmverity_va + (KAP_PA & 0xfff);
#endif
    uint32_t *kap_status_flag = (uint32_t *)(kap_status_va);
#endif

    switch (cmd_id) {
        case CMD_ID_KAP_STATUS:
                return fcKapStatus();
                break;
        case CMD_ID_DISABLE_KAP:
                KAP_STATUS_FUSE = 1;
                *kap_status_flag = KAP_MAGIC|FC_KAP_OFF;
                break;
        case CMD_ID_DISABLE_KAP_BL:
                /* This cmd_id is to disable KAP mode from the bootloader */
                KAP_STATUS_FUSE = 1;
                *kap_status_flag = KAP_MAGIC|FC_KAP_OFF;
                break;
        case CMD_ID_BOOT_STS_KAP_ON:
                //tima_util_log("KAP is on at BL", 0, 0, 0);
                KAP_BOOT_STATUS_FUSE = 1;
                *kap_status_flag = KAP_MAGIC|FC_KAP_ON;
                break;
        case CMD_ID_BOOT_KAP_VIO:
                //tima_util_log("BL detected warranty bit blown", 0, 0, 0);
                KAP_VIOLATION_FUSE = 1;
                *kap_status_flag = KAP_MAGIC|FC_KAP_VIOL;
                break;
        default:
        	      return 1;  // wrong cmd_id
    }
    return 0;
}
#endif //End of KAP

uint32_t fcMakeL1PTE(uint32_t phys)
{
	uint32_t pteL1 = phys;
	pteL1 |= L1_TYPE_SECTION
		| L1_DOMAIN(0)
		| L1_BIT_SECTION_TEX0;

	pteL1 |= L1_BIT_SECTION_XN;

	pteL1 |= L1_SECTION_AP_PRW_URW;

	return pteL1;
}

uint64_t makeL1Pte64(uint64_t physAddr)
{
 uint64_t pteL1 = physAddr;

 // map 1/2 MB section
 #if defined(ARM_LPAE)
 pteL1 |= L1_LONG_TYPE_BLOCK | L1_LONG_BIT_BLOCK_AF;
 pteL1 |= L1_LONG_BLOCK_SHAREABLE_IS;
 #else
 pteL1 |= L1_TYPE_SECTION;
 pteL1 |= L1_DOMAIN(0x0);
 // all mappings are SMP CPU shared, so future MobiCore
 // versions running on multiple core wont have problems.
 // While MobiCore runs on CPU0 only, this would only be necessary
 // for Swd/NWd shared sections, as NWd runs on all CPUs.
 pteL1 |= L1_BIT_SECTION_S;
 #endif
 /* normal cacheable memory */
 #if defined(ARM_LPAE)
 pteL1 |= L1_LONG_ATTRINDX_NORMAL_UNCACHED;
 #else
 /* Normal memory, Outer and Inner Write-Back, Write-Allocate */
 /* TEX[2:0]=001, C=1 B=1 */
 pteL1 |= (L1_BIT_SECTION_TEX0 | L1_BIT_SECTION_C | L1_BIT_SECTION_B);
 #endif
#if 0
 // Nwd shared non secure memory
 #if defined(ARM_LPAE)
 pteL1 |= L1_LONG_BIT_BLOCK_NS;
 #else
 pteL1 |= L1_BIT_SECTION_NS; // set NS
 #endif
#endif

 #if defined(ARM_LPAE)
 pteL1 |= L1_LONG_BIT_BLOCK_XN | L1_LONG_BIT_BLOCK_PXN;
 #else
 pteL1 |= L1_BIT_SECTION_XN;
 #endif

 // If kernel space then we always map as read/write
 #if defined(ARM_LPAE)
 pteL1 |= L1_LONG_BLOCK_AP_PRW;
 #else
 pteL1 |= L1_SECTION_AP_PRW; // Kernel RW user -
 #endif

 return pteL1;
}

uint64_t makeL1Pte64_CACHED(uint64_t physAddr)
{
 uint64_t pteL1 = physAddr;

 // map 1/2 MB section
 #if defined(ARM_LPAE)
 pteL1 |= L1_LONG_TYPE_BLOCK | L1_LONG_BIT_BLOCK_AF;
 pteL1 |= L1_LONG_BLOCK_SHAREABLE_IS;
 #else
 pteL1 |= L1_TYPE_SECTION;
 pteL1 |= L1_DOMAIN(0x0);
 // all mappings are SMP CPU shared, so future MobiCore
 // versions running on multiple core wont have problems.
 // While MobiCore runs on CPU0 only, this would only be necessary
 // for Swd/NWd shared sections, as NWd runs on all CPUs.
 pteL1 |= L1_BIT_SECTION_S;
 #endif
 /* normal cacheable memory */
 #if defined(ARM_LPAE)
 pteL1 |= L1_LONG_ATTRINDX_NORMAL_CACHED;
 #else
 /* Normal memory, Outer and Inner Write-Back, Write-Allocate */
 /* TEX[2:0]=001, C=1 B=1 */
 pteL1 |= (L1_BIT_SECTION_TEX0 | L1_BIT_SECTION_C | L1_BIT_SECTION_B);
 #endif
#if 0
 // Nwd shared non secure memory
 #if defined(ARM_LPAE)
 pteL1 |= L1_LONG_BIT_BLOCK_NS;
 #else
 pteL1 |= L1_BIT_SECTION_NS; // set NS
 #endif
#endif

 #if defined(ARM_LPAE)
 pteL1 |= L1_LONG_BIT_BLOCK_XN | L1_LONG_BIT_BLOCK_PXN;
 #else
 pteL1 |= L1_BIT_SECTION_XN;
 #endif

 // If kernel space then we always map as read/write
 #if defined(ARM_LPAE)
 pteL1 |= L1_LONG_BLOCK_AP_PRW;
 #else
 pteL1 |= L1_SECTION_AP_PRW; // Kernel RW user -
 #endif

 return pteL1;
}

#if defined(CONFIG_EXYNOS5410) || defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5422) || defined(CONFIG_EXYNOS5433)
/*
 * The function for writing HDCP authentication key.
 */
void WriteHDCPAuthKey(bool prot)
{
#if TBASE_API_LEVEL >= 5
	if (prot) {
		/* write HDCP authentication key to internal RAM */
		*(uint32_t *)((uint32_t *)sram_hash_table_va + HDCP_AUTH_MAP_OFFSET) = HDCP_AUTH_KEY0;
		*(uint32_t *)((uint32_t *)sram_hash_table_va + HDCP_AUTH_MAP_OFFSET + 0x4) = HDCP_AUTH_KEY1;
		*(uint32_t *)((uint32_t *)sram_hash_table_va + HDCP_AUTH_MAP_OFFSET + 0x8) = HDCP_AUTH_KEY2;
		*(uint32_t *)((uint32_t *)sram_hash_table_va + HDCP_AUTH_MAP_OFFSET + 0xC) = HDCP_AUTH_KEY3;
	} else {
		/* clear HDCP authentication key to internal RAM */
		*(uint32_t *)((uint32_t *)sram_hash_table_va + HDCP_AUTH_MAP_OFFSET) = 0x0;
		*(uint32_t *)((uint32_t *)sram_hash_table_va + HDCP_AUTH_MAP_OFFSET + 0x4) = 0x0;
		*(uint32_t *)((uint32_t *)sram_hash_table_va + HDCP_AUTH_MAP_OFFSET + 0x8) = 0x0;
		*(uint32_t *)((uint32_t *)sram_hash_table_va + HDCP_AUTH_MAP_OFFSET + 0xC) = 0x0;
	}
#else
	if (prot) {
		/* write HDCP authentication key to internal RAM */
		*(uint32_t *)(HDCP_AUTH_VA) = HDCP_AUTH_KEY0;
		*(uint32_t *)(HDCP_AUTH_VA + 0x4) = HDCP_AUTH_KEY1;
		*(uint32_t *)(HDCP_AUTH_VA + 0x8) = HDCP_AUTH_KEY2;
		*(uint32_t *)(HDCP_AUTH_VA + 0xC) = HDCP_AUTH_KEY3;
	} else {
		/* clear HDCP authentication key to internal RAM */
		*(uint32_t *)(HDCP_AUTH_VA) = 0x0;
		*(uint32_t *)(HDCP_AUTH_VA + 0x4) = 0x0;
		*(uint32_t *)(HDCP_AUTH_VA + 0x8) = 0x0;
		*(uint32_t *)(HDCP_AUTH_VA + 0xC) = 0x0;
	}
#endif
}

/*
 * The function for checking HDMI power/clock/enabling.
 */
int checkHDMI(
) {
	int value;

#if TBASE_API_LEVEL >= 5
	/* Check HDMI power */
	value = *((volatile uint32_t *)((uint32_t *)pmu_media_sfr_va + DISP1_CONFIGURATION)) & (0x7 << 0);
	if (!value)
		return HDMI_DISCONNECTED;

	/* Check HDMI clock */
	value = *((volatile uint32_t *)((uint32_t *)cmu_top_sfr_va + CLK_GATE_IP_DISP1)) & (1 << 6);
	if (!value)
		return HDMI_DISCONNECTED;

	/* Check HDMI enable */
	value = *((volatile uint32_t *)((uint32_t *)hdmi_sfr_va + HDMI_CON_0)) & 0x1;
	if (!value)
		return HDMI_DISCONNECTED;
#else //TBASE_API_LEVEL >= 5
	/* Check HDMI power */
#if defined(CONFIG_EXYNOS5433)
	value = *((volatile uint32_t *)(PMU_MEDIA_SFR_VA + DISP_CONFIGURATION)) & (0x7 << 0);
#else
	value = *((volatile uint32_t *)(PMU_MEDIA_SFR_VA + DISP1_CONFIGURATION)) & (0x7 << 0);
#endif
	if (!value)
		return HDMI_DISCONNECTED;

	/* Check HDMI clock */
#if defined(CONFIG_EXYNOS5433)
	value = *((volatile uint32_t *)(CMU_DISP_SFR_VA + CLK_GATE_IP_DISP0)) & (1 << 1);
#else
	value = *((volatile uint32_t *)(CMU_TOP_SFR_VA + CLK_GATE_IP_DISP1)) & (1 << 6);
#endif
	if (!value)
		return HDMI_DISCONNECTED;

	/* Check HDMI enable */
	value = *((volatile uint32_t *)(HDMI_SFR_VA + HDMI_CON_0)) & 0x1;
	if (!value)
		return HDMI_DISCONNECTED;
#endif //TBASE_API_LEVEL >= 5
	return HDMI_CONNECTED;
}

/*
 * FastCall handler for HDCP authentication value.
 */
void fcHDCPValue(
	fastcall_registers_t regs
) {
	uint32_t hdcp_value;

	static unsigned int g_HDCP_Tempered = FALSE;
	static unsigned int g_HDCP_calledFunction = FN_HDCP_NOTHING;

	regs[1] = MC_FC_RET_OK;
	hdcp_value = regs[2];

	if (hdcp_value & SCM_CP_HDCP_START) {	// START Bit Setting
		if (hdcp_value & SCM_CP_HDCP_SUCCESS) {
			if (hdcp_value & SCM_CP_HDCP_FAIL) {	// START | SUCCESS | FAIL Bit Setting
				if ((checkHDMI() == HDMI_DISCONNECTED) || g_HDCP_calledFunction == FN_HDCP_SUCCESS) {
					g_HDCP_Tempered = TRUE;
				}
				else {
					g_HDCP_calledFunction = FN_HDCP_FAIL;
				}
				WriteHDCPAuthKey(FALSE);
			}
			else {	// START | SUCCESS Bit Setting
				if ((checkHDMI() == HDMI_DISCONNECTED) || g_HDCP_calledFunction == FN_HDCP_FAIL || g_HDCP_Tempered == TRUE) {
					g_HDCP_Tempered = TRUE;
					WriteHDCPAuthKey(FALSE);
				}
				else {
					g_HDCP_calledFunction = FN_HDCP_SUCCESS;
					WriteHDCPAuthKey(TRUE);
				}
			}
			return;
		}
		else if (hdcp_value & SCM_CP_HDCP_FAIL) { 	// START | FAIL Bit Setting
			if ((checkHDMI() == HDMI_DISCONNECTED) || g_HDCP_calledFunction == FN_HDCP_SUCCESS) {
				g_HDCP_Tempered = TRUE;
			}
			else {
				g_HDCP_calledFunction = FN_HDCP_FAIL;
			}
			WriteHDCPAuthKey(FALSE);
			return;
		}
	}
	else if (hdcp_value & SCM_CP_HDCP_END) {	// END Bit Setting
		g_HDCP_Tempered = FALSE;
		g_HDCP_calledFunction = FN_HDCP_NOTHING;
		WriteHDCPAuthKey(FALSE);
		return;
	}
	else {	// Wrong Bit Setting
		g_HDCP_Tempered = TRUE;
		WriteHDCPAuthKey(FALSE);
		return;
	}
}
#endif

/*
 * FastCall handler for copying hash values and strings for TIMA.
 */
int fcTIMACopyHashValue(
	fastcall_registers_t regs,
	struct fcContext *context)
{
#if TBASE_API_LEVEL >= 5
	tima_ctx_t *tima_ctx = (tima_ctx_t *)(dram_hash_table_va);
#if defined(SRAM_HASH_TABLE_PA)
	uint32_t *sram_hash_table = (uint32_t *)(sram_hash_table_va - ((uint32_t)(sram_hash_table_va) & (SIZE_4KB - 1)) + (SRAM_HASH_TABLE_PA & (SIZE_4KB - 1)));
#endif
#if defined(TIMA_HAVE_GOOD_MEASUREMENT)
	uint32_t *good_meas_addr = (uint32_t *)(good_measurement_va - ((uint32_t)(good_measurement_va) & (SIZE_4KB - 1)) + (GOOD_MEASUREMENT_OFFSET & (SIZE_4KB - 1)));
#endif
#else //TBASE_API_LEVEL >= 5
	tima_ctx_t *tima_ctx = (tima_ctx_t *)DRAM_HASH_TABLE_VA;
#if defined(SRAM_HASH_TABLE_PA)
	uint32_t *sram_hash_table = (uint32_t *)(SRAM_HASH_TABLE_VA + (SRAM_HASH_TABLE_PA & (SIZE_4KB - 1)));
#endif
#if defined(TIMA_HAVE_GOOD_MEASUREMENT)
	uint32_t *good_meas_addr = (uint32_t *)(GOOD_MEASUREMENT_VA + (GOOD_MEASUREMENT_OFFSET & (SIZE_4KB - 1)));
#endif
#endif //TBASE_API_LEVEL >= 5
#if !defined(TIMA_KERNEL_HASH_IN_SRAM)
	uint32_t *kernel_hash_addr;
#endif
	uint8_t *magic_str;
	uint8_t *warr_str;
	uint32_t i;
	uint32_t no_of_hash = 4;

#if defined(TIMA_TBOOT_CTX) 
	uint32_t tboot_ctx_phy, offset;
	tboot_ctx *tboot_ctx_vir;

	tboot_ctx_phy = (uint32_t)regs[1];
	offset = tboot_ctx_phy & (TIMA_MAX_SIZE - 1);
#if !defined(TIMA_FEATURE_FOR_64BIT)	
	tboot_ctx_vir = setL1Entry(context, 0, fcMakeL1PTE(tboot_ctx_phy & 0xFFF00000));
#else
	tboot_ctx_vir = context->setL1Entry64(context, 0, makeL1Pte64(tboot_ctx_phy & 0xFFE00000));
#endif

	tboot_ctx_vir = (tboot_ctx *)((uint32_t)tboot_ctx_vir + offset);
#if !defined(TIMA_KERNEL_HASH_IN_SRAM)
	kernel_hash_addr = (uint32_t *)tboot_ctx_vir->kernel_hash;
#endif
	magic_str = (uint8_t *)tboot_ctx_vir->magic_str;
	warr_str = (uint8_t *)tboot_ctx_vir->warranty_str;
#else
#if TBASE_API_LEVEL >= 5
	kernel_hash_addr = (uint32_t *)(kernel_hash_value_va);
#else
	kernel_hash_addr = (uint32_t *)KERNEL_HASH_VALUE_VA;
#endif
	magic_str = (uint8_t *)kernel_hash_addr + 0x400;	/* kernel_hash_addr + 1KB */
	warr_str = (uint8_t *)kernel_hash_addr + 0x410;		/* magic_string + 16Byte */
#endif

	if (g_check_call_tima != 0) {
		regs[1] = MC_FC_RET_ERR_INVALID;
		return -1;
	}

	regs[1] = MC_FC_RET_OK;

	/* Copy TIMA Magic string */
	for (i = 0; i < sizeof(tima_ctx->magic_string); i++)
		tima_ctx->magic_string[i] = magic_str[i];

	if (!memcmp((uint8_t *)tboot_ctx_vir->svb_magic, "SVB", 3)) {
		/* Copy SVB Magic string */
		for (i = 0; i < sizeof(tboot_ctx_vir->svb_magic); i++)
			tima_ctx->svb_magic[i] = tboot_ctx_vir->svb_magic[i];

		/* Copy Vbmeta hash */
		for (i = 0; i < sizeof(tboot_ctx_vir->vbmeta_hash); i++)
			tima_ctx->vpcr1[i] = tboot_ctx_vir->vbmeta_hash[i];

#if 0 /* Debug Code */
		UART_PSH("from :tboot_ctx_vir->svb_magic = ", tboot_ctx_vir->svb_magic[0]);
		UART_PSH("from :tboot_ctx_vir->svb_magic = ", tboot_ctx_vir->svb_magic[1]);	
		UART_PSH("from :tboot_ctx_vir->svb_magic = ", tboot_ctx_vir->svb_magic[2]);
		UART_PSH("from :tboot_ctx_vir->vbmeta_hash = ", tboot_ctx_vir->vbmeta_hash[0]);
		UART_PSH("from :tboot_ctx_vir->vbmeta_hash = ", tboot_ctx_vir->vbmeta_hash[1]);
		UART_PSH("from :tboot_ctx_vir->vbmeta_hash = ", tboot_ctx_vir->vbmeta_hash[2]);

		UART_PSH("to :tima_ctx->svb_magic = ", tima_ctx->svb_magic[0]);
		UART_PSH("to :tima_ctx->svb_magic = ", tima_ctx->svb_magic[1]);
		UART_PSH("to :tima_ctx->svb_magic = ", tima_ctx->svb_magic[2]);
		UART_PSH("to :tima_ctx->vpcr1 = ", tima_ctx->vpcr1[0]);
		UART_PSH("to :tima_ctx->vpcr1 = ", tima_ctx->vpcr1[1]);
		UART_PSH("to :tima_ctx->vpcr1 = ", tima_ctx->vpcr1[2]);
#endif
	} else {
#if defined(SRAM_HASH_TABLE_PA)
	/* Copy hash values in iRAM to hash table in DRAM */
	for (i = 0; i < (SHA256_DIGEST_LEN / sizeof(uint32_t)); i++)
		tima_ctx->vpcr1[i] = sram_hash_table[i];	/* EL3 or EPBL */

	for (i = 0; i < (SHA256_DIGEST_LEN / sizeof(uint32_t)); i++)
		tima_ctx->vpcr2[i] = sram_hash_table[i + 8];	/* BL2 */

	for (i = 0; i < (SHA256_DIGEST_LEN / sizeof(uint32_t)); i++)
		tima_ctx->vpcr3[i] = sram_hash_table[i + 16];	/* Secure OS */

	for (i = 0; i < (SHA256_DIGEST_LEN / sizeof(uint32_t)); i++)
		tima_ctx->vpcr4[i] = sram_hash_table[i + 24];	/* S-boot */

#if defined(TIMA_KERNEL_HASH_IN_SRAM)
	for (i = 0; i < (SHA256_DIGEST_LEN / sizeof(uint32_t)); i++)
		tima_ctx->vpcr5[i] = sram_hash_table[i + 32];	/* kernel */
	no_of_hash++;
#endif

#if defined(TIMA_CMBIN_HASH_IN_SRAM)
	for (i = 0; i < (SHA256_DIGEST_LEN / sizeof(uint32_t)); i++)
		tima_ctx->vpcr6[i] = sram_hash_table[i + 40];	/* cmbin */
	no_of_hash++;
#endif

#if defined(TIMA_DRAMEL3_HASH_IN_SRAM)
	for (i = 0; i < (SHA256_DIGEST_LEN / sizeof(uint32_t)); i++)
		tima_ctx->vpcr7[i] = sram_hash_table[i + 48];	/* dram_el3 */
	no_of_hash++;
#endif
	
	/* Clear hash values in iRAM */
	for (i = 0; i < ((SHA256_DIGEST_LEN / sizeof(uint32_t)) * no_of_hash); i++)
		sram_hash_table[i] = 0x0;
#endif
	}

	/* Copy hash value of kernel into hash table */
#if !defined(TIMA_KERNEL_HASH_IN_SRAM)
	for (i = 0; i < (SHA256_DIGEST_LEN / sizeof(uint32_t)); i++)
		tima_ctx->vpcr5[i] = kernel_hash_addr[i];	/* Kernel */

	/* Clear hash value of kernel */
	for (i = 0; i < (SHA256_DIGEST_LEN / sizeof(uint32_t)); i++)
		kernel_hash_addr[i] = 0x0;	/* Kernel */
#endif

	/* Copy Warranty string */
	for (i = 0; i < sizeof(tima_ctx->warranty_string); i++)
		tima_ctx->warranty_string[i] = warr_str[i];

#if defined(TIMA_HAVE_GOOD_MEASUREMENT)
	/* Clear 256bytes to store good measurement */
	memset(good_meas_addr, 0x0, 256);
#endif

	g_check_call_tima = 1;

	return 0;
}

#if defined(TIMA_SHARED_INFO)
/*
 * FastCall handler for sharing TIMA information.
 */
int fcTIMASharedInfo(
	fastcall_registers_t regs,
	struct fcContext *context)
{
	uint32_t tima_info_phy, offset;
	tima_info *tima_info_vir;

	if((regs[1] >= g_trusted_boot_addr) || (regs[1] <= SDRAM_BASE_ADDR))
		return 0;

	tima_info_phy = (uint32_t)regs[1];
	offset = tima_info_phy & (TIMA_MAX_SIZE - 1);
#if !defined(TIMA_FEATURE_FOR_64BIT)	
	tima_info_vir = setL1Entry(context, 0, fcMakeL1PTE(tima_info_phy & 0xFFF00000));
#else
	tima_info_vir = context->setL1Entry64(context, 0, makeL1Pte64(tima_info_phy & 0xFFE00000));
#endif

	tima_info_vir = (tima_info *)((uint32_t)tima_info_vir + offset);
	tima_info_data.screen_res = tima_info_vir->screen_res;
	return 0;
}

int fcTIMAGetSharedInfo(
	fastcall_registers_t regs,
	struct fcContext *context)
{
	regs[2]=tima_info_data.screen_res;
	return 0;
}

#endif

/*
 * FastCall handler to support TUI Multi-Resolution.
 */
#if defined(TUI_MULTI_RESOLUTION_SUPPORT)
int fcTUISetResolutionInfo(
		fastcall_registers_t regs,
		struct fcContext *context)
{
	uint32_t width;
	uint32_t height;

	width = regs[1];
	height = regs[2];

	current_screen_width = width;
	current_screen_height = height;
	
	return 0;
}

int fcTUIGetResolutionInfo(
		fastcall_registers_t regs,
		struct fcContext *context)
{
	regs[1] = current_screen_width;
	regs[2] = current_screen_height;
	
	return 0;
}
#endif

#if defined(ICCC_SECURE_PARAMETERS_AREA)
static int IcccSvbResult(fastcall_registers_t regs, struct fcContext *context)
{
	uint32_t val = (uint32_t)regs[1];

#if TBASE_API_LEVEL >= 5
	iccc_secure_pamameters_info_t *iccc_secure_param = (iccc_secure_pamameters_info_t *)(iccc_secure_parameter_va - ((uint32_t)(iccc_secure_parameter_va) & (SIZE_4KB - 1)) + (ICCC_SECURE_PARAMETERS_OFFSET & (SIZE_4KB - 1)));
#else
	iccc_secure_pamameters_info_t *iccc_secure_param = (iccc_secure_pamameters_info_t *)(ICCC_SECURE_PARAMETER_VA + (ICCC_SECURE_PARAMETERS_OFFSET & (SIZE_4KB - 1)));
#endif

	iccc_secure_param->sys_secure_info.trustboot_flag = val;
	UART_PSH("ICCC : IcccSvbResult = 0x", iccc_secure_param->sys_secure_info.trustboot_flag);

	return 0;
}

static int IcccDataLock(fastcall_registers_t regs, struct fcContext *context)
{
#if TBASE_API_LEVEL >= 5
	uint32_t *iccc_lock_flag = (uint32_t *)(iccc_secure_parameter_va - ((uint32_t)(iccc_secure_parameter_va) & (SIZE_4KB - 1)) + (ICCC_LOCK_FLAG_OFFSET & (SIZE_4KB - 1)));
#else
	uint32_t *iccc_lock_flag = (uint32_t *)(ICCC_SECURE_PARAMETER_VA + (ICCC_LOCK_FLAG_OFFSET & (SIZE_4KB - 1)));
#endif

 	*iccc_lock_flag = ICCC_TRUSTBOOT_LOCK;
	UART_PSH("ICCC : IcccDataLock = 0x", *iccc_lock_flag);

	return 0;
}

int fcTIMASaveSecureParam(fastcall_registers_t regs, struct fcContext *context)
{
	int i;
	uint32_t smc_secure_phy, offset;
#if TBASE_API_LEVEL >= 5
	iccc_secure_pamameters_info_t *iccc_secure_param = (iccc_secure_pamameters_info_t *)(iccc_secure_parameter_va - ((uint32_t)(iccc_secure_parameter_va) & (SIZE_4KB - 1)) + (ICCC_SECURE_PARAMETERS_OFFSET & (SIZE_4KB - 1)));
	uint32_t *iccc_lock_flag = (uint32_t *)(iccc_secure_parameter_va - ((uint32_t)(iccc_secure_parameter_va) & (SIZE_4KB - 1)) + (ICCC_LOCK_FLAG_OFFSET & (SIZE_4KB - 1)));
#else
	iccc_secure_pamameters_info_t *iccc_secure_param = (iccc_secure_pamameters_info_t *)(ICCC_SECURE_PARAMETER_VA + (ICCC_SECURE_PARAMETERS_OFFSET & (SIZE_4KB - 1)));
	uint32_t *iccc_lock_flag = (uint32_t *)(ICCC_SECURE_PARAMETER_VA + (ICCC_LOCK_FLAG_OFFSET & (SIZE_4KB - 1)));
#endif
	smc_secure_info_t *smc_secure_vir;

// To fix issue SI-5239 , only one time call is allowed
	if (g_check_call_iccc != 0) {
		uart_ps("ICCC : only one time call is allowed");
		return -1;
	}

	memset(iccc_secure_param,0x0,ICCC_SECURE_PARAMETERS_LENGTH);
	memset(iccc_lock_flag,0x0,sizeof(uint32_t));
	smc_secure_phy = (uint32_t)regs[1];
	offset = smc_secure_phy & (TIMA_MAX_SIZE - 1);

#if !defined(TIMA_FEATURE_FOR_64BIT)
		smc_secure_vir = setL1Entry(context, 0, fcMakeL1PTE(smc_secure_phy & 0xFFF00000));
#else
		smc_secure_vir = context->setL1Entry64(context, 0, makeL1Pte64(smc_secure_phy & 0xFFE00000));
#endif

	smc_secure_vir = (smc_secure_info_t *)((uint32_t)smc_secure_vir + offset);

	iccc_secure_param->bl_secure_info.header.magic_str = (uint16_t)BL_MAGIC_STR;
	iccc_secure_param->bl_secure_info.header.used_size = (uint16_t)(sizeof(bl_secure_info_t));
	iccc_secure_param->bl_secure_info.rp_ver = smc_secure_vir->rp_ver;
	iccc_secure_param->bl_secure_info.kernel_rp = smc_secure_vir->kernel_rp;
	iccc_secure_param->bl_secure_info.system_rp = smc_secure_vir->system_rp;
	iccc_secure_param->bl_secure_info.test_bit = smc_secure_vir->test_bit;
	iccc_secure_param->bl_secure_info.sec_boot = smc_secure_vir->sec_boot;
	iccc_secure_param->bl_secure_info.react_lock = smc_secure_vir->react_lock;
	iccc_secure_param->bl_secure_info.kiwi_lock = smc_secure_vir->kiwi_lock;
	iccc_secure_param->bl_secure_info.frp_lock = smc_secure_vir->frp_lock;
	iccc_secure_param->bl_secure_info.cc_mode = smc_secure_vir->cc_mode;
	iccc_secure_param->bl_secure_info.mdm_mode = smc_secure_vir->mdm_mode;
	iccc_secure_param->bl_secure_info.curr_bin_status = smc_secure_vir->curr_bin_status;
	iccc_secure_param->bl_secure_info.afw_value = smc_secure_vir->afw_value;
	iccc_secure_param->bl_secure_info.warranty_bit = smc_secure_vir->warranty_bit;
#ifdef ICCC_ADD_CPUID
	iccc_secure_param->bl_secure_info.ap_serial_0= smc_secure_vir->ap_serial_0;
	iccc_secure_param->bl_secure_info.ap_serial_1= smc_secure_vir->ap_serial_1;
#endif
	iccc_secure_param->bl_secure_info.em_status = smc_secure_vir->em_status;
	iccc_secure_param->bl_secure_info.em_token = smc_secure_vir->em_token;

	if(smc_secure_vir->kap_status != (uint32_t)0xFFFFFFFF)
#if defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) ||\
	defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS5430) ||\
	defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7570) ||\
	defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
		iccc_secure_param->bl_secure_info.kap_status = (uint32_t)((fcKapStatus()) & 0xF);
#else
		iccc_secure_param->bl_secure_info.kap_status = 0xFFFFFFFF;
#endif
	else
		iccc_secure_param->bl_secure_info.kap_status = smc_secure_vir->kap_status;

	for(i = 0; i<MAX_IMAGES ; i++) {
		if(smc_secure_vir->image_status[i] != 0xFF)
			iccc_secure_param->bl_secure_info.image_status[i] = (uint32_t)(smc_secure_vir->image_status[i]);
		else
			iccc_secure_param->bl_secure_info.image_status[i] = 0xFFFFFFFF;
	}

#if defined(CONFIG_PARAMEXPANSION_ICCC)
	iccc_secure_param->bl_secure_info.image_status_bl = (uint32_t)(smc_secure_vir->image_status_bl);
	iccc_secure_param->bl_secure_info.WbHistory = smc_secure_vir->WbHistory;
#endif

	iccc_secure_param->ta_secure_info.header.magic_str = (uint16_t)TA_MAGIC_STR;
	iccc_secure_param->ta_secure_info.header.used_size = (uint16_t)(sizeof(ta_secure_info_t));
	iccc_secure_param->ta_secure_info.pkm_text = 0xFFFFFFFF;
	iccc_secure_param->ta_secure_info.pkm_ro = 0xFFFFFFFF;
	iccc_secure_param->ta_secure_info.selinux_status = 0xFFFFFFFF;
	iccc_secure_param->ta_secure_info.sectimer_base = 0xFFFFFFFF;
	iccc_secure_param->ta_secure_info.sectimer_flag = 0xFFFFFFFF;
	iccc_secure_param->ta_secure_info.sectimer_status = 0xFFFFFFFF;
	iccc_secure_param->ta_secure_info.hdm_status = 0xFFFFFFFF;

	for (i = 0; i < sizeof(iccc_secure_param->ta_secure_info.atn_blob_hash)/sizeof(uint32_t); i++)
		iccc_secure_param->ta_secure_info.atn_blob_hash[i] = 0xFFFFFFFF;

	iccc_secure_param->kern_secure_info.header.magic_str =  (uint16_t)KERN_MAGIC_STR;
	iccc_secure_param->kern_secure_info.header.used_size = (uint16_t)(sizeof(kern_secure_info_t));
	iccc_secure_param->kern_secure_info.dmv_status = smc_secure_vir->dmv_status;

	iccc_secure_param->sys_secure_info.header.magic_str =  (uint16_t)SYS_MAGIC_STR;
	iccc_secure_param->sys_secure_info.header.used_size = (uint16_t)(sizeof(sys_secure_info_t));
	iccc_secure_param->sys_secure_info.sysscope_flag = smc_secure_vir->sysscope_flag;
	iccc_secure_param->sys_secure_info.trustboot_flag = 0xFFFFFFFF;
	iccc_secure_param->sys_secure_info.tima_version_flag = 0xFFFFFFFF;


#ifdef CONFIG_ROT_IN_ICCC	
	iccc_secure_param->rot_secure_info.header.magic_str =  (uint16_t)ROT_MAGIC_STR;
	iccc_secure_param->rot_secure_info.header.used_size = (uint16_t)(sizeof(rot_secure_info_t));
	iccc_secure_param->rot_secure_info.verified_boot_state = smc_secure_vir->verified_boot_state;
	iccc_secure_param->rot_secure_info.device_locked = smc_secure_vir->device_locked;
	iccc_secure_param->rot_secure_info.os_version = smc_secure_vir->os_version;
	iccc_secure_param->rot_secure_info.patch_month_year = smc_secure_vir->patch_month_year;
	for(i = 0; i<ROT_KEY_SIZE/sizeof(uint32_t) ; i++) {
		iccc_secure_param->rot_secure_info.verified_boot_key[i] = *(uint32_t *)(smc_secure_vir->verified_boot_key+(i * 4));
	}

#endif		
	iccc_secure_param->rot_secure_info.boot_patch_level = smc_secure_vir->boot_patch_level;
	iccc_secure_param->rot_secure_info.vendor_patch_level = smc_secure_vir->vendor_patch_level;
	for(i = 0; i < sizeof(iccc_secure_param->kern_secure_info.verified_boot_hash)/sizeof(uint32_t) ; i++) {
		iccc_secure_param->kern_secure_info.verified_boot_hash[i] = smc_secure_vir->verified_boot_hash[i];
	}

#if ICCC_DEBUG
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.header.magic_str = ", iccc_secure_param->bl_secure_info.header.magic_str);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.header.used_size = ", iccc_secure_param->bl_secure_info.header.used_size);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.rp_ver = ", iccc_secure_param->bl_secure_info.rp_ver);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.kernel_rp = ", iccc_secure_param->bl_secure_info.kernel_rp);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.system_rp = ", iccc_secure_param->bl_secure_info.system_rp);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.test_bit = ", iccc_secure_param->bl_secure_info.test_bit);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.sec_boot = ", iccc_secure_param->bl_secure_info.sec_boot);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.react_lock = ", iccc_secure_param->bl_secure_info.react_lock);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.kiwi_lock = ", iccc_secure_param->bl_secure_info.kiwi_lock);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.frp_lock = ", iccc_secure_param->bl_secure_info.frp_lock);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.cc_mode = ", iccc_secure_param->bl_secure_info.cc_mode);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.mdm_mode = ", iccc_secure_param->bl_secure_info.mdm_mode);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.curr_bin_status = ", iccc_secure_param->bl_secure_info.curr_bin_status);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.afw_value = ", iccc_secure_param->bl_secure_info.afw_value);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.warranty_bit = ", iccc_secure_param->bl_secure_info.warranty_bit);
#ifdef ICCC_ADD_CPUID
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.ap_serial_0 = ", iccc_secure_param->bl_secure_info.ap_serial_0);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.ap_serial_1 = ", iccc_secure_param->bl_secure_info.ap_serial_1);
#endif
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.em_status = ", iccc_secure_param->bl_secure_info.em_status);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.em_token = ", iccc_secure_param->bl_secure_info.em_token);
	UART_PSH("ICCC : iccc_secure_param->bl_secure_info.kap_status = ", iccc_secure_param->bl_secure_info.kap_status);
	for(i = 0; i<MAX_IMAGES ; i++) {
		UART_PSH("ICCC : iccc_secure_param->bl_secure_info.image_status[i] = ", iccc_secure_param->bl_secure_info.image_status[i]);
	}
	UART_PSH("ICCC : iccc_secure_param->rot_secure_info.boot_patch_level = ", iccc_secure_param->rot_secure_info.boot_patch_level);
	UART_PSH("ICCC : iccc_secure_param->rot_secure_info.vendor_patch_level = ", iccc_secure_param->rot_secure_info.vendor_patch_level);
	for(i = 0; i < sizeof(iccc_secure_param->kern_secure_info.verified_boot_hash)/sizeof(uint32_t) ; i++) {
		UART_PSH("ICCC : iccc_secure_param->kern_secure_info.verified_boot_hash[i] = ", iccc_secure_param->kern_secure_info.verified_boot_hash[i]);
	}

	UART_PSH("ICCC : iccc_secure_param->ta_secure_info.header.magic_str = ", iccc_secure_param->ta_secure_info.header.magic_str);
	UART_PSH("ICCC : iccc_secure_param->ta_secure_info.header.used_size = ", iccc_secure_param->ta_secure_info.header.used_size);
	UART_PSH("ICCC : iccc_secure_param->ta_secure_info.pkm_text = ", iccc_secure_param->ta_secure_info.pkm_text);
	UART_PSH("ICCC : iccc_secure_param->ta_secure_info.pkm_ro = ", iccc_secure_param->ta_secure_info.pkm_ro);
	UART_PSH("ICCC : iccc_secure_param->ta_secure_info.selinux_status = ", iccc_secure_param->ta_secure_info.selinux_status);
	UART_PSH("ICCC : iccc_secure_param->kern_secure_info.header.magic_str = ", iccc_secure_param->kern_secure_info.header.magic_str);
	UART_PSH("ICCC : iccc_secure_param->kern_secure_info.header.used_size = ", iccc_secure_param->kern_secure_info.header.used_size);
	UART_PSH("ICCC : iccc_secure_param->kern_secure_info.dmv_status = ", iccc_secure_param->kern_secure_info.dmv_status);
	UART_PSH("ICCC : iccc_secure_param->sys_secure_info.header.magic_str = ", iccc_secure_param->sys_secure_info.header.magic_str);
	UART_PSH("ICCC : iccc_secure_param->sys_secure_info.header.used_size = ", iccc_secure_param->sys_secure_info.header.used_size);
	UART_PSH("ICCC : iccc_secure_param->sys_secure_info.sysscope_flag = ", iccc_secure_param->sys_secure_info.sysscope_flag);
	UART_PSH("ICCC : iccc_secure_param->sys_secure_info.trustboot_flag = ", iccc_secure_param->sys_secure_info.trustboot_flag);
	UART_PSH("ICCC : iccc_secure_param->sys_secure_info.tima_version_flag = ", iccc_secure_param->sys_secure_info.tima_version_flag);
	UART_PSH("ICCC : iccc_lock_flag = ", iccc_lock_flag);
	UART_PSH("ICCC : iccc_lock_flag value = ", *iccc_lock_flag);
#ifdef CONFIG_ROT_IN_ICCC	
	UART_PSH("ICCC : iccc_secure_param->rot_secure_info.header.magic_str = ", iccc_secure_param->rot_secure_info.header.magic_str);
	UART_PSH("ICCC : iccc_secure_param->rot_secure_info.header.used_size = ", iccc_secure_param->rot_secure_info.header.used_size);
	UART_PSH("ICCC : iccc_secure_param->rot_secure_info.verified_boot_state = ", iccc_secure_param->rot_secure_info.verified_boot_state);
	UART_PSH("ICCC : iccc_secure_param->rot_secure_info.device_locked = ", iccc_secure_param->rot_secure_info.device_locked);
	UART_PSH("ICCC : iccc_secure_param->rot_secure_info.os_version = ", iccc_secure_param->rot_secure_info.os_version);
	UART_PSH("ICCC : iccc_secure_param->rot_secure_info.patch_month_year = ", iccc_secure_param->rot_secure_info.patch_month_year);
	for(i = 0; i<ROT_KEY_SIZE/sizeof(uint32_t) ; i++) {
		UART_PSH("ICCC : iccc_secure_param->rot_secure_info.verified_boot_key[i] = ", iccc_secure_param->rot_secure_info.verified_boot_key[i]);
	}
#endif	
#endif

	g_check_call_iccc = 1;
	return 0;
}


int fcTIMAIcccDmvSet(fastcall_registers_t regs,struct fcContext *context)
{
  	uint32_t value;
	int temp;
	value = regs[1];
	temp = regs[2];
#if TBASE_API_LEVEL >= 5
	iccc_secure_pamameters_info_t *iccc_secure_param = (iccc_secure_pamameters_info_t *)(iccc_secure_parameter_va - ((uint32_t)(iccc_secure_parameter_va) & (SIZE_4KB - 1)) + (ICCC_SECURE_PARAMETERS_OFFSET & (SIZE_4KB - 1)));
#else
	iccc_secure_pamameters_info_t *iccc_secure_param = (iccc_secure_pamameters_info_t *)(ICCC_SECURE_PARAMETER_VA + (ICCC_SECURE_PARAMETERS_OFFSET & (SIZE_4KB - 1)));
#endif

	if(temp == 0) {
		if(g_check_call_iccc_dmv != 0) {
			uart_ps("ICCC : only one time write call is allowed in dmv area");
			return -1;
		}
		iccc_secure_param->kern_secure_info.dmv_status = value;
		g_check_call_iccc_dmv = 1;
	}
	else {
		temp = iccc_secure_param->kern_secure_info.dmv_status;
		return temp; 
	}
	return 0;
}
#endif

#if defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS5260) || defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS4415)
int fcEfuseWriter(
	fastcall_registers_t regs
) {
	return efuse_writer(regs);
}
#endif

uint32_t fcOEMFlagWrite(
	fastcall_registers_t regs
) {
	if(regs[2] > NUM_OEM_FLAG - 1){
		return MC_FC_RET_ERR_INVALID_OEM_FLAG;
	} else{
		g_oem_flag[regs[2]] = 0x1;	// tampered
		return MC_FC_RET_OK;
	}
}

uint32_t fcOEMFlagRead(
	fastcall_registers_t regs
) {
	if(regs[2] > NUM_OEM_FLAG - 1){
		return MC_FC_RET_ERR_INVALID_OEM_FLAG;
	} else{
		return g_oem_flag[regs[2]];
	}
}

#if defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) ||\
	defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS5430) ||\
	defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7570) ||\
	defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
#define NORMAL          10
#define RECOVERY        11

#define FAILED          0xcafebabe
#define SUCCEEDED       0xdeadbeef

#define CMD_UPDATE_BOOT_MODE                    0
#define CMD_UPDATE_SYSTEM_IMAGE_CHECK_STATUS    1
#define CMD_RESTORE_SYSTEM_IMAGE_CHECK_STATUS   2
#define CMD_READ_SYSTEM_IMAGE_CHECK_STATUS      3

#define ERR_DMVERITY_NOT_IN_RECOVERY -1
#define ERR_DMVERITY_UPDATES_LOCKED -2
#define ERR_DMVERITY_INVALID_CMD_ID -3

#if TBASE_API_LEVEL < 5
uint32_t *boot_mode = (uint32_t *)DMVERITY_BOOT_MODE_VA;
uint32_t *system_image_check = (uint32_t *)DMVERITY_SYSTEM_CHECK_VA;
#endif

static uint32_t lock_updates = 0;
uint32_t fcDMVsyscall(
    fastcall_registers_t regs
) {
#if TBASE_API_LEVEL >= 5
#if defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) || \
    defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
	uint32_t *boot_mode = (uint32_t *)(dmverity_va - ((uint32_t)(dmverity_va) & (SIZE_4KB - 1)) + DMVERITY_OFFSET);
	uint32_t *system_image_check = (uint32_t *)(dmverity_va - ((uint32_t)(dmverity_va) & (SIZE_4KB - 1)) + (DMVERITY_OFFSET + sizeof(uint32_t)));
#else
	uint32_t *boot_mode = (uint32_t *)(dmverity_va - ((uint32_t)(dmverity_va) & (SIZE_4KB - 1)) + (DMVERITY_PA & (SIZE_4KB - 1)));
	uint32_t *system_image_check = (uint32_t *)(dmverity_va - ((uint32_t)(dmverity_va) & (SIZE_4KB - 1)) + ((DMVERITY_PA + sizeof(uint32_t)) & (SIZE_4KB - 1)));
#endif
#endif

    uint32_t cmd_id = regs[1];
    uint32_t arg1 = regs[2];

    /* First will be all read-only command-ids. They will always be accessible */
    if (cmd_id == CMD_READ_SYSTEM_IMAGE_CHECK_STATUS) {
        /* TODO: Check value of rsp */
        if (*boot_mode == RECOVERY) {
            return *system_image_check;
        } else {
            /* not in recovery mode */
            return ERR_DMVERITY_NOT_IN_RECOVERY;
        }
    }

    if (cmd_id == 5)
        return *boot_mode;

    if (cmd_id == 6)
        return *system_image_check;

    /* Now that read-only command-ids are done. Check for update lock */
    if (lock_updates == 1) {
        return ERR_DMVERITY_UPDATES_LOCKED;
    }

    /* Write cmd ids */
    if (cmd_id == CMD_UPDATE_SYSTEM_IMAGE_CHECK_STATUS) {
        if (arg1)
                *system_image_check = SUCCEEDED;
        else
                *system_image_check = FAILED;
        return 0;
    } else if (cmd_id == CMD_RESTORE_SYSTEM_IMAGE_CHECK_STATUS) {
        *system_image_check = arg1;
        return 0;
    } else if (cmd_id == CMD_UPDATE_BOOT_MODE) {
        /* Update to this value is allowed only once during boot-up, it is then i
         * locked 
         */
        lock_updates = 1;

        if (arg1)
            *boot_mode = RECOVERY;
        else {
            *boot_mode = NORMAL;
            /* Reset system_image_check to a known value */
            *system_image_check = FAILED;
        }
        return 0;
    } else {
        return ERR_DMVERITY_INVALID_CMD_ID;
    }

}

#if !defined (CONFIG_EXYNOS5430)
#if !defined (CONFIG_EXYNOS3475) && !defined (CONFIG_EXYNOS7870) && !defined (CONFIG_EXYNOS7880) &&\
	!defined (CONFIG_EXYNOS7420) && !defined (CONFIG_EXYNOS8890) && !defined (CONFIG_EXYNOS7570) &&\
	!defined (CONFIG_EXYNOS7885) && !defined (CONFIG_EXYNOS8895) && !defined (CONFIG_EXYNOS9810)
int fcOTPControl(
	fastcall_registers_t regs
) {
	return otp_control(regs);
}

int fcRNGGetSeed(
	fastcall_registers_t regs
) {
	return rng_get_seed(regs);
}
#endif
#endif
#endif

#if defined(CONFIG_EXYNOS3475)
int fcRNGGetSeed(
	fastcall_registers_t regs
) {
	return rng_get_seed(regs);
}
#endif

#if defined(CONFIG_FP_TZ_CONTROL)
uint32_t fcFpTzControl(
	fastcall_registers_t regs,
	uint32_t pin_conf
) {
	uint32_t ret;

	ret = fp_set_tzpc_secure(regs, pin_conf);
	if (ret) {
		return ret;
	}

	ret = fp_set_gpio_init(regs);
	if (ret) {
		return ret;
	}
	return 0;
}
uint32_t fcFpPmSuspend(
	fastcall_registers_t regs
) {
	return fp_save_gpio_regs(regs);
}

uint32_t fcFpPmSuspendCsHigh(
	fastcall_registers_t regs
) {
	return fp_save_gpio_regs_cs_high(regs);
}

uint32_t fcFpPmResume(
	fastcall_registers_t regs
) {
	return fp_restore_gpio_regs(regs);
}

uint32_t fcFpBtpOcpControl(
	fastcall_registers_t regs,
	uint32_t gpio_dat_bit
) {
	return fp_set_gpio_btp_ocp(regs, gpio_dat_bit);
}

uint32_t fcFpBtpOcpDisable(
	fastcall_registers_t regs
) {
	return fp_disable_gpio_btp_ocp(regs);
}

uint32_t fcFpCsPinSet(
	fastcall_registers_t regs
) {
	return fp_set_spi_cs(regs);
}

uint32_t fcFpTestFunction(
	fastcall_registers_t regs
) {
	return fp_test_fastcall_function(regs);
}
#endif

#if defined(TIMA_RUNTIME_SKIP_MSR)
#define	MC_FC_RT_KEYSTORE_SKIP ((uint32_t)(0x83000010))
#define OTP_USE_OEM_KEY_OFFSET       (1 << 0)
#define OTP_PREORDER_KEY_MASK      (0x00FF0000)
#define OTP_BAN_OEM_KEY_OFFSET          (1 << 2)
#define OTP_TEST_BIT_OFFSET             (1 << 2)

#define GET_SECURE_BOOT (SECURE_BOOT_ENABLE_VA + (SECURE_BOOT_ENABLE_PA & (SIZE_4KB - 1)))
#define OTP_read_custom_key (*(volatile unsigned int *)GET_SECURE_BOOT)
#define __SECURE                0x1
#define __NON_SECURE            0x0

uint32_t fcTIMAGetSecureBootStatus(void)
{
	int ret = 0;
#if TBASE_API_LEVEL >= 5
	uint32_t otp_read_custom_key = *((volatile unsigned int *)(secure_boot_enable_va - ((uint32_t)(secure_boot_enable_va) & (SIZE_4KB - 1)) + (SECURE_BOOT_ENABLE_PA & (SIZE_4KB - 1))));

	if (otp_read_custom_key & OTP_BAN_OEM_KEY_OFFSET) {
		if (otp_read_custom_key & OTP_PREORDER_KEY_MASK)
			ret = __SECURE;
		else
			ret = __NON_SECURE;
	}
	else if (otp_read_custom_key & OTP_USE_OEM_KEY_OFFSET)
		ret = __SECURE;
	else if (otp_read_custom_key & OTP_PREORDER_KEY_MASK)
		ret = __SECURE;
	else
		ret = __NON_SECURE;
	//UART_PSH("fcTIMAGetSecureBootStatus() : otp_read_custom_key = ", otp_read_custom_key);
#else
	if (OTP_read_custom_key & OTP_BAN_OEM_KEY_OFFSET) {
		if (OTP_read_custom_key & OTP_PREORDER_KEY_MASK)
			ret = __SECURE;
		else
			ret = __NON_SECURE;
	}
	else if (OTP_read_custom_key & OTP_USE_OEM_KEY_OFFSET)
		ret = __SECURE;
	else if (OTP_read_custom_key & OTP_PREORDER_KEY_MASK)
		ret = __SECURE;
	else
		ret = __NON_SECURE;
	//UART_PSH("fcTIMAGetSecureBootStatus() : OTP_read_custom_key = ", OTP_read_custom_key);
#endif
	return ret;
}
#endif /*TIMA_RUNTIME_SKIP_MSR*/

int str_to_int(char *str)
{
	int int_val=0; 
	while(*str){
		int_val = int_val*10 + *str - '0';
		str++;
	}
	return int_val;
} 

uint32_t fcBuildinfo(void)
{
	int build_info;
	build_info = str_to_int(_BUILD_INFO);
	UART_PSH("build_info = 0x", build_info);
	return build_info;
}

/**
 * Fastcall initialization routine.
 * Called at boot.
 * Return 0, if an initialization goes OK,
 * if something fails return not zero and fastcalls are not
 * allowed
 */
#if defined(CONFIG_EXYNOS5422) || defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS3470) ||\
	defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS3472) || defined(CONFIG_EXYNOS3250) ||\
	defined(CONFIG_EXYNOS4415) || defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS5410) ||\
	defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) ||\
	defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) ||\
	defined(CONFIG_EXYNOS7570) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810) ||\
	defined(CONFIG_EXYNOS7885)
uint32_t fcInit(struct fcContext *context)
{
    // Initialization code here - Runs in Kernel context
    // We expect at least 4 registers
    if (context->registers < 4)
        return E_INVALID;

#if !defined(TIMA_FEATURE_FOR_64BIT)
    // Get the pointer to the memory mapping function
    setL1Entry = context->setL1Entry;
    // Set the L1 table to fault
    setL1Entry(context, 0, L1_TYPE_FAULT);
	/* START: Add for RKP 1to1 mapping */
#if defined(CONFIG_EXYNOS3250)
	if(context->prepareIdenticalMapping)
		context->prepareIdenticalMapping(context, 0x00000000, 0xF0000000, 0);
#endif
#else

#if defined(TIMA_MST_DRV)
	memset(pVirtBaseAddr,0x0,sizeof(pVirtBaseAddr));
#endif

    // Set the L1 table to fault
    context->setL1Entry64(context, 0, L1_TYPE_FAULT);
#if defined(CONFIG_EXYNOS5422) 
    if(context->prepareIdenticalMapping)
  	context->prepareIdenticalMapping(context, 0x00000000, 0xF0000000, 0);
#endif
#endif
    return 0;
}
#else
uint32_t fcInit(fcContext_ptr context)
{
    // Initialization code here - Runs in Kernel context
    // We expect at least 4 registers
    if (context->registers < 4)
        return E_INVALID;

    // Get the pointer to the memory mapping function
    setL1Entry = context->setL1Entry;
    // Set the L1 table to fault
    setL1Entry(context, 0, L1_TYPE_FAULT);

    return 0;
}
#endif

/*---------------------------------------------------------------------------*/
/**
 * Fastcall routine.
 */
#if defined(CONFIG_EXYNOS5422) || defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS3470) ||\
	defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS3472) || defined(CONFIG_EXYNOS3250) ||\
	defined(CONFIG_EXYNOS4415) || defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS5410) ||\
	defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) ||\
	defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) ||\
	defined(CONFIG_EXYNOS7570) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810) ||\
	defined(CONFIG_EXYNOS7885)
uint32_t fcMain(
    fastcall_registers_t regs,
    struct fcContext *context,
    word_t flags)
{
	uint32_t fastCallID = regs[0];
#if defined(TIMA_MST_DRV) /* TIMA_MST_DRV */
	unsigned char mst_track_data[TRACK_DATA_SIZE];
	uint64_t mst_align=0;
	uint64_t mstPhy=0;
	uint32_t bus_id=0;
#endif

#if defined(TIMA_MST_DRV) || defined(CONFIG_FP_TZ_CONTROL) || defined(CONFIG_SECURE_CAMERA)
	uint32_t protection_result = 0;
	fastcall_registers_t protection_ret;
#endif
	switch (fastCallID) {
#if defined(CONFIG_EXYNOS5422) || defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS5410) || defined(CONFIG_EXYNOS5420)
	case (uint32_t) MC_FC_HDCP_VALUE:
		fcHDCPValue(regs);
		break;
#endif
	case (uint32_t) MC_FC_MAKE_TIMA_HASH_TABLE:
		if (fcTIMACopyHashValue(regs, context))
			return E_INVALID;
        break;
#if defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS4415) || defined(CONFIG_EXYNOS3475)
	case (uint32_t) MC_FC_EFUSE_WRITER:
		fcEfuseWriter(regs);
		break;
#endif
	case (uint32_t) MC_FC_OEM_FLAG_WRITE:
		regs[1] = fcOEMFlagWrite(regs);
		break;
	case (uint32_t) MC_FC_OEM_FLAG_READ:
		regs[1] = fcOEMFlagRead(regs);
		break;
#if defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS3475)
	case (uint32_t) MC_FC_GET_RANDOM_VALUE:
		regs[1] = fcRNGGetSeed(regs);
		break;
#endif
#if defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS7580)
	case (uint32_t) MC_FC_OTP_CONTROL:
		fcOTPControl(regs);
		break;
#endif
	case (uint32_t) MC_FC_BUILD_INFO:
		regs[0] = fcBuildinfo();
		break;
#if defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) ||\
	defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS5430) ||\
	defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7570) ||\
	defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
    case (uint32_t) MC_FC_DMVERITY:
#if defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS3475)
        regs[1] = fcDMVsyscall(regs);
#elif defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS7870) ||\
	  defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7570) ||\
	  defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
        regs[0] = fcDMVsyscall(regs);
#endif
        break;

        case (uint32_t) MC_FC_KAP_CALL:
#if defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS7870) ||\
	defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7570) ||\
	defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
        regs[0] = fcKAPsyscall(regs);
#else
        regs[1] = fcKAPsyscall(regs);
#endif
        break;
    case (uint32_t) MC_FC_KAP_STATUS:
#if defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS7870) ||\
	defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7570) ||\
	defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
         regs[0] = fcKapStatus();
#else
         regs[1] = fcKapStatus();
#endif
        break;

#endif

#if defined(CONFIG_ESE_TZ_CONTROL)
	case (uint32_t)MC_ESE_SECURE_PIN:
		regs[0] = set_tzpc_ese_secure((uint32_t)regs[1]);
		break;
	case (uint32_t)MC_ESE_PM_SUSPEND:
		if (regs[2] == 1)
			regs[0] = suspend_ese_gpio_regs_ot((uint32_t)regs[1]);
		else
			regs[0] = suspend_ese_gpio_regs((uint32_t)regs[1]);
		break;
	case (uint32_t)MC_ESE_PM_RESUME:
		regs[0] = resume_ese_gpio_regs((uint32_t)regs[1]);
		break;
#endif

#if defined(TIMA_MST_DRV) || defined(CONFIG_FP_TZ_CONTROL)
	case (uint32_t) MC_FC_SECURE_PIN:
		if(pin_conf_flag == 1){
			pin_conf = regs[1];
			system_rev = regs[3];
			pin_conf_flag = 0;
		}

#if defined(CONFIG_EXYNOS5422) || defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS3470) ||\
	defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS3472) || defined(CONFIG_EXYNOS3250) ||\
	defined(CONFIG_EXYNOS4415) || defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS5410) ||\
	defined(CONFIG_EXYNOS5420)
		protection_ret = &regs[1];
#else
		protection_ret = &regs[0];
#endif

		*protection_ret = 0;

#if defined(TIMA_MST_DRV)
		if(pin_conf == ZERO_IN_MODE || pin_conf == NOBLE_ZERO2_IN_MODE || pin_conf == A_PHASE_EN_MODE ||\
		   pin_conf == HERO_PHASE_EN_MODE || pin_conf == GRACE_PHASE_EN_MODE ||  pin_conf == A3Y17_PHASE_EN_MODE ||\
		   pin_conf == A57Y17_PHASE_EN_MODE || pin_conf == DREAM_PHASE_EN_MODE || pin_conf == JACKPOT_PHASE_EN_MODE ||\
		   pin_conf == STAR_PHASE_EN_MODE){
			protection_result = set_gpio_mst_secure(pin_conf);
			if (protection_result) {
				*protection_ret |= MST_RET_BIT;
			}
			
#if defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS7870) ||\
    defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS8895)
			// set mst gpio by defalut
			set_gpio_mst_default(pin_conf);
			// saved gpio register by default
			set_saved_gpio_mst_default();
#else
			gpio_set_mst_gpio_pin(pin_conf);
			gpio_set_mst_init(pin_conf, gpio_mst_md_pin, gpio_mst_pd_pin, gpio_mst_pwr_en_pin);
#endif
		}else{
			*protection_ret = MST_NOT_SUPPORT;
		}
#endif

#if defined(CONFIG_FP_TZ_CONTROL)
		if (regs[2] == FP_MODE) {
			protection_result = fcFpTzControl(regs, pin_conf);
			if (protection_result) {
				*protection_ret |= FP_RET_BIT;
			}
		}
#endif

		if ((*protection_ret & MST_RET_BIT) || (*protection_ret & FP_RET_BIT) || (*protection_ret & MST_NOT_SUPPORT)) {
			*protection_ret |= TZPC_ERROR_PREFIX;
		} else {
			*protection_ret = 0;
		}
		break;
#endif

#if defined(TIMA_MST_DRV) /* TIMA_MST_DRV */
	case (uint32_t) MC_FC_NFC_ACTION:
		regs[0] = fcNFCAction(regs);
		break;

	case (uint32_t) MC_FC_SECURE_GPIO_RECOVERY:
		bus_id = regs[1];
		recover_gpio_mst(bus_id);
		regs[0] = bus_id;
		break;

	case (uint32_t) MC_FC_LPA_MODE:
		if(pin_conf == ZERO_IN_MODE || pin_conf == NOBLE_ZERO2_IN_MODE){
			regs[0] = save_mst_gpio_regs(pin_conf);
			set_gpio_lpa_mode(pin_conf);
		}else{
			regs[0] = MST_NOT_SUPPORT;
		}
		break;

	case (uint32_t) MC_FC_MST_CONTROL:
		// skip the call from Nwd
		if(!(flags & 0x1)){
			return E_OK;
		}
		
		mstPhy = regs[2]<<32;
		mstPhy = mstPhy + regs[3];

		if(mstPhy !=  g_trusted_boot_addr + GOOD_MEASUREMENT_OFFSET - SIZE_4KB)
			break;
			
		mst_align = mstPhy & 0x00000000001FFFFF;
		mstPhy = mstPhy & 0xFFFFFFFFFFE00000;

		pVirtBaseAddr[0] = context->setL1Entry64(context, 0, makeL1Pte64_CACHED(mstPhy));
		if ((pVirtBaseAddr[0] == NULL)) {
			regs[0] = 0;
			return E_INVALID;
		}
		memcpy(mst_track_data,(char *)((uint32_t)pVirtBaseAddr[0] + mst_align), TRACK_DATA_SIZE);

		regs[0] = fcMstTransmit(regs, mst_track_data, pin_conf, system_rev);
		break;

	case (uint32_t) MC_FC_MST_SUSPEND:
		if(pin_conf == ZERO_IN_MODE || pin_conf == NOBLE_ZERO2_IN_MODE || pin_conf == A_PHASE_EN_MODE ||\
		   pin_conf == HERO_PHASE_EN_MODE || pin_conf == GRACE_PHASE_EN_MODE || pin_conf == A3Y17_PHASE_EN_MODE ||\
		   pin_conf == A57Y17_PHASE_EN_MODE || pin_conf == DREAM_PHASE_EN_MODE || pin_conf == JACKPOT_PHASE_EN_MODE ||\
	           pin_conf == STAR_PHASE_EN_MODE){
			regs[0] = save_mst_gpio_regs(pin_conf);
			set_gpio_sleep_state(pin_conf);
		}else{
			regs[0] = MST_NOT_SUPPORT;
		}
		break;

	case (uint32_t) MC_FC_MST_RESUME:
		if(pin_conf == ZERO_IN_MODE || pin_conf == NOBLE_ZERO2_IN_MODE || pin_conf == A_PHASE_EN_MODE ||\
		   pin_conf == HERO_PHASE_EN_MODE || pin_conf == GRACE_PHASE_EN_MODE || pin_conf == A3Y17_PHASE_EN_MODE ||\
		   pin_conf == A57Y17_PHASE_EN_MODE || pin_conf == DREAM_PHASE_EN_MODE || pin_conf == JACKPOT_PHASE_EN_MODE ||\
	           pin_conf == STAR_PHASE_EN_MODE){
			regs[0] = restore_mst_gpio_regs(pin_conf);
		}else{
			regs[0] = MST_NOT_SUPPORT;
		}		
		break;

	case (uint32_t) MC_FC_MST_TEST_TRANSMIT:
		/* track1 data transmit */
		if(regs[1] == 1){
			regs[0] = fcMstTransmit(regs, mst_test_track1, pin_conf, system_rev);
		/* track2 data transmit */
		}else if(regs[1] == 2){
			regs[0] = fcMstTransmit(regs, mst_test_track2, pin_conf, system_rev);
		}else
			regs[0] = -1;
		break;
#endif /* TIMA_MST_DRV end*/
#if defined(TIMA_SHARED_INFO)
	case (uint32_t) MC_FC_TIMA_SHARED_INFO:
		if(tima_info_data.screen_res == 0){
#if defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS8890) ||\
	defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS7570)
			regs[0] = fcTIMASharedInfo(regs, context);
#else
			regs[1] = fcTIMASharedInfo(regs, context);
#endif
		} else {
#if defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS8890) ||\
	defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS7570)
			regs[0] = 0;
#else
			regs[1] = 0;
#endif
		}
		break;
	case (uint32_t) MC_FC_GET_TIMA_SHARED_INFO:
		regs[1] = fcTIMAGetSharedInfo(regs, context);
		break;
#endif /* TIMA_SHARED_INFO end*/

#if defined(TUI_MULTI_RESOLUTION_SUPPORT)
	case (uint32_t) MC_FC_TUI_SET_RESOLUTION_INFO:
		regs[0] = fcTUISetResolutionInfo(regs, context);
		break;

	case (uint32_t) MC_FC_TUI_GET_RESOLUTION_INFO:
		regs[0] = fcTUIGetResolutionInfo(regs, context);		
		break;
#endif /* TUI_MULTI_RESOLUTION_SUPPORT end*/

#if defined(TIMA_RUNTIME_SKIP_MSR)
	case (uint32_t) MC_FC_RT_KEYSTORE_SKIP:
		regs[1] = fcTIMAGetSecureBootStatus();
		break;
#endif /* TIMA_RUNTIME_SKIP_MSR end*/
#if defined(CONFIG_FP_TZ_CONTROL)
	case (uint32_t) MC_FC_FP_PM_SUSPEND:
		regs[0] = fcFpPmSuspend(regs);
		break;

	case (uint32_t) MC_FC_FP_PM_SUSPEND_RETAIN:
	case (uint32_t) MC_FC_FP_PM_SUSPEND_CS_HIGH:
		regs[0] = fcFpPmSuspendCsHigh(regs);
		break;

	case (uint32_t) MC_FC_FP_PM_RESUME:
		regs[0] = fcFpPmResume(regs);
		break;

	case (uint32_t) MC_FC_FP_BTP_OCP_HIGH:
		regs[0] = fcFpBtpOcpControl(regs, FP_GPIO_HIGH);
		break;

	case (uint32_t) MC_FC_FP_BTP_OCP_LOW:
		regs[0] = fcFpBtpOcpControl(regs, FP_GPIO_LOW);
		break;

	case (uint32_t) MC_FC_FP_BTP_OCP_NONE:
		regs[0] = fcFpBtpOcpDisable(regs);
		break;

	case (uint32_t) MC_FC_FP_CS_SET:
		regs[0] = fcFpCsPinSet(regs);
		break;

	case (uint32_t) MC_FC_FP_TEST_FASTCALL:
		regs[0] = fcFpTestFunction(regs);
		break;
#endif
#if defined(CONFIG_SECURE_CAMERA)
	case (uint32_t) MC_SECURE_CAMERA_INIT:
		protection_result = sec_cam_init(regs);
		if (protection_result) {
			regs[0] = SECURE_CAMERA_ERROR | protection_result;
		} else {
			regs[0] = 0;
		}
		break;
#if (!defined(CONFIG_EXYNOS8895) && !defined(CONFIG_EXYNOS9810)) // not needed for Exynos 8895
	case (uint32_t) MC_SECURE_CAMERA_CFW_ENABLE:
		regs[0] = sec_cam_cfw_enable();
		break;
#endif
	case (uint32_t) MC_SECURE_CAMERA_PREPARE:
		regs[0] = sec_cam_prepare(regs);
		break;
	case (uint32_t) MC_SECURE_CAMERA_UNPREPARE:
		regs[0] = sec_cam_unprepare(regs);
		break;
	case (uint32_t) MC_SECURE_CAMERA_I2C_RECOVERY:
		regs[0] = sec_cam_i2c_recovery(regs);
		break;
#endif
#ifdef CONFIG_KNOX_GEARPAY
	case (uint32_t) MC_FC_GEARPAY_BOOL_WRITE:
		/*
		 * FIXME: Need to instrument the mcdriver interface
		 * accessible from USER space to restrict this
		 * command ID OR check NS bit, or both.
		 */
		switch (regs[1]) {
		case TOUCH:
		{
			if (regs[2] == 1)
				g_touch_bool = 1;
			else if (regs[2] == 0)
				g_touch_bool = 0;
		}
		regs[1] = MC_FC_RET_OK;
		break;
		case PHYSBUTTON:
		{
			if (regs[2] == 1)
				g_physbutton_bool = 1;
			else if (regs[2] == 0)
				g_physbutton_bool = 0;
		}
		regs[1] = MC_FC_RET_OK;
		break;
		case STRAP:
		{
			if (regs[2] == 1)
				g_strap_bool = 1;
			else if (regs[2] == 0)
				g_strap_bool = 0;
		}
		regs[1] = MC_FC_RET_OK;
		break;
		default:
		{
			regs[1] = MC_FC_RET_ERR_INVALID_GEARPAY_FLAG;
			return E_INVALID;
		}
		}
		break;
#endif
#if defined(ICCC_SECURE_PARAMETERS_AREA)
	case (uint32_t) SMC_CMD_DMV_WRITE_STATUS:
#if defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS8890) ||\
	defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS5433) ||\
	defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS3470) ||\
	defined(CONFIG_EXYNOS7570) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
		regs[0] = fcTIMAIcccDmvSet(regs, context);
#else
		regs[1] = fcTIMAIcccDmvSet(regs, context);
#endif
		break;
	case (uint32_t) MC_FC_ICCC_SVB_RESULT:
		regs[1] = IcccSvbResult(regs, context);
		break;
	case (uint32_t) MC_FC_ICCC_DATA_LOCK:
		regs[1] = IcccDataLock(regs, context);
		break;
	case (uint32_t) MC_FC_SHARE_SECURE_INFO:
		regs[1] = fcTIMASaveSecureParam(regs, context);
		break;
#endif
	default:
		regs[1] = MC_FC_RET_ERR_INVALID;
		return E_INVALID;
	}

	return E_OK;
}
#else
uint32_t fcMain(
    fastcall_registers_t regs,
    struct fcContext_t *context)
{
	uint32_t fastCallID = regs[0];

	switch (fastCallID) {
#if defined(CONFIG_EXYNOS5410) || defined(CONFIG_EXYNOS5420)
	case (uint32_t) MC_FC_HDCP_VALUE:
		fcHDCPValue(regs);
		break;
#endif
	case (uint32_t) MC_FC_MAKE_TIMA_HASH_TABLE:
		if (fcTIMACopyHashValue(regs,context))
			return E_INVALID;
		break;
#if defined(CONFIG_EXYNOS5260)
	case (uint32_t) MC_FC_EFUSE_WRITER:
		fcEfuseWriter(regs);
		break;
#endif
	case (uint32_t) MC_FC_OEM_FLAG_WRITE:
		regs[1] = fcOEMFlagWrite(regs);
		break;
	case (uint32_t) MC_FC_OEM_FLAG_READ:
		regs[1] = fcOEMFlagRead(regs);
		break;
	default:
		regs[1] = MC_FC_RET_ERR_INVALID;
		return E_INVALID;
	}

	return E_OK;
}
#endif
