/**
 * @file   main.c
 * @brief  Main for FastCall driver.
 *
 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
 */

#include "drStd.h"
#include "DrApi/DrApiThread.h"
#include "DrApi/DrApiMcSystem.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 "drCommon.h"
#include "drMobicore.h"
#include "version.h"
#include "dbg.h"
#include "fcdrv_hw_hal.h"

#include "regs-cmu.h"
#include "regs-pmu.h"
#include "regs-media.h"
#include "regs-tzasc.h"
#include "regs-sss.h"

#include "fcHDCP.h"
#include "fcTIMA.h"
#include "fcEfuse.h"
#include "fcUART.h"
#if defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS7580)
#include "otp.h"
#endif

#if defined(TIMA_MST_DRV)
#include "regs-gpio-mst.h"
#include "gpio-mst.h"
#endif

#if defined(CONFIG_FP_TZ_CONTROL)
#include "regs-gpio-fp.h"
#include "gpio-fp.h"
#endif

#if defined(CONFIG_ESE_TZ_CONTROL)
#include "regs-gpio-ese.h"
#include "gpio-ese.h"
#include "gpio-ese-platform.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"
#include "DrApi/DrApiError.h"
#endif

CHECK_VERSION(FC_DRIVER)
DECLARE_DRIVER_MAIN_STACK(2048)

/* TIMA Trusted-boot region address */
extern uint32_t g_trusted_boot_addr;

extern void *entryVector[];
#if defined(TIMA_SHARED_INFO)
extern tima_info tima_info_data;
#endif

/* External functions */
extern void drIpchInit(void);
extern _NORETURN void drExchLoop(void);

/**
 * Initialization function
 */
 
#if TBASE_API_LEVEL >= 5
addr_t hdmi_sfr_va, pmu_media_sfr_va, cmu_top_sfr_va, tzasc_va;
addr_t dram_hash_table_va, sram_hash_table_va, kernel_hash_value_va;
addr_t good_measurement_va, iccc_secure_parameter_va, secure_boot_enable_va;
addr_t sss_sfr_va, uart_sfr_va, dmverity_va;
addr_t gpj0_va, gpj1_va, gpf3_va, tzpc13_va, tzpc_peric_va, fp_tzpc_spi_sfr_va, fp_tzpc_gpio_sfr_va, fp_gpio_sfr_va;
#if defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
addr_t fp_tzpc_usi_sfr_va, fp_usi_i_mode_sfr_va;
#endif

static drApiResult_t doInitialization( void )
{
	drApiResult_t ret = DRAPI_OK;
	uint32_t hash_table_pa;

#if defined(CONFIG_EXYNOS5410) || defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5422) ||\
	defined(CONFIG_EXYNOS5433) || 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)
	/* mapping for HDCP authentication */
	ret = drApiMapPhysicalBuffer((uint64_t)HDMI_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&hdmi_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): hdmi_sfr_va error: ", ret);
		return ret;
	}

	ret = drApiMapPhysicalBuffer((uint64_t)PMU_MEDIA_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&pmu_media_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): pmu_media_sfr_va error: ", ret);
		return ret;
	}

	ret = drApiMapPhysicalBuffer((uint64_t)CMU_TOP_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&cmu_top_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): cmu_top_sfr_va error: ", ret);
		return ret;
	}
#endif
	/* Get physical address of hash table */
	ret = drApiMapPhysicalBuffer((uint64_t)TZASC0_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&tzasc_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): tzasc_va error: ", ret);
		return ret;
	}
#if defined(CONFIG_4X12) || defined(CONFIG_EXYNOS3470) || defined(CONFIG_EXYNOS4415)
	hash_table_pa = read_sfr_value((uint32_t)(tzasc_va + TZRS_LOW3));
#elif defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
	hash_table_pa = read_sfr_value((uint32_t)(tzasc_va + TZRS_LOW0))
						<< TZ_INTERLEAVING_SHIFT;
#else
	hash_table_pa = read_sfr_value((uint32_t)(tzasc_va + TZRS_LOW1))
						<< TZ_INTERLEAVING_SHIFT;
#if defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7570) || defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS7885) 
	hash_table_pa = hash_table_pa << TZ_INTERLEAVING_SHIFT2 ;
#endif
#endif
	g_trusted_boot_addr = hash_table_pa;
	ret = drApiUnmapBuffer(tzasc_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): tzasc_va unmap error: ", ret);
		return ret;
	}

	ret = drApiMapPhysicalBuffer((uint64_t)hash_table_pa,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&dram_hash_table_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): dram_hash_table_va error: ", ret);
		return ret;
	}

#if defined(SRAM_HASH_TABLE_PA)
	ret = drApiMapPhysicalBuffer((uint64_t)SRAM_HASH_TABLE_PA,
			SIZE_2KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&sram_hash_table_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): sram_hash_table_va error: ", ret);
		return ret;
	}
#endif
#if defined(KERNEL_HASH_VALUE_PA)
	ret = drApiMapPhysicalBuffer((uint64_t)KERNEL_HASH_VALUE_PA,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&kernel_hash_value_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): kernel_hash_value_va error: ", ret);
		return ret;
	}
#endif
#if defined(TIMA_HAVE_GOOD_MEASUREMENT)
	ret = drApiMapPhysicalBuffer((uint64_t)(hash_table_pa + GOOD_MEASUREMENT_OFFSET),
			SIZE_4KB - (GOOD_MEASUREMENT_OFFSET % SIZE_4KB),
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&good_measurement_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): good_measurement_va error: ", ret);
		return ret;
	}
#endif
#if defined(ICCC_SECURE_PARAMETERS_AREA)
	ret = drApiMapPhysicalBuffer((uint64_t)(hash_table_pa + ICCC_SECURE_PARAMETERS_OFFSET),
			SIZE_4KB - (ICCC_SECURE_PARAMETERS_OFFSET % SIZE_4KB),
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&iccc_secure_parameter_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): iccc_secure_parameter_va error: ", ret);
		return ret;
	}
#endif
#if defined(TIMA_RUNTIME_SKIP_MSR)
	ret = drApiMapPhysicalBuffer((uint64_t)SECURE_BOOT_ENABLE_PA & ~(SIZE_4KB - 1),
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&secure_boot_enable_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): secure_boot_enable_va error: ", ret);
		return ret;
	}
#endif
#if defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS5260) || defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS4415)
	/* mapping for EfuseWriter */
	ret = drApiMapPhysicalBuffer((uint64_t)EFUSE_SC_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&efuse_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): efuse_sfr_va error: ", ret);
		return ret;
	}

	ret = drApiMapPhysicalBuffer((uint64_t)MAIN_EFUSE_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&main_efuse_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): main_efuse_va error: ", ret);
		return ret;
	}

	ret = drApiMapPhysicalBuffer((uint64_t)ROOT_KEY_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&root_key_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): root_key_va error: ", ret);
		return ret;
	}

	ret = drApiMapPhysicalBuffer((uint64_t)NANTIRBK_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&nantirbk_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): nantirbk_va error: ", ret);
		return ret;
	}
#endif
#if defined(CONFIG_EXYNOS5430)
	ret = drApiMapPhysicalBuffer((uint64_t)SECURE_JTAG_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&secure_jtag_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): secure_jtag_va error: ", ret);
		return ret;
	}
#endif
	ret = drApiMapPhysicalBuffer((uint64_t)SSS_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&sss_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): sss_sfr_va error: ", ret);
		return ret;
	}
#if defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS7580)
	/* mapping for OTP controller */
	ret = drApiMapPhysicalBuffer((uint64_t)OTP_CONTROL_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&otp_control_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): otp_control_sfr_va error: ", ret);
		return ret;
	}
#endif
#if defined(CONFIG_EXYNOS5260) || defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS5433) ||\
	defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS3475) ||\
	defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) ||\
	defined(CONFIG_EXYNOS7570) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
	ret = drApiMapPhysicalBuffer((uint64_t)UART1_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&uart_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): uart_sfr_va error: ", ret);
		return ret;
	}
#elif defined(CONFIG_EXYNOS5422) || defined(CONFIG_EXYNOS3470) || defined(CONFIG_EXYNOS3472) ||\
	defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS3250) || defined(CONFIG_EXYNOS7885)
	ret = drApiMapPhysicalBuffer((uint64_t)UART2_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&uart_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): uart_sfr_va error: ", ret);
		return ret;
	}
#elif defined(CONFIG_EXYNOS4415)
	ret = drApiMapPhysicalBuffer((uint64_t)UART3_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&uart_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): uart_sfr_va error: ", ret);
		return ret;
	}
#endif

#if defined(CONFIG_EXYNOS5433)|| defined(CONFIG_EXYNOS7420) ||\
	defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7570)
	ret = drApiMapPhysicalBuffer((uint64_t)DMVERITY_PA & ~(SIZE_4KB - 1),
		SIZE_4KB,
		MAP_READABLE | MAP_WRITABLE | MAP_IO,
		(void **)&dmverity_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): dmverity_va error: ", ret);
		return ret;
	}
#elif defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS7885) ||\
	  defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
	ret = drApiMapPhysicalBuffer((uint64_t)(hash_table_pa + DMVERITY_OFFSET) & ~(SIZE_4KB - 1),
		SIZE_4KB,
		MAP_READABLE | MAP_WRITABLE | MAP_IO,
		(void **)&dmverity_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): dmverity_va error: ", ret);
		return ret;
	}
#endif

#if defined(TIMA_MST_DRV)
	ret = drApiMapPhysicalBuffer((uint64_t)GPJ0_BASE,
		SIZE_4KB,
		MAP_READABLE | MAP_WRITABLE | MAP_IO,
		(void **)&gpj0_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): gpj0_va error: ", ret);
		return ret;
	}

	ret = drApiMapPhysicalBuffer((uint64_t)GPJ1_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&gpj1_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): gpj1_va error: ", ret);
		return ret;
	}

	ret = drApiMapPhysicalBuffer((uint64_t)GPF3_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&gpf3_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): gpf3_va error: ", ret);
		return ret;
	}
#endif
#if defined(TIMA_MST_DRV)
#if defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS7870) ||\
    defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS8890)
	ret = drApiMapPhysicalBuffer((uint64_t)TZPC13_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&tzpc13_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): tzpc13_va error: ", ret);
		return ret;
	}
#else
/* 
 * TZPC method changed from EXYNOS8895
 * TZPC_PERIC_BASE addr should be used
 * EXYNOS8895, EXYNOS7885, EXYNOS9810
 */
	ret = drApiMapPhysicalBuffer((uint64_t)TZPC_PERIC_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&tzpc_peric_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): tzpc_peric_va error: ", ret);
		return ret;
	}
#endif
#endif

#if defined(CONFIG_FP_TZ_CONTROL)
	ret = drApiMapPhysicalBuffer((uint64_t)FP_TZPC_SPI_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&fp_tzpc_spi_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): fp_tzpc_spi_sfr_va error: ", ret);
		return ret;
	}
#if defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
	ret = drApiMapPhysicalBuffer((uint64_t)FP_TZPC_USI_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&fp_tzpc_usi_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): fp_tzpc_usi_sfr_va error: ", ret);
		return ret;
	}
#endif
#if defined(FP_GPIO_PROTECTION)
	ret = drApiMapPhysicalBuffer((uint64_t)FP_TZPC_GPIO_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&fp_tzpc_gpio_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): fp_tzpc_gpio_sfr_va error: ", ret);
		return ret;
	}
#endif
	ret = drApiMapPhysicalBuffer((uint64_t)FP_GPIO_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&fp_gpio_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): fp_gpio_sfr_va error: ", ret);
		return ret;
	}
#if defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
	/* set the usi00_i_mode sfr base */
	ret = drApiMapPhysicalBuffer((uint64_t)FP_USI_I_MODE_SFR_BASE,
			SIZE_4KB,
			MAP_READABLE | MAP_WRITABLE | MAP_IO,
			(void **)&fp_usi_i_mode_sfr_va);
	if (ret != DRAPI_OK) {
		sec_errh("doInitialization(): fp_usi_i_mode_sfr_va error: ", ret);
		return ret;
	}
#endif
#endif

#if defined(CONFIG_ESE_TZ_CONTROL)
	ese_sec_map();
#endif

#if defined(CONFIG_SECURE_CAMERA)
	sec_cam_sec_map();
#endif

	/**
	* All mappings must happen before installing the FC handler
	* otherwise the fastcall handler will not see the MMU changes.
	*/
#if defined(CONFIG_EXYNOS5260)
	ret = drApiInstallFc(entryVector, FASTCALL_OWNER_SIP);
#else
	ret = drApiInstallFc(entryVector, FASTCALL_OWNER_OEM);
#endif
	if (ret != E_OK) {
		sec_errh("Fail to install Fastcall handler. ret = ", ret);
		return ret;
	}

	sec_dbg("doInitialization(): Hook installed");
	return ret;
}

#else //TBASE_API_LEVEL >= 5
static drApiResult_t doInitialization( void )
{
	drApiResult_t ret = E_OK;
	uint32_t hash_table_pa;

#if defined(CONFIG_EXYNOS5410) || defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5422) ||\
	defined(CONFIG_EXYNOS5433) || 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)
	/* mapping for HDCP authentication */
	sec_map(HDMI_SFR_VA, HDMI_SFR_BASE, SIZE_4KB);
	sec_map(PMU_MEDIA_SFR_VA, PMU_MEDIA_SFR_BASE, SIZE_4KB);
#if defined(CONFIG_EXYNOS5433)
	sec_map(CMU_DISP_SFR_VA, CMU_DISP_SFR_BASE, SIZE_4KB);
#else
	sec_map(CMU_TOP_SFR_VA, CMU_TOP_SFR_BASE, SIZE_4KB);
#endif
#endif

	/* Get physical address of hash table */
	sec_map(TZASC_VA, TZASC0_SFR_BASE, SIZE_4KB);
#if defined(CONFIG_4X12) || defined(CONFIG_EXYNOS3470) || defined(CONFIG_EXYNOS4415)
	hash_table_pa = read_sfr_value((uint32_t)(TZASC_VA + TZRS_LOW3));
#elif defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
	hash_table_pa = read_sfr_value((uint32_t)(TZASC_VA + TZRS_LOW0))
						<< TZ_INTERLEAVING_SHIFT;
#else
	hash_table_pa = read_sfr_value((uint32_t)(TZASC_VA + TZRS_LOW1))
						<< TZ_INTERLEAVING_SHIFT;
#if defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7570) || defined(CONFIG_EXYNOS7880) || defined(CONFIG_EXYNOS7885) 
	hash_table_pa = hash_table_pa << TZ_INTERLEAVING_SHIFT2 ;
#endif
#endif
	g_trusted_boot_addr = hash_table_pa;
	sec_unmap(TZASC_VA, SIZE_4KB);

	sec_map(DRAM_HASH_TABLE_VA, hash_table_pa, SIZE_4KB);

#ifdef PAY_MINI_IN_SERVER_SIGNED_NONCE
        memset((void *)(DRAM_HASH_TABLE_VA + PAY_MINI_SERVER_SIGNED_NONCE_OFFSET), 0, PAY_MINI_SERVER_SIGNED_NONCE_SIZE);
#endif

#if defined(SRAM_HASH_TABLE_PA)
	sec_map(SRAM_HASH_TABLE_VA, SRAM_HASH_TABLE_PA, SIZE_4KB);
#endif

#if defined(KERNEL_HASH_VALUE_PA)
	sec_map(KERNEL_HASH_VALUE_VA, KERNEL_HASH_VALUE_PA, SIZE_4KB);
#endif

#if defined(TIMA_HAVE_GOOD_MEASUREMENT)
	sec_map(GOOD_MEASUREMENT_VA, (hash_table_pa + GOOD_MEASUREMENT_OFFSET), SIZE_4KB);
#endif
#if defined(ICCC_SECURE_PARAMETERS_AREA)
	sec_map(ICCC_SECURE_PARAMETER_VA, (hash_table_pa + ICCC_SECURE_PARAMETERS_OFFSET), SIZE_4KB);
#endif

#if defined(TIMA_RUNTIME_SKIP_MSR)
	sec_map(SECURE_BOOT_ENABLE_VA, SECURE_BOOT_ENABLE_PA & ~(SIZE_4KB - 1), SIZE_4KB);
#endif

#if defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS5260) || defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS4415)
	/* mapping for EfuseWriter */
	sec_map(EFUSE_SFR_VA, EFUSE_SC_BASE, SIZE_4KB);
	sec_map(MAIN_EFUSE_VA, MAIN_EFUSE_BASE, SIZE_4KB);
	sec_map(ROOT_KEY_VA, ROOT_KEY_BASE, SIZE_4KB);
	sec_map(NANTIRBK_VA, NANTIRBK_BASE, SIZE_4KB);
#endif
#if defined(CONFIG_EXYNOS5430)
    sec_map(SECURE_JTAG_VA, SECURE_JTAG_BASE, SIZE_4KB);
#endif
	sec_map(SSS_SFR_VA, SSS_SFR_BASE, SIZE_8KB);
#if defined(CONFIG_EXYNOS5433) || defined(CONFIG_EXYNOS7580)
	/* mapping for OTP controller */
	sec_map(OTP_CONTROL_SFR_VA, OTP_CONTROL_SFR_BASE, SIZE_4KB);
#endif
#if defined(CONFIG_EXYNOS5260) || defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS5433) ||\
	defined(CONFIG_EXYNOS7420) || defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS3475) ||\
	defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7880) ||\
	defined(CONFIG_EXYNOS7570) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
	sec_map(UART_SFR_VA, UART1_SFR_BASE, SIZE_4KB);
#elif defined(CONFIG_EXYNOS5422) || defined(CONFIG_EXYNOS3470) || defined(CONFIG_EXYNOS3472) ||\
	defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS3250) || defined(CONFIG_EXYNOS7885)
	sec_map(UART_SFR_VA, UART2_SFR_BASE, SIZE_4KB);
#elif defined(CONFIG_EXYNOS4415)
	sec_map(UART_SFR_VA, UART3_SFR_BASE, SIZE_4KB);
#endif

#if defined(CONFIG_EXYNOS5433)|| defined(CONFIG_EXYNOS7420) ||\
	defined(CONFIG_EXYNOS5430) || defined(CONFIG_EXYNOS3475) || defined(CONFIG_EXYNOS8890) || defined(CONFIG_EXYNOS7570)
	sec_map(DMVERITY_BOOT_MODE_VA & ~(SIZE_4KB - 1), DMVERITY_PA & ~(SIZE_4KB - 1), SIZE_4KB);
    sec_map(KAP_STATUS_VA & ~(SIZE_4KB - 1), KAP_PA & ~(SIZE_4KB - 1), SIZE_4KB);
#elif defined(CONFIG_EXYNOS7580) || defined(CONFIG_EXYNOS7880)|| defined(CONFIG_EXYNOS7870) || defined(CONFIG_EXYNOS7885) || defined(CONFIG_EXYNOS8895) || defined(CONFIG_EXYNOS9810)
	sec_map(DMVERITY_BOOT_MODE_VA & ~(SIZE_4KB - 1), (hash_table_pa + DMVERITY_OFFSET) & ~(SIZE_4KB - 1), SIZE_4KB);
    sec_map(KAP_STATUS_VA & ~(SIZE_4KB - 1), (hash_table_pa + KAP_OFFSET) & ~(SIZE_4KB - 1), SIZE_4KB);
#endif

#if defined(TIMA_MST_DRV)
	sec_map(VA_GPJ0, GPJ0_BASE, SIZE_4KB);
	sec_map(VA_GPJ1, GPJ1_BASE, SIZE_4KB);
	sec_map(VA_GPF3, GPF3_BASE, SIZE_4KB);
	sec_map(VA_CMU_PERIC1, PERIC1_BASE, SIZE_4KB);
	sec_map(VA_TZPC13, TZPC13_BASE, SIZE_4KB);
#endif

#if defined(CONFIG_FP_TZ_CONTROL)
	sec_map(FP_TZPC_SPI_SFR_VA, FP_TZPC_SPI_SFR_BASE, SIZE_4KB);
#if defined(FP_GPIO_PROTECTION)
	sec_map(FP_TZPC_GPIO_SFR_VA, FP_TZPC_GPIO_SFR_BASE, SIZE_4KB);
#endif
	sec_map(FP_GPIO_SFR_VA, FP_GPIO_SFR_BASE, SIZE_4KB);
#endif

#if defined(CONFIG_ESE_TZ_CONTROL)
	/* Reserved addresses 0x95000 ~ 0x9A000 for eSE */
	ese_sec_map(ESE_SFR_VA_BASE, SIZE_4KB);
#endif

#if defined(CONFIG_SECURE_CAMERA)
   /* Reserved addresses 0xA0000 ~ 0xAD000 for Secure Camera */
   sec_cam_sec_map();
#endif

	/**
	* All mappings must happen before installing the FC handler
	* otherwise the fastcall handler will not see the MMU changes.
	*/
#if defined(CONFIG_EXYNOS5260)
	ret = drApiInstallFc(entryVector, FASTCALL_OWNER_SIP);
#else
	ret = drApiInstallFc(entryVector, FASTCALL_OWNER_OEM);
#endif
	if (ret != E_OK) {
		sec_errh("Fail to install Fastcall handler. ret = ", ret);
		return ret;
	}

	sec_dbg("doInitialization(): Hook installed");
	return ret;
}
#endif //TBASE_API_LEVEL >= 5

static drApiResult_t doInitialise_SecDriver(void)
{
	drApiResult_t ret = E_OK;

	/* Init HW - Nothing to do now */

	return ret;
}

/*
 * Main routine for the example driver.
 * Initializes the Api data structures and starts the required threads.
 */
_DRAPI_ENTRY void drMain(const addr_t dciBuffer, const uint32_t dciBufferLen)
{
	sec_dbg("drMain(): Driver thread started ");
#if defined(TIMA_SHARED_INFO)
	memset(&tima_info_data,0,sizeof(tima_info));
#endif

	/* Initialization */
	if (E_OK != doInitialise_SecDriver()) {
		sec_err("drMain(): Initialization failed");

		/* No need to proceed further. Shutdown the main thread */
		if (E_OK != drApiStopThread(NILTHREAD))
			sec_err("drMain(): Unable to stop main thread");
	}

	/* FC handler Initialization */
	if (E_OK != doInitialization()) {
		sec_err("drMain(): FC handler Initialization failed");

		/* No need to proceed further. Shutdown the main thread */
		if (E_OK != drApiStopThread(NILTHREAD))
			sec_err("drMain(): FC handler Unable to stop main thread");
	}

	/* Check version */
	checkVersion_FC_DRIVER();
	dbgSN(msgBuf);

	/* Start IPC handler */
	drIpchInit();

	/* Start exception handler */
	drExchLoop();
}

/** @} */
