Merge pull request #710 from dp-arm/dp/fiptool-usage

fiptool: Invoke command specific usage function
diff --git a/docs/firmware-design.md b/docs/firmware-design.md
index 68cad2e..90ce4b1 100644
--- a/docs/firmware-design.md
+++ b/docs/firmware-design.md
@@ -716,7 +716,7 @@
 |`PSCI_FEATURES`        | Yes     |                                           |
 |`CPU_FREEZE`           | No      |                                           |
 |`CPU_DEFAULT_SUSPEND`  | No      |                                           |
-|`CPU_HW_STATE`         | No      |                                           |
+|`NODE_HW_STATE`        | Yes*    |                                           |
 |`SYSTEM_SUSPEND`       | Yes*    |                                           |
 |`PSCI_SET_SUSPEND_MODE`| No      |                                           |
 |`PSCI_STAT_RESIDENCY`  | Yes*    |                                           |
diff --git a/docs/porting-guide.md b/docs/porting-guide.md
index 8dad4a0..195c937 100644
--- a/docs/porting-guide.md
+++ b/docs/porting-guide.md
@@ -1832,6 +1832,20 @@
 power state encoding for `power_state` parameter of PSCI_STAT_COUNT/RESIDENCY
 APIs as described in Section 5.18 of [PSCI].
 
+#### plat_psci_ops.get_node_hw_state()
+
+This is an optional function. If implemented this function is intended to return
+the power state of a node (identified by the first parameter, the `MPIDR`) in
+the power domain topology (identified by the second parameter, `power_level`),
+as retrieved from a power controller or equivalent component on the platform.
+Upon successful completion, the implementation must map and return the final
+status among `HW_ON`, `HW_OFF` or `HW_STANDBY`. Upon encountering failures, it
+must return either `PSCI_E_INVALID_PARAMS` or `PSCI_E_NOT_SUPPORTED` as
+appropriate.
+
+Implementations are not expected to handle `power_levels` greater than
+`PLAT_MAX_PWR_LVL`.
+
 3.6  Interrupt Management framework (in BL31)
 ----------------------------------------------
 BL31 implements an Interrupt Management Framework (IMF) to manage interrupts
diff --git a/docs/user-guide.md b/docs/user-guide.md
index a6959b1..d545262 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -64,7 +64,7 @@
 Install the required packages to build Trusted Firmware with the following
 command:
 
-    sudo apt-get install build-essential gcc make git
+    sudo apt-get install build-essential gcc make git libssl-dev
 
 Download and install the AArch64 little-endian GCC cross compiler as indicated
 in the [Linaro instructions][Linaro SW Instructions].
@@ -74,8 +74,6 @@
 *   `device-tree-compiler` package if you need to rebuild the Flattened Device
     Tree (FDT) source files (`.dts` files) provided with this software.
 
-*   `libssl-dev` package if Trusted Board Boot is enabled in the build.
-
 *   For debugging, ARM [Development Studio 5 (DS-5)][DS-5].
 
 
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index d13e2c9..ac43372 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -120,10 +120,12 @@
  ******************************************************************************/
 void gicv3_distif_init(void)
 {
+	unsigned int bitmap = 0;
+
 	assert(driver_data);
 	assert(driver_data->gicd_base);
-	assert(driver_data->g1s_interrupt_array);
-	assert(driver_data->g0_interrupt_array);
+	assert(driver_data->g1s_interrupt_array ||
+	       driver_data->g0_interrupt_array);
 
 	assert(IS_IN_EL3());
 
@@ -146,21 +148,25 @@
 	gicv3_spis_configure_defaults(driver_data->gicd_base);
 
 	/* Configure the G1S SPIs */
-	gicv3_secure_spis_configure(driver_data->gicd_base,
+	if (driver_data->g1s_interrupt_array) {
+		gicv3_secure_spis_configure(driver_data->gicd_base,
 					driver_data->g1s_interrupt_num,
 					driver_data->g1s_interrupt_array,
 					INTR_GROUP1S);
+		bitmap |= CTLR_ENABLE_G1S_BIT;
+	}
 
 	/* Configure the G0 SPIs */
-	gicv3_secure_spis_configure(driver_data->gicd_base,
+	if (driver_data->g0_interrupt_array) {
+		gicv3_secure_spis_configure(driver_data->gicd_base,
 					driver_data->g0_interrupt_num,
 					driver_data->g0_interrupt_array,
 					INTR_GROUP0);
+		bitmap |= CTLR_ENABLE_G0_BIT;
+	}
 
 	/* Enable the secure SPIs now that they have been configured */
-	gicd_set_ctlr(driver_data->gicd_base,
-		      CTLR_ENABLE_G1S_BIT | CTLR_ENABLE_G0_BIT,
-		      RWP_TRUE);
+	gicd_set_ctlr(driver_data->gicd_base, bitmap, RWP_TRUE);
 }
 
 /*******************************************************************************
@@ -177,8 +183,8 @@
 	assert(driver_data->rdistif_base_addrs);
 	assert(driver_data->gicd_base);
 	assert(gicd_read_ctlr(driver_data->gicd_base) & CTLR_ARE_S_BIT);
-	assert(driver_data->g1s_interrupt_array);
-	assert(driver_data->g0_interrupt_array);
+	assert(driver_data->g1s_interrupt_array ||
+	       driver_data->g0_interrupt_array);
 
 	assert(IS_IN_EL3());
 
@@ -188,16 +194,20 @@
 	gicv3_ppi_sgi_configure_defaults(gicr_base);
 
 	/* Configure the G1S SGIs/PPIs */
-	gicv3_secure_ppi_sgi_configure(gicr_base,
-					   driver_data->g1s_interrupt_num,
-					   driver_data->g1s_interrupt_array,
-					   INTR_GROUP1S);
+	if (driver_data->g1s_interrupt_array) {
+		gicv3_secure_ppi_sgi_configure(gicr_base,
+					driver_data->g1s_interrupt_num,
+					driver_data->g1s_interrupt_array,
+					INTR_GROUP1S);
+	}
 
 	/* Configure the G0 SGIs/PPIs */
-	gicv3_secure_ppi_sgi_configure(gicr_base,
-					   driver_data->g0_interrupt_num,
-					   driver_data->g0_interrupt_array,
-					   INTR_GROUP0);
+	if (driver_data->g0_interrupt_array) {
+		gicv3_secure_ppi_sgi_configure(gicr_base,
+					driver_data->g0_interrupt_num,
+					driver_data->g0_interrupt_array,
+					INTR_GROUP0);
+	}
 }
 
 /*******************************************************************************
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index f9f0715..4d936ad 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -273,6 +273,7 @@
 
 DEFINE_SYSREG_RW_FUNCS(vpidr_el2)
 DEFINE_SYSREG_RW_FUNCS(vmpidr_el2)
+DEFINE_SYSREG_RW_FUNCS(cntp_ctl_el0)
 
 DEFINE_SYSREG_READ_FUNC(isr_el1)
 
diff --git a/include/lib/pmf/pmf_asm_macros.S b/include/lib/pmf/pmf_asm_macros.S
index 42dcd79..be7338b 100644
--- a/include/lib/pmf/pmf_asm_macros.S
+++ b/include/lib/pmf/pmf_asm_macros.S
@@ -34,12 +34,11 @@
 #define PMF_TS_SIZE	8
 
 	/*
-	 * This macro calculates the offset into the memory
-	 * region where the per-cpu timestamp value is stored
-	 * for the given service name and timestamp id.
+	 * This macro calculates the address of the per-cpu timestamp
+	 * for the given service name and local timestamp id.
 	 * Clobbers: x0 - x9
 	 */
-	.macro pmf_calc_timestamp_offset _name _tid
+	.macro pmf_calc_timestamp_addr _name _tid
 	mov	x9, x30
 	bl	plat_my_core_pos
 	mov	x30, x9
diff --git a/include/lib/pmf/pmf_helpers.h b/include/lib/pmf/pmf_helpers.h
index 9be6050..bb4242c 100644
--- a/include/lib/pmf/pmf_helpers.h
+++ b/include/lib/pmf/pmf_helpers.h
@@ -71,7 +71,9 @@
  */
 #define PMF_ALLOCATE_TIMESTAMP_MEMORY(_name, _total_id)		\
 	unsigned long long pmf_ts_mem_ ## _name[_total_id]	\
-	__section("pmf_timestamp_array") __used;
+	__aligned(CACHE_WRITEBACK_GRANULE)			\
+	__section("pmf_timestamp_array")			\
+	__used;
 
 /*
  * Convenience macro to validate tid index for the given TS array.
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
index a583fef..02cbbf3 100644
--- a/include/lib/psci/psci.h
+++ b/include/lib/psci/psci.h
@@ -78,6 +78,8 @@
 #define PSCI_SYSTEM_OFF			0x84000008
 #define PSCI_SYSTEM_RESET		0x84000009
 #define PSCI_FEATURES			0x8400000A
+#define PSCI_NODE_HW_STATE_AARCH32	0x8400000d
+#define PSCI_NODE_HW_STATE_AARCH64	0xc400000d
 #define PSCI_SYSTEM_SUSPEND_AARCH32	0x8400000E
 #define PSCI_SYSTEM_SUSPEND_AARCH64	0xc400000E
 #define PSCI_STAT_RESIDENCY_AARCH32	0x84000010
@@ -200,6 +202,17 @@
 } aff_info_state_t;
 
 /*
+ * These are the power states reported by PSCI_NODE_HW_STATE API for the
+ * specified CPU. The definitions of these states can be found in Section 5.15.3
+ * of PSCI specification (ARM DEN 0022C).
+ */
+typedef enum {
+	HW_ON = 0,
+	HW_OFF = 1,
+	HW_STANDBY = 2
+} node_hw_state_t;
+
+/*
  * Macro to represent invalid affinity level within PSCI.
  */
 #define PSCI_INVALID_PWR_LVL	(PLAT_MAX_PWR_LVL + 1)
@@ -293,6 +306,7 @@
 	int (*translate_power_state_by_mpidr)(u_register_t mpidr,
 				    unsigned int power_state,
 				    psci_power_state_t *output_state);
+	int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);
 } plat_psci_ops_t;
 
 /*******************************************************************************
@@ -330,6 +344,8 @@
 int psci_migrate(u_register_t target_cpu);
 int psci_migrate_info_type(void);
 long psci_migrate_info_up_cpu(void);
+int psci_node_hw_state(u_register_t target_cpu,
+		       unsigned int power_level);
 int psci_features(unsigned int psci_fid);
 void __dead2 psci_power_down_wfi(void);
 void psci_arch_setup(void);
diff --git a/include/lib/xlat_tables.h b/include/lib/xlat_tables.h
index d2ac6db..0e9800a 100644
--- a/include/lib/xlat_tables.h
+++ b/include/lib/xlat_tables.h
@@ -32,13 +32,27 @@
 #define __XLAT_TABLES_H__
 
 /* Miscellaneous MMU related constants */
+#define NUM_2MB_IN_GB		(1 << 9)
+#define NUM_4K_IN_2MB		(1 << 9)
+#define NUM_GB_IN_4GB		(1 << 2)
+
+#define TWO_MB_SHIFT		21
+#define ONE_GB_SHIFT		30
 #define FOUR_KB_SHIFT		12
 
+#define ONE_GB_INDEX(x)		((x) >> ONE_GB_SHIFT)
+#define TWO_MB_INDEX(x)		((x) >> TWO_MB_SHIFT)
+#define FOUR_KB_INDEX(x)	((x) >> FOUR_KB_SHIFT)
+
 #define INVALID_DESC		0x0
 #define BLOCK_DESC		0x1 /* Table levels 0-2 */
 #define TABLE_DESC		0x3 /* Table levels 0-2 */
 #define PAGE_DESC		0x3 /* Table level 3 */
 
+#define FIRST_LEVEL_DESC_N	ONE_GB_SHIFT
+#define SECOND_LEVEL_DESC_N	TWO_MB_SHIFT
+#define THIRD_LEVEL_DESC_N	FOUR_KB_SHIFT
+
 #define XN			(1ull << 2)
 #define PXN			(1ull << 1)
 #define CONT_HINT		(1ull << 0)
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index 25aab24..d2e8729 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -37,6 +37,12 @@
 #include <utils.h>
 #include <xlat_tables.h>
 
+/*******************************************************************************
+ * Forward declarations
+ ******************************************************************************/
+struct bl31_params;
+struct meminfo;
+
 #define ARM_CASSERT_MMAP						\
 	CASSERT((ARRAY_SIZE(plat_arm_mmap) + ARM_BL_REGIONS)		\
 		<= MAX_MMAP_REGIONS,					\
@@ -145,7 +151,7 @@
 void arm_bl1_plat_arch_setup(void);
 
 /* BL2 utility functions */
-void arm_bl2_early_platform_setup(meminfo_t *mem_layout);
+void arm_bl2_early_platform_setup(struct meminfo *mem_layout);
 void arm_bl2_platform_setup(void);
 void arm_bl2_plat_arch_setup(void);
 uint32_t arm_get_spsr_for_bl32_entry(void);
@@ -158,7 +164,7 @@
 void arm_bl2u_plat_arch_setup(void);
 
 /* BL31 utility functions */
-void arm_bl31_early_platform_setup(bl31_params_t *from_bl2,
+void arm_bl31_early_platform_setup(struct bl31_params *from_bl2,
 				void *plat_params_from_bl2);
 void arm_bl31_platform_setup(void);
 void arm_bl31_plat_runtime_setup(void);
diff --git a/include/plat/arm/css/common/css_def.h b/include/plat/arm/css/common/css_def.h
index 636daf2..173de1b 100644
--- a/include/plat/arm/css/common/css_def.h
+++ b/include/plat/arm/css/common/css_def.h
@@ -148,5 +148,15 @@
 /* Trusted mailbox base address common to all CSS */
 #define PLAT_ARM_TRUSTED_MAILBOX_BASE	ARM_TRUSTED_SRAM_BASE
 
+/*
+ * Parsing of CPU and Cluster states, as returned by 'Get CSS Power State' SCP
+ * command
+ */
+#define CSS_CLUSTER_PWR_STATE_ON	0
+#define CSS_CLUSTER_PWR_STATE_OFF	3
+
+#define CSS_CPU_PWR_STATE_ON		1
+#define CSS_CPU_PWR_STATE_OFF		0
+#define CSS_CPU_PWR_STATE(state, n)	(((state) >> (n)) & 1)
 
 #endif /* __CSS_DEF_H__ */
diff --git a/include/plat/arm/css/common/css_pm.h b/include/plat/arm/css/common/css_pm.h
index ea6a5d2..4a6ca81 100644
--- a/include/plat/arm/css/common/css_pm.h
+++ b/include/plat/arm/css/common/css_pm.h
@@ -45,5 +45,6 @@
 void __dead2 css_system_reset(void);
 void css_cpu_standby(plat_local_state_t cpu_state);
 void css_get_sys_suspend_power_state(psci_power_state_t *req_state);
+int css_node_hw_state(u_register_t mpidr, unsigned int power_level);
 
 #endif /* __CSS_PM_H__ */
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
index 3ad3dd4..23bd106 100644
--- a/lib/psci/psci_main.c
+++ b/lib/psci/psci_main.c
@@ -295,6 +295,31 @@
 	return resident_cpu_mpidr;
 }
 
+int psci_node_hw_state(u_register_t target_cpu,
+		       unsigned int power_level)
+{
+	int rc;
+
+	/* Validate target_cpu */
+	rc = psci_validate_mpidr(target_cpu);
+	if (rc != PSCI_E_SUCCESS)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Validate power_level against PLAT_MAX_PWR_LVL */
+	if (power_level > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/*
+	 * Dispatch this call to platform to query power controller, and pass on
+	 * to the caller what it returns
+	 */
+	assert(psci_plat_pm_ops->get_node_hw_state);
+	rc = psci_plat_pm_ops->get_node_hw_state(target_cpu, power_level);
+	assert((rc >= HW_ON && rc <= HW_STANDBY) || rc == PSCI_E_NOT_SUPPORTED
+			|| rc == PSCI_E_INVALID_PARAMS);
+	return rc;
+}
+
 int psci_features(unsigned int psci_fid)
 {
 	unsigned int local_caps = psci_caps;
@@ -378,6 +403,9 @@
 		case PSCI_MIG_INFO_UP_CPU_AARCH32:
 			return psci_migrate_info_up_cpu();
 
+		case PSCI_NODE_HW_STATE_AARCH32:
+			return psci_node_hw_state(x1, x2);
+
 		case PSCI_SYSTEM_SUSPEND_AARCH32:
 			return psci_system_suspend(x1, x2);
 
@@ -422,6 +450,9 @@
 		case PSCI_MIG_INFO_UP_CPU_AARCH64:
 			return psci_migrate_info_up_cpu();
 
+		case PSCI_NODE_HW_STATE_AARCH64:
+			return psci_node_hw_state(x1, x2);
+
 		case PSCI_SYSTEM_SUSPEND_AARCH64:
 			return psci_system_suspend(x1, x2);
 
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
index b795c8e..781b3b5 100644
--- a/lib/psci/psci_private.h
+++ b/lib/psci/psci_private.h
@@ -68,6 +68,7 @@
 			define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) |	\
 			define_psci_cap(PSCI_MIG_AARCH64) |		\
 			define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64) |	\
+			define_psci_cap(PSCI_NODE_HW_STATE_AARCH64) |	\
 			define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64) |	\
 			define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64) |	\
 			define_psci_cap(PSCI_STAT_COUNT_AARCH64))
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index 20d0635..263ab68 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -238,6 +238,13 @@
 	plat_setup_psci_ops(mailbox_ep, &psci_plat_pm_ops);
 	assert(psci_plat_pm_ops);
 
+	/*
+	 * Flush `psci_plat_pm_ops` as it will be accessed by secondary CPUs
+	 * during warm boot before data cache is enabled.
+	 */
+	flush_dcache_range((uintptr_t)&psci_plat_pm_ops,
+					sizeof(psci_plat_pm_ops));
+
 	/* Initialize the psci capability */
 	psci_caps = PSCI_GENERIC_CAP;
 
@@ -256,6 +263,8 @@
 		psci_caps |=  define_psci_cap(PSCI_SYSTEM_OFF);
 	if (psci_plat_pm_ops->system_reset)
 		psci_caps |=  define_psci_cap(PSCI_SYSTEM_RESET);
+	if (psci_plat_pm_ops->get_node_hw_state)
+		psci_caps |= define_psci_cap(PSCI_NODE_HW_STATE_AARCH64);
 
 #if ENABLE_PSCI_STAT
 	psci_caps |=  define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
index 3976ef2..66c0c3d 100644
--- a/plat/arm/board/fvp/fvp_pm.c
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -287,6 +287,42 @@
 	panic();
 }
 
+static int fvp_node_hw_state(u_register_t target_cpu,
+			     unsigned int power_level)
+{
+	unsigned int psysr;
+	int ret;
+
+	/*
+	 * The format of 'power_level' is implementation-defined, but 0 must
+	 * mean a CPU. We also allow 1 to denote the cluster
+	 */
+	if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1)
+		return PSCI_E_INVALID_PARAMS;
+
+	/*
+	 * Read the status of the given MPDIR from FVP power controller. The
+	 * power controller only gives us on/off status, so map that to expected
+	 * return values of the PSCI call
+	 */
+	psysr = fvp_pwrc_read_psysr(target_cpu);
+	if (psysr == PSYSR_INVALID)
+		return PSCI_E_INVALID_PARAMS;
+
+	switch (power_level) {
+	case ARM_PWR_LVL0:
+		ret = (psysr & PSYSR_AFF_L0) ? HW_ON : HW_OFF;
+		break;
+	case ARM_PWR_LVL1:
+		ret = (psysr & PSYSR_AFF_L1) ? HW_ON : HW_OFF;
+		break;
+	default:
+		assert(0);
+	}
+
+	return ret;
+}
+
 /*******************************************************************************
  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
  * platform layer will take care of registering the handlers with PSCI.
@@ -301,5 +337,6 @@
 	.system_off = fvp_system_off,
 	.system_reset = fvp_system_reset,
 	.validate_power_state = arm_validate_power_state,
-	.validate_ns_entrypoint = arm_validate_ns_entrypoint
+	.validate_ns_entrypoint = arm_validate_ns_entrypoint,
+	.get_node_hw_state = fvp_node_hw_state
 };
diff --git a/plat/arm/board/juno/juno_pm.c b/plat/arm/board/juno/juno_pm.c
index cbf994a..c355d94 100644
--- a/plat/arm/board/juno/juno_pm.c
+++ b/plat/arm/board/juno/juno_pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -88,5 +88,6 @@
 	.validate_power_state		= juno_validate_power_state,
 	.validate_ns_entrypoint		= arm_validate_ns_entrypoint,
 	.get_sys_suspend_power_state	= css_get_sys_suspend_power_state,
-	.translate_power_state_by_mpidr = juno_translate_power_state_by_mpidr
+	.translate_power_state_by_mpidr = juno_translate_power_state_by_mpidr,
+	.get_node_hw_state		= css_node_hw_state
 };
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index 801d937..7607f61 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -299,6 +299,43 @@
 }
 
 /*******************************************************************************
+ * Handler to query CPU/cluster power states from SCP
+ ******************************************************************************/
+int css_node_hw_state(u_register_t mpidr, unsigned int power_level)
+{
+	int rc, element;
+	unsigned int cpu_state, cluster_state;
+
+	/*
+	 * The format of 'power_level' is implementation-defined, but 0 must
+	 * mean a CPU. We also allow 1 to denote the cluster
+	 */
+	if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Query SCP */
+	rc = scpi_get_css_power_state(mpidr, &cpu_state, &cluster_state);
+	if (rc != 0)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Map power states of CPU and cluster to expected PSCI return codes */
+	if (power_level == ARM_PWR_LVL0) {
+		/*
+		 * The CPU state returned by SCP is an 8-bit bit mask
+		 * corresponding to each CPU in the cluster
+		 */
+		element = mpidr & MPIDR_AFFLVL_MASK;
+		return CSS_CPU_PWR_STATE(cpu_state, element) ==
+			CSS_CPU_PWR_STATE_ON ? HW_ON : HW_OFF;
+	} else {
+		assert(cluster_state == CSS_CLUSTER_PWR_STATE_ON ||
+				cluster_state == CSS_CLUSTER_PWR_STATE_OFF);
+		return cluster_state == CSS_CLUSTER_PWR_STATE_ON ? HW_ON :
+			HW_OFF;
+	}
+}
+
+/*******************************************************************************
  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
  * platform will take care of registering the handlers with PSCI.
  ******************************************************************************/
@@ -312,5 +349,6 @@
 	.system_off		= css_system_off,
 	.system_reset		= css_system_reset,
 	.validate_power_state	= arm_validate_power_state,
-	.validate_ns_entrypoint = arm_validate_ns_entrypoint
+	.validate_ns_entrypoint = arm_validate_ns_entrypoint,
+	.get_node_hw_state	= css_node_hw_state
 };
diff --git a/plat/arm/css/common/css_scpi.c b/plat/arm/css/common/css_scpi.c
index 02d573c..90a8939 100644
--- a/plat/arm/css/common/css_scpi.c
+++ b/plat/arm/css/common/css_scpi.c
@@ -41,11 +41,18 @@
 #define SCPI_SHARED_MEM_AP_TO_SCP	(PLAT_CSS_SCP_COM_SHARED_MEM_BASE \
 								 + 0x100)
 
+/* Header and payload addresses for commands from AP to SCP */
 #define SCPI_CMD_HEADER_AP_TO_SCP		\
 	((scpi_cmd_t *) SCPI_SHARED_MEM_AP_TO_SCP)
 #define SCPI_CMD_PAYLOAD_AP_TO_SCP		\
 	((void *) (SCPI_SHARED_MEM_AP_TO_SCP + sizeof(scpi_cmd_t)))
 
+/* Header and payload addresses for responses from SCP to AP */
+#define SCPI_RES_HEADER_SCP_TO_AP \
+	((scpi_cmd_t *) SCPI_SHARED_MEM_SCP_TO_AP)
+#define SCPI_RES_PAYLOAD_SCP_TO_AP \
+	((void *) (SCPI_SHARED_MEM_SCP_TO_AP + sizeof(scpi_cmd_t)))
+
 /* ID of the MHU slot used for the SCPI protocol */
 #define SCPI_MHU_SLOT_ID		0
 
@@ -160,7 +167,69 @@
 	 * from the sender, which could interfere with its power state request.
 	 */
 
+	scpi_secure_message_end();
+}
+
+/*
+ * Query and obtain CSS power state from SCP.
+ *
+ * In response to the query, SCP returns power states of all CPUs in all
+ * clusters of the system. The returned response is then filtered based on the
+ * supplied MPIDR. Power states of requested cluster and CPUs within are updated
+ * via. supplied non-NULL pointer arguments.
+ *
+ * Returns 0 on success, or -1 on errors.
+ */
+int scpi_get_css_power_state(unsigned int mpidr, unsigned int *cpu_state_p,
+		unsigned int *cluster_state_p)
+{
+	scpi_cmd_t *cmd;
+	scpi_cmd_t response;
+	int power_state, cpu, cluster, rc = -1;
+
+	/*
+	 * Extract CPU and cluster membership of the given MPIDR. SCPI caters
+	 * for only up to 0xf clusters, and 8 CPUs per cluster
+	 */
+	cpu = mpidr & MPIDR_AFFLVL_MASK;
+	cluster = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	if (cpu >= 8 || cluster >= 0xf)
+		return -1;
+
+	scpi_secure_message_start();
+
+	/* Populate request headers */
+	cmd = memset(SCPI_CMD_HEADER_AP_TO_SCP, 0, sizeof(*cmd));
+	cmd->id = SCPI_CMD_GET_CSS_POWER_STATE;
+
+	/*
+	 * Send message and wait for SCP's response
+	 */
+	scpi_secure_message_send(0);
+	scpi_secure_message_receive(&response);
+
+	if (response.status != SCP_OK)
+		goto exit;
+
+	/* Validate SCP response */
+	if (!CHECK_RESPONSE(response, cluster))
+		goto exit;
+
+	/* Extract power states for required cluster */
+	power_state = *(((uint16_t *) SCPI_RES_PAYLOAD_SCP_TO_AP) + cluster);
+	if (CLUSTER_ID(power_state) != cluster)
+		goto exit;
+
+	/* Update power state via. pointers */
+	if (cluster_state_p)
+		*cluster_state_p = CLUSTER_POWER_STATE(power_state);
+	if (cpu_state_p)
+		*cpu_state_p = CPU_POWER_STATE(power_state);
+	rc = 0;
+
+exit:
 	scpi_secure_message_end();
+	return rc;
 }
 
 uint32_t scpi_sys_power_state(scpi_system_state_t system_state)
diff --git a/plat/arm/css/common/css_scpi.h b/plat/arm/css/common/css_scpi.h
index 4a601f3..1fb55e4 100644
--- a/plat/arm/css/common/css_scpi.h
+++ b/plat/arm/css/common/css_scpi.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -81,9 +81,34 @@
 typedef enum {
 	SCPI_CMD_SCP_READY = 0x01,
 	SCPI_CMD_SET_CSS_POWER_STATE = 0x03,
+	SCPI_CMD_GET_CSS_POWER_STATE = 0x04,
 	SCPI_CMD_SYS_POWER_STATE = 0x05
 } scpi_command_t;
 
+/*
+ * Macros to parse SCP response to GET_CSS_POWER_STATE command
+ *
+ *   [3:0] : cluster ID
+ *   [7:4] : cluster state: 0 = on; 3 = off; rest are reserved
+ *   [15:8]: on/off state for individual CPUs in the cluster
+ *
+ * Payload is in little-endian
+ */
+#define CLUSTER_ID(_resp)		((_resp) & 0xf)
+#define CLUSTER_POWER_STATE(_resp)	(((_resp) >> 4) & 0xf)
+
+/* Result is a bit mask of CPU on/off states in the cluster */
+#define CPU_POWER_STATE(_resp)		(((_resp) >> 8) & 0xff)
+
+/*
+ * For GET_CSS_POWER_STATE, SCP returns the power states of every cluster. The
+ * size of response depends on the number of clusters in the system. The
+ * SCP-to-AP payload contains 2 bytes per cluster. Make sure the response is
+ * large enough to contain power states of a given cluster
+ */
+#define CHECK_RESPONSE(_resp, _clus) \
+	(_resp.size >= (((_clus) + 1) * 2))
+
 typedef enum {
 	scpi_power_on = 0,
 	scpi_power_retention = 1,
@@ -101,6 +126,8 @@
 					scpi_power_state_t cpu_state,
 					scpi_power_state_t cluster_state,
 					scpi_power_state_t css_state);
+int scpi_get_css_power_state(unsigned int mpidr, unsigned int *cpu_state_p,
+		unsigned int *cluster_state_p);
 uint32_t scpi_sys_power_state(scpi_system_state_t system_state);
 
 
diff --git a/plat/mediatek/mt8173/drivers/uart/8250_console.S b/plat/mediatek/common/drivers/uart/8250_console.S
similarity index 100%
rename from plat/mediatek/mt8173/drivers/uart/8250_console.S
rename to plat/mediatek/common/drivers/uart/8250_console.S
diff --git a/plat/mediatek/mt8173/drivers/uart/uart8250.h b/plat/mediatek/common/drivers/uart/uart8250.h
similarity index 100%
rename from plat/mediatek/mt8173/drivers/uart/uart8250.h
rename to plat/mediatek/common/drivers/uart/uart8250.h
diff --git a/plat/mediatek/mt6795/aarch64/plat_helpers.S b/plat/mediatek/mt6795/aarch64/plat_helpers.S
new file mode 100644
index 0000000..eb0611a
--- /dev/null
+++ b/plat/mediatek/mt6795/aarch64/plat_helpers.S
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_report_exception
+	.globl	platform_is_primary_cpu
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	platform_mem_init
+
+
+	.macro crash_ram_log
+	 /*
+	 * Check teearg->atf_log_buf_size.
+	 * Exit if atf_log_buf_size equals 0
+	 */
+	adr	x2, ptr_atf_crash_flag
+	ldr	x2, [x2]
+	/* exit if ptr_atf_crash_flag equals NULL */
+	cbz x2, exit_putc
+
+	/*
+	 * set atf crash magic number
+	 */
+1:
+	adr	x2, ptr_atf_crash_flag
+	ldr	x2, [x2]
+	mov_imm x1, 0xdead1abf
+	/* p_atf_log_ctrl->atf_crash_flag = 0xdead1abf */
+	str	w1, [x2]
+	/* can't use w3 return addr, w4, start of buffer addr */
+	ldr	w2, [x2]
+	cmp	w2, w1
+	b.ne	1b
+
+	/*
+	 * get cpu id
+	 */
+	mrs	x1, mpidr_el1
+	/* refer to platform_get_core_pos */
+	and	x2, x1, #MPIDR_CPU_MASK
+	and	x1, x1, #MPIDR_CLUSTER_MASK
+	/* x1 = cpu id (cpu id = aff0 + aff1*4 ) */
+	add	x1, x2, x1, LSR #6
+
+	adr	x2, ptr_atf_except_write_pos_per_cpu
+	ldr	x2, [x2]
+	/*
+	 * plus (cpu_id * 8)-->
+	 * &p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id]
+	 * x2 = &p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id];
+	 */
+	add x2, x2, x1, LSL # 3
+	/* log write */
+	/* w1 = p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id] */
+	ldr	x1, [x2]
+	/* *x1 = w0-->
+	 *  *(p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id]) = c)
+	 */
+	strb	w0, [x1]
+	/* w1++ */
+	add	x1, x1, #1
+	/* p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id] = w1 */
+	str	x1, [x2]
+exit_putc:
+	.endm
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	/* Do not do cold boot for secondary CPU */
+cb_panic:
+	b	cb_panic
+endfunc plat_secondary_cold_boot_setup
+
+func platform_is_primary_cpu
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #PLAT_PRIMARY_CPU
+	cset	x0, eq
+	ret
+endfunc platform_is_primary_cpu
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0, x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, UART0_BASE
+	mov_imm	x1, UART_CLOCK
+	mov_imm	x2, UART_BAUDRATE
+	b	console_init
+	ret
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(void)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm x1, UART0_BASE
+	b	console_core_putc
+	ret
+endfunc plat_crash_console_putc
+
+	/* --------------------------------------------------------
+	 * void platform_mem_init (void);
+	 *
+	 * Any memory init, relocation to be done before the
+	 * platform boots. Called very early in the boot process.
+	 * --------------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
diff --git a/plat/mediatek/mt6795/bl31.ld.S b/plat/mediatek/mt6795/bl31.ld.S
new file mode 100644
index 0000000..44510a7
--- /dev/null
+++ b/plat/mediatek/mt6795/bl31.ld.S
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <platform_def.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(bl31_entrypoint)
+
+
+MEMORY {
+	RAM (rwx): ORIGIN = BL31_BASE, LENGTH = BL31_TZRAM_SIZE
+	RAM2 (rwx): ORIGIN = TZRAM2_BASE, LENGTH = TZRAM2_SIZE
+}
+
+
+SECTIONS
+{
+    . = BL31_BASE;
+
+    ASSERT(. == ALIGN(2048),
+           "vector base is not aligned on a 2K boundary.")
+
+    __RO_START__ = .;
+    vector . : {
+        *(.vectors)
+    } >RAM
+
+    ASSERT(. == ALIGN(4096),
+           "BL31_BASE address is not aligned on a page boundary.")
+
+    ro . : {
+        *bl31_entrypoint.o(.text*)
+        *(.text*)
+        *(.rodata*)
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __RT_SVC_DESCS_START__ = .;
+        KEEP(*(rt_svc_descs))
+        __RT_SVC_DESCS_END__ = .;
+
+        /*
+         * Ensure 8-byte alignment for cpu_ops so that its fields are also
+         * aligned. Also ensure cpu_ops inclusion.
+         */
+        . = ALIGN(8);
+        __CPU_OPS_START__ = .;
+        KEEP(*(cpu_ops))
+        __CPU_OPS_END__ = .;
+
+        __RO_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked as read-only,
+         * executable.  No RW data from the next section must creep in.
+         * Ensure the rest of the current memory page is unused.
+         */
+        . = NEXT(4096);
+        __RO_END__ = .;
+    } >RAM
+
+    ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
+           "cpu_ops not defined for this platform.")
+
+    /*
+     * Define a linker symbol to mark start of the RW memory area for this
+     * image.
+     */
+    __RW_START__ = . ;
+
+    .data . : {
+        __DATA_START__ = .;
+        *(.data*)
+        __DATA_END__ = .;
+    } >RAM
+
+#ifdef BL31_PROGBITS_LIMIT
+    ASSERT(. <= BL31_PROGBITS_LIMIT, "BL3-1 progbits has exceeded its limit.")
+#endif
+
+    stacks (NOLOAD) : {
+        __STACKS_START__ = .;
+        *(tzfw_normal_stacks)
+        __STACKS_END__ = .;
+    } >RAM
+
+    /*
+     * The .bss section gets initialised to 0 at runtime.
+     * Its base address must be 16-byte aligned.
+     */
+    .bss (NOLOAD) : ALIGN(16) {
+        __BSS_START__ = .;
+        *(.bss*)
+        *(COMMON)
+#if !USE_COHERENT_MEM
+        /*
+         * Bakery locks are stored in normal .bss memory
+         *
+         * Each lock's data is spread across multiple cache lines, one per CPU,
+         * but multiple locks can share the same cache line.
+         * The compiler will allocate enough memory for one CPU's bakery locks,
+         * the remaining cache lines are allocated by the linker script
+         */
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __BAKERY_LOCK_START__ = .;
+        *(bakery_lock)
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __PERCPU_BAKERY_LOCK_SIZE__ = ABSOLUTE(. - __BAKERY_LOCK_START__);
+        . = . + (__PERCPU_BAKERY_LOCK_SIZE__ * (PLATFORM_CORE_COUNT - 1));
+        __BAKERY_LOCK_END__ = .;
+#ifdef PLAT_PERCPU_BAKERY_LOCK_SIZE
+    ASSERT(__PERCPU_BAKERY_LOCK_SIZE__ == PLAT_PERCPU_BAKERY_LOCK_SIZE,
+        "PLAT_PERCPU_BAKERY_LOCK_SIZE does not match bakery lock requirements");
+#endif
+#endif
+        __BSS_END__ = .;
+        __RW_END__ = .;
+    } >RAM
+
+    ASSERT(. <= BL31_LIMIT, "BL3-1 image has exceeded its limit.")
+
+    /*
+     * The xlat_table section is for full, aligned page tables (4K).
+     * Removing them from .bss avoids forcing 4K alignment on
+     * the .bss section and eliminates the unecessary zero init
+     */
+    xlat_table (NOLOAD) : {
+        *(xlat_table)
+    } >RAM2
+
+#if USE_COHERENT_MEM
+    /*
+     * The base address of the coherent memory section must be page-aligned (4K)
+     * to guarantee that the coherent data are stored on their own pages and
+     * are not mixed with normal data.  This is required to set up the correct
+     * memory attributes for the coherent data page tables.
+     */
+    coherent_ram (NOLOAD) : ALIGN(4096) {
+        __COHERENT_RAM_START__ = .;
+        /*
+         * Bakery locks are stored in coherent memory
+         *
+         * Each lock's data is contiguous and fully allocated by the compiler
+         */
+        *(bakery_lock)
+        *(tzfw_coherent_mem)
+        __COHERENT_RAM_END_UNALIGNED__ = .;
+        /*
+         * Memory page(s) mapped to this section will be marked
+         * as device memory.  No other unexpected data must creep in.
+         * Ensure the rest of the current memory page is unused.
+         */
+        . = NEXT(4096);
+        __COHERENT_RAM_END__ = .;
+    } >RAM2
+#endif
+
+    /*
+     * Define a linker symbol to mark end of the RW memory area for this
+     * image.
+     */
+    __BL31_END__ = .;
+
+    __BSS_SIZE__ = SIZEOF(.bss);
+#if USE_COHERENT_MEM
+    __COHERENT_RAM_UNALIGNED_SIZE__ =
+        __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
+#endif
+
+    ASSERT(. <= TZRAM2_LIMIT, "TZRAM2 image has exceeded its limit.")
+}
diff --git a/plat/mediatek/mt6795/bl31_plat_setup.c b/plat/mediatek/mt6795/bl31_plat_setup.c
new file mode 100644
index 0000000..3a8612d
--- /dev/null
+++ b/plat/mediatek/mt6795/bl31_plat_setup.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <arm_gic.h>
+#include <assert.h>
+#include <arch_helpers.h>
+#include <bl_common.h>
+#include <cci.h>
+#include <console.h>
+#include <context_mgmt.h>
+#include <debug.h>
+#include <generic_delay_timer.h>
+#include <mcucfg.h>
+#include <mmio.h>
+#include <mtk_sip_svc.h>
+#include <mtk_plat_common.h>
+#include <mt_cpuxgpt.h>
+#include <platform.h>
+#include <plat_private.h>
+#include <string.h>
+#include <xlat_tables.h>
+/*******************************************************************************
+ * Declarations of linker defined symbols which will help us find the layout
+ * of trusted SRAM
+ ******************************************************************************/
+unsigned long __RO_START__;
+unsigned long __RO_END__;
+
+unsigned long __COHERENT_RAM_START__;
+unsigned long __COHERENT_RAM_END__;
+
+/*
+ * The next 2 constants identify the extents of the code & RO data region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses.
+ */
+#define BL31_RO_BASE (unsigned long)(&__RO_START__)
+#define BL31_RO_LIMIT (unsigned long)(&__RO_END__)
+
+/*
+ * The next 2 constants identify the extents of the coherent memory region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols
+ * refer to page-aligned addresses.
+ */
+#define BL31_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
+#define BL31_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL3-1 from BL2.
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+static const int cci_map[] = {
+	PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX,
+	PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX
+};
+
+static uint32_t cci_map_length = ARRAY_SIZE(cci_map);
+
+/* Table of regions to map using the MMU.  */
+static const mmap_region_t plat_mmap[] = {
+	/* for TF text, RO, RW */
+	MAP_REGION_FLAT(MTK_DEV_RNG0_BASE, MTK_DEV_RNG0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MTK_DEV_RNG1_BASE, MTK_DEV_RNG1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(RAM_CONSOLE_BASE & ~(PAGE_SIZE_MASK), RAM_CONSOLE_SIZE,
+						MT_DEVICE | MT_RW | MT_NS),
+	{ 0 }
+
+};
+
+/*******************************************************************************
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ ******************************************************************************/
+#define DEFINE_CONFIGURE_MMU_EL(_el)					\
+	void plat_configure_mmu_el ## _el(unsigned long total_base,	\
+				unsigned long total_size,	\
+				unsigned long ro_start,	\
+				unsigned long ro_limit,	\
+				unsigned long coh_start,	\
+				unsigned long coh_limit)	\
+	{								\
+		mmap_add_region(total_base, total_base,			\
+				total_size,				\
+				MT_MEMORY | MT_RW | MT_SECURE);		\
+		mmap_add_region(ro_start, ro_start,			\
+				ro_limit - ro_start,			\
+				MT_MEMORY | MT_RO | MT_SECURE);		\
+		mmap_add_region(coh_start, coh_start,			\
+				coh_limit - coh_start,			\
+				MT_DEVICE | MT_RW | MT_SECURE);		\
+		mmap_add(plat_mmap);					\
+		init_xlat_tables();					\
+									\
+		enable_mmu_el ## _el(0);				\
+	}
+
+/* Define EL3 variants of the function initialising the MMU */
+DEFINE_CONFIGURE_MMU_EL(3)
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+void plat_cci_init(void)
+{
+	/* Initialize CCI driver */
+	cci_init(PLAT_MT_CCI_BASE, cci_map, cci_map_length);
+}
+
+void plat_cci_enable(void)
+{
+	/*
+	 * Enable CCI coherency for this cluster.
+	 * No need for locks as no other cpu is active at the moment.
+	 */
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+}
+
+void plat_cci_disable(void)
+{
+	cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
+}
+
+
+static void platform_setup_cpu(void)
+{
+	/* setup big cores */
+	mmio_write_32((uintptr_t)&mt6795_mcucfg->mp1_config_res,
+		MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK |
+		MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK |
+		MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK |
+		MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK |
+		MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK);
+	mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp1_miscdbg, MP1_AINACTS);
+	mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp1_clkenm_div,
+		MP1_SW_CG_GEN);
+	mmio_clrbits_32((uintptr_t)&mt6795_mcucfg->mp1_rst_ctl,
+		MP1_L2RSTDISABLE);
+
+	/* set big cores arm64 boot mode */
+	mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp1_cpucfg,
+		MP1_CPUCFG_64BIT);
+
+	/* set LITTLE cores arm64 boot mode */
+	mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp0_rv_addr[0].rv_addr_hw,
+		MP0_CPUCFG_64BIT);
+}
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ?
+			&bl33_image_ep_info : &bl32_image_ep_info;
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ * BL2 has flushed this information to memory, so we are guaranteed to pick up
+ * good data.
+ ******************************************************************************/
+void bl31_early_platform_setup(bl31_params_t *from_bl2,
+						 void *plat_params_from_bl2)
+{
+	struct mtk_bl_param_t *pmtk_bl_param =
+	(struct mtk_bl_param_t *)from_bl2;
+	struct atf_arg_t *teearg;
+	unsigned long long normal_base;
+	unsigned long long atf_base;
+
+	assert(from_bl2 != NULL);
+	/*
+	 * Mediatek preloader(i.e, BL2) is in 32 bit state, high 32bits
+	 * of 64 bit GP registers are UNKNOWN if CPU warm reset from 32 bit
+	 * to 64 bit state. So we need to clear high 32bit,
+	 * which may be random value.
+	 */
+	pmtk_bl_param =
+	(struct mtk_bl_param_t *)((uint64_t)pmtk_bl_param & 0x00000000ffffffff);
+	plat_params_from_bl2 =
+	(void *)((uint64_t)plat_params_from_bl2 & 0x00000000ffffffff);
+
+	teearg  = (struct atf_arg_t *)pmtk_bl_param->tee_info_addr;
+
+	console_init(teearg->atf_log_port, UART_CLOCK, UART_BAUDRATE);
+	memcpy((void *)&gteearg, (void *)teearg, sizeof(struct atf_arg_t));
+
+	normal_base = 0;
+    /* in ATF boot time, timer for cntpct_el0 is not initialized
+     * so it will not count now.
+     */
+	atf_base = read_cntpct_el0();
+	sched_clock_init(normal_base, atf_base);
+
+	VERBOSE("bl31_setup\n");
+
+	/* Populate entry point information for BL3-2 and BL3-3 */
+	SET_PARAM_HEAD(&bl32_image_ep_info,
+				PARAM_EP,
+				VERSION_1,
+				0);
+	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+	bl32_image_ep_info.pc = BL32_BASE;
+
+	SET_PARAM_HEAD(&bl33_image_ep_info,
+				PARAM_EP,
+				VERSION_1,
+				0);
+	/*
+	 * Tell BL3-1 where the non-trusted software image
+	 * is located and the entry state information
+	 */
+	/* BL33_START_ADDRESS */
+	bl33_image_ep_info.pc = pmtk_bl_param->bl33_start_addr;
+	bl33_image_ep_info.spsr = plat_get_spsr_for_bl33_entry();
+	bl33_image_ep_info.args.arg4 =  pmtk_bl_param->bootarg_loc;
+	bl33_image_ep_info.args.arg5 =  pmtk_bl_param->bootarg_size;
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+}
+/*******************************************************************************
+ * Perform any BL3-1 platform setup code
+ ******************************************************************************/
+
+void bl31_platform_setup(void)
+{
+	platform_setup_cpu();
+
+	generic_delay_timer_init();
+
+	plat_mt_gic_driver_init();
+	/* Initialize the gic cpu and distributor interfaces */
+	plat_mt_gic_init();
+
+	/* Topologies are best known to the platform. */
+	mt_setup_topology();
+}
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the mmu in a quick and dirty way.
+ * Init MTK propiartary log buffer control field.
+ ******************************************************************************/
+void bl31_plat_arch_setup(void)
+{
+	/* Enable non-secure access to CCI-400 registers */
+	mmio_write_32(CCI400_BASE + CCI_SEC_ACCESS_OFFSET, 0x1);
+
+	plat_cci_init();
+	plat_cci_enable();
+
+	if (gteearg.atf_log_buf_size != 0) {
+		INFO("mmap atf buffer : 0x%x, 0x%x\n\r",
+			gteearg.atf_log_buf_start,
+			gteearg.atf_log_buf_size);
+
+		mmap_add_region(
+			gteearg.atf_log_buf_start &
+			~(PAGE_SIZE_2MB_MASK),
+			gteearg.atf_log_buf_start &
+			~(PAGE_SIZE_2MB_MASK),
+			PAGE_SIZE_2MB,
+			MT_DEVICE | MT_RW | MT_NS);
+
+		INFO("mmap atf buffer (force 2MB aligned):0x%x, 0x%x\n",
+			(gteearg.atf_log_buf_start & ~(PAGE_SIZE_2MB_MASK)),
+		PAGE_SIZE_2MB);
+	}
+	/*
+	 * add TZRAM_BASE to memory map
+	 * then set RO and COHERENT to different attribute
+	 */
+	plat_configure_mmu_el3(
+		(TZRAM_BASE & ~(PAGE_SIZE_MASK)),
+		(TZRAM_SIZE & ~(PAGE_SIZE_MASK)),
+		(BL31_RO_BASE & ~(PAGE_SIZE_MASK)),
+		BL31_RO_LIMIT,
+		BL31_COHERENT_RAM_BASE,
+		BL31_COHERENT_RAM_LIMIT);
+	/* Initialize for ATF log buffer */
+	if (gteearg.atf_log_buf_size != 0) {
+		gteearg.atf_aee_debug_buf_size = ATF_AEE_BUFFER_SIZE;
+		gteearg.atf_aee_debug_buf_start =
+			gteearg.atf_log_buf_start +
+			gteearg.atf_log_buf_size - ATF_AEE_BUFFER_SIZE;
+		INFO("ATF log service is registered (0x%x, aee:0x%x)\n",
+			gteearg.atf_log_buf_start,
+			gteearg.atf_aee_debug_buf_start);
+	} else{
+		gteearg.atf_aee_debug_buf_size = 0;
+		gteearg.atf_aee_debug_buf_start = 0;
+	}
+
+	/* Platform code before bl31_main */
+	/* compatible to the earlier chipset */
+
+	/* Show to ATF log buffer & UART */
+	INFO("BL3-1: %s\n", version_string);
+	INFO("BL3-1: %s\n", build_message);
+
+}
+#if 0
+/* MTK Define */
+#define ACTLR_CPUECTLR_BIT    (1 << 1)
+
+void enable_ns_access_to_cpuectlr(void)
+{
+	unsigned int next_actlr;
+
+
+	/* ACTLR_EL1 do not implement CUPECTLR  */
+	next_actlr = read_actlr_el2();
+	next_actlr |= ACTLR_CPUECTLR_BIT;
+	write_actlr_el2(next_actlr);
+
+	next_actlr = read_actlr_el3();
+	next_actlr |= ACTLR_CPUECTLR_BIT;
+	write_actlr_el3(next_actlr);
+}
+#endif
+/*******************************************************************************
+ * This function prepare boot argument for 64 bit kernel entry
+ ******************************************************************************/
+static entry_point_info_t *bl31_plat_get_next_kernel64_ep_info(void)
+{
+	entry_point_info_t *next_image_info;
+	unsigned long el_status;
+	unsigned int mode;
+
+	el_status = 0;
+	mode = 0;
+
+	/* Kernel image is always non-secured */
+	next_image_info = &bl33_image_ep_info;
+
+	/* Figure out what mode we enter the non-secure world in */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	if (el_status) {
+		INFO("Kernel_EL2\n");
+		mode = MODE_EL2;
+	} else{
+		INFO("Kernel_EL1\n");
+		mode = MODE_EL1;
+	}
+
+	INFO("Kernel is 64Bit\n");
+	next_image_info->spsr =
+		SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	next_image_info->pc = get_kernel_info_pc();
+	next_image_info->args.arg0 = get_kernel_info_r0();
+	next_image_info->args.arg1 = get_kernel_info_r1();
+
+	INFO("pc=0x%lx, r0=0x%lx, r1=0x%lx\n",
+				 next_image_info->pc,
+				 next_image_info->args.arg0,
+				 next_image_info->args.arg1);
+
+
+	SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE);
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * This function prepare boot argument for 32 bit kernel entry
+ ******************************************************************************/
+static entry_point_info_t *bl31_plat_get_next_kernel32_ep_info(void)
+{
+	entry_point_info_t *next_image_info;
+	unsigned int mode;
+
+	mode = 0;
+
+	/* Kernel image is always non-secured */
+	next_image_info = &bl33_image_ep_info;
+
+	/* Figure out what mode we enter the non-secure world in */
+	mode = MODE32_hyp;
+	/*
+	* TODO: Consider the possibility of specifying the SPSR in
+	* the FIP ToC and allowing the platform to have a say as
+	* well.
+	*/
+
+	INFO("Kernel is 32Bit\n");
+	next_image_info->spsr =
+		SPSR_MODE32(mode, SPSR_T_ARM, SPSR_E_LITTLE,
+		(DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT));
+	next_image_info->pc = get_kernel_info_pc();
+	next_image_info->args.arg0 = get_kernel_info_r0();
+	next_image_info->args.arg1 = get_kernel_info_r1();
+	next_image_info->args.arg2 = get_kernel_info_r2();
+
+	INFO("pc=0x%lx, r0=0x%lx, r1=0x%lx, r2=0x%lx\n",
+				 next_image_info->pc,
+				 next_image_info->args.arg0,
+				 next_image_info->args.arg1,
+				 next_image_info->args.arg2);
+
+
+	SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE);
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	else
+		return NULL;
+}
+
+/*******************************************************************************
+ * This function prepare boot argument for kernel entrypoint
+ ******************************************************************************/
+void bl31_prepare_kernel_entry(uint64_t k32_64)
+{
+	entry_point_info_t *next_image_info;
+	uint32_t image_type;
+
+	/* Determine which image to execute next */
+	/* image_type = bl31_get_next_image_type(); */
+	image_type = NON_SECURE;
+
+	/* Program EL3 registers to enable entry into the next EL */
+	if (k32_64 == 0)
+		next_image_info = bl31_plat_get_next_kernel32_ep_info();
+	else
+		next_image_info = bl31_plat_get_next_kernel64_ep_info();
+
+	assert(next_image_info);
+	assert(image_type == GET_SECURITY_STATE(next_image_info->h.attr));
+
+	INFO("BL3-1: Preparing for EL3 exit to %s world, Kernel\n",
+		(image_type == SECURE) ? "secure" : "normal");
+	INFO("BL3-1: Next image address = 0x%llx\n",
+		(unsigned long long) next_image_info->pc);
+	INFO("BL3-1: Next image spsr = 0x%x\n", next_image_info->spsr);
+	cm_init_context(read_mpidr_el1(), next_image_info);
+	cm_prepare_el3_exit(image_type);
+}
diff --git a/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.c b/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.c
new file mode 100644
index 0000000..2430c47
--- /dev/null
+++ b/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <arch_helpers.h>
+#include <mmio.h>
+#include <mt_cpuxgpt.h>
+#include <stdint.h>
+#include <platform.h>
+#include <debug.h>
+#define CPUXGPT_BASE	0x10200000
+#define INDEX_BASE		(CPUXGPT_BASE+0x0674)
+#define CTL_BASE		(CPUXGPT_BASE+0x0670)
+
+uint64_t normal_time_base;
+uint64_t atf_time_base;
+
+void sched_clock_init(uint64_t normal_base, uint64_t atf_base)
+{
+	normal_time_base = normal_base;
+	atf_time_base = atf_base;
+}
+
+uint64_t sched_clock(void)
+{
+	uint64_t cval;
+
+	cval = (((read_cntpct_el0() - atf_time_base)*1000)/
+		SYS_COUNTER_FREQ_IN_MHZ) + normal_time_base;
+	return cval;
+}
+
+/*
+  * Return: 0 - Trying to disable the CPUXGPT control bit,
+  * and not allowed to disable it.
+  * Return: 1 - reg_addr is not realted to disable the control bit.
+  */
+unsigned char check_cpuxgpt_write_permission(unsigned int reg_addr,
+	unsigned int reg_value)
+{
+	unsigned int idx;
+	unsigned int ctl_val;
+
+	if (reg_addr == CTL_BASE) {
+		idx = mmio_read_32(INDEX_BASE);
+
+		/* idx 0: CPUXGPT system control */
+		if (idx == 0) {
+			ctl_val = mmio_read_32(CTL_BASE);
+			if (ctl_val & 1) {
+				/*
+				 * if enable bit already set,
+				 * then bit 0 is not allow to set as 0
+				 */
+				if (!(reg_value & 1))
+					return 0;
+			}
+		}
+	}
+	return 1;
+}
+
diff --git a/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.h b/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.h
new file mode 100644
index 0000000..edd045c
--- /dev/null
+++ b/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MT_CPUXGPT_H__
+#define __MT_CPUXGPT_H__
+
+/* REG */
+#define INDEX_CTL_REG       0x000
+#define INDEX_STA_REG       0x004
+#define INDEX_CNT_L_INIT    0x008
+#define INDEX_CNT_H_INIT    0x00C
+
+/* CTL_REG SET */
+#define EN_CPUXGPT          0x01
+#define EN_AHLT_DEBUG       0x02
+#define CLK_DIV1            (0x1 << 8)
+#define CLK_DIV2            (0x2 << 8)
+#define CLK_DIV4            (0x4 << 8)
+#define CLK_DIV_MASK        (~(0x7<<8))
+
+void generic_timer_backup(void);
+void sched_clock_init(uint64_t normal_base, uint64_t atf_base);
+uint64_t sched_clock(void);
+
+#endif /* __MT_CPUXGPT_H__ */
diff --git a/plat/mediatek/mt6795/include/mcucfg.h b/plat/mediatek/mt6795/include/mcucfg.h
new file mode 100644
index 0000000..879e7fa
--- /dev/null
+++ b/plat/mediatek/mt6795/include/mcucfg.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MCUCFG_H__
+#define __MCUCFG_H__
+
+#include <platform_def.h>
+#include <stdint.h>
+
+struct mt6795_mcucfg_regs {
+	uint32_t mp0_ca7l_cache_config;
+	struct {
+		uint32_t mem_delsel0;
+		uint32_t mem_delsel1;
+	} mp0_cpu[4];
+	uint32_t mp0_cache_mem_delsel0;
+	uint32_t mp0_cache_mem_delsel1;
+	uint32_t mp0_axi_config;
+	uint32_t mp0_misc_config[2];
+	struct {
+		uint32_t rv_addr_lw;
+		uint32_t rv_addr_hw;
+	} mp0_rv_addr[4];
+	uint32_t mp0_ca7l_cfg_dis;
+	uint32_t mp0_ca7l_clken_ctrl;
+	uint32_t mp0_ca7l_rst_ctrl;
+	uint32_t mp0_ca7l_misc_config;
+	uint32_t mp0_ca7l_dbg_pwr_ctrl;
+	uint32_t mp0_rw_rsvd0;
+	uint32_t mp0_rw_rsvd1;
+	uint32_t mp0_ro_rsvd;
+	uint32_t reserved0_0[100];
+	uint32_t mp1_cpucfg;
+	uint32_t mp1_miscdbg;
+	uint32_t reserved0_1[13];
+	uint32_t mp1_rst_ctl;
+	uint32_t mp1_clkenm_div;
+	uint32_t reserved0_2[7];
+	uint32_t mp1_config_res;
+	uint32_t reserved0_3[13];
+	struct {
+		uint32_t rv_addr_lw;
+		uint32_t rv_addr_hw;
+	} mp1_rv_addr[2];
+	uint32_t reserved0_4[84];
+	uint32_t mp0_rst_status;		/* 0x400 */
+	uint32_t mp0_dbg_ctrl;
+	uint32_t mp0_dbg_flag;
+	uint32_t mp0_ca7l_ir_mon;
+	struct {
+		uint32_t pc_lw;
+		uint32_t pc_hw;
+		uint32_t fp_arch32;
+		uint32_t sp_arch32;
+		uint32_t fp_arch64_lw;
+		uint32_t fp_arch64_hw;
+		uint32_t sp_arch64_lw;
+		uint32_t sp_arch64_hw;
+	} mp0_dbg_core[4];
+	uint32_t dfd_ctrl;
+	uint32_t dfd_cnt_l;
+	uint32_t dfd_cnt_h;
+	uint32_t misccfg_mp0_rw_rsvd;
+	uint32_t misccfg_sec_vio_status0;
+	uint32_t misccfg_sec_vio_status1;
+	uint32_t reserved1[22];
+	uint32_t misccfg_rw_rsvd;		/* 0x500 */
+	uint32_t mcusys_dbg_mon_sel_a;
+	uint32_t mcusys_dbg_mon;
+	uint32_t reserved2[61];
+	uint32_t mcusys_config_a;		/* 0x600 */
+	uint32_t mcusys_config1_a;
+	uint32_t mcusys_gic_peribase_a;
+	uint32_t reserved3;
+	uint32_t sec_range0_start;		/* 0x610 */
+	uint32_t sec_range0_end;
+	uint32_t sec_range_enable;
+	uint32_t reserved4;
+	uint32_t int_pol_ctl[8];		/* 0x620 */
+	uint32_t aclken_div;			/* 0x640 */
+	uint32_t pclken_div;
+	uint32_t l2c_sram_ctrl;
+	uint32_t armpll_jit_ctrl;
+	uint32_t cci_addrmap;			/* 0x650 */
+	uint32_t cci_config;
+	uint32_t cci_periphbase;
+	uint32_t cci_nevntcntovfl;
+	uint32_t cci_clk_ctrl;			/* 0x660 */
+	uint32_t cci_acel_s1_ctrl;
+	uint32_t bus_fabric_dcm_ctrl;
+	uint32_t reserved5;
+	uint32_t xgpt_ctl;			/* 0x670 */
+	uint32_t xgpt_idx;
+	uint32_t ptpod2_ctl0;
+	uint32_t ptpod2_ctl1;
+	uint32_t mcusys_revid;
+	uint32_t mcusys_rw_rsvd0;
+	uint32_t mcusys_rw_rsvd1;
+};
+
+static struct mt6795_mcucfg_regs *const mt6795_mcucfg = (void *)MCUCFG_BASE;
+
+/* cpu boot mode */
+enum {
+	MP0_CPUCFG_64BIT_SHIFT = 12,
+	MP1_CPUCFG_64BIT_SHIFT = 28,
+	MP0_CPUCFG_64BIT = 0xf << MP0_CPUCFG_64BIT_SHIFT,
+	MP1_CPUCFG_64BIT = 0xf << MP1_CPUCFG_64BIT_SHIFT
+};
+
+/* scu related */
+enum {
+	MP0_ACINACTM_SHIFT = 4,
+	MP1_ACINACTM_SHIFT = 0,
+	MP0_ACINACTM = 1 << MP0_ACINACTM_SHIFT,
+	MP1_ACINACTM = 1 << MP1_ACINACTM_SHIFT
+};
+
+enum {
+	MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0,
+	MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4,
+	MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8,
+	MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12,
+	MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16,
+
+	MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK =
+		0xf << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT
+};
+
+enum {
+	MP1_AINACTS_SHIFT = 4,
+	MP1_AINACTS = 1 << MP1_AINACTS_SHIFT
+};
+
+enum {
+	MP1_SW_CG_GEN_SHIFT = 12,
+	MP1_SW_CG_GEN = 1 << MP1_SW_CG_GEN_SHIFT
+};
+
+enum {
+	MP1_L2RSTDISABLE_SHIFT = 14,
+	MP1_L2RSTDISABLE = 1 << MP1_L2RSTDISABLE_SHIFT
+};
+
+#endif  /* __MCUCFG_H__ */
diff --git a/plat/mediatek/mt6795/include/plat_macros.S b/plat/mediatek/mt6795/include/plat_macros.S
new file mode 100644
index 0000000..ef9d1d8
--- /dev/null
+++ b/plat/mediatek/mt6795/include/plat_macros.S
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cci.h>
+#include <gic_v2.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n"	\
+		" Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+	/* ---------------------------------------------
+	 * The below macro prints out relevant GIC
+	 * registers whenever an unhandled exception is
+	 * taken in BL3-1.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	mov_imm x16, BASE_GICD_BASE
+	mov_imm x17, BASE_GICC_BASE
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+gicd_ispendr_loop:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	exit_print_gic_regs
+	bl	asm_print_hex
+
+	adr	x4, spacer
+	bl	asm_print_str
+
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+
+	adr	x4, newline
+	bl	asm_print_str
+	b	gicd_ispendr_loop
+exit_print_gic_regs:
+	.endm
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+	/* ------------------------------------------------
+	 * The below macro prints out relevant interconnect
+	 * registers whenever an unhandled exception is
+	 * taken in BL3-1.
+	 * Clobbers: x0 - x9, sp
+	 * ------------------------------------------------
+	 */
+	.macro plat_print_interconnect_regs
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX))
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET(	\
+			PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX))
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+	.endm
diff --git a/plat/mediatek/mt6795/include/plat_private.h b/plat/mediatek/mt6795/include/plat_private.h
new file mode 100644
index 0000000..7385c49
--- /dev/null
+++ b/plat/mediatek/mt6795/include/plat_private.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PLAT_PRIVATE_H__
+#define __PLAT_PRIVATE_H__
+#include <stdint.h>
+#include <xlat_tables.h>
+
+void plat_configure_mmu_el3(unsigned long total_base,
+					unsigned long total_size,
+					unsigned long,
+					unsigned long,
+					unsigned long,
+					unsigned long);
+
+void plat_cci_init(void);
+void plat_cci_enable(void);
+void plat_cci_disable(void);
+
+/* Declarations for plat_mt_gic.c */
+void plat_mt_gic_init(void);
+
+/* Declarations for plat_topology.c */
+int mt_setup_topology(void);
+void plat_delay_timer_init(void);
+
+void plat_mt_gic_driver_init(void);
+void plat_mt_gic_init(void);
+void plat_mt_gic_cpuif_enable(void);
+void plat_mt_gic_cpuif_disable(void);
+void plat_mt_gic_pcpu_init(void);
+
+#endif /* __PLAT_PRIVATE_H__ */
diff --git a/plat/mediatek/mt6795/include/plat_sip_calls.h b/plat/mediatek/mt6795/include/plat_sip_calls.h
new file mode 100644
index 0000000..a4844f4
--- /dev/null
+++ b/plat/mediatek/mt6795/include/plat_sip_calls.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PLAT_SIP_CALLS_H__
+#define __PLAT_SIP_CALLS_H__
+
+/*******************************************************************************
+ * Plat SiP function constants
+ ******************************************************************************/
+#define MTK_PLAT_SIP_NUM_CALLS	0
+
+#endif /* __PLAT_SIP_CALLS_H__ */
diff --git a/plat/mediatek/mt6795/include/platform_def.h b/plat/mediatek/mt6795/include/platform_def.h
new file mode 100644
index 0000000..275333f
--- /dev/null
+++ b/plat/mediatek/mt6795/include/platform_def.h
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PLATFORM_DEF_H__
+#define __PLATFORM_DEF_H__
+
+#define PLAT_PRIMARY_CPU  0x0
+
+/* Special value used to verify platform parameters from BL2 to BL3-1 */
+#define MT_BL31_PLAT_PARAM_VAL  0x0f1e2d3c4b5a6978ULL
+
+#define IO_PHYS             (0x10000000)
+#define INFRACFG_AO_BASE    (IO_PHYS + 0x1000)
+#define MCUCFG_BASE         (IO_PHYS + 0x200000)
+#define PERI_BASE           (IO_PHYS + 0x1000000)
+
+
+#define GPIO_BASE           (IO_PHYS + 0x370000)
+#define SPM_BASE            (IO_PHYS + 0x6000)
+#define RGU_BASE            (MCUCFG_BASE + 0x11000)
+#define PMIC_WRAP_BASE      (IO_PHYS + 0x10000)
+
+#define TRNG_base           (MCUCFG_BASE + 0x230000)
+#define MT_GIC_BASE         (0x10220000)
+#define MCU_SYS_SIZE        (0x700000)
+#define PLAT_MT_CCI_BASE    (IO_PHYS + 0x390000)
+
+/* Aggregate of all devices in the first GB */
+#define MTK_DEV_RNG0_BASE   IO_PHYS
+#define MTK_DEV_RNG0_SIZE   0x400000
+#define MTK_DEV_RNG1_BASE   (PERI_BASE)
+#define MTK_DEV_RNG1_SIZE   0x4000000
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define UART0_BASE (PERI_BASE + 0x2000)
+
+#define UART_BAUDRATE   (921600)
+#define UART_CLOCK (26000000)
+
+/*******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS	13000000
+#define SYS_COUNTER_FREQ_IN_MHZ		(SYS_COUNTER_FREQ_IN_TICKS/1000000)
+
+/*******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+
+/* Base MTK_platform compatible GIC memory map */
+#define BASE_GICD_BASE      (MT_GIC_BASE+0x1000)
+#define BASE_GICC_BASE      (MT_GIC_BASE + 0x2000)
+#define BASE_GICR_BASE      (MT_GIC_BASE + 0x200000)
+#define BASE_GICH_BASE      (MT_GIC_BASE + 0x4000)
+#define BASE_GICV_BASE      (MT_GIC_BASE + 0x6000)
+
+#define INT_POL_CTL0        0x10200620
+#define GIC_PRIVATE_SIGNALS (32)
+
+/*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX  4
+#define PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX  3
+
+/*******************************************************************************
+ * WDT Registers
+ ******************************************************************************/
+#define MTK_WDT_BASE                        (RGU_BASE)
+#define MTK_WDT_SIZE                        (0x1000)
+#define MTK_WDT_MODE                        (MTK_WDT_BASE+0x0000)
+#define MTK_WDT_LENGTH                      (MTK_WDT_BASE+0x0004)
+#define MTK_WDT_RESTART                     (MTK_WDT_BASE+0x0008)
+#define MTK_WDT_STATUS                      (MTK_WDT_BASE+0x000C)
+#define MTK_WDT_INTERVAL                    (MTK_WDT_BASE+0x0010)
+#define MTK_WDT_SWRST                       (MTK_WDT_BASE+0x0014)
+#define MTK_WDT_SWSYSRST                    (MTK_WDT_BASE+0x0018)
+#define MTK_WDT_NONRST_REG                  (MTK_WDT_BASE+0x0020)
+#define MTK_WDT_NONRST_REG2                 (MTK_WDT_BASE+0x0024)
+#define MTK_WDT_REQ_MODE                    (MTK_WDT_BASE+0x0030)
+#define MTK_WDT_REQ_IRQ_EN                  (MTK_WDT_BASE+0x0034)
+#define MTK_WDT_DEBUG_CTL                   (MTK_WDT_BASE+0x0040)
+
+/*WDT_STATUS*/
+#define MTK_WDT_STATUS_HWWDT_RST            (0x80000000)
+#define MTK_WDT_STATUS_SWWDT_RST            (0x40000000)
+#define MTK_WDT_STATUS_IRQWDT_RST           (0x20000000)
+#define MTK_WDT_STATUS_DEBUGWDT_RST         (0x00080000)
+#define MTK_WDT_STATUS_SPMWDT_RST           (0x0002)
+#define MTK_WDT_STATUS_SPM_THERMAL_RST      (0x0001)
+#define MTK_WDT_STATUS_THERMAL_DIRECT_RST   (1<<18)
+#define MTK_WDT_STATUS_SECURITY_RST         (1<<28)
+
+#define MTK_WDT_MODE_DUAL_MODE              0x0040
+#define MTK_WDT_MODE_IRQ                    0x0008
+#define MTK_WDT_MODE_KEY                    0x22000000
+#define MTK_WDT_MODE_EXTEN                  0x0004
+#define MTK_WDT_SWRST_KEY                   0x1209
+#define MTK_WDT_RESTART_KEY                 (0x1971)
+
+/* FIQ platform related define */
+#define MT_IRQ_SEC_SGI_0  8
+#define MT_IRQ_SEC_SGI_1  9
+#define MT_IRQ_SEC_SGI_2  10
+#define MT_IRQ_SEC_SGI_3  11
+#define MT_IRQ_SEC_SGI_4  12
+#define MT_IRQ_SEC_SGI_5  13
+#define MT_IRQ_SEC_SGI_6  14
+#define MT_IRQ_SEC_SGI_7  15
+
+#define FIQ_SMP_CALL_SGI  MT_IRQ_SEC_SGI_5
+
+#define PLAT_ARM_G0_IRQS	FIQ_SMP_CALL_SGI
+
+#define DEBUG_XLAT_TABLE 0
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT    "elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH      aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#if DEBUG_XLAT_TABLE
+#define PLATFORM_STACK_SIZE 0x800
+#elif IMAGE_BL1
+#define PLATFORM_STACK_SIZE 0x440
+#elif IMAGE_BL2
+#define PLATFORM_STACK_SIZE 0x400
+#elif IMAGE_BL31
+#define PLATFORM_STACK_SIZE 0x800
+#elif IMAGE_BL32
+#define PLATFORM_STACK_SIZE 0x440
+#endif
+
+#define FIRMWARE_WELCOME_STR    "Booting Trusted Firmware\n"
+#if ENABLE_PLAT_COMPAT
+#define PLATFORM_MAX_AFFLVL     MPIDR_AFFLVL2
+#else
+#define PLAT_MAX_PWR_LVL        2 /* MPIDR_AFFLVL2 */
+#endif
+
+#define PLATFORM_CACHE_LINE_SIZE      64
+#define PLATFORM_SYSTEM_COUNT         1
+#define PLATFORM_CLUSTER_COUNT        2
+#define PLATFORM_CLUSTER0_CORE_COUNT  4
+#define PLATFORM_CLUSTER1_CORE_COUNT  4
+#define PLATFORM_CORE_COUNT   (PLATFORM_CLUSTER1_CORE_COUNT + \
+					PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER 4
+#define PLATFORM_NUM_AFFS   (PLATFORM_SYSTEM_COUNT +  \
+					PLATFORM_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT)
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+/* ATF Argument */
+#define ATF_ARG_SIZE      (0x800)
+
+/* TF txet, ro, rw, internal SRAM, Size: release: 80KB, debug: 92KB */
+#define TZRAM_BASE        (0x110000)
+#if DEBUG
+#define TZRAM_SIZE        (0x1C400)
+#else
+#define TZRAM_SIZE        (0x1C400)
+#endif
+#define TZRAM2_BASE	   0x00100000
+#define TZRAM2_SIZE	   0xDC00
+#define TZRAM2_LIMIT		(TZRAM2_BASE + TZRAM2_SIZE)
+
+#define RAM_CONSOLE_BASE  0x0012D000
+#define RAM_CONSOLE_SIZE  0x00001000
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL3-1 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL3-1 debug size plus a
+ * little space for growth.
+ */
+#define BL31_BASE           (TZRAM_BASE + 0x1000)
+#define BL31_LIMIT          (TZRAM_BASE + TZRAM_SIZE)
+#define BSS1_STACK_LIMIT    (TZRAM_BASE + TZRAM_SIZE)
+#define BL31_TZRAM_SIZE     (TZRAM_SIZE - ATF_ARG_SIZE)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define ADDR_SPACE_SIZE   (1ull << 32)
+#define MAX_XLAT_TABLES   7
+#define MAX_MMAP_REGIONS  16
+
+
+/*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define CCI400_BASE                     0x10390000
+#define CCI400_SL_IFACE_CLUSTER0        4
+#define CCI400_SL_IFACE_CLUSTER1        3
+#define CCI400_SL_IFACE_INDEX(mpidr)  (mpidr & MPIDR_CLUSTER_MASK ? \
+					CCI400_SL_IFACE_CLUSTER1 :   \
+					CCI400_SL_IFACE_CLUSTER0)
+#define CCI_SEC_ACCESS_OFFSET           (0x8)
+
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT     6
+#define CACHE_WRITEBACK_GRANULE   (1 << CACHE_WRITEBACK_SHIFT)
+
+#define BL32_BASE                 (0x0)
+
+/*
+ * Load address of BL3-3 for this platform port
+ */
+#define LK_SIZE_LIMIT				(0x100000)
+#define PLAT_MTK_NS_IMAGE_OFFSET	(0x41E00000)
+/* 16KB */
+#define ATF_AEE_BUFFER_SIZE         (0x4000)
+#define PAGE_SIZE_2MB_MASK          (PAGE_SIZE_2MB - 1)
+#define IS_PAGE_2MB_ALIGNED(addr)   (((addr) & PAGE_SIZE_2MB_MASK) == 0)
+#define PAGE_SIZE_2MB               (1 << PAGE_SIZE_2MB_SHIFT)
+#define PAGE_SIZE_2MB_SHIFT         TWO_MB_SHIFT
+
+#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/mediatek/mt6795/include/power_tracer.h b/plat/mediatek/mt6795/include/power_tracer.h
new file mode 100644
index 0000000..ab9390d
--- /dev/null
+++ b/plat/mediatek/mt6795/include/power_tracer.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __POWER_TRACER_H__
+#define __POWER_TRACER_H__
+
+#define CPU_UP		0
+#define CPU_DOWN	1
+#define CPU_SUSPEND	2
+#define CLUSTER_UP	3
+#define CLUSTER_DOWN	4
+#define CLUSTER_SUSPEND	5
+
+void trace_power_flow(unsigned long mpidr, unsigned char mode);
+
+#endif
diff --git a/plat/mediatek/mt6795/include/scu.h b/plat/mediatek/mt6795/include/scu.h
new file mode 100644
index 0000000..e59fd43
--- /dev/null
+++ b/plat/mediatek/mt6795/include/scu.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SCU_H__
+#define __SCU_H__
+
+void disable_scu(unsigned long mpidr);
+void enable_scu(unsigned long mpidr);
+
+#endif
diff --git a/plat/mediatek/mt6795/include/spm.h b/plat/mediatek/mt6795/include/spm.h
new file mode 100644
index 0000000..32f8d8f
--- /dev/null
+++ b/plat/mediatek/mt6795/include/spm.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SPM_H__
+#define __SPM_H__
+
+#define SPM_POWERON_CONFIG_SET			(SPM_BASE + 0x000)
+#define SPM_POWER_ON_VAL0			(SPM_BASE + 0x010)
+#define SPM_POWER_ON_VAL1			(SPM_BASE + 0x014)
+#define SPM_CLK_SETTLE				(SPM_BASE + 0x100)
+#define SPM_CA7_CPU1_PWR_CON			(SPM_BASE + 0x218)
+#define SPM_CA7_CPU2_PWR_CON			(SPM_BASE + 0x21c)
+#define SPM_CA7_CPU3_PWR_CON			(SPM_BASE + 0x220)
+#define SPM_CA7_CPU1_L1_PDN			(SPM_BASE + 0x264)
+#define SPM_CA7_CPU2_L1_PDN			(SPM_BASE + 0x26c)
+#define SPM_CA7_CPU3_L1_PDN			(SPM_BASE + 0x274)
+#define SPM_MD32_SRAM_CON			(SPM_BASE + 0x2c8)
+#define SPM_PCM_CON0				(SPM_BASE + 0x310)
+#define SPM_PCM_CON1				(SPM_BASE + 0x314)
+#define SPM_PCM_IM_PTR				(SPM_BASE + 0x318)
+#define SPM_PCM_IM_LEN				(SPM_BASE + 0x31c)
+#define SPM_PCM_REG_DATA_INI			(SPM_BASE + 0x320)
+#define SPM_PCM_EVENT_VECTOR0			(SPM_BASE + 0x340)
+#define SPM_PCM_EVENT_VECTOR1			(SPM_BASE + 0x344)
+#define SPM_PCM_EVENT_VECTOR2			(SPM_BASE + 0x348)
+#define SPM_PCM_EVENT_VECTOR3			(SPM_BASE + 0x34c)
+#define SPM_PCM_MAS_PAUSE_MASK			(SPM_BASE + 0x354)
+#define SPM_PCM_PWR_IO_EN			(SPM_BASE + 0x358)
+#define SPM_PCM_TIMER_VAL			(SPM_BASE + 0x35c)
+#define SPM_PCM_TIMER_OUT			(SPM_BASE + 0x360)
+#define SPM_PCM_REG0_DATA			(SPM_BASE + 0x380)
+#define SPM_PCM_REG1_DATA			(SPM_BASE + 0x384)
+#define SPM_PCM_REG2_DATA			(SPM_BASE + 0x388)
+#define SPM_PCM_REG3_DATA			(SPM_BASE + 0x38c)
+#define SPM_PCM_REG4_DATA			(SPM_BASE + 0x390)
+#define SPM_PCM_REG5_DATA			(SPM_BASE + 0x394)
+#define SPM_PCM_REG6_DATA			(SPM_BASE + 0x398)
+#define SPM_PCM_REG7_DATA			(SPM_BASE + 0x39c)
+#define SPM_PCM_REG8_DATA			(SPM_BASE + 0x3a0)
+#define SPM_PCM_REG9_DATA			(SPM_BASE + 0x3a4)
+#define SPM_PCM_REG10_DATA			(SPM_BASE + 0x3a8)
+#define SPM_PCM_REG11_DATA			(SPM_BASE + 0x3ac)
+#define SPM_PCM_REG12_DATA			(SPM_BASE + 0x3b0)
+#define SPM_PCM_REG13_DATA			(SPM_BASE + 0x3b4)
+#define SPM_PCM_REG14_DATA			(SPM_BASE + 0x3b8)
+#define SPM_PCM_REG15_DATA			(SPM_BASE + 0x3bc)
+#define SPM_PCM_EVENT_REG_STA			(SPM_BASE + 0x3c0)
+#define SPM_PCM_FSM_STA				(SPM_BASE + 0x3c4)
+#define SPM_PCM_IM_HOST_RW_PTR			(SPM_BASE + 0x3c8)
+#define SPM_PCM_IM_HOST_RW_DAT			(SPM_BASE + 0x3cc)
+#define SPM_PCM_EVENT_VECTOR4			(SPM_BASE + 0x3d0)
+#define SPM_PCM_EVENT_VECTOR5			(SPM_BASE + 0x3d4)
+#define SPM_PCM_EVENT_VECTOR6			(SPM_BASE + 0x3d8)
+#define SPM_PCM_EVENT_VECTOR7			(SPM_BASE + 0x3dc)
+#define SPM_PCM_SW_INT_SET			(SPM_BASE + 0x3e0)
+#define SPM_PCM_SW_INT_CLEAR			(SPM_BASE + 0x3e4)
+#define SPM_CLK_CON				(SPM_BASE + 0x400)
+#define SPM_SLEEP_PTPOD2_CON			(SPM_BASE + 0x408)
+#define SPM_APMCU_PWRCTL			(SPM_BASE + 0x600)
+#define SPM_AP_DVFS_CON_SET			(SPM_BASE + 0x604)
+#define SPM_AP_STANBY_CON			(SPM_BASE + 0x608)
+#define SPM_PWR_STATUS				(SPM_BASE + 0x60c)
+#define SPM_PWR_STATUS_2ND			(SPM_BASE + 0x610)
+#define SPM_AP_BSI_REQ				(SPM_BASE + 0x614)
+#define SPM_SLEEP_TIMER_STA			(SPM_BASE + 0x720)
+#define SPM_SLEEP_WAKEUP_EVENT_MASK		(SPM_BASE + 0x810)
+#define SPM_SLEEP_CPU_WAKEUP_EVENT		(SPM_BASE + 0x814)
+#define SPM_SLEEP_MD32_WAKEUP_EVENT_MASK	(SPM_BASE + 0x818)
+#define SPM_PCM_WDT_TIMER_VAL			(SPM_BASE + 0x824)
+#define SPM_PCM_WDT_TIMER_OUT			(SPM_BASE + 0x828)
+#define SPM_PCM_MD32_MAILBOX			(SPM_BASE + 0x830)
+#define SPM_PCM_MD32_IRQ			(SPM_BASE + 0x834)
+#define SPM_SLEEP_ISR_MASK			(SPM_BASE + 0x900)
+#define SPM_SLEEP_ISR_STATUS			(SPM_BASE + 0x904)
+#define SPM_SLEEP_ISR_RAW_STA			(SPM_BASE + 0x910)
+#define SPM_SLEEP_MD32_ISR_RAW_STA		(SPM_BASE + 0x914)
+#define SPM_SLEEP_WAKEUP_MISC			(SPM_BASE + 0x918)
+#define SPM_SLEEP_BUS_PROTECT_RDY		(SPM_BASE + 0x91c)
+#define SPM_SLEEP_SUBSYS_IDLE_STA		(SPM_BASE + 0x920)
+#define SPM_PCM_RESERVE				(SPM_BASE + 0xb00)
+#define SPM_PCM_RESERVE2			(SPM_BASE + 0xb04)
+#define SPM_PCM_FLAGS				(SPM_BASE + 0xb08)
+#define SPM_PCM_SRC_REQ				(SPM_BASE + 0xb0c)
+#define SPM_PCM_DEBUG_CON			(SPM_BASE + 0xb20)
+#define SPM_CA7_CPU0_IRQ_MASK			(SPM_BASE + 0xb30)
+#define SPM_CA7_CPU1_IRQ_MASK			(SPM_BASE + 0xb34)
+#define SPM_CA7_CPU2_IRQ_MASK			(SPM_BASE + 0xb38)
+#define SPM_CA7_CPU3_IRQ_MASK			(SPM_BASE + 0xb3c)
+#define SPM_CA15_CPU0_IRQ_MASK			(SPM_BASE + 0xb40)
+#define SPM_CA15_CPU1_IRQ_MASK			(SPM_BASE + 0xb44)
+#define SPM_CA15_CPU2_IRQ_MASK			(SPM_BASE + 0xb48)
+#define SPM_CA15_CPU3_IRQ_MASK			(SPM_BASE + 0xb4c)
+#define SPM_PCM_PASR_DPD_0			(SPM_BASE + 0xb60)
+#define SPM_PCM_PASR_DPD_1			(SPM_BASE + 0xb64)
+#define SPM_PCM_PASR_DPD_2			(SPM_BASE + 0xb68)
+#define SPM_PCM_PASR_DPD_3			(SPM_BASE + 0xb6c)
+#define SPM_SLEEP_CA7_WFI0_EN			(SPM_BASE + 0xf00)
+#define SPM_SLEEP_CA7_WFI1_EN			(SPM_BASE + 0xf04)
+#define SPM_SLEEP_CA7_WFI2_EN			(SPM_BASE + 0xf08)
+#define SPM_SLEEP_CA7_WFI3_EN			(SPM_BASE + 0xf0c)
+#define SPM_SLEEP_CA15_WFI0_EN			(SPM_BASE + 0xf10)
+#define SPM_SLEEP_CA15_WFI1_EN			(SPM_BASE + 0xf14)
+#define SPM_SLEEP_CA15_WFI2_EN			(SPM_BASE + 0xf18)
+#define SPM_SLEEP_CA15_WFI3_EN			(SPM_BASE + 0xf1c)
+
+#define SPM_PROJECT_CODE	0xb16
+
+#define SPM_REGWR_EN		(1U << 0)
+#define SPM_REGWR_CFG_KEY	(SPM_PROJECT_CODE << 16)
+
+#define SPM_CPU_PDN_DIS		(1U << 0)
+#define SPM_INFRA_PDN_DIS	(1U << 1)
+#define SPM_DDRPHY_PDN_DIS	(1U << 2)
+#define SPM_DUALVCORE_PDN_DIS	(1U << 3)
+#define SPM_PASR_DIS		(1U << 4)
+#define SPM_DPD_DIS		(1U << 5)
+#define SPM_SODI_DIS		(1U << 6)
+#define SPM_MEMPLL_RESET	(1U << 7)
+#define SPM_MAINPLL_PDN_DIS	(1U << 8)
+#define SPM_CPU_DVS_DIS		(1U << 9)
+#define SPM_CPU_DORMANT		(1U << 10)
+#define SPM_EXT_VSEL_GPIO103	(1U << 11)
+#define SPM_DDR_HIGH_SPEED	(1U << 12)
+#define SPM_OPT			(1U << 13)
+
+#define POWER_ON_VAL1_DEF	0x01011820
+#define PCM_FSM_STA_DEF		0x48490
+#define PCM_END_FSM_STA_DEF	0x08490
+#define PCM_END_FSM_STA_MASK	0x3fff0
+#define PCM_HANDSHAKE_SEND1	0xbeefbeef
+
+#define PCM_WDT_TIMEOUT		(30 * 32768)
+#define PCM_TIMER_MAX		(0xffffffff - PCM_WDT_TIMEOUT)
+
+#define CON0_PCM_KICK		(1U << 0)
+#define CON0_IM_KICK		(1U << 1)
+#define CON0_IM_SLEEP_DVS	(1U << 3)
+#define CON0_PCM_SW_RESET	(1U << 15)
+#define CON0_CFG_KEY		(SPM_PROJECT_CODE << 16)
+
+#define CON1_IM_SLAVE		(1U << 0)
+#define CON1_MIF_APBEN		(1U << 3)
+#define CON1_PCM_TIMER_EN	(1U << 5)
+#define CON1_IM_NONRP_EN	(1U << 6)
+#define CON1_PCM_WDT_EN		(1U << 8)
+#define CON1_PCM_WDT_WAKE_MODE	(1U << 9)
+#define CON1_SPM_SRAM_SLP_B	(1U << 10)
+#define CON1_SPM_SRAM_ISO_B	(1U << 11)
+#define CON1_EVENT_LOCK_EN	(1U << 12)
+#define CON1_CFG_KEY		(SPM_PROJECT_CODE << 16)
+
+#define PCM_PWRIO_EN_R0		(1U << 0)
+#define PCM_PWRIO_EN_R7		(1U << 7)
+#define PCM_RF_SYNC_R0		(1U << 16)
+#define PCM_RF_SYNC_R2		(1U << 18)
+#define PCM_RF_SYNC_R6		(1U << 22)
+#define PCM_RF_SYNC_R7		(1U << 23)
+
+#define CC_SYSCLK0_EN_0		(1U << 0)
+#define CC_SYSCLK0_EN_1		(1U << 1)
+#define CC_SYSCLK1_EN_0		(1U << 2)
+#define CC_SYSCLK1_EN_1		(1U << 3)
+#define CC_SYSSETTLE_SEL	(1U << 4)
+#define CC_LOCK_INFRA_DCM	(1U << 5)
+#define CC_SRCLKENA_MASK_0	(1U << 6)
+#define CC_CXO32K_RM_EN_MD1	(1U << 9)
+#define CC_CXO32K_RM_EN_MD2	(1U << 10)
+#define CC_CLKSQ1_SEL		(1U << 12)
+#define CC_DISABLE_DORM_PWR	(1U << 14)
+#define CC_MD32_DCM_EN		(1U << 18)
+
+#define WFI_OP_AND		1
+#define WFI_OP_OR		0
+
+#define WAKE_MISC_PCM_TIMER	(1U << 19)
+#define WAKE_MISC_CPU_WAKE	(1U << 20)
+
+/* define WAKE_SRC_XXX */
+#define WAKE_SRC_SPM_MERGE	(1 << 0)
+#define WAKE_SRC_KP		(1 << 2)
+#define WAKE_SRC_WDT		(1 << 3)
+#define WAKE_SRC_GPT		(1 << 4)
+#define WAKE_SRC_EINT		(1 << 6)
+#define WAKE_SRC_LOW_BAT	(1 << 9)
+#define WAKE_SRC_MD32		(1 << 10)
+#define WAKE_SRC_USB_CD		(1 << 14)
+#define WAKE_SRC_USB_PDN	(1 << 15)
+#define WAKE_SRC_AFE		(1 << 20)
+#define WAKE_SRC_THERM		(1 << 21)
+#define WAKE_SRC_SYSPWREQ	(1 << 24)
+#define WAKE_SRC_SEJ		(1 << 27)
+#define WAKE_SRC_ALL_MD32	(1 << 28)
+#define WAKE_SRC_CPU_IRQ	(1 << 29)
+
+#endif /* __SPM_H__ */
diff --git a/plat/mediatek/mt6795/plat_delay_timer.c b/plat/mediatek/mt6795/plat_delay_timer.c
new file mode 100644
index 0000000..797ce05
--- /dev/null
+++ b/plat/mediatek/mt6795/plat_delay_timer.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch_helpers.h>
+#include <delay_timer.h>
+#include <platform_def.h>
+
+static uint32_t plat_get_timer_value(void)
+{
+	/*
+	 * Generic delay timer implementation expects the timer to be a down
+	 * counter. We apply bitwise NOT operator to the tick values returned
+	 * by read_cntpct_el0() to simulate the down counter.
+	 */
+	return (uint32_t)(~read_cntpct_el0());
+}
+
+static const timer_ops_t plat_timer_ops = {
+	.get_timer_value	= plat_get_timer_value,
+	.clk_mult		= 1,
+	.clk_div		= SYS_COUNTER_FREQ_IN_MHZ,
+};
+
+void plat_delay_timer_init(void)
+{
+	timer_init(&plat_timer_ops);
+}
diff --git a/plat/mediatek/mt6795/plat_mt_gic.c b/plat/mediatek/mt6795/plat_mt_gic.c
new file mode 100644
index 0000000..8679d07
--- /dev/null
+++ b/plat/mediatek/mt6795/plat_mt_gic.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <gicv2.h>
+#include <plat_arm.h>
+#include <platform.h>
+#include <platform_def.h>
+
+const unsigned int g0_interrupt_array[] = {
+	PLAT_ARM_G0_IRQS
+};
+
+gicv2_driver_data_t arm_gic_data = {
+	.gicd_base = BASE_GICD_BASE,
+	.gicc_base = BASE_GICC_BASE,
+	.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
+	.g0_interrupt_array = g0_interrupt_array,
+};
+
+void plat_mt_gic_driver_init(void)
+{
+	gicv2_driver_init(&arm_gic_data);
+}
+
+void plat_mt_gic_init(void)
+{
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+void plat_mt_gic_cpuif_enable(void)
+{
+	gicv2_cpuif_enable();
+}
+
+void plat_mt_gic_cpuif_disable(void)
+{
+	gicv2_cpuif_disable();
+}
+
+void plat_mt_gic_pcpu_init(void)
+{
+	gicv2_pcpu_distif_init();
+}
diff --git a/plat/mediatek/mt6795/plat_pm.c b/plat/mediatek/mt6795/plat_pm.c
new file mode 100644
index 0000000..96fdab0
--- /dev/null
+++ b/plat/mediatek/mt6795/plat_pm.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <bakery_lock.h>
+#include <cci.h>
+#include <console.h>
+#include <debug.h>
+#include <errno.h>
+#include <mcucfg.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <plat_private.h>
+#include <power_tracer.h>
+#include <psci.h>
+#include <scu.h>
+
+struct core_context {
+	unsigned long timer_data[8];
+	unsigned int count;
+	unsigned int rst;
+	unsigned int abt;
+	unsigned int brk;
+};
+
+struct cluster_context {
+	struct core_context core[PLATFORM_MAX_CPUS_PER_CLUSTER];
+};
+
+/*
+ * Top level structure to hold the complete context of a multi cluster system
+ */
+struct system_context {
+	struct cluster_context cluster[PLATFORM_CLUSTER_COUNT];
+};
+
+/*
+ * Top level structure which encapsulates the context of the entire system
+ */
+static struct system_context dormant_data[1];
+
+static inline struct cluster_context *system_cluster(
+						struct system_context *system,
+						uint32_t clusterid)
+{
+	return &system->cluster[clusterid];
+}
+
+static inline struct core_context *cluster_core(struct cluster_context *cluster,
+						uint32_t cpuid)
+{
+	return &cluster->core[cpuid];
+}
+
+static struct cluster_context *get_cluster_data(unsigned long mpidr)
+{
+	uint32_t clusterid;
+
+	clusterid = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	return system_cluster(dormant_data, clusterid);
+}
+
+static struct core_context *get_core_data(unsigned long mpidr)
+{
+	struct cluster_context *cluster;
+	uint32_t cpuid;
+
+	cluster = get_cluster_data(mpidr);
+	cpuid = mpidr & MPIDR_CPU_MASK;
+
+	return cluster_core(cluster, cpuid);
+}
+
+static void mt_save_generic_timer(unsigned long *container)
+{
+	uint64_t ctl;
+	uint64_t val;
+
+	__asm__ volatile("mrs	%x0, cntkctl_el1\n\t"
+			 "mrs	%x1, cntp_cval_el0\n\t"
+			 "stp	%x0, %x1, [%2, #0]"
+			 : "=&r" (ctl), "=&r" (val)
+			 : "r" (container)
+			 : "memory");
+
+	__asm__ volatile("mrs	%x0, cntp_tval_el0\n\t"
+			 "mrs	%x1, cntp_ctl_el0\n\t"
+			 "stp	%x0, %x1, [%2, #16]"
+			 : "=&r" (val), "=&r" (ctl)
+			 : "r" (container)
+			 : "memory");
+
+	__asm__ volatile("mrs	%x0, cntv_tval_el0\n\t"
+			 "mrs	%x1, cntv_ctl_el0\n\t"
+			 "stp	%x0, %x1, [%2, #32]"
+			 : "=&r" (val), "=&r" (ctl)
+			 : "r" (container)
+			 : "memory");
+}
+
+static void mt_restore_generic_timer(unsigned long *container)
+{
+	uint64_t ctl;
+	uint64_t val;
+
+	__asm__ volatile("ldp	%x0, %x1, [%2, #0]\n\t"
+			 "msr	cntkctl_el1, %x0\n\t"
+			 "msr	cntp_cval_el0, %x1"
+			 : "=&r" (ctl), "=&r" (val)
+			 : "r" (container)
+			 : "memory");
+
+	__asm__ volatile("ldp	%x0, %x1, [%2, #16]\n\t"
+			 "msr	cntp_tval_el0, %x0\n\t"
+			 "msr	cntp_ctl_el0, %x1"
+			 : "=&r" (val), "=&r" (ctl)
+			 : "r" (container)
+			 : "memory");
+
+	__asm__ volatile("ldp	%x0, %x1, [%2, #32]\n\t"
+			 "msr	cntv_tval_el0, %x0\n\t"
+			 "msr	cntv_ctl_el0, %x1"
+			 : "=&r" (val), "=&r" (ctl)
+			 : "r" (container)
+			 : "memory");
+}
+
+static void stop_generic_timer(void)
+{
+	/*
+	 * Disable the timer and mask the irq to prevent
+	 * suprious interrupts on this cpu interface. It
+	 * will bite us when we come back if we don't. It
+	 * will be replayed on the inbound cluster.
+	 */
+	uint64_t cntpctl = read_cntp_ctl_el0();
+
+	write_cntp_ctl_el0(clr_cntp_ctl_enable(cntpctl));
+}
+
+static void mt_cpu_save(unsigned long mpidr)
+{
+	struct core_context *core;
+
+	core = get_core_data(mpidr);
+	mt_save_generic_timer(core->timer_data);
+
+	/* disable timer irq, and upper layer should enable it again. */
+	stop_generic_timer();
+}
+
+static void mt_cpu_restore(unsigned long mpidr)
+{
+	struct core_context *core;
+
+	core = get_core_data(mpidr);
+	mt_restore_generic_timer(core->timer_data);
+}
+
+static void mt_platform_save_context(unsigned long mpidr)
+{
+	/* mcusys_save_context: */
+	mt_cpu_save(mpidr);
+}
+
+static void mt_platform_restore_context(unsigned long mpidr)
+{
+	/* mcusys_restore_context: */
+	mt_cpu_restore(mpidr);
+}
+
+/*******************************************************************************
+* Private function which is used to determine if any platform actions
+* should be performed for the specified affinity instance given its
+* state. Nothing needs to be done if the 'state' is not off or if this is not
+* the highest affinity level which will enter the 'state'.
+*******************************************************************************/
+static int32_t plat_do_plat_actions(unsigned int afflvl, unsigned int state)
+{
+	unsigned int max_phys_off_afflvl;
+
+	assert(afflvl <= MPIDR_AFFLVL2);
+
+	if (state != PSCI_STATE_OFF)
+		return -EAGAIN;
+
+	/*
+	 * Find the highest affinity level which will be suspended and postpone
+	 * all the platform specific actions until that level is hit.
+	 */
+	max_phys_off_afflvl = psci_get_max_phys_off_afflvl();
+	assert(max_phys_off_afflvl != PSCI_INVALID_DATA);
+	if (afflvl != max_phys_off_afflvl)
+		return -EAGAIN;
+
+	return 0;
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance is about to enter
+ * standby.
+ ******************************************************************************/
+static void plat_affinst_standby(unsigned int power_state)
+{
+	unsigned int target_afflvl;
+
+	/* Sanity check the requested state */
+	target_afflvl = psci_get_pstate_afflvl(power_state);
+
+	/*
+	 * It's possible to enter standby only on affinity level 0 i.e. a cpu
+	 * on the MTK_platform. Ignore any other affinity level.
+	 */
+	if (target_afflvl == MPIDR_AFFLVL0) {
+		/*
+		 * Enter standby state. dsb is good practice before using wfi
+		 * to enter low power states.
+		 */
+		dsb();
+		wfi();
+	}
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance is about to be turned
+ * on. The level and mpidr determine the affinity instance.
+ ******************************************************************************/
+static int plat_affinst_on(unsigned long mpidr,
+		    unsigned long sec_entrypoint,
+		    unsigned int afflvl,
+		    unsigned int state)
+{
+	int rc = PSCI_E_SUCCESS;
+	unsigned long cpu_id;
+	unsigned long cluster_id;
+	uintptr_t rv;
+
+	/*
+	 * It's possible to turn on only affinity level 0 i.e. a cpu
+	 * on the MTK_platform. Ignore any other affinity level.
+	 */
+	if (afflvl != MPIDR_AFFLVL0)
+		return rc;
+
+	cpu_id = mpidr & MPIDR_CPU_MASK;
+	cluster_id = mpidr & MPIDR_CLUSTER_MASK;
+
+	if (cluster_id)
+		rv = (uintptr_t)&mt6795_mcucfg->mp1_rv_addr[cpu_id].rv_addr_lw;
+	else
+		rv = (uintptr_t)&mt6795_mcucfg->mp0_rv_addr[cpu_id].rv_addr_lw;
+
+	mmio_write_32(rv, sec_entrypoint);
+	INFO("mt_on[%ld:%ld], entry %x\n",
+		cluster_id, cpu_id, mmio_read_32(rv));
+
+	return rc;
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance is about to be turned
+ * off. The level and mpidr determine the affinity instance. The 'state' arg.
+ * allows the platform to decide whether the cluster is being turned off and
+ * take apt actions.
+ *
+ * CAUTION: This function is called with coherent stacks so that caches can be
+ * turned off, flushed and coherency disabled. There is no guarantee that caches
+ * will remain turned on across calls to this function as each affinity level is
+ * dealt with. So do not write & read global variables across calls. It will be
+ * wise to do flush a write to the global to prevent unpredictable results.
+ ******************************************************************************/
+static void plat_affinst_off(unsigned int afflvl, unsigned int state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+
+	/* Determine if any platform actions need to be executed. */
+	if (plat_do_plat_actions(afflvl, state) == -EAGAIN)
+		return;
+
+	/* Prevent interrupts from spuriously waking up this cpu */
+	plat_mt_gic_cpuif_disable();
+
+	trace_power_flow(mpidr, CPU_DOWN);
+
+	if (afflvl != MPIDR_AFFLVL0) {
+		/* Disable coherency if this cluster is to be turned off */
+		plat_cci_disable();
+
+		trace_power_flow(mpidr, CLUSTER_DOWN);
+	}
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance is about to be
+ * suspended. The level and mpidr determine the affinity instance. The 'state'
+ * arg. allows the platform to decide whether the cluster is being turned off
+ * and take apt actions.
+ *
+ * CAUTION: This function is called with coherent stacks so that caches can be
+ * turned off, flushed and coherency disabled. There is no guarantee that caches
+ * will remain turned on across calls to this function as each affinity level is
+ * dealt with. So do not write & read global variables across calls. It will be
+ * wise to do flush a write to the global to prevent unpredictable results.
+ ******************************************************************************/
+static void plat_affinst_suspend(unsigned long sec_entrypoint,
+			  unsigned int afflvl,
+			  unsigned int state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+	unsigned long cluster_id;
+	unsigned long cpu_id;
+	uintptr_t rv;
+
+	/* Determine if any platform actions need to be executed. */
+	if (plat_do_plat_actions(afflvl, state) == -EAGAIN)
+		return;
+
+	cpu_id = mpidr & MPIDR_CPU_MASK;
+	cluster_id = mpidr & MPIDR_CLUSTER_MASK;
+
+	if (cluster_id)
+		rv = (uintptr_t)&mt6795_mcucfg->mp1_rv_addr[cpu_id].rv_addr_lw;
+	else
+		rv = (uintptr_t)&mt6795_mcucfg->mp0_rv_addr[cpu_id].rv_addr_lw;
+
+	mmio_write_32(rv, sec_entrypoint);
+
+	if (afflvl >= MPIDR_AFFLVL0)
+		mt_platform_save_context(mpidr);
+
+	/* Perform the common cluster specific operations */
+	if (afflvl >= MPIDR_AFFLVL1) {
+		/* Disable coherency if this cluster is to be turned off */
+		plat_cci_disable();
+		disable_scu(mpidr);
+
+		trace_power_flow(mpidr, CLUSTER_SUSPEND);
+	}
+
+	if (afflvl >= MPIDR_AFFLVL2) {
+		/* Prevent interrupts from spuriously waking up this cpu */
+		plat_mt_gic_cpuif_disable();
+	}
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance has just been powered
+ * on after being turned off earlier. The level and mpidr determine the affinity
+ * instance. The 'state' arg. allows the platform to decide whether the cluster
+ * was turned off prior to wakeup and do what's necessary to setup it up
+ * correctly.
+ ******************************************************************************/
+static void plat_affinst_on_finish(unsigned int afflvl, unsigned int state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+
+	/* Determine if any platform actions need to be executed. */
+	if (plat_do_plat_actions(afflvl, state) == -EAGAIN)
+		return;
+
+	/* Perform the common cluster specific operations */
+	if (afflvl >= MPIDR_AFFLVL1) {
+		enable_scu(mpidr);
+
+		/* Enable coherency if this cluster was off */
+		plat_cci_enable();
+		trace_power_flow(mpidr, CLUSTER_UP);
+	}
+
+	/* Enable the gic cpu interface */
+	plat_mt_gic_cpuif_enable();
+	plat_mt_gic_pcpu_init();
+	trace_power_flow(mpidr, CPU_UP);
+}
+
+/*******************************************************************************
+ * MTK_platform handler called when an affinity instance has just been powered
+ * on after having been suspended earlier. The level and mpidr determine the
+ * affinity instance.
+ ******************************************************************************/
+static void plat_affinst_suspend_finish(unsigned int afflvl, unsigned int state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+
+	/* Determine if any platform actions need to be executed. */
+	if (plat_do_plat_actions(afflvl, state) == -EAGAIN)
+		return;
+
+	if (afflvl >= MPIDR_AFFLVL2) {
+		/* Enable the gic cpu interface */
+		plat_mt_gic_init();
+		plat_mt_gic_cpuif_enable();
+	}
+
+	/* Perform the common cluster specific operations */
+	if (afflvl >= MPIDR_AFFLVL1) {
+		enable_scu(mpidr);
+
+		/* Enable coherency if this cluster was off */
+		plat_cci_enable();
+		trace_power_flow(mpidr, CLUSTER_UP);
+	}
+
+	if (afflvl >= MPIDR_AFFLVL0)
+		mt_platform_restore_context(mpidr);
+
+	plat_mt_gic_pcpu_init();
+}
+
+static unsigned int plat_get_sys_suspend_power_state(void)
+{
+	/* StateID: 0, StateType: 1(power down), PowerLevel: 2(system) */
+	return psci_make_powerstate(0, 1, 2);
+}
+
+/*******************************************************************************
+ * MTK handlers to shutdown/reboot the system
+ ******************************************************************************/
+static void __dead2 plat_system_off(void)
+{
+	INFO("MTK System Off\n");
+	wfi();
+	ERROR("MTK System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 plat_system_reset(void)
+{
+	/* Write the System Configuration Control Register */
+	INFO("MTK System Reset\n");
+
+	mmio_clrbits_32(MTK_WDT_BASE,
+		(MTK_WDT_MODE_DUAL_MODE | MTK_WDT_MODE_IRQ));
+	mmio_setbits_32(MTK_WDT_BASE, (MTK_WDT_MODE_KEY | MTK_WDT_MODE_EXTEN));
+	mmio_setbits_32(MTK_WDT_SWRST, MTK_WDT_SWRST_KEY);
+
+	wfi();
+	ERROR("MTK System Reset: operation not handled.\n");
+	panic();
+}
+
+/*******************************************************************************
+ * Export the platform handlers to enable psci to invoke them
+ ******************************************************************************/
+static const plat_pm_ops_t plat_plat_pm_ops = {
+	.affinst_standby		= plat_affinst_standby,
+	.affinst_on			= plat_affinst_on,
+	.affinst_off			= plat_affinst_off,
+	.affinst_suspend		= plat_affinst_suspend,
+	.affinst_on_finish		= plat_affinst_on_finish,
+	.affinst_suspend_finish		= plat_affinst_suspend_finish,
+	.system_off			= plat_system_off,
+	.system_reset			= plat_system_reset,
+	.get_sys_suspend_power_state	= plat_get_sys_suspend_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops & initialize the mtk_platform power
+ * controller
+ ******************************************************************************/
+int platform_setup_pm(const plat_pm_ops_t **plat_ops)
+{
+	*plat_ops = &plat_plat_pm_ops;
+	return 0;
+}
diff --git a/plat/mediatek/mt6795/plat_sip_svc.c b/plat/mediatek/mt6795/plat_sip_svc.c
new file mode 100644
index 0000000..9bb0f34
--- /dev/null
+++ b/plat/mediatek/mt6795/plat_sip_svc.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <console.h>
+#include <debug.h>
+#include <mmio.h>
+#include <mt_cpuxgpt.h>
+#include <mtk_sip_svc.h>
+#include <plat_private.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <mtk_plat_common.h>
+#include <runtime_svc.h>
+#include <xlat_tables.h>
+
+/*******************************************************************************
+ * SIP top level handler for servicing SMCs.
+ ******************************************************************************/
+uint64_t mediatek_plat_sip_handler(uint32_t smc_fid,
+				uint64_t x1,
+				uint64_t x2,
+				uint64_t x3,
+				uint64_t x4,
+				void *cookie,
+				void *handle,
+				uint64_t flags)
+{
+	uint64_t rc = 0;
+	uint32_t ns;
+
+	/* Determine which security state this SMC originated from */
+	ns = is_caller_non_secure(flags);
+
+	VERBOSE("sip_smc_handler\n");
+	VERBOSE("id=0x%x\n", smc_fid);
+	VERBOSE("x1=0x%lx, x2=0x%lx, x3=0x%lx, x4=0x%lx\n", x1, x2, x3, x4);
+
+	if (!ns) {
+		/* SiP SMC service secure world's call */
+		switch (smc_fid) {
+		default:
+			rc = SMC_UNK;
+		}
+	} else {
+		/* SiP SMC service normal world's call */
+		switch (smc_fid) {
+		default:
+			rc = SMC_UNK;
+		}
+	}
+
+	if (rc == SMC_UNK) {
+		console_init(gteearg.atf_log_port,
+			UART_CLOCK, UART_BAUDRATE);
+		ERROR("%s: unhandled NS(%d) SMC (0x%x)\n",
+			__func__, ns, smc_fid);
+		console_uninit();
+	}
+	SMC_RET1(handle, rc);
+}
diff --git a/plat/mediatek/mt6795/plat_topology.c b/plat/mediatek/mt6795/plat_topology.c
new file mode 100644
index 0000000..b1feac0
--- /dev/null
+++ b/plat/mediatek/mt6795/plat_topology.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch.h>
+#include <platform_def.h>
+#include <psci.h>
+
+unsigned int plat_get_aff_count(unsigned int aff_lvl, unsigned long mpidr)
+{
+	/* Report 1 (absent) instance at levels higher that the cluster level */
+	if (aff_lvl > MPIDR_AFFLVL1)
+		return PLATFORM_SYSTEM_COUNT;
+
+	if (aff_lvl == MPIDR_AFFLVL1)
+		return PLATFORM_CLUSTER_COUNT;
+
+	return mpidr & 0x100 ? PLATFORM_CLUSTER1_CORE_COUNT :
+			       PLATFORM_CLUSTER0_CORE_COUNT;
+}
+
+unsigned int plat_get_aff_state(unsigned int aff_lvl, unsigned long mpidr)
+{
+	return aff_lvl <= MPIDR_AFFLVL2 ? PSCI_AFF_PRESENT : PSCI_AFF_ABSENT;
+}
+
+int mt_setup_topology(void)
+{
+	/* [TODO] Make topology configurable via SCC */
+	return 0;
+}
diff --git a/plat/mediatek/mt6795/platform.mk b/plat/mediatek/mt6795/platform.mk
new file mode 100644
index 0000000..97f2e1c
--- /dev/null
+++ b/plat/mediatek/mt6795/platform.mk
@@ -0,0 +1,95 @@
+#
+# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# Neither the name of ARM nor the names of its contributors may be used
+# to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+MTK_PLAT		:=	plat/mediatek
+MTK_PLAT_SOC		:=	${MTK_PLAT}/${PLAT}
+
+# Add OEM customized codes
+OEMS				:= true
+MTK_SIP_KERNEL_BOOT_ENABLE := 1
+
+
+ifneq (${OEMS},none)
+  OEMS_INCLUDES		:= -I${MTK_PLAT}/common/custom/
+  OEMS_SOURCES		:=	${MTK_PLAT}/common/custom/oem_svc.c
+endif
+
+PLAT_INCLUDES		:=	-I${MTK_PLAT}/common/				\
+				-I${MTK_PLAT}/common/drivers/uart			\
+				-I${MTK_PLAT_SOC}/				\
+				-I${MTK_PLAT_SOC}/drivers/timer/			\
+				-I${MTK_PLAT_SOC}/include/					\
+				-Iinclude/plat/arm/common/					\
+				-Iinclude/common/tbbr/					\
+				${OEMS_INCLUDES}
+
+PLAT_BL_COMMON_SOURCES	:=	lib/aarch64/xlat_tables.c			\
+				plat/common/aarch64/plat_common.c		\
+				plat/common/plat_gic.c
+
+BL31_SOURCES		+=	drivers/arm/cci/cci.c				\
+				drivers/delay_timer/generic_delay_timer.c	\
+				drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v2/gicv2_main.c			\
+				drivers/arm/gic/v2/gicv2_helpers.c		\
+				plat/common/plat_gicv2.c			\
+				drivers/console/console.S			\
+				drivers/delay_timer/delay_timer.c		\
+				lib/cpus/aarch64/cortex_a53.S			\
+				plat/common/aarch64/platform_mp_stack.S		\
+				${MTK_PLAT_SOC}/bl31_plat_setup.c		\
+				${MTK_PLAT_SOC}/plat_mt_gic.c			\
+				${MTK_PLAT}/common/mtk_sip_svc.c		\
+				${MTK_PLAT}/common/mtk_plat_common.c		\
+				${MTK_PLAT}/common/drivers/uart/8250_console.S		\
+				${MTK_PLAT_SOC}/aarch64/plat_helpers.S		\
+				${MTK_PLAT_SOC}/drivers/timer/mt_cpuxgpt.c	\
+				${MTK_PLAT_SOC}/plat_sip_svc.c	\
+				${MTK_PLAT_SOC}/plat_delay_timer.c		\
+				${MTK_PLAT_SOC}/plat_pm.c			\
+				${MTK_PLAT_SOC}/plat_topology.c			\
+				${MTK_PLAT_SOC}/power_tracer.c			\
+				${MTK_PLAT_SOC}/scu.c		\
+				${OEMS_SOURCES}
+
+# Flag used by the MTK_platform port to determine the version of ARM GIC
+# architecture to use for interrupt management in EL3.
+ARM_GIC_ARCH		:=	2
+$(eval $(call add_define,ARM_GIC_ARCH))
+
+# Enable workarounds for selected Cortex-A53 erratas.
+ERRATA_A53_826319	:=	1
+ERRATA_A53_836870	:=	1
+
+# indicate the reset vector address can be programmed
+PROGRAMMABLE_RESET_ADDRESS	:=	1
+
+$(eval $(call add_define,MTK_SIP_KERNEL_BOOT_ENABLE))
+
diff --git a/plat/mediatek/mt6795/power_tracer.c b/plat/mediatek/mt6795/power_tracer.c
new file mode 100644
index 0000000..e6ea434
--- /dev/null
+++ b/plat/mediatek/mt6795/power_tracer.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch.h>
+#include <debug.h>
+#include <power_tracer.h>
+
+#define trace_log(...)  INFO("psci: " __VA_ARGS__)
+
+void trace_power_flow(unsigned long mpidr, unsigned char mode)
+{
+	switch (mode) {
+	case CPU_UP:
+		trace_log("core %ld:%ld ON\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS,
+			  (mpidr & MPIDR_CPU_MASK));
+		break;
+	case CPU_DOWN:
+		trace_log("core %ld:%ld OFF\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS,
+			  (mpidr & MPIDR_CPU_MASK));
+		break;
+	case CPU_SUSPEND:
+		trace_log("core %ld:%ld SUSPEND\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS,
+			  (mpidr & MPIDR_CPU_MASK));
+		break;
+	case CLUSTER_UP:
+		trace_log("cluster %ld ON\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS);
+		break;
+	case CLUSTER_DOWN:
+		trace_log("cluster %ld OFF\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS);
+		break;
+	case CLUSTER_SUSPEND:
+		trace_log("cluster %ld SUSPEND\n",
+			  (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS);
+		break;
+	default:
+		trace_log("unknown power mode\n");
+		break;
+	}
+}
diff --git a/plat/mediatek/mt6795/scu.c b/plat/mediatek/mt6795/scu.c
new file mode 100644
index 0000000..1f4ae6e
--- /dev/null
+++ b/plat/mediatek/mt6795/scu.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch.h>
+#include <mcucfg.h>
+#include <mmio.h>
+
+void disable_scu(unsigned long mpidr)
+{
+	if (mpidr & MPIDR_CLUSTER_MASK)
+		mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp1_miscdbg,
+			MP1_ACINACTM);
+	else
+		mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp0_axi_config,
+			MP0_ACINACTM);
+}
+
+void enable_scu(unsigned long mpidr)
+{
+	if (mpidr & MPIDR_CLUSTER_MASK)
+		mmio_clrbits_32((uintptr_t)&mt6795_mcucfg->mp1_miscdbg,
+			MP1_ACINACTM);
+	else
+		mmio_clrbits_32((uintptr_t)&mt6795_mcucfg->mp0_axi_config,
+			MP0_ACINACTM);
+}
diff --git a/plat/mediatek/mt8173/platform.mk b/plat/mediatek/mt8173/platform.mk
index c815110..54ca475 100644
--- a/plat/mediatek/mt8173/platform.mk
+++ b/plat/mediatek/mt8173/platform.mk
@@ -32,13 +32,13 @@
 MTK_PLAT_SOC		:=	${MTK_PLAT}/${PLAT}
 
 PLAT_INCLUDES		:=	-I${MTK_PLAT}/common/				\
+				-I${MTK_PLAT}/common/drivers/uart/		\
 				-I${MTK_PLAT_SOC}/drivers/crypt/		\
 				-I${MTK_PLAT_SOC}/drivers/mtcmos/		\
 				-I${MTK_PLAT_SOC}/drivers/pmic/			\
 				-I${MTK_PLAT_SOC}/drivers/rtc/			\
 				-I${MTK_PLAT_SOC}/drivers/spm/			\
 				-I${MTK_PLAT_SOC}/drivers/timer/		\
-				-I${MTK_PLAT_SOC}/drivers/uart/			\
 				-I${MTK_PLAT_SOC}/include/
 
 PLAT_BL_COMMON_SOURCES	:=	lib/xlat_tables/xlat_tables_common.c		\
@@ -58,6 +58,7 @@
 				lib/cpus/aarch64/cortex_a57.S			\
 				lib/cpus/aarch64/cortex_a72.S			\
 				plat/common/aarch64/platform_mp_stack.S		\
+				${MTK_PLAT}/common/drivers/uart/8250_console.S	\
 				${MTK_PLAT}/common/mtk_plat_common.c		\
 				${MTK_PLAT}/common/mtk_sip_svc.c		\
 				${MTK_PLAT_SOC}/aarch64/plat_helpers.S		\
@@ -72,7 +73,6 @@
 				${MTK_PLAT_SOC}/drivers/spm/spm_mcdi.c		\
 				${MTK_PLAT_SOC}/drivers/spm/spm_suspend.c	\
 				${MTK_PLAT_SOC}/drivers/timer/mt_cpuxgpt.c	\
-				${MTK_PLAT_SOC}/drivers/uart/8250_console.S	\
 				${MTK_PLAT_SOC}/plat_mt_gic.c			\
 				${MTK_PLAT_SOC}/plat_pm.c			\
 				${MTK_PLAT_SOC}/plat_sip_calls.c		\
diff --git a/plat/rockchip/common/include/plat_params.h b/plat/rockchip/common/include/plat_params.h
index cad4535..8c64796 100644
--- a/plat/rockchip/common/include/plat_params.h
+++ b/plat/rockchip/common/include/plat_params.h
@@ -63,11 +63,31 @@
  * alignment fault will occur during accessing its data member.
  */
 
+#define BL31_GPIO_DIR_OUT		0
+#define BL31_GPIO_DIR_IN		1
+
+#define BL31_GPIO_LEVEL_LOW		0
+#define BL31_GPIO_LEVEL_HIGH		1
+
+#define BL31_GPIO_PULL_NONE		0
+#define BL31_GPIO_PULL_UP		1
+#define BL31_GPIO_PULL_DOWN		2
+
 /* param type */
 enum {
 	PARAM_NONE = 0,
 	PARAM_RESET,
 	PARAM_POWEROFF,
+	PARAM_SUSPEND_GPIO,
+	PARAM_SUSPEND_APIO,
+};
+
+struct apio_info {
+	uint8_t apio1 : 1;
+	uint8_t apio2 : 1;
+	uint8_t apio3 : 1;
+	uint8_t apio4 : 1;
+	uint8_t apio5 : 1;
 };
 
 struct gpio_info {
@@ -88,4 +108,9 @@
 	struct gpio_info gpio;
 };
 
+struct bl31_apio_param {
+	struct bl31_plat_param h;
+	struct apio_info apio;
+};
+
 #endif /* __PLAT_PARAMS_H__ */
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
index b9b634e..ad01266 100644
--- a/plat/rockchip/common/include/plat_private.h
+++ b/plat/rockchip/common/include/plat_private.h
@@ -121,8 +121,10 @@
 
 void platform_cpu_warmboot(void);
 
-void *plat_get_rockchip_gpio_reset(void);
-void *plat_get_rockchip_gpio_poweroff(void);
+struct gpio_info *plat_get_rockchip_gpio_reset(void);
+struct gpio_info *plat_get_rockchip_gpio_poweroff(void);
+struct gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count);
+struct apio_info *plat_get_rockchip_suspend_apio(void);
 void plat_rockchip_gpio_init(void);
 
 extern const unsigned char rockchip_power_domain_tree_desc[];
diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c
index 2a49556..646c1e1 100644
--- a/plat/rockchip/common/params_setup.c
+++ b/plat/rockchip/common/params_setup.c
@@ -40,25 +40,39 @@
 #include <plat_private.h>
 #include <string.h>
 
-static struct bl31_plat_param *bl31_params_head;
-static struct bl31_gpio_param param_reset;
-static struct bl31_gpio_param param_poweroff;
+static struct gpio_info param_reset;
+static struct gpio_info param_poweroff;
+static struct bl31_apio_param param_apio;
 static struct gpio_info *rst_gpio;
 static struct gpio_info *poweroff_gpio;
+static struct gpio_info suspend_gpio[10];
+uint32_t suspend_gpio_cnt;
+static struct apio_info *suspend_apio;
 
-void *plat_get_rockchip_gpio_reset(void)
+struct gpio_info *plat_get_rockchip_gpio_reset(void)
 {
 	return rst_gpio;
 }
 
-void *plat_get_rockchip_gpio_poweroff(void)
+struct gpio_info *plat_get_rockchip_gpio_poweroff(void)
 {
 	return poweroff_gpio;
 }
 
+struct gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count)
+{
+	*count = suspend_gpio_cnt;
+
+	return &suspend_gpio[0];
+}
+
+struct apio_info *plat_get_rockchip_suspend_apio(void)
+{
+	return suspend_apio;
+}
+
 void params_early_setup(void *plat_param_from_bl2)
 {
-	struct bl31_plat_param *param;
 	struct bl31_plat_param *bl2_param;
 	struct bl31_gpio_param *gpio_param;
 
@@ -67,25 +81,38 @@
 	while (bl2_param) {
 		switch (bl2_param->type) {
 		case PARAM_RESET:
-			param = (struct bl31_plat_param *)&param_reset;
-			memcpy((void *)param, (void *)bl2_param,
-				sizeof(struct bl31_gpio_param));
-			gpio_param = (struct bl31_gpio_param *)param;
-			rst_gpio = &gpio_param->gpio;
+			gpio_param = (struct bl31_gpio_param *)bl2_param;
+			memcpy(&param_reset, &gpio_param->gpio,
+			       sizeof(struct gpio_info));
+			rst_gpio = &param_reset;
 			break;
 		case PARAM_POWEROFF:
-			param = (struct bl31_plat_param *)&param_poweroff;
-			memcpy((void *)param, (void *)bl2_param,
-				sizeof(struct bl31_gpio_param));
-			gpio_param = (struct bl31_gpio_param *)param;
-			poweroff_gpio = &gpio_param->gpio;
+			gpio_param = (struct bl31_gpio_param *)bl2_param;
+			memcpy(&param_poweroff, &gpio_param->gpio,
+				sizeof(struct gpio_info));
+			poweroff_gpio = &param_poweroff;
+			break;
+		case PARAM_SUSPEND_GPIO:
+			if (suspend_gpio_cnt >= ARRAY_SIZE(suspend_gpio)) {
+				ERROR("exceed support suspend gpio number\n");
+				break;
+			}
+			gpio_param = (struct bl31_gpio_param *)bl2_param;
+			memcpy(&suspend_gpio[suspend_gpio_cnt],
+			       &gpio_param->gpio,
+			       sizeof(struct gpio_info));
+			suspend_gpio_cnt++;
+			break;
+		case PARAM_SUSPEND_APIO:
+			memcpy(&param_apio, bl2_param,
+			       sizeof(struct bl31_apio_param));
+			suspend_apio = &param_apio.apio;
 			break;
 		default:
-			NOTICE("not expected type found\n");
-			return; /* don't continue if unexpected type found */
+			ERROR("not expected type found %ld\n",
+			      bl2_param->type);
+			break;
 		}
-		param->next = bl31_params_head;
-		bl31_params_head = param;
 		bl2_param = bl2_param->next;
 	}
 }
diff --git a/plat/rockchip/common/plat_pm.c b/plat/rockchip/common/plat_pm.c
old mode 100755
new mode 100644
index 3c2c79a..d28100d
--- a/plat/rockchip/common/plat_pm.c
+++ b/plat/rockchip/common/plat_pm.c
@@ -283,9 +283,10 @@
 		rockchip_ops->cores_pwr_dm_resume();
 	/*
 	 * Program the gic per-cpu distributor or re-distributor interface.
-	 * For sys power domain operation, resuming of the gic needs to operate in
-	 * rockchip_ops->sys_pwr_dm_resume, according to the sys power mode implements.
-	*/
+	 * For sys power domain operation, resuming of the gic needs to operate
+	 * in rockchip_ops->sys_pwr_dm_resume, according to the sys power mode
+	 * implements.
+	 */
 	plat_rockchip_gic_cpuif_enable();
 
 comm_finish:
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.c b/plat/rockchip/rk3399/drivers/dram/dram.c
index ddae84d..94aa076 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram.c
+++ b/plat/rockchip/rk3399/drivers/dram/dram.c
@@ -2147,7 +2147,7 @@
 {
 	int pll_cnt, i;
 
-	pll_cnt = sizeof(dpll_rates_table) / sizeof(struct pll_div);
+	pll_cnt = ARRAY_SIZE(dpll_rates_table);
 
 	/* Assumming rate_table is in descending order */
 	for (i = 0; i < pll_cnt; i++) {
@@ -2155,6 +2155,10 @@
 			break;
 	}
 
+	/* if mhz lower than lowest frequency in table, use lowest frequency */
+	if (i == pll_cnt)
+		i = pll_cnt - 1;
+
 	return i;
 }
 
@@ -2174,7 +2178,7 @@
 	return (24 * fbdiv) / refdiv / postdiv1 / postdiv2;
 }
 
-uint64_t ddr_get_rate(void)
+uint32_t ddr_get_rate(void)
 {
 	uint32_t refdiv, postdiv1, fbdiv, postdiv2;
 
@@ -2464,7 +2468,6 @@
 	 * target freq.
 	 */
 	dram_get_parameter(&rk3399_dram_status.timing_config, &dram_timing);
-
 	gen_rk3399_ctl_params(&rk3399_dram_status.timing_config,
 			      &dram_timing, index);
 	gen_rk3399_pi_params(&rk3399_dram_status.timing_config,
@@ -2494,7 +2497,7 @@
 		tf_printf("%u\n", p[i]);
 }
 
-uint64_t ddr_set_rate(uint64_t hz)
+uint32_t ddr_set_rate(uint32_t hz)
 {
 	uint32_t low_power, index;
 	uint32_t mhz = hz / (1000 * 1000);
@@ -2503,13 +2506,13 @@
 	    rk3399_dram_status.index_freq[rk3399_dram_status.current_index])
 		goto out;
 
+	index = to_get_clk_index(mhz);
+	mhz = dpll_rates_table[index].mhz;
+
 	low_power = exit_low_power();
 	index = prepare_ddr_timing(mhz);
-	if (index > 1) {
-		/* set timing error, quit */
-		mhz = 0;
+	if (index > 1)
 		goto out;
-	}
 
 	dcf_start(mhz, index);
 	wait_dcf_done();
@@ -2526,7 +2529,7 @@
 	return mhz;
 }
 
-uint64_t ddr_round_rate(uint64_t hz)
+uint32_t ddr_round_rate(uint32_t hz)
 {
 	int index;
 	uint32_t mhz = hz / (1000 * 1000);
@@ -2536,7 +2539,7 @@
 	return dpll_rates_table[index].mhz * 1000 * 1000;
 }
 
-uint64_t dts_timing_receive(uint64_t timing, uint64_t index)
+uint32_t dts_timing_receive(uint32_t timing, uint32_t index)
 {
 	uint32_t *p = (uint32_t *) &dts_parameter;
 	static uint32_t receive_nums;
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.h b/plat/rockchip/rk3399/drivers/dram/dram.h
index 62c5170..4f99070 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram.h
+++ b/plat/rockchip/rk3399/drivers/dram/dram.h
@@ -321,9 +321,9 @@
 #define DDR_RESTORE_SP(save_sp)   ddr_save_sp(save_sp)
 
 void ddr_init(void);
-uint64_t ddr_set_rate(uint64_t hz);
-uint64_t ddr_round_rate(uint64_t hz);
-uint64_t ddr_get_rate(void);
+uint32_t ddr_set_rate(uint32_t hz);
+uint32_t ddr_round_rate(uint32_t hz);
+uint32_t ddr_get_rate(void);
 void clr_dcf_irq(void);
-uint64_t dts_timing_receive(uint64_t timing, uint64_t index);
+uint32_t dts_timing_receive(uint32_t timing, uint32_t index);
 #endif
diff --git a/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c b/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
index eca9fbc..4995d56 100644
--- a/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
+++ b/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c
@@ -52,48 +52,105 @@
 
 #define PMU_GPIO_PORT0	0
 #define PMU_GPIO_PORT1	1
+#define GPIO_PORT2	2
+#define GPIO_PORT3	3
+#define GPIO_PORT4	4
 
 #define PMU_GRF_GPIO0A_P	0x40
 #define GRF_GPIO2A_P		0xe040
 #define GPIO_P_MASK		0x03
 
-/*
- * gpio clock disabled when not operate
- * so need to enable gpio clock before operate gpio
- * after setting, need to disable gpio clock
- * gate 1: disable clock; 0: enable clock
- */
-static void gpio_clk(int gpio, uint32_t gate)
+#define GET_GPIO_PORT(pin)	(pin / 32)
+#define GET_GPIO_NUM(pin)	(pin % 32)
+#define GET_GPIO_BANK(pin)	((pin % 32) / 8)
+#define GET_GPIO_ID(pin)	((pin % 32) % 8)
+
+/* returns old clock state, enables clock, in order to do GPIO access */
+static int gpio_get_clock(uint32_t gpio_number)
 {
-	uint32_t port = gpio / 32;
+	uint32_t port = GET_GPIO_PORT(gpio_number);
+	uint32_t clock_state = 0;
 
 	assert(port < 5);
 
 	switch (port) {
-	case 0:
+	case PMU_GPIO_PORT0:
+		clock_state = (mmio_read_32(PMUCRU_BASE +
+					    CRU_PMU_CLKGATE_CON(1)) >>
+					    PCLK_GPIO0_GATE_SHIFT) & 0x01;
 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
-			      BITS_WITH_WMASK(gate, CLK_GATE_MASK,
+			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
 					      PCLK_GPIO0_GATE_SHIFT));
 		break;
-	case 1:
+	case PMU_GPIO_PORT1:
+		clock_state = (mmio_read_32(PMUCRU_BASE +
+					    CRU_PMU_CLKGATE_CON(1)) >>
+					    PCLK_GPIO1_GATE_SHIFT) & 0x01;
 		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
-			      BITS_WITH_WMASK(gate, CLK_GATE_MASK,
+			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
 					      PCLK_GPIO1_GATE_SHIFT));
 		break;
-	case 2:
+	case GPIO_PORT2:
+		clock_state = (mmio_read_32(CRU_BASE +
+					    CRU_CLKGATE_CON(31)) >>
+					    PCLK_GPIO2_GATE_SHIFT) & 0x01;
 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
-			      BITS_WITH_WMASK(gate, CLK_GATE_MASK,
+			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
 					      PCLK_GPIO2_GATE_SHIFT));
 		break;
-	case 3:
+	case GPIO_PORT3:
+		clock_state = (mmio_read_32(CRU_BASE +
+					    CRU_CLKGATE_CON(31)) >>
+					    PCLK_GPIO3_GATE_SHIFT) & 0x01;
 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
-			      BITS_WITH_WMASK(gate, CLK_GATE_MASK,
+			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
 					      PCLK_GPIO3_GATE_SHIFT));
+		break;
+	case GPIO_PORT4:
+		clock_state = (mmio_read_32(CRU_BASE +
+					    CRU_CLKGATE_CON(31)) >>
+					    PCLK_GPIO4_GATE_SHIFT) & 0x01;
+		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			      BITS_WITH_WMASK(0, CLK_GATE_MASK,
+					      PCLK_GPIO4_GATE_SHIFT));
+		break;
+	default:
+		break;
+	}
+
+	return clock_state;
+}
+
+/* restores old state of gpio clock */
+void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state)
+{
+	uint32_t port = GET_GPIO_PORT(gpio_number);
 
+	switch (port) {
+	case PMU_GPIO_PORT0:
+		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
+			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+					      PCLK_GPIO0_GATE_SHIFT));
+		break;
+	case PMU_GPIO_PORT1:
+		mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1),
+			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+					      PCLK_GPIO1_GATE_SHIFT));
 		break;
-	case 4:
+	case GPIO_PORT2:
 		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
-			      BITS_WITH_WMASK(gate, CLK_GATE_MASK,
+			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+					      PCLK_GPIO2_GATE_SHIFT));
+		break;
+	case GPIO_PORT3:
+		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
+					      PCLK_GPIO3_GATE_SHIFT));
+
+		break;
+	case GPIO_PORT4:
+		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+			      BITS_WITH_WMASK(clock_state, CLK_GATE_MASK,
 					      PCLK_GPIO4_GATE_SHIFT));
 		break;
 	default:
@@ -101,16 +158,58 @@
 	}
 }
 
+static int get_pull(int gpio)
+{
+	uint32_t port = GET_GPIO_PORT(gpio);
+	uint32_t bank = GET_GPIO_BANK(gpio);
+	uint32_t id = GET_GPIO_ID(gpio);
+	uint32_t val, clock_state;
+
+	assert((port < 5) && (bank < 4));
+
+	clock_state = gpio_get_clock(gpio);
+
+	if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) {
+		val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P +
+				   port * 16 + bank * 4);
+		val = (val >> (id * 2)) & GPIO_P_MASK;
+	} else {
+		val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P +
+				   (port - 2) * 16 + bank * 4);
+		val = (val >> (id * 2)) & GPIO_P_MASK;
+	}
+	gpio_put_clock(gpio, clock_state);
+
+	/*
+	 * in gpio0a, gpio0b, gpio2c, gpio2d,
+	 * 00: Z
+	 * 01: pull down
+	 * 10: Z
+	 * 11: pull up
+	 * different with other gpio, so need to correct it
+	 */
+	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
+		if (val == 3)
+			val = GPIO_PULL_UP;
+		else if (val == 1)
+			val = GPIO_PULL_DOWN;
+		else
+			val = 0;
+	}
+
+	return val;
+}
+
 static void set_pull(int gpio, int pull)
 {
-	uint32_t port = gpio / 32;
-	uint32_t num = gpio % 32;
-	uint32_t bank = num / 8;
-	uint32_t id = num % 8;
+	uint32_t port = GET_GPIO_PORT(gpio);
+	uint32_t bank = GET_GPIO_BANK(gpio);
+	uint32_t id = GET_GPIO_ID(gpio);
+	uint32_t clock_state;
 
-	assert((port < 5) && (num < 32));
+	assert((port < 5) && (bank < 4));
 
-	gpio_clk(gpio, 0);
+	clock_state = gpio_get_clock(gpio);
 
 	/*
 	 * in gpio0a, gpio0b, gpio2c, gpio2d,
@@ -120,7 +219,7 @@
 	 * 11: pull up
 	 * different with other gpio, so need to correct it
 	 */
-	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 2))) {
+	if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) {
 		if (pull == GPIO_PULL_UP)
 			pull = 3;
 		else if (pull == GPIO_PULL_DOWN)
@@ -138,17 +237,18 @@
 			      (port - 2) * 16 + bank * 4,
 			      BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2));
 	}
-	gpio_clk(gpio, 1);
+	gpio_put_clock(gpio, clock_state);
 }
 
 static void set_direction(int gpio, int direction)
 {
-	uint32_t port = gpio / 32;
-	uint32_t num = gpio % 32;
+	uint32_t port = GET_GPIO_PORT(gpio);
+	uint32_t num = GET_GPIO_NUM(gpio);
+	uint32_t clock_state;
 
 	assert((port < 5) && (num < 32));
 
-	gpio_clk(gpio, 0);
+	clock_state = gpio_get_clock(gpio);
 
 	/*
 	 * in gpio.h
@@ -158,18 +258,18 @@
 	 * so need to revert direction value
 	 */
 	mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num);
-	gpio_clk(gpio, 1);
+	gpio_put_clock(gpio, clock_state);
 }
 
 static int get_direction(int gpio)
 {
-	uint32_t port = gpio / 32;
-	uint32_t num = gpio % 32;
-	int direction;
+	uint32_t port = GET_GPIO_PORT(gpio);
+	uint32_t num = GET_GPIO_NUM(gpio);
+	int direction, clock_state;
 
 	assert((port < 5) && (num < 32));
 
-	gpio_clk(gpio, 0);
+	clock_state = gpio_get_clock(gpio);
 
 	/*
 	 * in gpio.h
@@ -180,37 +280,38 @@
 	 */
 	direction = !((mmio_read_32(gpio_port[port] +
 				    SWPORTA_DDR) >> num) & 0x1);
-	gpio_clk(gpio, 1);
+	gpio_put_clock(gpio, clock_state);
 
 	return direction;
 }
 
 static int get_value(int gpio)
 {
-	uint32_t port = gpio / 32;
-	uint32_t num = gpio % 32;
-	int value;
+	uint32_t port = GET_GPIO_PORT(gpio);
+	uint32_t num = GET_GPIO_NUM(gpio);
+	int value, clock_state;
 
 	assert((port < 5) && (num < 32));
 
-	gpio_clk(gpio, 0);
+	clock_state = gpio_get_clock(gpio);
 	value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1;
-	gpio_clk(gpio, 1);
+	gpio_put_clock(gpio, clock_state);
 
 	return value;
 }
 
 static void set_value(int gpio, int value)
 {
-	uint32_t port = gpio / 32;
-	uint32_t num = gpio % 32;
+	uint32_t port = GET_GPIO_PORT(gpio);
+	uint32_t num = GET_GPIO_NUM(gpio);
+	uint32_t clock_state;
 
 	assert((port < 5) && (num < 32));
 
-	gpio_clk(gpio, 0);
+	clock_state = gpio_get_clock(gpio);
 	mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num,
 							 !!value << num);
-	gpio_clk(gpio, 0);
+	gpio_put_clock(gpio, clock_state);
 }
 
 const gpio_ops_t rk3399_gpio_ops = {
@@ -219,6 +320,7 @@
 	.get_value = get_value,
 	.set_value = set_value,
 	.set_pull = set_pull,
+	.get_pull = get_pull,
 };
 
 void plat_rockchip_gpio_init(void)
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
old mode 100755
new mode 100644
index 50953d8..07a5b1e
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -874,6 +874,190 @@
 	mmio_clrbits_32(PMU_BASE + PMU_BUS_CLR, hw_idle);
 }
 
+static uint32_t iomux_status[12];
+static uint32_t pull_mode_status[12];
+static uint32_t gpio_direction[3];
+static uint32_t gpio_2_4_clk_gate;
+
+static void suspend_apio(void)
+{
+	struct apio_info *suspend_apio;
+	int i;
+
+	suspend_apio = plat_get_rockchip_suspend_apio();
+
+	if (!suspend_apio)
+		return;
+
+	/* save gpio2 ~ gpio4 iomux and pull mode */
+	for (i = 0; i < 12; i++) {
+		iomux_status[i] = mmio_read_32(GRF_BASE +
+				GRF_GPIO2A_IOMUX + i * 4);
+		pull_mode_status[i] = mmio_read_32(GRF_BASE +
+				GRF_GPIO2A_P + i * 4);
+	}
+
+	/* store gpio2 ~ gpio4 clock gate state */
+	gpio_2_4_clk_gate = (mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)) >>
+				PCLK_GPIO2_GATE_SHIFT) & 0x07;
+
+	/* enable gpio2 ~ gpio4 clock gate */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+		      BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT));
+
+	/* save gpio2 ~ gpio4 direction */
+	gpio_direction[0] = mmio_read_32(GPIO2_BASE + 0x04);
+	gpio_direction[1] = mmio_read_32(GPIO3_BASE + 0x04);
+	gpio_direction[2] = mmio_read_32(GPIO4_BASE + 0x04);
+
+	/* apio1 charge gpio3a0 ~ gpio3c7 */
+	if (suspend_apio->apio1) {
+
+		/* set gpio3a0 ~ gpio3c7 iomux to gpio */
+		mmio_write_32(GRF_BASE + GRF_GPIO3A_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+		mmio_write_32(GRF_BASE + GRF_GPIO3B_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+		mmio_write_32(GRF_BASE + GRF_GPIO3C_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+		/* set gpio3a0 ~ gpio3c7 pull mode to pull none */
+		mmio_write_32(GRF_BASE + GRF_GPIO3A_P, REG_SOC_WMSK | 0);
+		mmio_write_32(GRF_BASE + GRF_GPIO3B_P, REG_SOC_WMSK | 0);
+		mmio_write_32(GRF_BASE + GRF_GPIO3C_P, REG_SOC_WMSK | 0);
+
+		/* set gpio3a0 ~ gpio3c7 to input */
+		mmio_clrbits_32(GPIO3_BASE + 0x04, 0x00ffffff);
+	}
+
+	/* apio2 charge gpio2a0 ~ gpio2b4 */
+	if (suspend_apio->apio2) {
+
+		/* set gpio2a0 ~ gpio2b4 iomux to gpio */
+		mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+		mmio_write_32(GRF_BASE + GRF_GPIO2B_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+		/* set gpio2a0 ~ gpio2b4 pull mode to pull none */
+		mmio_write_32(GRF_BASE + GRF_GPIO2A_P, REG_SOC_WMSK | 0);
+		mmio_write_32(GRF_BASE + GRF_GPIO2B_P, REG_SOC_WMSK | 0);
+
+		/* set gpio2a0 ~ gpio2b4 to input */
+		mmio_clrbits_32(GPIO2_BASE + 0x04, 0x00001fff);
+	}
+
+	/* apio3 charge gpio2c0 ~ gpio2d4*/
+	if (suspend_apio->apio3) {
+
+		/* set gpio2a0 ~ gpio2b4 iomux to gpio */
+		mmio_write_32(GRF_BASE + GRF_GPIO2C_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+		mmio_write_32(GRF_BASE + GRF_GPIO2D_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+		/* set gpio2c0 ~ gpio2d4 pull mode to pull none */
+		mmio_write_32(GRF_BASE + GRF_GPIO2C_P, REG_SOC_WMSK | 0);
+		mmio_write_32(GRF_BASE + GRF_GPIO2D_P, REG_SOC_WMSK | 0);
+
+		/* set gpio2c0 ~ gpio2d4 to input */
+		mmio_clrbits_32(GPIO2_BASE + 0x04, 0x1fff0000);
+	}
+
+	/* apio4 charge gpio4c0 ~ gpio4c7, gpio4d0 ~ gpio4d6 */
+	if (suspend_apio->apio4) {
+
+		/* set gpio4c0 ~ gpio4d6 iomux to gpio */
+		mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+		mmio_write_32(GRF_BASE + GRF_GPIO4D_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+		/* set gpio4c0 ~ gpio4d6 pull mode to pull none */
+		mmio_write_32(GRF_BASE + GRF_GPIO4C_P, REG_SOC_WMSK | 0);
+		mmio_write_32(GRF_BASE + GRF_GPIO4D_P, REG_SOC_WMSK | 0);
+
+		/* set gpio4c0 ~ gpio4d6 to input */
+		mmio_clrbits_32(GPIO4_BASE + 0x04, 0x7fff0000);
+	}
+
+	/* apio5 charge gpio3d0 ~ gpio3d7, gpio4a0 ~ gpio4a7*/
+	if (suspend_apio->apio5) {
+		/* set gpio3d0 ~ gpio4a7 iomux to gpio */
+		mmio_write_32(GRF_BASE + GRF_GPIO3D_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+		mmio_write_32(GRF_BASE + GRF_GPIO4A_IOMUX,
+			      REG_SOC_WMSK | GRF_IOMUX_GPIO);
+
+		/* set gpio3d0 ~ gpio4a7 pull mode to pull none */
+		mmio_write_32(GRF_BASE + GRF_GPIO3D_P, REG_SOC_WMSK | 0);
+		mmio_write_32(GRF_BASE + GRF_GPIO4A_P, REG_SOC_WMSK | 0);
+
+		/* set gpio4c0 ~ gpio4d6 to input */
+		mmio_clrbits_32(GPIO3_BASE + 0x04, 0xff000000);
+		mmio_clrbits_32(GPIO4_BASE + 0x04, 0x000000ff);
+	}
+}
+
+static void resume_apio(void)
+{
+	struct apio_info *suspend_apio;
+	int i;
+
+	suspend_apio = plat_get_rockchip_suspend_apio();
+
+	if (!suspend_apio)
+		return;
+
+	for (i = 0; i < 12; i++) {
+		mmio_write_32(GRF_BASE + GRF_GPIO2A_P + i * 4,
+			      REG_SOC_WMSK | pull_mode_status[i]);
+		mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4,
+			      REG_SOC_WMSK | iomux_status[i]);
+	}
+
+	/* set gpio2 ~ gpio4 direction back to store value */
+	mmio_write_32(GPIO2_BASE + 0x04, gpio_direction[0]);
+	mmio_write_32(GPIO3_BASE + 0x04, gpio_direction[1]);
+	mmio_write_32(GPIO4_BASE + 0x04, gpio_direction[2]);
+
+	/* set gpio2 ~ gpio4 clock gate back to store value */
+	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31),
+		      BITS_WITH_WMASK(gpio_2_4_clk_gate, 0x07,
+				      PCLK_GPIO2_GATE_SHIFT));
+}
+
+static void suspend_gpio(void)
+{
+	struct gpio_info *suspend_gpio;
+	uint32_t count;
+	int i;
+
+	suspend_gpio = plat_get_rockchip_suspend_gpio(&count);
+
+	for (i = 0; i < count; i++) {
+		gpio_set_value(suspend_gpio[i].index, suspend_gpio[i].polarity);
+		gpio_set_direction(suspend_gpio[i].index, GPIO_DIR_OUT);
+		udelay(1);
+	}
+}
+
+static void resume_gpio(void)
+{
+	struct gpio_info *suspend_gpio;
+	uint32_t count;
+	int i;
+
+	suspend_gpio = plat_get_rockchip_suspend_gpio(&count);
+
+	for (i = count - 1; i >= 0; i--) {
+		gpio_set_value(suspend_gpio[i].index,
+			       !suspend_gpio[i].polarity);
+		gpio_set_direction(suspend_gpio[i].index, GPIO_DIR_OUT);
+		udelay(1);
+	}
+}
+
 static int sys_pwr_domain_suspend(void)
 {
 	uint32_t wait_cnt = 0;
@@ -919,7 +1103,6 @@
 		}
 	}
 	mmio_setbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN));
-
 	/*
 	 * Disabling PLLs/PWM/DVFS is approaching WFI which is
 	 * the last steps in suspend.
@@ -928,6 +1111,8 @@
 	disable_dvfs_plls();
 	disable_pwms();
 	disable_nodvfs_plls();
+	suspend_apio();
+	suspend_gpio();
 
 	return 0;
 }
@@ -937,6 +1122,8 @@
 	uint32_t wait_cnt = 0;
 	uint32_t status = 0;
 
+	resume_apio();
+	resume_gpio();
 	enable_nodvfs_plls();
 	enable_pwms();
 	/* PWM regulators take time to come up; give 300us to be safe. */
@@ -952,7 +1139,6 @@
 	 * somewhere.
 	 */
 	mmio_write_32(PMU_BASE + PMU_WAKEUP_STATUS, 0xffffffff);
-
 	mmio_write_32(PMU_BASE + PMU_WKUP_CFG4, 0x00);
 
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
@@ -1003,6 +1189,9 @@
 				BIT(PMU_CLR_PERILP) |
 				BIT(PMU_CLR_PMU) |
 				BIT(PMU_CLR_GIC));
+
+	plat_rockchip_gic_cpuif_enable();
+
 	return 0;
 }
 
@@ -1010,7 +1199,7 @@
 {
 	struct gpio_info *rst_gpio;
 
-	rst_gpio = (struct gpio_info *)plat_get_rockchip_gpio_reset();
+	rst_gpio = plat_get_rockchip_gpio_reset();
 
 	if (rst_gpio) {
 		gpio_set_direction(rst_gpio->index, GPIO_DIR_OUT);
@@ -1027,7 +1216,7 @@
 {
 	struct gpio_info *poweroff_gpio;
 
-	poweroff_gpio = (struct gpio_info *)plat_get_rockchip_gpio_poweroff();
+	poweroff_gpio = plat_get_rockchip_gpio_poweroff();
 
 	if (poweroff_gpio) {
 		/*
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.h b/plat/rockchip/rk3399/drivers/pmu/pmu.h
index 65fe7db..ab2896b 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.h
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.h
@@ -875,7 +875,32 @@
 #define MAX_WAIT_COUNT		1000
 
 #define	GRF_SOC_CON4		0x0e210
-#define GRF_GPIO4C_IOMUX	0x0e028
+
+#define GRF_GPIO2A_IOMUX	0xe000
+#define GRF_GPIO2B_IOMUX	0xe004
+#define GRF_GPIO2C_IOMUX	0xe008
+#define GRF_GPIO2D_IOMUX	0xe00c
+#define GRF_GPIO3A_IOMUX	0xe010
+#define GRF_GPIO3B_IOMUX	0xe014
+#define GRF_GPIO3C_IOMUX	0xe018
+#define GRF_GPIO3D_IOMUX	0xe01c
+#define GRF_GPIO4A_IOMUX	0xe020
+#define GRF_GPIO4B_IOMUX	0xe024
+#define GRF_GPIO4C_IOMUX	0xe028
+#define GRF_GPIO4D_IOMUX	0xe02c
+
+#define GRF_GPIO2A_P		0xe040
+#define GRF_GPIO2B_P		0xe044
+#define GRF_GPIO2C_P		0xe048
+#define GRF_GPIO2D_P		0xe04C
+#define GRF_GPIO3A_P		0xe050
+#define GRF_GPIO3B_P		0xe054
+#define GRF_GPIO3C_P		0xe058
+#define GRF_GPIO3D_P		0xe05C
+#define GRF_GPIO4A_P		0xe060
+#define GRF_GPIO4B_P		0xe064
+#define GRF_GPIO4C_P		0xe068
+#define GRF_GPIO4D_P		0xe06C
 
 #define PMUGRF_GPIO0A_SMT	0x0120
 #define PMUGRF_SOC_CON0		0x0180
diff --git a/plat/rockchip/rk3399/plat_sip_calls.c b/plat/rockchip/rk3399/plat_sip_calls.c
index 6069be2..a20ee2d 100644
--- a/plat/rockchip/rk3399/plat_sip_calls.c
+++ b/plat/rockchip/rk3399/plat_sip_calls.c
@@ -31,33 +31,33 @@
 #include <runtime_svc.h>
 #include <dram.h>
 
-#define RK_SIP_DDR_CFG64	0x82000008
-#define CONFIG_DRAM_INIT	0x00
-#define CONFIG_DRAM_SET_RATE	0x01
-#define CONFIG_DRAM_ROUND_RATE	0x02
-#define CONFIG_DRAM_SET_AT_SR	0x03
-#define CONFIG_DRAM_GET_BW	0x04
-#define CONFIG_DRAM_GET_RATE	0x05
-#define CONFIG_DRAM_CLR_IRQ	0x06
-#define CONFIG_DRAM_SET_PARAM   0x07
+#define RK_SIP_DDR_CFG		0x82000008
+#define DRAM_INIT		0x00
+#define DRAM_SET_RATE		0x01
+#define DRAM_ROUND_RATE		0x02
+#define DRAM_SET_AT_SR		0x03
+#define DRAM_GET_BW		0x04
+#define DRAM_GET_RATE		0x05
+#define DRAM_CLR_IRQ		0x06
+#define DRAM_SET_PARAM		0x07
 
-uint64_t ddr_smc_handler(uint64_t arg0, uint64_t arg1, uint64_t id)
+uint32_t ddr_smc_handler(uint64_t arg0, uint64_t arg1, uint64_t id)
 {
 	switch (id) {
-	case CONFIG_DRAM_INIT:
+	case DRAM_INIT:
 		ddr_init();
 		break;
-	case CONFIG_DRAM_SET_RATE:
-		return ddr_set_rate(arg0);
-	case CONFIG_DRAM_ROUND_RATE:
-		return ddr_round_rate(arg0);
-	case CONFIG_DRAM_GET_RATE:
+	case DRAM_SET_RATE:
+		return ddr_set_rate((uint32_t)arg0);
+	case DRAM_ROUND_RATE:
+		return ddr_round_rate((uint32_t)arg0);
+	case DRAM_GET_RATE:
 		return ddr_get_rate();
-	case CONFIG_DRAM_CLR_IRQ:
+	case DRAM_CLR_IRQ:
 		clr_dcf_irq();
 		break;
-	case CONFIG_DRAM_SET_PARAM:
-		dts_timing_receive(arg0, arg1);
+	case DRAM_SET_PARAM:
+		dts_timing_receive((uint32_t)arg0, (uint32_t)arg1);
 		break;
 	default:
 		break;
@@ -76,7 +76,7 @@
 				   uint64_t flags)
 {
 	switch (smc_fid) {
-	case RK_SIP_DDR_CFG64:
+	case RK_SIP_DDR_CFG:
 		SMC_RET1(handle, ddr_smc_handler(x1, x2, x3));
 	default:
 		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
index 1ba301d..60a1605 100644
--- a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
@@ -29,6 +29,7 @@
  */
 
 #include <debug.h>
+#include <generic_delay_timer.h>
 #include <mmio.h>
 #include <platform.h>
 #include <xlat_tables.h>
@@ -89,6 +90,18 @@
 	return 100000000;
 }
 
+unsigned int zynqmp_get_silicon_id(void)
+{
+	uint32_t id;
+
+	id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
+
+	id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK;
+	id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
+
+	return id;
+}
+
 #if LOG_LEVEL >= LOG_LEVEL_NOTICE
 static const struct {
 	unsigned int id;
@@ -140,18 +153,6 @@
 	},
 };
 
-static unsigned int zynqmp_get_silicon_id(void)
-{
-	uint32_t id;
-
-	id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
-
-	id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK;
-	id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
-
-	return id;
-}
-
 static char *zynqmp_get_silicon_idcode_name(void)
 {
 	unsigned int id;
@@ -289,6 +290,8 @@
 	/* Program freq register in System counter and enable system counter. */
 	mmio_write_32(IOU_SCNTRS_BASEFREQ, zynqmp_get_system_timer_freq());
 	mmio_write_32(IOU_SCNTRS_CONTROL, IOU_SCNTRS_CONTROL_EN);
+
+	generic_delay_timer_init();
 }
 
 unsigned int plat_get_syscnt_freq2(void)
diff --git a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
index d878b86..c05b094 100644
--- a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
+++ b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
@@ -118,11 +118,31 @@
 	NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
 }
 
+/* Enable the test setup */
+#ifndef ZYNQMP_TESTING
+static void zynqmp_testing_setup(void) { }
+#else
+static void zynqmp_testing_setup(void)
+{
+	uint32_t actlr_el3, actlr_el2;
+
+	/* Enable CPU ACTLR AND L2ACTLR RW access from non-secure world */
+	actlr_el3 = read_actlr_el3();
+	actlr_el2 = read_actlr_el2();
+
+	actlr_el3 |= ACTLR_EL3_L2ACTLR_BIT | ACTLR_EL3_CPUACTLR_BIT;
+	actlr_el2 |= ACTLR_EL3_L2ACTLR_BIT | ACTLR_EL3_CPUACTLR_BIT;
+	write_actlr_el3(actlr_el3);
+	write_actlr_el2(actlr_el2);
+}
+#endif
+
 void bl31_platform_setup(void)
 {
 	/* Initialize the gic cpu and distributor interfaces */
 	plat_arm_gic_driver_init();
 	plat_arm_gic_init();
+	zynqmp_testing_setup();
 }
 
 void bl31_plat_runtime_setup(void)
diff --git a/plat/xilinx/zynqmp/include/platform_def.h b/plat/xilinx/zynqmp/include/platform_def.h
index a35bd12..3c1a9e5 100644
--- a/plat/xilinx/zynqmp/include/platform_def.h
+++ b/plat/xilinx/zynqmp/include/platform_def.h
@@ -56,8 +56,7 @@
  * little space for growth.
  */
 #ifndef ZYNQMP_ATF_MEM_BASE
-# define BL31_BASE			0xfffe5000
-# define BL31_PROGBITS_LIMIT		0xffffa000
+# define BL31_BASE			0xfffea000
 # define BL31_LIMIT			0xffffffff
 #else
 # define BL31_BASE			(ZYNQMP_ATF_MEM_BASE)
@@ -101,11 +100,7 @@
  ******************************************************************************/
 #define ADDR_SPACE_SIZE			(1ull << 32)
 #define MAX_MMAP_REGIONS		7
-#if IMAGE_BL32
-# define MAX_XLAT_TABLES		5
-#else
-# define MAX_XLAT_TABLES		4
-#endif
+#define MAX_XLAT_TABLES			5
 
 #define CACHE_WRITEBACK_SHIFT   6
 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c
index 56eb742..55227ea 100644
--- a/plat/xilinx/zynqmp/plat_psci.c
+++ b/plat/xilinx/zynqmp/plat_psci.c
@@ -147,7 +147,7 @@
 	 * invoking CPU_on function, during which resume address will
 	 * be set.
 	 */
-	pm_self_suspend(proc->node_id, MAX_LATENCY, 0, 0);
+	pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0);
 }
 
 static void zynqmp_nopmu_pwr_domain_suspend(const psci_power_state_t *target_state)
@@ -179,6 +179,7 @@
 
 static void zynqmp_pwr_domain_suspend(const psci_power_state_t *target_state)
 {
+	unsigned int state;
 	unsigned int cpu_id = plat_my_core_pos();
 	const struct pm_proc *proc = pm_get_proc(cpu_id);
 
@@ -186,15 +187,14 @@
 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
 			__func__, i, target_state->pwr_domain_state[i]);
 
+	state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ?
+		PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
+
 	/* Send request to PMU to suspend this core */
-	pm_self_suspend(proc->node_id, MAX_LATENCY, 0, zynqmp_sec_entry);
+	pm_self_suspend(proc->node_id, MAX_LATENCY, state, zynqmp_sec_entry);
 
 	/* APU is to be turned off */
 	if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
-		/* Power down L2 cache */
-		pm_set_requirement(NODE_L2, 0, 0, REQ_ACK_NO);
-		/* Send request for OCM retention state */
-		set_ocm_retention();
 		/* disable coherency */
 		plat_arm_interconnect_exit_coherency();
 	}
@@ -242,6 +242,13 @@
 
 	/* enable coherency */
 	plat_arm_interconnect_enter_coherency();
+	/* APU was turned off */
+	if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+		plat_arm_gic_init();
+	} else {
+		gicv2_cpuif_enable();
+		gicv2_pcpu_distif_init();
+	}
 }
 
 /*******************************************************************************
@@ -308,7 +315,20 @@
 {
 	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
 
+	int pstate = psci_get_pstate_type(power_state);
+
+	assert(req_state);
+
+	/* Sanity check the requested state */
+	if (pstate == PSTATE_TYPE_STANDBY)
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
+	else
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+
+	/* We expect the 'state id' to be zero */
+	if (psci_get_pstate_id(power_state))
+		return PSCI_E_INVALID_PARAMS;
+
-	/* FIXME: populate req_state */
 	return PSCI_E_SUCCESS;
 }
 
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
index 9bde5ff..33c55a0 100644
--- a/plat/xilinx/zynqmp/platform.mk
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -31,6 +31,7 @@
 PSCI_EXTENDED_STATE_ID := 1
 A53_DISABLE_NON_TEMPORAL_HINT := 0
 SEPARATE_CODE_AND_RODATA := 1
+RESET_TO_BL31 := 1
 
 ifdef ZYNQMP_ATF_MEM_BASE
     $(eval $(call add_define,ZYNQMP_ATF_MEM_BASE))
@@ -64,6 +65,8 @@
 
 PLAT_BL_COMMON_SOURCES	:=	lib/xlat_tables/xlat_tables_common.c		\
 				lib/xlat_tables/aarch64/xlat_tables.c		\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
 				drivers/arm/gic/common/gic_common.c		\
 				drivers/arm/gic/v2/gicv2_main.c			\
 				drivers/arm/gic/v2/gicv2_helpers.c		\
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
index eac7801..e859ee3 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -76,7 +76,7 @@
  * pm_self_suspend() - PM call for processor to suspend itself
  * @nid		Node id of the processor or subsystem
  * @latency	Requested maximum wakeup latency (not supported)
- * @state	Requested state (not supported)
+ * @state	Requested state
  * @address	Resume address
  *
  * This is a blocking call, it will return only once PMU has responded.
@@ -97,7 +97,7 @@
 	 * Do client specific suspend operations
 	 * (e.g. set powerdown request bit)
 	 */
-	pm_client_suspend(proc);
+	pm_client_suspend(proc, state);
 	/* Send request to the PMU */
 	PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency,
 			 state, address, (address >> 32));
@@ -476,7 +476,7 @@
 
 	/* Send request to the PMU */
 	PM_PACK_PAYLOAD4(payload, PM_MMIO_WRITE, address, mask, value);
-	return pm_ipi_send(primary_proc, payload);
+	return pm_ipi_send_sync(primary_proc, payload, NULL);
 }
 
 /**
@@ -497,3 +497,47 @@
 	PM_PACK_PAYLOAD2(payload, PM_MMIO_READ, address);
 	return pm_ipi_send_sync(primary_proc, payload, value);
 }
+
+/**
+ * pm_fpga_load() - Load the bitstream into the PL.
+ *
+ * This function provides access to the xilfpga library to load
+ * the Bit-stream into PL.
+ *
+ * address_low: lower 32-bit Linear memory space address
+ *
+ * address_high: higher 32-bit Linear memory space address
+ *
+ * size:	Number of 32bit words
+ *
+ * @return      Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_fpga_load(uint32_t address_low,
+				uint32_t address_high,
+				uint32_t size,
+				uint32_t flags)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD5(payload, PM_FPGA_LOAD, address_high, address_low,
+						size, flags);
+	return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_fpga_get_status() - Read value from fpga status register
+ * @value       Value to read
+ *
+ * This function provides access to the xilfpga library to get
+ * the fpga status
+ * @return      Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_fpga_get_status(unsigned int *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD1(payload, PM_FPGA_GET_STATUS);
+	return pm_ipi_send_sync(primary_proc, payload, value);
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
index 22bdb47..26d83e7 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
@@ -109,4 +109,10 @@
 				 unsigned int mask,
 				 unsigned int value);
 enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value);
+enum pm_ret_status pm_fpga_load(uint32_t address_high,
+				uint32_t address_low,
+				uint32_t size,
+				uint32_t flags);
+enum pm_ret_status pm_fpga_get_status(unsigned int *value);
+
 #endif /* _PM_API_SYS_H_ */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.c b/plat/xilinx/zynqmp/pm_service/pm_client.c
index cf0d5f0..b77a1cf 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_client.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_client.c
@@ -33,26 +33,25 @@
  * for getting information about and changing state of the APU.
  */
 
+#include <assert.h>
 #include <bakery_lock.h>
 #include <gicv2.h>
+#include <gic_common.h>
 #include <bl_common.h>
 #include <mmio.h>
+#include <string.h>
 #include <utils.h>
 #include "pm_api_sys.h"
 #include "pm_client.h"
 #include "pm_ipi.h"
 #include "../zynqmp_def.h"
 
-#define OCM_BANK_0	0xFFFC0000
-#define OCM_BANK_1	(OCM_BANK_0 + 0x10000)
-#define OCM_BANK_2	(OCM_BANK_1 + 0x10000)
-#define OCM_BANK_3	(OCM_BANK_2 + 0x10000)
-
+#define IRQ_MAX		84
+#define NUM_GICD_ISENABLER	((IRQ_MAX >> 5) + 1)
 #define UNDEFINED_CPUID		(~0)
+
 DEFINE_BAKERY_LOCK(pm_client_secure_lock);
 
-/* Declaration of linker defined symbol */
-extern unsigned long __BL31_END__;
 extern const struct pm_ipi apu_ipi;
 
 /* Order in pm_procs_all array must match cpu ids */
@@ -79,36 +78,146 @@
 	},
 };
 
+/* Interrupt to PM node ID map */
+static enum pm_node_id irq_node_map[IRQ_MAX + 1] = {
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,	/* 3 */
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,	/* 7 */
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,	/* 11 */
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_NAND,
+	NODE_QSPI,	/* 15 */
+	NODE_GPIO,
+	NODE_I2C_0,
+	NODE_I2C_1,
+	NODE_SPI_0,	/* 19 */
+	NODE_SPI_1,
+	NODE_UART_0,
+	NODE_UART_1,
+	NODE_CAN_0,	/* 23 */
+	NODE_CAN_1,
+	NODE_UNKNOWN,
+	NODE_RTC,
+	NODE_RTC,	/* 27 */
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,	/* 31 */
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,	/* 35, NODE_IPI_APU */
+	NODE_TTC_0,
+	NODE_TTC_0,
+	NODE_TTC_0,
+	NODE_TTC_1,	/* 39 */
+	NODE_TTC_1,
+	NODE_TTC_1,
+	NODE_TTC_2,
+	NODE_TTC_2,	/* 43 */
+	NODE_TTC_2,
+	NODE_TTC_3,
+	NODE_TTC_3,
+	NODE_TTC_3,	/* 47 */
+	NODE_SD_0,
+	NODE_SD_1,
+	NODE_SD_0,
+	NODE_SD_1,	/* 51 */
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,
+	NODE_UNKNOWN,	/* 55 */
+	NODE_UNKNOWN,
+	NODE_ETH_0,
+	NODE_ETH_0,
+	NODE_ETH_1,	/* 59 */
+	NODE_ETH_1,
+	NODE_ETH_2,
+	NODE_ETH_2,
+	NODE_ETH_3,	/* 63 */
+	NODE_ETH_3,
+	NODE_USB_0,
+	NODE_USB_0,
+	NODE_USB_0,	/* 67 */
+	NODE_USB_0,
+	NODE_USB_0,
+	NODE_USB_1,
+	NODE_USB_1,	/* 71 */
+	NODE_USB_1,
+	NODE_USB_1,
+	NODE_USB_1,
+	NODE_USB_0,	/* 75 */
+	NODE_USB_0,
+	NODE_ADMA,
+	NODE_ADMA,
+	NODE_ADMA,	/* 79 */
+	NODE_ADMA,
+	NODE_ADMA,
+	NODE_ADMA,
+	NODE_ADMA,	/* 83 */
+	NODE_ADMA,
+};
+
 /**
- * set_ocm_retention() - Configure OCM memory banks for retention
+ * irq_to_pm_node - Get PM node ID corresponding to the interrupt number
+ * @irq:	Interrupt number
  *
- * APU specific requirements for suspend action:
- * OCM has to enter retention state in order to preserve saved
- * context after suspend request. OCM banks are determined by
- * __BL31_END__ linker symbol.
- *
- * Return:	Returns status, either success or error+reason
+ * Return:	PM node ID corresponding to the specified interrupt
  */
-enum pm_ret_status set_ocm_retention(void)
+static enum pm_node_id irq_to_pm_node(unsigned int irq)
 {
-	enum pm_ret_status ret;
+	assert(irq <= IRQ_MAX);
+	return irq_node_map[irq];
+}
 
-	/* OCM_BANK_0 will always be occupied */
-	ret = pm_set_requirement(NODE_OCM_BANK_0, PM_CAP_CONTEXT, 0,
-				 REQ_ACK_NO);
+/**
+ * pm_client_set_wakeup_sources - Set all slaves with enabled interrupts as wake
+ *				sources in the PMU firmware
+ */
+static void pm_client_set_wakeup_sources(void)
+{
+	uint32_t reg_num;
+	uint8_t pm_wakeup_nodes_set[NODE_MAX];
+	uintptr_t isenabler1 = BASE_GICD_BASE + GICD_ISENABLER + 4;
 
-	/* Check for other OCM banks  */
-	if ((unsigned long)&__BL31_END__ >= OCM_BANK_1)
-		ret = pm_set_requirement(NODE_OCM_BANK_1, PM_CAP_CONTEXT, 0,
-					 REQ_ACK_NO);
-	if ((unsigned long)&__BL31_END__ >= OCM_BANK_2)
-		ret = pm_set_requirement(NODE_OCM_BANK_2, PM_CAP_CONTEXT, 0,
-					 REQ_ACK_NO);
-	if ((unsigned long)&__BL31_END__ >= OCM_BANK_3)
-		ret = pm_set_requirement(NODE_OCM_BANK_3, PM_CAP_CONTEXT, 0,
-					 REQ_ACK_NO);
+	memset(&pm_wakeup_nodes_set, 0, sizeof(pm_wakeup_nodes_set));
 
-	return ret;
+	for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) {
+		uint32_t base_irq = reg_num << ISENABLER_SHIFT;
+		uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2));
+
+		if (!reg)
+			continue;
+
+		while (reg) {
+			enum pm_node_id node;
+			uint32_t idx, ret, irq, lowest_set = reg & (-reg);
+
+			idx = __builtin_ctz(lowest_set);
+			irq = base_irq + idx;
+
+			if (irq > IRQ_MAX)
+				break;
+
+			node = irq_to_pm_node(irq);
+			reg &= ~lowest_set;
+
+			if ((node != NODE_UNKNOWN) &&
+			    (!pm_wakeup_nodes_set[node])) {
+				ret = pm_set_wakeup_source(NODE_APU, node, 1);
+				pm_wakeup_nodes_set[node] = !ret;
+			}
+		}
+	}
 }
 
 /**
@@ -162,11 +271,15 @@
  *
  * This function should contain any PU-specific actions
  * required prior to sending suspend request to PMU
+ * Actions taken depend on the state system is suspending to.
  */
-void pm_client_suspend(const struct pm_proc *proc)
+void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
 {
 	bakery_lock_get(&pm_client_secure_lock);
 
+	if (state == PM_STATE_SUSPEND_TO_RAM)
+		pm_client_set_wakeup_sources();
+
 	/* Set powerdown request */
 	mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask);
 
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.h b/plat/xilinx/zynqmp/pm_service/pm_client.h
index 9483b0d..7f80d5b 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_client.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_client.h
@@ -40,7 +40,7 @@
 #include "pm_common.h"
 
 /* Functions to be implemented by each PU */
-void pm_client_suspend(const struct pm_proc *proc);
+void pm_client_suspend(const struct pm_proc *proc, unsigned int state);
 void pm_client_abort_suspend(void);
 void pm_client_wakeup(const struct pm_proc *proc);
 enum pm_ret_status set_ocm_retention(void);
diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h
index adeec64..aec335a 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_defs.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h
@@ -53,6 +53,10 @@
 #define MAX_LATENCY	(~0U)
 #define MAX_QOS		100U
 
+/* State arguments of the self suspend */
+#define PM_STATE_CPU_IDLE		0x0U
+#define PM_STATE_SUSPEND_TO_RAM		0xFU
+
 /*********************************************************************
  * Enum definitions
  ********************************************************************/
@@ -82,6 +86,10 @@
 	PM_RESET_GET_STATUS,
 	PM_MMIO_WRITE,
 	PM_MMIO_READ,
+	PM_INIT,
+	PM_FPGA_LOAD,
+	PM_FPGA_GET_STATUS,
+	PM_GET_CHIPID,
 	PM_API_MAX
 };
 
@@ -143,6 +151,12 @@
 	NODE_IOPLL,
 	NODE_DDR,
 	NODE_IPI_APU,
+	NODE_IPI_RPU_0,
+	NODE_GPU,
+	NODE_PCIE,
+	NODE_PCAP,
+	NODE_RTC,
+	NODE_MAX
 };
 
 enum pm_request_ack {
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
index e3c25c3..9c08ffb 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
@@ -228,6 +228,22 @@
 		ret = pm_mmio_read(pm_arg[0], &value);
 		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
 	}
+
+	case PM_FPGA_LOAD:
+		ret = pm_fpga_load(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_FPGA_GET_STATUS:
+	{
+		uint32_t value;
+
+		ret = pm_fpga_get_status(&value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_GET_CHIPID:
+		SMC_RET1(handle, zynqmp_get_silicon_id());
+
 	default:
 		WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
 		SMC_RET1(handle, SMC_UNK);
diff --git a/plat/xilinx/zynqmp/zynqmp_def.h b/plat/xilinx/zynqmp/zynqmp_def.h
index 4bb332e..65bc25f 100644
--- a/plat/xilinx/zynqmp/zynqmp_def.h
+++ b/plat/xilinx/zynqmp/zynqmp_def.h
@@ -201,4 +201,8 @@
 
 #define ZYNQMP_CSU_VERSION_OFFSET	0x44
 
+/* Access control register defines */
+#define ACTLR_EL3_L2ACTLR_BIT	(1 << 6)
+#define ACTLR_EL3_CPUACTLR_BIT	(1 << 0)
+
 #endif /* __ZYNQMP_DEF_H__ */
diff --git a/plat/xilinx/zynqmp/zynqmp_private.h b/plat/xilinx/zynqmp/zynqmp_private.h
index ddef37b..abcdebc 100644
--- a/plat/xilinx/zynqmp/zynqmp_private.h
+++ b/plat/xilinx/zynqmp/zynqmp_private.h
@@ -39,6 +39,7 @@
 unsigned int zynqmp_get_uart_clk(void);
 int zynqmp_is_pmu_up(void);
 unsigned int zynqmp_get_bootmode(void);
+unsigned int zynqmp_get_silicon_id(void);
 
 /* For FSBL handover */
 void fsbl_atf_handover(entry_point_info_t *bl32_image_ep_info,
diff --git a/tools/fiptool/Makefile b/tools/fiptool/Makefile
index 3bc372a..df76a75 100644
--- a/tools/fiptool/Makefile
+++ b/tools/fiptool/Makefile
@@ -44,6 +44,7 @@
 else
   CFLAGS += -O2
 endif
+LDLIBS := -lcrypto
 
 ifeq (${V},0)
   Q := @
@@ -62,7 +63,7 @@
 
 ${PROJECT}: ${OBJECTS} Makefile
 	@echo "  LD      $@"
-	${Q}${CC} ${OBJECTS} -o $@
+	${Q}${CC} ${OBJECTS} -o $@ ${LDLIBS}
 	@${ECHO_BLANK_LINE}
 	@echo "Built $@ successfully"
 	@${ECHO_BLANK_LINE}
diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c
index 9ae4678..b3f02f6 100644
--- a/tools/fiptool/fiptool.c
+++ b/tools/fiptool/fiptool.c
@@ -42,6 +42,8 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <openssl/sha.h>
+
 #include "fiptool.h"
 #include "firmware_image_package.h"
 #include "tbbr_config.h"
@@ -354,6 +356,14 @@
 	opts[idx].val = val;
 }
 
+static void md_print(unsigned char *md, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++)
+		printf("%02x", md[i]);
+}
+
 static int info_cmd(int argc, char *argv[])
 {
 	image_t *image;
@@ -391,10 +401,16 @@
 		    (unsigned long long)image_offset,
 		    (unsigned long long)image_size);
 		if (image->toc_entry != NULL)
-			printf(", cmdline=\"--%s\"\n",
+			printf(", cmdline=\"--%s\"",
 			    image->toc_entry->cmdline_name);
-		else
-			putchar('\n');
+		if (verbose) {
+			unsigned char md[SHA256_DIGEST_LENGTH];
+
+			SHA256(image->buffer, image_size, md);
+			printf(", sha256=");
+			md_print(md, sizeof(md));
+		}
+		putchar('\n');
 		image_offset += image_size;
 	}