Merge pull request #854 from rockchip-linux/pm_plat

rockchip: plat_pm.c: Change callbacks implement for our SOCs.
diff --git a/.gitignore b/.gitignore
index c0d5183..2f9c89d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,9 @@
 # Ignore header files copied.
 tools/fiptool/firmware_image_package.h
 tools/fiptool/uuid.h
+
+# GNU GLOBAL files
+GPATH
+GRTAGS
+GSYMS
+GTAGS
diff --git a/Makefile b/Makefile
index 9e148fb..932fb3b 100644
--- a/Makefile
+++ b/Makefile
@@ -37,6 +37,11 @@
 # Default goal is build all images
 .DEFAULT_GOAL			:= all
 
+# Avoid any implicit propagation of command line variable definitions to
+# sub-Makefiles, like CFLAGS that we reserved for the firmware images'
+# usage. Other command line options like "-s" are still propagated as usual.
+MAKEOVERRIDES =
+
 MAKE_HELPERS_DIRECTORY := make_helpers/
 include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
 include ${MAKE_HELPERS_DIRECTORY}build_env.mk
@@ -111,7 +116,7 @@
 
 # Default build string (git branch and commit)
 ifeq (${BUILD_STRING},)
-        BUILD_STRING	:=	$(shell git log -n 1 --pretty=format:"%h")
+        BUILD_STRING	:=	$(shell git describe --always --dirty --tags 2> /dev/null)
 endif
 VERSION_STRING		:=	v${VERSION_MAJOR}.${VERSION_MINOR}(${BUILD_TYPE}):${BUILD_STRING}
 
@@ -346,11 +351,6 @@
         endif
 endif
 
-# Make sure PMF is enabled if PSCI STAT is enabled.
-ifeq (${ENABLE_PSCI_STAT},1)
-ENABLE_PMF			:= 1
-endif
-
 ifneq (${FIP_ALIGN},0)
 FIP_ARGS += --align ${FIP_ALIGN}
 endif
@@ -397,6 +397,9 @@
 $(eval $(call assert_boolean,TRUSTED_BOARD_BOOT))
 $(eval $(call assert_boolean,USE_COHERENT_MEM))
 
+$(eval $(call assert_numeric,ARM_ARCH_MAJOR))
+$(eval $(call assert_numeric,ARM_ARCH_MINOR))
+
 ################################################################################
 # Add definitions to the cpp preprocessor based on the current build options.
 # This is done after including the platform specific makefile to allow the
@@ -404,6 +407,8 @@
 ################################################################################
 
 $(eval $(call add_define,ARM_CCI_PRODUCT_ID))
+$(eval $(call add_define,ARM_ARCH_MAJOR))
+$(eval $(call add_define,ARM_ARCH_MINOR))
 $(eval $(call add_define,ARM_GIC_ARCH))
 $(eval $(call add_define,ASM_ASSERTION))
 $(eval $(call add_define,COLD_BOOT_SINGLE_CPU))
diff --git a/bl1/bl1.ld.S b/bl1/bl1.ld.S
index b9554d1..b69065e 100644
--- a/bl1/bl1.ld.S
+++ b/bl1/bl1.ld.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -133,7 +133,8 @@
 
     /*
      * The .bss section gets initialised to 0 at runtime.
-     * Its base address must be 16-byte aligned.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
      */
     .bss : ALIGN(16) {
         __BSS_START__ = .;
diff --git a/bl1/bl1_fwu.c b/bl1/bl1_fwu.c
index 1cc7daf..f7fae68 100644
--- a/bl1/bl1_fwu.c
+++ b/bl1/bl1_fwu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, 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:
@@ -335,7 +335,7 @@
 		 */
 		if (image_desc->state == IMAGE_STATE_COPIED) {
 			/* Clear the memory.*/
-			memset((void *)base_addr, 0, total_size);
+			zero_normalmem((void *)base_addr, total_size);
 			flush_dcache_range(base_addr, total_size);
 
 			/* Indicate that image can be copied again*/
diff --git a/bl2/aarch64/bl2_entrypoint.S b/bl2/aarch64/bl2_entrypoint.S
index 25363ac..31f7787 100644
--- a/bl2/aarch64/bl2_entrypoint.S
+++ b/bl2/aarch64/bl2_entrypoint.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -94,12 +94,12 @@
 	 */
 	ldr	x0, =__BSS_START__
 	ldr	x1, =__BSS_SIZE__
-	bl	zeromem16
+	bl	zeromem
 
 #if USE_COHERENT_MEM
 	ldr	x0, =__COHERENT_RAM_START__
 	ldr	x1, =__COHERENT_RAM_UNALIGNED_SIZE__
-	bl	zeromem16
+	bl	zeromem
 #endif
 
 	/* --------------------------------------------
diff --git a/bl2/bl2.ld.S b/bl2/bl2.ld.S
index fa694de..b9275f3 100644
--- a/bl2/bl2.ld.S
+++ b/bl2/bl2.ld.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -113,7 +113,8 @@
 
     /*
      * The .bss section gets initialised to 0 at runtime.
-     * Its base address must be 16-byte aligned.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
      */
     .bss : ALIGN(16) {
         __BSS_START__ = .;
diff --git a/bl2u/aarch64/bl2u_entrypoint.S b/bl2u/aarch64/bl2u_entrypoint.S
index 1175c6f..9fa84bf 100644
--- a/bl2u/aarch64/bl2u_entrypoint.S
+++ b/bl2u/aarch64/bl2u_entrypoint.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, 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:
@@ -94,7 +94,7 @@
 	 */
 	ldr	x0, =__BSS_START__
 	ldr	x1, =__BSS_SIZE__
-	bl	zeromem16
+	bl	zeromem
 
 	/* --------------------------------------------
 	 * Allocate a stack whose memory will be marked
diff --git a/bl2u/bl2u.ld.S b/bl2u/bl2u.ld.S
index d72589f..91e8556 100644
--- a/bl2u/bl2u.ld.S
+++ b/bl2u/bl2u.ld.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, 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:
@@ -100,7 +100,8 @@
 
     /*
      * The .bss section gets initialised to 0 at runtime.
-     * Its base address must be 16-byte aligned.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
      */
     .bss : ALIGN(16) {
         __BSS_START__ = .;
diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S
index 9a05e6c..e5d6232 100644
--- a/bl31/bl31.ld.S
+++ b/bl31/bl31.ld.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -158,7 +158,8 @@
 
     /*
      * The .bss section gets initialised to 0 at runtime.
-     * Its base address must be 16-byte aligned.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
      */
     .bss (NOLOAD) : ALIGN(16) {
         __BSS_START__ = .;
diff --git a/bl32/sp_min/sp_min.ld.S b/bl32/sp_min/sp_min.ld.S
index e0e23e8..f1d4d0b 100644
--- a/bl32/sp_min/sp_min.ld.S
+++ b/bl32/sp_min/sp_min.ld.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, 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:
@@ -134,9 +134,10 @@
 
     /*
      * The .bss section gets initialised to 0 at runtime.
-     * Its base address must be 16-byte aligned.
+     * Its base address should be 8-byte aligned for better performance of the
+     * zero-initialization code.
      */
-    .bss (NOLOAD) : ALIGN(16) {
+    .bss (NOLOAD) : ALIGN(8) {
         __BSS_START__ = .;
         *(.bss*)
         *(COMMON)
diff --git a/bl32/sp_min/sp_min_main.c b/bl32/sp_min/sp_min_main.c
index 02663a2..f34716e 100644
--- a/bl32/sp_min/sp_min_main.c
+++ b/bl32/sp_min/sp_min_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, 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:
@@ -45,6 +45,7 @@
 #include <stdint.h>
 #include <string.h>
 #include <types.h>
+#include <utils.h>
 #include "sp_min_private.h"
 
 /* Pointers to per-core cpu contexts */
@@ -203,7 +204,7 @@
 	smc_set_next_ctx(NON_SECURE);
 
 	next_smc_ctx = smc_get_next_ctx();
-	memset(next_smc_ctx, 0, sizeof(smc_ctx_t));
+	zeromem(next_smc_ctx, sizeof(smc_ctx_t));
 
 	copy_cpu_ctx_to_smc_stx(get_regs_ctx(cm_get_context(NON_SECURE)),
 			next_smc_ctx);
diff --git a/bl32/tsp/aarch64/tsp_entrypoint.S b/bl32/tsp/aarch64/tsp_entrypoint.S
index 4c296d4..bdb882a 100644
--- a/bl32/tsp/aarch64/tsp_entrypoint.S
+++ b/bl32/tsp/aarch64/tsp_entrypoint.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -120,12 +120,12 @@
 	 */
 	ldr	x0, =__BSS_START__
 	ldr	x1, =__BSS_SIZE__
-	bl	zeromem16
+	bl	zeromem
 
 #if USE_COHERENT_MEM
 	ldr	x0, =__COHERENT_RAM_START__
 	ldr	x1, =__COHERENT_RAM_UNALIGNED_SIZE__
-	bl	zeromem16
+	bl	zeromem
 #endif
 
 	/* --------------------------------------------
diff --git a/bl32/tsp/tsp.ld.S b/bl32/tsp/tsp.ld.S
index 7e24f66..d93e3bb 100644
--- a/bl32/tsp/tsp.ld.S
+++ b/bl32/tsp/tsp.ld.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -104,7 +104,8 @@
 
     /*
      * The .bss section gets initialised to 0 at runtime.
-     * Its base address must be 16-byte aligned.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
      */
     .bss : ALIGN(16) {
         __BSS_START__ = .;
diff --git a/common/bl_common.c b/common/bl_common.c
index 47bdad5..1d66530 100644
--- a/common/bl_common.c
+++ b/common/bl_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -347,7 +347,7 @@
 				 image_data->image_size);
 	if (rc != 0) {
 		/* Authentication error, zero memory and flush it right away. */
-		memset((void *)image_data->image_base, 0x00,
+		zero_normalmem((void *)image_data->image_base,
 		       image_data->image_size);
 		flush_dcache_range(image_data->image_base,
 				   image_data->image_size);
@@ -543,7 +543,7 @@
 				 image_data->image_size);
 	if (rc != 0) {
 		/* Authentication error, zero memory and flush it right away. */
-		memset((void *)image_data->image_base, 0x00,
+		zero_normalmem((void *)image_data->image_base,
 		       image_data->image_size);
 		flush_dcache_range(image_data->image_base,
 				   image_data->image_size);
diff --git a/docs/cpu-specific-build-macros.md b/docs/cpu-specific-build-macros.md
index a743487..bd7d4ed 100644
--- a/docs/cpu-specific-build-macros.md
+++ b/docs/cpu-specific-build-macros.md
@@ -58,7 +58,7 @@
 
 *   `ERRATA_A53_836870`: This applies errata 836870 workaround to Cortex-A53
      CPU. This needs to be enabled only for revision <= r0p3 of the CPU. From
-     r0p4 and onwards, this errata is enabled by default.
+     r0p4 and onwards, this errata is enabled by default in hardware.
 
 For Cortex-A57, following errata build flags are defined :
 
diff --git a/docs/firmware-design.md b/docs/firmware-design.md
index bd6e2f6..523fa55 100644
--- a/docs/firmware-design.md
+++ b/docs/firmware-design.md
@@ -16,8 +16,9 @@
 11. [Use of coherent memory in Trusted Firmware](#11--use-of-coherent-memory-in-trusted-firmware)
 12. [Isolating code and read-only data on separate memory pages](#12--isolating-code-and-read-only-data-on-separate-memory-pages)
 13. [Performance Measurement Framework](#13--performance-measurement-framework)
-14. [Code Structure](#14--code-structure)
-15. [References](#15--references)
+14. [ARMv8 Architecture Extensions](#14--armv8-architecture-extensions)
+15. [Code Structure](#15--code-structure)
+16. [References](#16--references)
 
 
 1.  Introduction
@@ -1342,7 +1343,7 @@
 
 The following linker symbols are defined for this purpose:
 
-*   `__BSS_START__`          Must be aligned on a 16-byte boundary.
+*   `__BSS_START__`
 *   `__BSS_SIZE__`
 *   `__COHERENT_RAM_START__` Must be aligned on a page-size boundary.
 *   `__COHERENT_RAM_END__`   Must be aligned on a page-size boundary.
@@ -2208,7 +2209,39 @@
 5.  `pmf_helpers.h` is an internal header used by `pmf.h`.
 
 
-14.  Code Structure
+14.  ARMv8 Architecture Extensions
+----------------------------------
+
+ARM Trusted Firmware makes use of ARMv8 Architecture Extensions where
+applicable. This section lists the usage of Architecture Extensions, and build
+flags controlling them.
+
+In general, and unless individually mentioned, the build options
+`ARM_ARCH_MAJOR` and `ARM_ARCH_MINOR` selects the Architecture Extension to
+target when building ARM Trusted Firmware. Subsequent ARM Architecture
+Extensions are backward compatible with previous versions.
+
+The build system only requires that `ARM_ARCH_MAJOR` and `ARM_ARCH_MINOR` have a
+valid numeric value. These build options only control whether or not
+Architecture Extension-specific code is included in the build. Otherwise, ARM
+Trusted Firmware targets the base ARMv8.0 architecture; i.e. as if
+`ARM_ARCH_MAJOR` == 8 and `ARM_ARCH_MINOR` == 0, which are also their respective
+default values.
+
+See also the _Summary of build options_ in [User Guide].
+
+For details on the Architecture Extension and available features, please refer
+to the respective Architecture Extension Supplement.
+
+### ARMv8.1
+
+This Architecture Extension is targeted when `ARM_ARCH_MAJOR` >= 8, or when
+`ARM_ARCH_MAJOR` == 8 and `ARM_ARCH_MINOR` >= 1.
+
+*  The Compare and Swap instruction is used to implement spinlocks. Otherwise,
+   the load-/store-exclusive instruction pair is used.
+
+15.  Code Structure
 -------------------
 
 Trusted Firmware code is logically divided between the three boot loader
@@ -2252,7 +2285,7 @@
 kernel at boot time. These can be found in the `fdts` directory.
 
 
-15.  References
+16.  References
 ---------------
 
 1.  Trusted Board Boot Requirements CLIENT PDD (ARM DEN 0006B-5). Available
diff --git a/docs/plat/nvidia-tegra.md b/docs/plat/nvidia-tegra.md
index b29532c..b45fec6 100644
--- a/docs/plat/nvidia-tegra.md
+++ b/docs/plat/nvidia-tegra.md
@@ -62,9 +62,32 @@
 Platforms wanting to use different TZDRAM_BASE, can add 'TZDRAM_BASE=<value>'
 to the build command line.
 
+The Tegra platform code expects a pointer to the following platform specific
+structure via 'x1' register from the BL2 layer which is used by the
+bl31_early_platform_setup() handler to extract the TZDRAM carveout base and
+size for loading the Trusted OS and the UART port ID to be used. The Tegra
+memory controller driver programs this base/size in order to restrict NS
+accesses.
+
+typedef struct plat_params_from_bl2 {
+	/* TZ memory size */
+	uint64_t tzdram_size;
+	/* TZ memory base */
+	uint64_t tzdram_base;
+	/* UART port ID */
+	int uart_id;
+} plat_params_from_bl2_t;
+
 Power Management
 ================
 The PSCI implementation expects each platform to expose the 'power state'
 parameter to be used during the 'SYSTEM SUSPEND' call. The state-id field
 is implementation defined on Tegra SoCs and is preferably defined by
 tegra_def.h.
+
+Tegra configs
+=============
+
+* 'tegra_enable_l2_ecc_parity_prot': This flag enables the L2 ECC and Parity
+   Protection bit, for ARM Cortex-A57 CPUs, during CPU boot. This flag will
+   be enabled by Tegrs SoCs during 'Cluster power up' or 'System Suspend' exit.
diff --git a/docs/plat/xilinx-zynqmp.md b/docs/plat/xilinx-zynqmp.md
index 09546b0..d2dc8b7 100644
--- a/docs/plat/xilinx-zynqmp.md
+++ b/docs/plat/xilinx-zynqmp.md
@@ -12,12 +12,12 @@
 
 To build:
 ```bash
-make ERROR_DEPRECATED=1 RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp bl31
+make ERROR_DEPRECATED=1 CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp bl31
 ```
 
 To build bl32 TSP you have to rebuild bl31 too:
 ```bash
-make ERROR_DEPRECATED=1 RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp SPD=tspd bl31 bl32
+make ERROR_DEPRECATED=1 CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp SPD=tspd bl31 bl32
 ```
 
 # ZynqMP platform specific build options
diff --git a/docs/porting-guide.md b/docs/porting-guide.md
index e8486f1..a5e5966 100644
--- a/docs/porting-guide.md
+++ b/docs/porting-guide.md
@@ -1707,10 +1707,56 @@
 convert the power-state parameter (possibly encoding a composite power state)
 passed in a PSCI `CPU_SUSPEND` call to this representation.
 
-The following functions must be implemented to initialize PSCI functionality in
-the ARM Trusted Firmware.
+The following functions form part of platform port of PSCI functionality.
 
 
+### Function : plat_psci_stat_accounting_start() [optional]
+
+    Argument : const psci_power_state_t *
+    Return   : void
+
+This is an optional hook that platforms can implement for residency statistics
+accounting before entering a low power state.  The `pwr_domain_state` field of
+`state_info` (first argument) can be inspected if stat accounting is done
+differently at CPU level versus higher levels.  As an example, if the element at
+index 0 (CPU power level) in the `pwr_domain_state` array indicates a power down
+state, special hardware logic may be programmed in order to keep track of the
+residency statistics.  For higher levels (array indices > 0), the residency
+statistics could be tracked in software using PMF.  If `ENABLE_PMF` is set, the
+default implementation will use PMF to capture timestamps.
+
+### Function : plat_psci_stat_accounting_stop() [optional]
+
+    Argument : const psci_power_state_t *
+    Return   : void
+
+This is an optional hook that platforms can implement for residency statistics
+accounting after exiting from a low power state.  The `pwr_domain_state` field
+of `state_info` (first argument) can be inspected if stat accounting is done
+differently at CPU level versus higher levels.  As an example, if the element at
+index 0 (CPU power level) in the `pwr_domain_state` array indicates a power down
+state, special hardware logic may be programmed in order to keep track of the
+residency statistics.  For higher levels (array indices > 0), the residency
+statistics could be tracked in software using PMF.  If `ENABLE_PMF` is set, the
+default implementation will use PMF to capture timestamps.
+
+### Function : plat_psci_stat_get_residency() [optional]
+
+    Argument : unsigned int, const psci_power_state_t *, int
+    Return   : u_register_t
+
+This is an optional interface that is is invoked after resuming from a low power
+state and provides the time spent resident in that low power state by the power
+domain at a particular power domain level.  When a CPU wakes up from suspend,
+all its parent power domain levels are also woken up.  The generic PSCI code
+invokes this function for each parent power domain that is resumed and it
+identified by the `lvl` (first argument) parameter.  The `state_info` (second
+argument) describes the low power state that the power domain has resumed from.
+The current CPU is the first CPU in the power domain to resume from the low
+power state and the `last_cpu_idx` (third parameter) is the index of the last
+CPU in the power domain to suspend and may be needed to calculate the residency
+for that power domain.
+
 ### Function : plat_get_target_pwr_state() [optional]
 
     Argument : unsigned int, const plat_local_state_t *, unsigned int
diff --git a/docs/user-guide.md b/docs/user-guide.md
index ebdb5a2..9d91c2a 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -37,6 +37,9 @@
 *   Linux kernel image
 *   Root filesystem
 
+Note: the ARM TF v1.3 release was tested with Linaro Release 16.06, and the
+latest version of ARM TF is tested with Linaro Release 16.12.
+
 This document also assumes that the user is familiar with the FVP models and
 the different command line options available to launch the model.
 
@@ -181,6 +184,14 @@
     is used to determine the number of valid slave interfaces available in the
     ARM CCI driver. Default is 400 (that is, CCI-400).
 
+*   `ARM_ARCH_MAJOR`: The major version of ARM Architecture to target when
+    compiling ARM Trusted Firmware. Its value must be numeric, and defaults to
+    8. See also, _ARMv8 Architecture Extensions_ in [Firmware Design].
+
+*   `ARM_ARCH_MINOR`: The minor version of ARM Architecture to target when
+    compiling ARM Trusted Firmware. Its value must be a numeric, and defaults
+    to 0. See also, _ARMv8 Architecture Extensions_ in [Firmware Design].
+
 *   `ARM_GIC_ARCH`: Choice of ARM GIC architecture version used by the ARM
     Legacy GIC driver for implementing the platform GIC API. This API is used
     by the interrupt management framework. Default is 2 (that is, version 2.0).
@@ -274,8 +285,9 @@
 
 *   `ENABLE_PSCI_STAT`: Boolean option to enable support for optional PSCI
      functions `PSCI_STAT_RESIDENCY` and `PSCI_STAT_COUNT`. Default is 0.
-     Enabling this option enables the `ENABLE_PMF` build option as well.
-     The PMF is used for collecting the statistics.
+     In the absence of an alternate stat collection backend, `ENABLE_PMF` must
+     be enabled. If `ENABLE_PMF` is set, the residency statistics are tracked in
+     software.
 
 *   `ENABLE_RUNTIME_INSTRUMENTATION`: Boolean option to enable runtime
     instrumentation which injects timestamp collection points into
@@ -319,8 +331,8 @@
 *   `LOAD_IMAGE_V2`: Boolean option to enable support for new version (v2) of
     image loading, which provides more flexibility and scalability around what
     images are loaded and executed during boot. Default is 0.
-    Note: `TRUSTED_BOARD_BOOT` is currently not supported when `LOAD_IMAGE_V2`
-    is enabled.
+    Note: `TRUSTED_BOARD_BOOT` is currently only supported for AArch64 when
+    `LOAD_IMAGE_V2` is enabled.
 
 *   `LOG_LEVEL`: Chooses the log level, which controls the amount of console log
     output compiled into the build. This should be one of the following:
@@ -878,8 +890,8 @@
 a single FIP binary. It assumes that a [Linaro Release][Linaro Release Notes]
 has been installed.
 
-Note currently [Linaro Release][Linaro Release Notes] only includes pre-built
-binaries for AArch64. For AArch32, pre-built binaries are not available.
+Note: Linaro Release 16.06 only includes pre-built binaries for AArch64. For
+AArch32, pre-built binaries are only available from Linaro Release 16.12.
 
 Note: follow the full instructions for one platform before switching to a
 different one. Mixing instructions for different platforms may result in
@@ -1099,19 +1111,19 @@
 9.  Running the software on FVP
 -------------------------------
 
-The AArch64 build of this version of ARM Trusted Firmware has been tested on
-the following ARM FVPs (64-bit host machine only).
+The latest version of the AArch64 build of ARM Trusted Firmware has been tested
+on the following ARM FVPs (64-bit host machine only).
 
 *   `Foundation_Platform` (Version 10.2, Build 10.2.20)
-*   `FVP_Base_AEMv8A-AEMv8A` (Version 7.7, Build 0.8.7701)
-*   `FVP_Base_Cortex-A57x4-A53x4` (Version 7.7, Build 0.8.7701)
-*   `FVP_Base_Cortex-A57x1-A53x1` (Version 7.7, Build 0.8.7701)
-*   `FVP_Base_Cortex-A57x2-A53x4` (Version 7.7, Build 0.8.7701)
+*   `FVP_Base_AEMv8A-AEMv8A` (Version 8.2, Build 0.8.8202)
+*   `FVP_Base_Cortex-A57x4-A53x4` (Version 8.2, Build 0.8.8202)
+*   `FVP_Base_Cortex-A57x1-A53x1` (Version 8.2, Build 0.8.8202)
+*   `FVP_Base_Cortex-A57x2-A53x4` (Version 8.2, Build 0.8.8202)
 
-The AArch32 build of this version of ARM Trusted Firmware has been tested on
-the following ARM FVPs (64-bit host machine only).
+The latest version of the AArch32 build of ARM Trusted Firmware has been tested
+on the following ARM FVPs (64-bit host machine only).
 
-*   `FVP_Base_AEMv8A-AEMv8A` (Version 7.7, Build 0.8.7701)
+*   `FVP_Base_AEMv8A-AEMv8A` (Version 8.2, Build 0.8.8202)
 *   `FVP_Base_Cortex-A32x4` (Version 10.1, Build 10.1.32)
 
 NOTE: The build numbers quoted above are those reported by launching the FVP
@@ -1131,6 +1143,9 @@
 parameter options. A brief description of the important ones that affect the ARM
 Trusted Firmware and normal world software behavior is provided below.
 
+Note the instructions in the following sections assume that Linaro Release 16.06
+is being used.
+
 ### Obtaining the Flattened Device Trees
 
 Depending on the FVP configuration and Linux configuration used, different
@@ -1436,12 +1451,12 @@
 
 - - - - - - - - - - - - - - - - - - - - - - - - - -
 
-_Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved._
+_Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved._
 
 
 [Firmware Design]:             firmware-design.md
 [ARM FVP website]:             https://developer.arm.com/products/system-design/fixed-virtual-platforms
-[Linaro Release Notes]:        https://community.arm.com/docs/DOC-10952#jive_content_id_Linaro_Release_1606
+[Linaro Release Notes]:        https://community.arm.com/tools/dev-platforms/b/documents/posts/linaro-release-notes-deprecated
 [ARM Platforms Portal]:        https://community.arm.com/groups/arm-development-platforms
 [Linaro SW Instructions]:      https://community.arm.com/docs/DOC-10803
 [Juno Instructions]:           https://community.arm.com/docs/DOC-10804
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.c b/drivers/auth/mbedtls/mbedtls_crypto.c
index 11d3ede..1a96e8f 100644
--- a/drivers/auth/mbedtls/mbedtls_crypto.c
+++ b/drivers/auth/mbedtls/mbedtls_crypto.c
@@ -217,7 +217,7 @@
 	}
 
 	/* Compare values */
-	rc = timingsafe_bcmp(data_hash, hash, mbedtls_md_get_size(md_info));
+	rc = memcmp(data_hash, hash, mbedtls_md_get_size(md_info));
 	if (rc != 0) {
 		return CRYPTO_ERR_HASH;
 	}
diff --git a/drivers/auth/mbedtls/mbedtls_x509_parser.c b/drivers/auth/mbedtls/mbedtls_x509_parser.c
index f9485de..092c346 100644
--- a/drivers/auth/mbedtls/mbedtls_x509_parser.c
+++ b/drivers/auth/mbedtls/mbedtls_x509_parser.c
@@ -43,6 +43,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <string.h>
+#include <utils.h>
 
 /* mbed TLS headers */
 #include <mbedtls/asn1.h>
@@ -71,7 +72,7 @@
 {
 #define ZERO_AND_CLEAN(x)					\
 	do {							\
-		memset(&x, 0, sizeof(x));			\
+		zeromem(&x, sizeof(x));				\
 		clean_dcache_range((uintptr_t)&x, sizeof(x));	\
 	} while (0);
 
@@ -111,7 +112,7 @@
 			     MBEDTLS_ASN1_SEQUENCE);
 
 	while (p < end) {
-		memset(&extn_oid, 0x0, sizeof(extn_oid));
+		zeromem(&extn_oid, sizeof(extn_oid));
 		is_critical = 0; /* DEFAULT FALSE */
 
 		mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
@@ -392,7 +393,7 @@
 	if (sig_alg1.len != sig_alg2.len) {
 		return IMG_PARSER_ERR_FORMAT;
 	}
-	if (0 != timingsafe_bcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) {
+	if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) {
 		return IMG_PARSER_ERR_FORMAT;
 	}
 	memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg));
diff --git a/drivers/emmc/emmc.c b/drivers/emmc/emmc.c
index 3fae2a1..1c1ea82 100644
--- a/drivers/emmc/emmc.c
+++ b/drivers/emmc/emmc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, 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:
@@ -36,6 +36,7 @@
 #include <emmc.h>
 #include <errno.h>
 #include <string.h>
+#include <utils.h>
 
 static const emmc_ops_t *ops;
 static unsigned int emmc_ocr_value;
@@ -53,7 +54,7 @@
 	int ret;
 
 	do {
-		memset(&cmd, 0, sizeof(emmc_cmd_t));
+		zeromem(&cmd, sizeof(emmc_cmd_t));
 		cmd.cmd_idx = EMMC_CMD13;
 		cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET;
 		cmd.resp_type = EMMC_RESPONSE_R1;
@@ -71,7 +72,7 @@
 	emmc_cmd_t cmd;
 	int ret, state;
 
-	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	zeromem(&cmd, sizeof(emmc_cmd_t));
 	cmd.cmd_idx = EMMC_CMD6;
 	cmd.cmd_arg = EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) |
 		      EXTCSD_VALUE(value) | 1;
@@ -107,14 +108,14 @@
 	ops->init();
 
 	/* CMD0: reset to IDLE */
-	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	zeromem(&cmd, sizeof(emmc_cmd_t));
 	cmd.cmd_idx = EMMC_CMD0;
 	ret = ops->send_cmd(&cmd);
 	assert(ret == 0);
 
 	while (1) {
 		/* CMD1: get OCR register */
-		memset(&cmd, 0, sizeof(emmc_cmd_t));
+		zeromem(&cmd, sizeof(emmc_cmd_t));
 		cmd.cmd_idx = EMMC_CMD1;
 		cmd.cmd_arg = OCR_SECTOR_MODE | OCR_VDD_MIN_2V7 |
 			      OCR_VDD_MIN_1V7;
@@ -127,14 +128,14 @@
 	}
 
 	/* CMD2: Card Identification */
-	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	zeromem(&cmd, sizeof(emmc_cmd_t));
 	cmd.cmd_idx = EMMC_CMD2;
 	cmd.resp_type = EMMC_RESPONSE_R2;
 	ret = ops->send_cmd(&cmd);
 	assert(ret == 0);
 
 	/* CMD3: Set Relative Address */
-	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	zeromem(&cmd, sizeof(emmc_cmd_t));
 	cmd.cmd_idx = EMMC_CMD3;
 	cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET;
 	cmd.resp_type = EMMC_RESPONSE_R1;
@@ -142,7 +143,7 @@
 	assert(ret == 0);
 
 	/* CMD9: CSD Register */
-	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	zeromem(&cmd, sizeof(emmc_cmd_t));
 	cmd.cmd_idx = EMMC_CMD9;
 	cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET;
 	cmd.resp_type = EMMC_RESPONSE_R2;
@@ -151,7 +152,7 @@
 	memcpy(&emmc_csd, &cmd.resp_data, sizeof(cmd.resp_data));
 
 	/* CMD7: Select Card */
-	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	zeromem(&cmd, sizeof(emmc_cmd_t));
 	cmd.cmd_idx = EMMC_CMD7;
 	cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET;
 	cmd.resp_type = EMMC_RESPONSE_R1;
@@ -181,7 +182,7 @@
 	assert(ret == 0);
 
 	if (is_cmd23_enabled()) {
-		memset(&cmd, 0, sizeof(emmc_cmd_t));
+		zeromem(&cmd, sizeof(emmc_cmd_t));
 		/* set block count */
 		cmd.cmd_idx = EMMC_CMD23;
 		cmd.cmd_arg = size / EMMC_BLOCK_SIZE;
@@ -189,7 +190,7 @@
 		ret = ops->send_cmd(&cmd);
 		assert(ret == 0);
 
-		memset(&cmd, 0, sizeof(emmc_cmd_t));
+		zeromem(&cmd, sizeof(emmc_cmd_t));
 		cmd.cmd_idx = EMMC_CMD18;
 	} else {
 		if (size > EMMC_BLOCK_SIZE)
@@ -213,7 +214,7 @@
 
 	if (is_cmd23_enabled() == 0) {
 		if (size > EMMC_BLOCK_SIZE) {
-			memset(&cmd, 0, sizeof(emmc_cmd_t));
+			zeromem(&cmd, sizeof(emmc_cmd_t));
 			cmd.cmd_idx = EMMC_CMD12;
 			ret = ops->send_cmd(&cmd);
 			assert(ret == 0);
@@ -240,17 +241,17 @@
 
 	if (is_cmd23_enabled()) {
 		/* set block count */
-		memset(&cmd, 0, sizeof(emmc_cmd_t));
+		zeromem(&cmd, sizeof(emmc_cmd_t));
 		cmd.cmd_idx = EMMC_CMD23;
 		cmd.cmd_arg = size / EMMC_BLOCK_SIZE;
 		cmd.resp_type = EMMC_RESPONSE_R1;
 		ret = ops->send_cmd(&cmd);
 		assert(ret == 0);
 
-		memset(&cmd, 0, sizeof(emmc_cmd_t));
+		zeromem(&cmd, sizeof(emmc_cmd_t));
 		cmd.cmd_idx = EMMC_CMD25;
 	} else {
-		memset(&cmd, 0, sizeof(emmc_cmd_t));
+		zeromem(&cmd, sizeof(emmc_cmd_t));
 		if (size > EMMC_BLOCK_SIZE)
 			cmd.cmd_idx = EMMC_CMD25;
 		else
@@ -272,7 +273,7 @@
 
 	if (is_cmd23_enabled() == 0) {
 		if (size > EMMC_BLOCK_SIZE) {
-			memset(&cmd, 0, sizeof(emmc_cmd_t));
+			zeromem(&cmd, sizeof(emmc_cmd_t));
 			cmd.cmd_idx = EMMC_CMD12;
 			ret = ops->send_cmd(&cmd);
 			assert(ret == 0);
@@ -291,21 +292,21 @@
 	assert(ops != 0);
 	assert((size != 0) && ((size % EMMC_BLOCK_SIZE) == 0));
 
-	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	zeromem(&cmd, sizeof(emmc_cmd_t));
 	cmd.cmd_idx = EMMC_CMD35;
 	cmd.cmd_arg = lba;
 	cmd.resp_type = EMMC_RESPONSE_R1;
 	ret = ops->send_cmd(&cmd);
 	assert(ret == 0);
 
-	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	zeromem(&cmd, sizeof(emmc_cmd_t));
 	cmd.cmd_idx = EMMC_CMD36;
 	cmd.cmd_arg = lba + (size / EMMC_BLOCK_SIZE) - 1;
 	cmd.resp_type = EMMC_RESPONSE_R1;
 	ret = ops->send_cmd(&cmd);
 	assert(ret == 0);
 
-	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	zeromem(&cmd, sizeof(emmc_cmd_t));
 	cmd.cmd_idx = EMMC_CMD38;
 	cmd.resp_type = EMMC_RESPONSE_R1B;
 	ret = ops->send_cmd(&cmd);
diff --git a/drivers/io/io_block.c b/drivers/io/io_block.c
index 4ec59bc..a855581 100644
--- a/drivers/io/io_block.c
+++ b/drivers/io/io_block.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, 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:
@@ -36,6 +36,7 @@
 #include <io_storage.h>
 #include <platform_def.h>
 #include <string.h>
+#include <utils.h>
 
 typedef struct {
 	io_block_dev_spec_t	*dev_spec;
@@ -135,8 +136,8 @@
 	result = find_first_block_state(state->dev_spec, &index);
 	if (result ==  0) {
 		/* free if device info is valid */
-		memset(state, 0, sizeof(block_dev_state_t));
-		memset(dev_info, 0, sizeof(io_dev_info_t));
+		zeromem(state, sizeof(block_dev_state_t));
+		zeromem(dev_info, sizeof(io_dev_info_t));
 		--block_dev_count;
 	}
 
diff --git a/drivers/io/io_fip.c b/drivers/io/io_fip.c
index 99cf15b..6724fc3 100644
--- a/drivers/io/io_fip.c
+++ b/drivers/io/io_fip.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, 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:
@@ -40,6 +40,7 @@
 #include <platform_def.h>
 #include <stdint.h>
 #include <string.h>
+#include <utils.h>
 #include <uuid.h>
 
 /* Useful for printing UUIDs when debugging.*/
@@ -351,7 +352,7 @@
 	 * If we had malloc() we would free() here.
 	 */
 	if (current_file.entry.offset_address != 0) {
-		memset(&current_file, 0, sizeof(current_file));
+		zeromem(&current_file, sizeof(current_file));
 	}
 
 	/* Clear the Entity info. */
diff --git a/drivers/io/io_memmap.c b/drivers/io/io_memmap.c
index fe39652..a97df6b 100644
--- a/drivers/io/io_memmap.c
+++ b/drivers/io/io_memmap.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, 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:
@@ -33,6 +33,7 @@
 #include <io_driver.h>
 #include <io_storage.h>
 #include <string.h>
+#include <utils.h>
 
 /* As we need to be able to keep state for seek, only one file can be open
  * at a time. Make this a structure and point to the entity->info. When we
@@ -118,7 +119,6 @@
 
 
 /* Open a file on the memmap device */
-/* TODO: Can we do any sensible limit checks on requested memory */
 static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
 			     io_entity_t *entity)
 {
@@ -152,13 +152,19 @@
 static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
 {
 	int result = -ENOENT;
+	file_state_t *fp;
 
 	/* We only support IO_SEEK_SET for the moment. */
 	if (mode == IO_SEEK_SET) {
 		assert(entity != NULL);
 
-		/* TODO: can we do some basic limit checks on seek? */
-		((file_state_t *)entity->info)->file_pos = offset;
+		fp = (file_state_t *) entity->info;
+
+		/* Assert that new file position is valid */
+		assert((offset >= 0) && (offset < fp->size));
+
+		/* Reset file position */
+		fp->file_pos = offset;
 		result = 0;
 	}
 
@@ -183,18 +189,24 @@
 			     size_t length, size_t *length_read)
 {
 	file_state_t *fp;
+	size_t pos_after;
 
 	assert(entity != NULL);
 	assert(buffer != (uintptr_t)NULL);
 	assert(length_read != NULL);
 
-	fp = (file_state_t *)entity->info;
+	fp = (file_state_t *) entity->info;
+
+	/* Assert that file position is valid for this read operation */
+	pos_after = fp->file_pos + length;
+	assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
 
 	memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length);
 
 	*length_read = length;
-	/* advance the file 'cursor' for incremental reads */
-	fp->file_pos += length;
+
+	/* Set file position after read */
+	fp->file_pos = pos_after;
 
 	return 0;
 }
@@ -205,19 +217,24 @@
 			      size_t length, size_t *length_written)
 {
 	file_state_t *fp;
+	size_t pos_after;
 
 	assert(entity != NULL);
 	assert(buffer != (uintptr_t)NULL);
 	assert(length_written != NULL);
 
-	fp = (file_state_t *)entity->info;
+	fp = (file_state_t *) entity->info;
+
+	/* Assert that file position is valid for this write operation */
+	pos_after = fp->file_pos + length;
+	assert((pos_after >= fp->file_pos) && (pos_after <= fp->size));
 
 	memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length);
 
 	*length_written = length;
 
-	/* advance the file 'cursor' for incremental writes */
-	fp->file_pos += length;
+	/* Set file position after write */
+	fp->file_pos = pos_after;
 
 	return 0;
 }
@@ -231,7 +248,7 @@
 	entity->info = 0;
 
 	/* This would be a mem free() if we had malloc.*/
-	memset((void *)&current_file, 0, sizeof(current_file));
+	zeromem((void *)&current_file, sizeof(current_file));
 
 	return 0;
 }
diff --git a/drivers/io/io_semihosting.c b/drivers/io/io_semihosting.c
index 30ca99c..e33a044 100644
--- a/drivers/io/io_semihosting.c
+++ b/drivers/io/io_semihosting.c
@@ -95,7 +95,7 @@
 		const uintptr_t spec, io_entity_t *entity)
 {
 	int result = -ENOENT;
-	long sh_result = -1;
+	long sh_result;
 	const io_file_spec_t *file_spec = (const io_file_spec_t *)spec;
 
 	assert(file_spec != NULL);
@@ -151,7 +151,7 @@
 		size_t *length_read)
 {
 	int result = -ENOENT;
-	long sh_result = -1;
+	long sh_result;
 	size_t bytes = length;
 	long file_handle;
 
@@ -176,7 +176,7 @@
 static int sh_file_write(io_entity_t *entity, const uintptr_t buffer,
 		size_t length, size_t *length_written)
 {
-	long sh_result = -1;
+	long sh_result;
 	long file_handle;
 	size_t bytes = length;
 
@@ -197,7 +197,7 @@
 /* Close a file on the semi-hosting device */
 static int sh_file_close(io_entity_t *entity)
 {
-	long sh_result = -1;
+	long sh_result;
 	long file_handle;
 
 	assert(entity != NULL);
diff --git a/drivers/partition/gpt.c b/drivers/partition/gpt.c
index 9240d5a..05f13f3 100644
--- a/drivers/partition/gpt.c
+++ b/drivers/partition/gpt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, 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:
@@ -33,6 +33,7 @@
 #include <errno.h>
 #include <gpt.h>
 #include <string.h>
+#include <utils.h>
 
 static int unicode_to_ascii(unsigned short *str_in, unsigned char *str_out)
 {
@@ -65,7 +66,7 @@
 		return -EINVAL;
 	}
 
-	memset(entry, 0, sizeof(partition_entry_t));
+	zeromem(entry, sizeof(partition_entry_t));
 	result = unicode_to_ascii(gpt_entry->name, (uint8_t *)entry->name);
 	if (result != 0) {
 		return result;
diff --git a/include/common/aarch32/el3_common_macros.S b/include/common/aarch32/el3_common_macros.S
index 463a080..f6b7527 100644
--- a/include/common/aarch32/el3_common_macros.S
+++ b/include/common/aarch32/el3_common_macros.S
@@ -98,6 +98,11 @@
 	orr	r0, r0, #FPEXC_EN_BIT
 	vmsr	FPEXC, r0
 	isb
+
+	/* Disable secure self-hosted invasive debug. */
+	ldr	r0, =SDCR_DEF_VAL
+	stcopr	r0, SDCR
+
 	.endm
 
 /* -----------------------------------------------------------------------------
diff --git a/include/common/aarch64/el3_common_macros.S b/include/common/aarch64/el3_common_macros.S
index cbfa6ee..e085f9f 100644
--- a/include/common/aarch64/el3_common_macros.S
+++ b/include/common/aarch64/el3_common_macros.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, 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:
@@ -79,10 +79,11 @@
 	msr	scr_el3, x0
 
 	/* ---------------------------------------------------------------------
-	 * Reset registers that may have architecturally unknown reset values
+	 * Disable secure self-hosted invasive debug.
 	 * ---------------------------------------------------------------------
 	 */
-	msr	mdcr_el3, xzr
+	mov_imm	x0, MDCR_DEF_VAL
+	msr	mdcr_el3, x0
 
 	/* ---------------------------------------------------------------------
 	 * Enable External Aborts and SError Interrupts now that the exception
@@ -252,12 +253,12 @@
 
 		ldr	x0, =__BSS_START__
 		ldr	x1, =__BSS_SIZE__
-		bl	zeromem16
+		bl	zeromem
 
 #if USE_COHERENT_MEM
 		ldr	x0, =__COHERENT_RAM_START__
 		ldr	x1, =__COHERENT_RAM_UNALIGNED_SIZE__
-		bl	zeromem16
+		bl	zeromem
 #endif
 
 #ifdef IMAGE_BL1
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h
index 170fa84..8525c7b 100644
--- a/include/lib/aarch32/arch.h
+++ b/include/lib/aarch32/arch.h
@@ -125,6 +125,14 @@
 #define SCTLR_AFE_BIT		(1 << 29)
 #define SCTLR_TE_BIT		(1 << 30)
 
+/* SDCR definitions */
+#define SDCR_SPD(x)		((x) << 14)
+#define SDCR_SPD_LEGACY		0x0
+#define SDCR_SPD_DISABLE	0x2
+#define SDCR_SPD_ENABLE		0x3
+
+#define SDCR_DEF_VAL		SDCR_SPD(SDCR_SPD_DISABLE)
+
 /* HSCTLR definitions */
 #define HSCTLR_RES1 	((1 << 29) | (1 << 28) | (1 << 23) | (1 << 22)	\
 			| (1 << 18) | (1 << 16) | (1 << 11) | (1 << 4)	\
@@ -345,6 +353,7 @@
 /* System register defines The format is: coproc, opt1, CRn, CRm, opt2 */
 #define SCR		p15, 0, c1, c1, 0
 #define SCTLR		p15, 0, c1, c0, 0
+#define SDCR		p15, 0, c1, c3, 1
 #define MPIDR		p15, 0, c0, c0, 5
 #define MIDR		p15, 0, c0, c0, 0
 #define VBAR		p15, 0, c12, c0, 0
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 3f71824..5876ce8 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -195,6 +195,15 @@
 #define SCR_NS_BIT		(1 << 0)
 #define SCR_VALID_BIT_MASK	0x2f8f
 
+/* MDCR definitions */
+#define MDCR_SPD32(x)		((x) << 14)
+#define MDCR_SPD32_LEGACY	0x0
+#define MDCR_SPD32_DISABLE	0x2
+#define MDCR_SPD32_ENABLE	0x3
+#define MDCR_SDD_BIT		(1 << 16)
+
+#define MDCR_DEF_VAL		(MDCR_SDD_BIT | MDCR_SPD32(MDCR_SPD32_DISABLE))
+
 /* HCR definitions */
 #define HCR_RW_BIT		(1ull << 31)
 #define HCR_AMO_BIT		(1 << 5)
diff --git a/include/lib/cpus/aarch64/cortex_a57.h b/include/lib/cpus/aarch64/cortex_a57.h
index c5a218b..9229a56 100644
--- a/include/lib/cpus/aarch64/cortex_a57.h
+++ b/include/lib/cpus/aarch64/cortex_a57.h
@@ -87,6 +87,8 @@
 #define L2_DATA_RAM_LATENCY_3_CYCLES	0x2
 #define L2_TAG_RAM_LATENCY_3_CYCLES	0x2
 
+#define L2_ECC_PARITY_PROTECTION_BIT	(1 << 21)
+
 /*******************************************************************************
  * L2 Extended Control register specific definitions.
  ******************************************************************************/
diff --git a/include/lib/cpus/aarch64/denver.h b/include/lib/cpus/aarch64/denver.h
index c7bee80..e083533 100644
--- a/include/lib/cpus/aarch64/denver.h
+++ b/include/lib/cpus/aarch64/denver.h
@@ -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:
@@ -31,10 +31,24 @@
 #ifndef __DENVER_H__
 #define __DENVER_H__
 
-/* MIDR for Denver v1.0 */
-#define DENVER_1_0_MIDR			0x4E0F0000
+/* MIDR values for Denver */
+#define DENVER_MIDR_PN0			0x4E0F0000
+#define DENVER_MIDR_PN1			0x4E0F0010
+#define DENVER_MIDR_PN2			0x4E0F0020
+#define DENVER_MIDR_PN3			0x4E0F0030
+#define DENVER_MIDR_PN4			0x4E0F0040
+
+/* Implementer code in the MIDR register */
+#define DENVER_IMPL			0x4E
 
 /* CPU state ids - implementation defined */
 #define DENVER_CPU_STATE_POWER_DOWN	0x3
 
+#ifndef __ASSEMBLY__
+
+/* Disable Dynamic Code Optimisation */
+void denver_disable_dco(void);
+
+#endif
+
 #endif /* __DENVER_H__ */
diff --git a/include/lib/pmf/pmf.h b/include/lib/pmf/pmf.h
index 7c33387..d5415f4 100644
--- a/include/lib/pmf/pmf.h
+++ b/include/lib/pmf/pmf.h
@@ -37,13 +37,13 @@
 /*
  * Constants used for/by PMF services.
  */
-#define PMF_ARM_TIF_IMPL_ID	(0x41000000)
+#define PMF_ARM_TIF_IMPL_ID	0x41
 #define PMF_TID_SHIFT		0
 #define PMF_TID_MASK		(0xFF << PMF_TID_SHIFT)
 #define PMF_SVC_ID_SHIFT	10
 #define PMF_SVC_ID_MASK		(0x3F << PMF_SVC_ID_SHIFT)
 #define PMF_IMPL_ID_SHIFT	24
-#define PMF_IMPL_ID_MASK	(0xFF << PMF_IMPL_ID_SHIFT)
+#define PMF_IMPL_ID_MASK	(0xFFU << PMF_IMPL_ID_SHIFT)
 
 /*
  * Flags passed to PMF_REGISTER_SERVICE
diff --git a/include/lib/stdlib/string.h b/include/lib/stdlib/string.h
index 902d9c1..56677b2 100644
--- a/include/lib/stdlib/string.h
+++ b/include/lib/stdlib/string.h
@@ -52,6 +52,7 @@
 void	*memchr(const void *, int, size_t) __pure;
 int	 memcmp(const void *, const void *, size_t) __pure;
 void	*memcpy(void * __restrict, const void * __restrict, size_t);
+void	*memcpy16(void * __restrict, const void * __restrict, size_t);
 void	*memmove(void *, const void *, size_t);
 void	*memset(void *, int, size_t);
 
diff --git a/include/lib/utils.h b/include/lib/utils.h
index b6bc9af..69bbb43 100644
--- a/include/lib/utils.h
+++ b/include/lib/utils.h
@@ -80,4 +80,35 @@
 # define ULL(_x)	(_x##ull)
 #endif
 
+/*
+ * C code should be put in this part of the header to avoid breaking ASM files
+ * or linker scripts including it.
+ */
+#if !(defined(__LINKER__) || defined(__ASSEMBLY__))
+
+#include <types.h>
+
+/*
+ * Fill a region of normal memory of size "length" in bytes with zero bytes.
+ *
+ * WARNING: This function can only operate on normal memory. This means that
+ *          the MMU must be enabled when using this function. Otherwise, use
+ *          zeromem.
+ */
+void zero_normalmem(void *mem, u_register_t length);
+
+/*
+ * Fill a region of memory of size "length" in bytes with null bytes.
+ *
+ * Unlike zero_normalmem, this function has no restriction on the type of
+ * memory targeted and can be used for any device memory as well as normal
+ * memory. This function must be used instead of zero_normalmem when MMU is
+ * disabled.
+ *
+ * NOTE: When data cache and MMU are enabled, prefer zero_normalmem for faster
+ *       zeroing.
+ */
+void zeromem(void *mem, u_register_t length);
+#endif /* !(defined(__LINKER__) || defined(__ASSEMBLY__)) */
+
 #endif /* __UTILS_H__ */
diff --git a/include/plat/arm/css/common/css_def.h b/include/plat/arm/css/common/css_def.h
index a2fe0d5..7cfaf59 100644
--- a/include/plat/arm/css/common/css_def.h
+++ b/include/plat/arm/css/common/css_def.h
@@ -101,6 +101,13 @@
 #define SSC_VERSION_DESIGNER_ID_MASK		0xff
 #define SSC_VERSION_PART_NUM_MASK		0xfff
 
+/* SSC debug configuration registers */
+#define SSC_DBGCFG_SET		0x14
+#define SSC_DBGCFG_CLR		0x18
+
+#define SPIDEN_INT_CLR_SHIFT	6
+#define SPIDEN_SEL_SET_SHIFT	7
+
 #ifndef __ASSEMBLY__
 
 /* SSC_VERSION related accessors */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index f904292..73bb643 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -254,6 +254,11 @@
 /*******************************************************************************
  * Optional PSCI functions (BL31).
  ******************************************************************************/
+void plat_psci_stat_accounting_start(const psci_power_state_t *state_info);
+void plat_psci_stat_accounting_stop(const psci_power_state_t *state_info);
+u_register_t plat_psci_stat_get_residency(unsigned int lvl,
+			const psci_power_state_t *state_info,
+			int last_cpu_index);
 plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
 			const plat_local_state_t *states,
 			unsigned int ncpu);
diff --git a/lib/aarch32/misc_helpers.S b/lib/aarch32/misc_helpers.S
index bf4084a..dc84799 100644
--- a/lib/aarch32/misc_helpers.S
+++ b/lib/aarch32/misc_helpers.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, 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:
@@ -34,6 +34,7 @@
 
 	.globl	smc
 	.globl	zeromem
+	.globl	zero_normalmem
 	.globl	memcpy4
 	.globl	disable_mmu_icache_secure
 	.globl	disable_mmu_secure
@@ -50,30 +51,108 @@
 endfunc smc
 
 /* -----------------------------------------------------------------------
- * void zeromem(void *mem, unsigned int length);
+ * void zeromem(void *mem, unsigned int length)
  *
- * Initialise a memory region to 0.
- * The memory address and length must be 4-byte aligned.
+ * Initialise a region in normal memory to 0. This functions complies with the
+ * AAPCS and can be called from C code.
+ *
  * -----------------------------------------------------------------------
  */
 func zeromem
-#if ASM_ASSERTION
-	tst	r0, #0x3
-	ASM_ASSERT(eq)
-	tst	r1, #0x3
-	ASM_ASSERT(eq)
-#endif
-	add	r2, r0, r1
-	mov	r1, #0
-z_loop:
-	cmp	r2, r0
-	beq	z_end
-	str	r1, [r0], #4
-	b	z_loop
-z_end:
+	/*
+	 * Readable names for registers
+	 *
+	 * Registers r0, r1 and r2 are also set by zeromem which
+	 * branches into the fallback path directly, so cursor, length and
+	 * stop_address should not be retargeted to other registers.
+	 */
+	cursor       .req r0 /* Start address and then current address */
+	length       .req r1 /* Length in bytes of the region to zero out */
+	/*
+	 * Reusing the r1 register as length is only used at the beginning of
+	 * the function.
+	 */
+	stop_address .req r1  /* Address past the last zeroed byte */
+	zeroreg1     .req r2  /* Source register filled with 0 */
+	zeroreg2     .req r3  /* Source register filled with 0 */
+	tmp	     .req r12 /* Temporary scratch register */
+
+	mov	zeroreg1, #0
+
+	/* stop_address is the address past the last to zero */
+	add	stop_address, cursor, length
+
+	/*
+	 * Length cannot be used anymore as it shares the same register with
+	 * stop_address.
+	 */
+	.unreq	length
+
+	/*
+	 * If the start address is already aligned to 8 bytes, skip this loop.
+	 */
+	tst	cursor, #(8-1)
+	beq	.Lzeromem_8bytes_aligned
+
+	/* Calculate the next address aligned to 8 bytes */
+	orr	tmp, cursor, #(8-1)
+	adds	tmp, tmp, #1
+	/* If it overflows, fallback to byte per byte zeroing */
+	beq	.Lzeromem_1byte_aligned
+	/* If the next aligned address is after the stop address, fall back */
+	cmp	tmp, stop_address
+	bhs	.Lzeromem_1byte_aligned
+
+	/* zero byte per byte */
+1:
+	strb	zeroreg1, [cursor], #1
+	cmp	cursor, tmp
+	bne	1b
+
+	/* zero 8 bytes at a time */
+.Lzeromem_8bytes_aligned:
+
+	/* Calculate the last 8 bytes aligned address. */
+	bic	tmp, stop_address, #(8-1)
+
+	cmp	cursor, tmp
+	bhs	2f
+
+	mov	zeroreg2, #0
+1:
+	stmia	cursor!, {zeroreg1, zeroreg2}
+	cmp	cursor, tmp
+	blo	1b
+2:
+
+	/* zero byte per byte */
+.Lzeromem_1byte_aligned:
+	cmp	cursor, stop_address
+	beq	2f
+1:
+	strb	zeroreg1, [cursor], #1
+	cmp	cursor, stop_address
+	bne	1b
+2:
 	bx	lr
+
+	.unreq	cursor
+	/*
+	 * length is already unreq'ed to reuse the register for another
+	 * variable.
+	 */
+	.unreq	stop_address
+	.unreq	zeroreg1
+	.unreq	zeroreg2
+	.unreq	tmp
 endfunc zeromem
 
+/*
+ * AArch32 does not have special ways of zeroing normal memory as AArch64 does
+ * using the DC ZVA instruction, so we just alias zero_normalmem to zeromem.
+ */
+.equ	zero_normalmem, zeromem
+
 /* --------------------------------------------------------------------------
  * void memcpy4(void *dest, const void *src, unsigned int length)
  *
diff --git a/lib/aarch64/misc_helpers.S b/lib/aarch64/misc_helpers.S
index 574146f..84265e0 100644
--- a/lib/aarch64/misc_helpers.S
+++ b/lib/aarch64/misc_helpers.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -37,6 +37,8 @@
 	.globl	eret
 	.globl	smc
 
+	.globl	zero_normalmem
+	.globl	zeromem
 	.globl	zeromem16
 	.globl	memcpy16
 
@@ -80,31 +82,358 @@
  *
  * Initialise a memory region to 0.
  * The memory address must be 16-byte aligned.
+ * NOTE: This function is deprecated and zeromem should be used instead.
  * -----------------------------------------------------------------------
  */
-func zeromem16
-#if ASM_ASSERTION
-	tst	x0, #0xf
-	ASM_ASSERT(eq)
-#endif
-	add	x2, x0, x1
-/* zero 16 bytes at a time */
-z_loop16:
-	sub	x3, x2, x0
-	cmp	x3, #16
-	b.lt	z_loop1
-	stp	xzr, xzr, [x0], #16
-	b	z_loop16
-/* zero byte per byte */
-z_loop1:
-	cmp	x0, x2
-	b.eq	z_end
-	strb	wzr, [x0], #1
-	b	z_loop1
-z_end:
-	ret
-endfunc zeromem16
+.equ	zeromem16, zeromem
 
+/* -----------------------------------------------------------------------
+ * void zero_normalmem(void *mem, unsigned int length);
+ *
+ * Initialise a region in normal memory to 0. This functions complies with the
+ * AAPCS and can be called from C code.
+ *
+ * NOTE: MMU must be enabled when using this function as it can only operate on
+ *       normal memory. It is intended to be mainly used from C code when MMU
+ *       is usually enabled.
+ * -----------------------------------------------------------------------
+ */
+.equ	zero_normalmem, zeromem_dczva
+
+/* -----------------------------------------------------------------------
+ * void zeromem(void *mem, unsigned int length);
+ *
+ * Initialise a region of device memory to 0. This functions complies with the
+ * AAPCS and can be called from C code.
+ *
+ * NOTE: When data caches and MMU are enabled, zero_normalmem can usually be
+ *       used instead for faster zeroing.
+ *
+ * -----------------------------------------------------------------------
+ */
+func zeromem
+	/* x2 is the address past the last zeroed address */
+	add	x2, x0, x1
+	/*
+	 * Uses the fallback path that does not use DC ZVA instruction and
+	 * therefore does not need enabled MMU
+	 */
+	b	.Lzeromem_dczva_fallback_entry
+endfunc zeromem
+
+/* -----------------------------------------------------------------------
+ * void zeromem_dczva(void *mem, unsigned int length);
+ *
+ * Fill a region of normal memory of size "length" in bytes with null bytes.
+ * MMU must be enabled and the memory be of
+ * normal type. This is because this function internally uses the DC ZVA
+ * instruction, which generates an Alignment fault if used on any type of
+ * Device memory (see section D3.4.9 of the ARMv8 ARM, issue k). When the MMU
+ * is disabled, all memory behaves like Device-nGnRnE memory (see section
+ * D4.2.8), hence the requirement on the MMU being enabled.
+ * NOTE: The code assumes that the block size as defined in DCZID_EL0
+ *       register is at least 16 bytes.
+ *
+ * -----------------------------------------------------------------------
+ */
+func zeromem_dczva
+
+	/*
+	 * The function consists of a series of loops that zero memory one byte
+	 * at a time, 16 bytes at a time or using the DC ZVA instruction to
+	 * zero aligned block of bytes, which is assumed to be more than 16.
+	 * In the case where the DC ZVA instruction cannot be used or if the
+	 * first 16 bytes loop would overflow, there is fallback path that does
+	 * not use DC ZVA.
+	 * Note: The fallback path is also used by the zeromem function that
+	 *       branches to it directly.
+	 *
+	 *              +---------+   zeromem_dczva
+	 *              |  entry  |
+	 *              +----+----+
+	 *                   |
+	 *                   v
+	 *              +---------+
+	 *              | checks  |>o-------+ (If any check fails, fallback)
+	 *              +----+----+         |
+	 *                   |              |---------------+
+	 *                   v              | Fallback path |
+	 *            +------+------+       |---------------+
+	 *            | 1 byte loop |       |
+	 *            +------+------+ .Lzeromem_dczva_initial_1byte_aligned_end
+	 *                   |              |
+	 *                   v              |
+	 *           +-------+-------+      |
+	 *           | 16 bytes loop |      |
+	 *           +-------+-------+      |
+	 *                   |              |
+	 *                   v              |
+	 *            +------+------+ .Lzeromem_dczva_blocksize_aligned
+	 *            | DC ZVA loop |       |
+	 *            +------+------+       |
+	 *       +--------+  |              |
+	 *       |        |  |              |
+	 *       |        v  v              |
+	 *       |   +-------+-------+ .Lzeromem_dczva_final_16bytes_aligned
+	 *       |   | 16 bytes loop |      |
+	 *       |   +-------+-------+      |
+	 *       |           |              |
+	 *       |           v              |
+	 *       |    +------+------+ .Lzeromem_dczva_final_1byte_aligned
+	 *       |    | 1 byte loop |       |
+	 *       |    +-------------+       |
+	 *       |           |              |
+	 *       |           v              |
+	 *       |       +---+--+           |
+	 *       |       | exit |           |
+	 *       |       +------+           |
+	 *       |			    |
+	 *       |           +--------------+    +------------------+ zeromem
+	 *       |           |  +----------------| zeromem function |
+	 *       |           |  |                +------------------+
+	 *       |           v  v
+	 *       |    +-------------+ .Lzeromem_dczva_fallback_entry
+	 *       |    | 1 byte loop |
+	 *       |    +------+------+
+	 *       |           |
+	 *       +-----------+
+	 */
+
+	/*
+	 * Readable names for registers
+	 *
+	 * Registers x0, x1 and x2 are also set by zeromem which
+	 * branches into the fallback path directly, so cursor, length and
+	 * stop_address should not be retargeted to other registers.
+	 */
+	cursor       .req x0 /* Start address and then current address */
+	length       .req x1 /* Length in bytes of the region to zero out */
+	/* Reusing x1 as length is never used after block_mask is set */
+	block_mask   .req x1 /* Bitmask of the block size read in DCZID_EL0 */
+	stop_address .req x2 /* Address past the last zeroed byte */
+	block_size   .req x3 /* Size of a block in bytes as read in DCZID_EL0 */
+	tmp1         .req x4
+	tmp2         .req x5
+
+#if ASM_ASSERTION
+	/*
+	 * Check for M bit (MMU enabled) of the current SCTLR_EL(1|3)
+	 * register value and panic if the MMU is disabled.
+	 */
+#if defined(IMAGE_BL1) || defined(IMAGE_BL31)
+	mrs	tmp1, sctlr_el3
+#else
+	mrs	tmp1, sctlr_el1
+#endif
+
+	tst	tmp1, #SCTLR_M_BIT
+	ASM_ASSERT(ne)
+#endif /* ASM_ASSERTION */
+
+	/* stop_address is the address past the last to zero */
+	add	stop_address, cursor, length
+
+	/*
+	 * Get block_size = (log2(<block size>) >> 2) (see encoding of
+	 * dczid_el0 reg)
+	 */
+	mrs	block_size, dczid_el0
+
+	/*
+	 * Select the 4 lowest bits and convert the extracted log2(<block size
+	 * in words>) to <block size in bytes>
+	 */
+	ubfx	block_size, block_size, #0, #4
+	mov	tmp2, #(1 << 2)
+	lsl	block_size, tmp2, block_size
+
+#if ASM_ASSERTION
+	/*
+	 * Assumes block size is at least 16 bytes to avoid manual realignment
+	 * of the cursor at the end of the DCZVA loop.
+	 */
+	cmp	block_size, #16
+	ASM_ASSERT(hs)
+#endif
+	/*
+	 * Not worth doing all the setup for a region less than a block and
+	 * protects against zeroing a whole block when the area to zero is
+	 * smaller than that. Also, as it is assumed that the block size is at
+	 * least 16 bytes, this also protects the initial aligning loops from
+	 * trying to zero 16 bytes when length is less than 16.
+	 */
+	cmp	length, block_size
+	b.lo	.Lzeromem_dczva_fallback_entry
+
+	/*
+	 * Calculate the bitmask of the block alignment. It will never
+	 * underflow as the block size is between 4 bytes and 2kB.
+	 * block_mask = block_size - 1
+	 */
+	sub	block_mask, block_size, #1
+
+	/*
+	 * length alias should not be used after this point unless it is
+	 * defined as a register other than block_mask's.
+	 */
+	 .unreq length
+
+	/*
+	 * If the start address is already aligned to zero block size, go
+	 * straight to the cache zeroing loop. This is safe because at this
+	 * point, the length cannot be smaller than a block size.
+	 */
+	tst	cursor, block_mask
+	b.eq	.Lzeromem_dczva_blocksize_aligned
+
+	/*
+	 * Calculate the first block-size-aligned address. It is assumed that
+	 * the zero block size is at least 16 bytes. This address is the last
+	 * address of this initial loop.
+	 */
+	orr	tmp1, cursor, block_mask
+	add	tmp1, tmp1, #1
+
+	/*
+	 * If the addition overflows, skip the cache zeroing loops. This is
+	 * quite unlikely however.
+	 */
+	cbz	tmp1, .Lzeromem_dczva_fallback_entry
+
+	/*
+	 * If the first block-size-aligned address is past the last address,
+	 * fallback to the simpler code.
+	 */
+	cmp	tmp1, stop_address
+	b.hi	.Lzeromem_dczva_fallback_entry
+
+	/*
+	 * If the start address is already aligned to 16 bytes, skip this loop.
+	 * It is safe to do this because tmp1 (the stop address of the initial
+	 * 16 bytes loop) will never be greater than the final stop address.
+	 */
+	tst	cursor, #0xf
+	b.eq	.Lzeromem_dczva_initial_1byte_aligned_end
+
+	/* Calculate the next address aligned to 16 bytes */
+	orr	tmp2, cursor, #0xf
+	add	tmp2, tmp2, #1
+	/* If it overflows, fallback to the simple path (unlikely) */
+	cbz	tmp2, .Lzeromem_dczva_fallback_entry
+	/*
+	 * Next aligned address cannot be after the stop address because the
+	 * length cannot be smaller than 16 at this point.
+	 */
+
+	/* First loop: zero byte per byte */
+1:
+	strb	wzr, [cursor], #1
+	cmp	cursor, tmp2
+	b.ne	1b
+.Lzeromem_dczva_initial_1byte_aligned_end:
+
+	/*
+	 * Second loop: we need to zero 16 bytes at a time from cursor to tmp1
+	 * before being able to use the code that deals with block-size-aligned
+	 * addresses.
+	 */
+	cmp	cursor, tmp1
+	b.hs	2f
+1:
+	stp	xzr, xzr, [cursor], #16
+	cmp	cursor, tmp1
+	b.lo	1b
+2:
+
+	/*
+	 * Third loop: zero a block at a time using DC ZVA cache block zeroing
+	 * instruction.
+	 */
+.Lzeromem_dczva_blocksize_aligned:
+	/*
+	 * Calculate the last block-size-aligned address. If the result equals
+	 * to the start address, the loop will exit immediately.
+	 */
+	bic	tmp1, stop_address, block_mask
+
+	cmp	cursor, tmp1
+	b.hs	2f
+1:
+	/* Zero the block containing the cursor */
+	dc	zva, cursor
+	/* Increment the cursor by the size of a block */
+	add	cursor, cursor, block_size
+	cmp	cursor, tmp1
+	b.lo	1b
+2:
+
+	/*
+	 * Fourth loop: zero 16 bytes at a time and then byte per byte the
+	 * remaining area
+	 */
+.Lzeromem_dczva_final_16bytes_aligned:
+	/*
+	 * Calculate the last 16 bytes aligned address. It is assumed that the
+	 * block size will never be smaller than 16 bytes so that the current
+	 * cursor is aligned to at least 16 bytes boundary.
+	 */
+	bic	tmp1, stop_address, #15
+
+	cmp	cursor, tmp1
+	b.hs	2f
+1:
+	stp	xzr, xzr, [cursor], #16
+	cmp	cursor, tmp1
+	b.lo	1b
+2:
+
+	/* Fifth and final loop: zero byte per byte */
+.Lzeromem_dczva_final_1byte_aligned:
+	cmp	cursor, stop_address
+	b.eq	2f
+1:
+	strb	wzr, [cursor], #1
+	cmp	cursor, stop_address
+	b.ne	1b
+2:
+	ret
+
+	/* Fallback for unaligned start addresses */
+.Lzeromem_dczva_fallback_entry:
+	/*
+	 * If the start address is already aligned to 16 bytes, skip this loop.
+	 */
+	tst	cursor, #0xf
+	b.eq	.Lzeromem_dczva_final_16bytes_aligned
+
+	/* Calculate the next address aligned to 16 bytes */
+	orr	tmp1, cursor, #15
+	add	tmp1, tmp1, #1
+	/* If it overflows, fallback to byte per byte zeroing */
+	cbz	tmp1, .Lzeromem_dczva_final_1byte_aligned
+	/* If the next aligned address is after the stop address, fall back */
+	cmp	tmp1, stop_address
+	b.hs	.Lzeromem_dczva_final_1byte_aligned
+
+	/* Fallback entry loop: zero byte per byte */
+1:
+	strb	wzr, [cursor], #1
+	cmp	cursor, tmp1
+	b.ne	1b
+
+	b	.Lzeromem_dczva_final_16bytes_aligned
+
+	.unreq	cursor
+	/*
+	 * length is already unreq'ed to reuse the register for another
+	 * variable.
+	 */
+	.unreq	stop_address
+	.unreq	block_size
+	.unreq	block_mask
+	.unreq	tmp1
+	.unreq	tmp2
+endfunc zeromem_dczva
 
 /* --------------------------------------------------------------------------
  * void memcpy16(void *dest, const void *src, unsigned int length)
diff --git a/lib/cpus/aarch64/denver.S b/lib/cpus/aarch64/denver.S
index 0b61440..fcfae8f 100644
--- a/lib/cpus/aarch64/denver.S
+++ b/lib/cpus/aarch64/denver.S
@@ -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:
@@ -35,6 +35,8 @@
 #include <cpu_macros.S>
 #include <plat_macros.S>
 
+	.global	denver_disable_dco
+
 	/* ---------------------------------------------
 	 * Disable debug interfaces
 	 * ---------------------------------------------
@@ -57,7 +59,6 @@
 	mov	x1, #1
 	lsl	x1, x1, x0
 	msr	s3_0_c15_c0_2, x1
-	isb
 	ret
 endfunc denver_enable_dco
 
@@ -111,22 +112,6 @@
 
 	mov	x19, x30
 
-	/* ----------------------------------------------------
-	 * We enter the 'core power gated with ARM state not
-	 * retained' power state during CPU power down. We let
-	 * DCO know that we expect to enter this power state
-	 * by writing to the ACTLR_EL1 register.
- 	 * ----------------------------------------------------
- 	 */
-	mov	x0, #DENVER_CPU_STATE_POWER_DOWN
-	msr	actlr_el1, x0
-
-	/* ---------------------------------------------
-	 * Force DCO to be quiescent
-	 * ---------------------------------------------
-	 */
-	bl	denver_disable_dco
-
 	/* ---------------------------------------------
 	 * Force the debug interfaces to be quiescent
 	 * ---------------------------------------------
@@ -163,7 +148,27 @@
 	ret
 endfunc denver_cpu_reg_dump
 
-declare_cpu_ops denver, DENVER_1_0_MIDR, \
+declare_cpu_ops denver, DENVER_MIDR_PN0, \
+	denver_reset_func, \
+	denver_core_pwr_dwn, \
+	denver_cluster_pwr_dwn
+
+declare_cpu_ops denver, DENVER_MIDR_PN1, \
+	denver_reset_func, \
+	denver_core_pwr_dwn, \
+	denver_cluster_pwr_dwn
+
+declare_cpu_ops denver, DENVER_MIDR_PN2, \
+	denver_reset_func, \
+	denver_core_pwr_dwn, \
+	denver_cluster_pwr_dwn
+
+declare_cpu_ops denver, DENVER_MIDR_PN3, \
+	denver_reset_func, \
+	denver_core_pwr_dwn, \
+	denver_cluster_pwr_dwn
+
+declare_cpu_ops denver, DENVER_MIDR_PN4, \
 	denver_reset_func, \
 	denver_core_pwr_dwn, \
 	denver_cluster_pwr_dwn
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
index 0659bff..4de30af 100644
--- a/lib/cpus/cpu-ops.mk
+++ b/lib/cpus/cpu-ops.mk
@@ -63,7 +63,7 @@
 
 # Flag to apply erratum 836870 workaround during reset. This erratum applies
 # only to revision <= r0p3 of the Cortex A53 cpu. From r0p4 and onwards, this
-# erratum workaround is enabled by default.
+# erratum workaround is enabled by default in hardware.
 ERRATA_A53_836870	?=0
 
 # Flag to apply erratum 806969 workaround during reset. This erratum applies
diff --git a/lib/el3_runtime/aarch32/context_mgmt.c b/lib/el3_runtime/aarch32/context_mgmt.c
index 51b7759..df22eaf 100644
--- a/lib/el3_runtime/aarch32/context_mgmt.c
+++ b/lib/el3_runtime/aarch32/context_mgmt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, 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:
@@ -38,6 +38,7 @@
 #include <platform_def.h>
 #include <smcc_helpers.h>
 #include <string.h>
+#include <utils.h>
 
 /*******************************************************************************
  * Context management library initialisation routine. This library is used by
@@ -84,7 +85,7 @@
 	security_state = GET_SECURITY_STATE(ep->h.attr);
 
 	/* Clear any residual register values from the context */
-	memset(ctx, 0, sizeof(*ctx));
+	zeromem(ctx, sizeof(*ctx));
 
 	reg_ctx = get_regs_ctx(ctx);
 
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index e26950d..5cce879 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -39,6 +39,7 @@
 #include <platform_def.h>
 #include <smcc_helpers.h>
 #include <string.h>
+#include <utils.h>
 
 
 /*******************************************************************************
@@ -91,7 +92,7 @@
 	security_state = GET_SECURITY_STATE(ep->h.attr);
 
 	/* Clear any residual register values from the context */
-	memset(ctx, 0, sizeof(*ctx));
+	zeromem(ctx, sizeof(*ctx));
 
 	/*
 	 * Base the context SCR on the current value, adjust for entry point
diff --git a/lib/locks/exclusive/aarch64/spinlock.S b/lib/locks/exclusive/aarch64/spinlock.S
index 1ca5912..bdc9ea0 100644
--- a/lib/locks/exclusive/aarch64/spinlock.S
+++ b/lib/locks/exclusive/aarch64/spinlock.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -33,7 +33,66 @@
 	.globl	spin_lock
 	.globl	spin_unlock
 
+#if (ARM_ARCH_MAJOR > 8) || ((ARM_ARCH_MAJOR == 8) && (ARM_ARCH_MINOR >= 1))
 
+/*
+ * When compiled for ARMv8.1 or later, choose spin locks based on Compare and
+ * Swap instruction.
+ */
+# define USE_CAS	1
+
+/*
+ * Lock contenders using CAS, upon failing to acquire the lock, wait with the
+ * monitor in open state. Therefore, a normal store upon unlocking won't
+ * generate an SEV. Use explicit SEV instruction with CAS unlock.
+ */
+# define COND_SEV()	sev
+
+#else
+
+# define USE_CAS	0
+
+/*
+ * Lock contenders using exclusive pairs, upon failing to acquire the lock, wait
+ * with the monitor in exclusive state. A normal store upon unlocking will
+ * implicitly generate an envent; so, no explicit SEV with unlock is required.
+ */
+# define COND_SEV()
+
+#endif
+
+#if USE_CAS
+
+	.arch	armv8.1-a
+
+/*
+ * Acquire lock using Compare and Swap instruction.
+ *
+ * Compare for 0 with acquire semantics, and swap 1. Wait until CAS returns
+ * 0.
+ *
+ * void spin_lock(spinlock_t *lock);
+ */
+func spin_lock
+	mov	w2, #1
+	sevl
+1:
+	wfe
+	mov	w1, wzr
+	casa	w1, w2, [x0]
+	cbnz	w1, 1b
+	ret
+endfunc spin_lock
+
+	.arch	armv8-a
+
+#else /* !USE_CAS */
+
+/*
+ * Acquire lock using load-/store-exclusive instruction pair.
+ *
+ * void spin_lock(spinlock_t *lock);
+ */
 func spin_lock
 	mov	w2, #1
 	sevl
@@ -45,8 +104,17 @@
 	ret
 endfunc spin_lock
 
+#endif /* USE_CAS */
 
+/*
+ * Release lock previously acquired by spin_lock.
+ *
+ * Unconditionally write 0, and conditionally generate an event.
+ *
+ * void spin_unlock(spinlock_t *lock);
+ */
 func spin_unlock
 	stlr	wzr, [x0]
+	COND_SEV()
 	ret
 endfunc spin_unlock
diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c
index 68cdd6e..9fdce49 100644
--- a/lib/psci/psci_common.c
+++ b/lib/psci/psci_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -37,6 +37,7 @@
 #include <debug.h>
 #include <platform.h>
 #include <string.h>
+#include <utils.h>
 #include "psci_private.h"
 
 /*
@@ -622,7 +623,7 @@
 	SET_PARAM_HEAD(ep, PARAM_EP, VERSION_1, ep_attr);
 
 	ep->pc = entrypoint;
-	memset(&ep->args, 0, sizeof(ep->args));
+	zeromem(&ep->args, sizeof(ep->args));
 	ep->args.arg0 = context_id;
 
 	mode = scr & SCR_HCE_BIT ? MODE32_hyp : MODE32_svc;
@@ -659,7 +660,7 @@
 	SET_PARAM_HEAD(ep, PARAM_EP, VERSION_1, ep_attr);
 
 	ep->pc = entrypoint;
-	memset(&ep->args, 0, sizeof(ep->args));
+	zeromem(&ep->args, sizeof(ep->args));
 	ep->args.arg0 = context_id;
 
 	/*
@@ -760,13 +761,7 @@
 				      cpu_idx);
 
 #if ENABLE_PSCI_STAT
-	/*
-	 * Capture power up time-stamp.
-	 * No cache maintenance is required as caches are off
-	 * and writes are direct to the main memory.
-	 */
-	PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
-		PMF_NO_CACHE_MAINT);
+	plat_psci_stat_accounting_stop(&state_info);
 #endif
 
 	psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
@@ -801,7 +796,7 @@
 	 * Since caches are now enabled, it's necessary to do cache
 	 * maintenance before reading that same data.
 	 */
-	psci_stats_update_pwr_up(end_pwrlvl, &state_info, PMF_CACHE_MAINT);
+	psci_stats_update_pwr_up(end_pwrlvl, &state_info);
 #endif
 
 	/*
@@ -957,7 +952,7 @@
 {
 	psci_power_state_t state_info;
 
-	memset(&state_info, 0, sizeof(state_info));
+	zeromem(&state_info, sizeof(state_info));
 	psci_get_target_local_pwr_states(PLAT_MAX_PWR_LVL, &state_info);
 
 	return psci_find_target_suspend_lvl(&state_info);
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
index 0a3a60a..5e166b5 100644
--- a/lib/psci/psci_main.c
+++ b/lib/psci/psci_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -117,13 +117,7 @@
 		psci_set_cpu_local_state(cpu_pd_state);
 
 #if ENABLE_PSCI_STAT
-		/*
-		 * Capture time-stamp before CPU standby
-		 * No cache maintenance is needed as caches
-		 * are ON through out the CPU standby operation.
-		 */
-		PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
-			PMF_NO_CACHE_MAINT);
+		plat_psci_stat_accounting_start(&state_info);
 #endif
 
 #if ENABLE_RUNTIME_INSTRUMENTATION
@@ -144,13 +138,10 @@
 #endif
 
 #if ENABLE_PSCI_STAT
-		/* Capture time-stamp after CPU standby */
-		PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
-			PMF_NO_CACHE_MAINT);
+		plat_psci_stat_accounting_stop(&state_info);
 
 		/* Update PSCI stats */
-		psci_stats_update_pwr_up(PSCI_CPU_PWR_LVL, &state_info,
-			PMF_NO_CACHE_MAINT);
+		psci_stats_update_pwr_up(PSCI_CPU_PWR_LVL, &state_info);
 #endif
 
 		return PSCI_E_SUCCESS;
diff --git a/lib/psci/psci_off.c b/lib/psci/psci_off.c
index 897bf31..394aaa3 100644
--- a/lib/psci/psci_off.c
+++ b/lib/psci/psci_off.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -137,13 +137,7 @@
 	psci_plat_pm_ops->pwr_domain_off(&state_info);
 
 #if ENABLE_PSCI_STAT
-	/*
-	 * Capture time-stamp while entering low power state.
-	 * No cache maintenance needed because caches are off
-	 * and writes are direct to main memory.
-	 */
-	PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
-		PMF_NO_CACHE_MAINT);
+	plat_psci_stat_accounting_start(&state_info);
 #endif
 
 exit:
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
index 781b3b5..ca8291e 100644
--- a/lib/psci/psci_private.h
+++ b/lib/psci/psci_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -35,7 +35,6 @@
 #include <bakery_lock.h>
 #include <bl_common.h>
 #include <cpu_data.h>
-#include <pmf.h>
 #include <psci.h>
 #include <spinlock.h>
 
@@ -106,15 +105,6 @@
 #define is_cpu_standby_req(is_power_down_state, retn_lvl) \
 		(((!(is_power_down_state)) && ((retn_lvl) == 0)) ? 1 : 0)
 
-/* Following are used as ID's to capture time-stamp */
-#define PSCI_STAT_ID_ENTER_LOW_PWR		0
-#define PSCI_STAT_ID_EXIT_LOW_PWR		1
-#define PSCI_STAT_TOTAL_IDS			2
-
-/* Declare PMF service functions for PSCI */
-PMF_DECLARE_CAPTURE_TIMESTAMP(psci_svc)
-PMF_DECLARE_GET_TIMESTAMP(psci_svc)
-
 /*******************************************************************************
  * The following two data structures implement the power domain tree. The tree
  * is used to track the state of all the nodes i.e. power domain instances
@@ -246,8 +236,7 @@
 void psci_stats_update_pwr_down(unsigned int end_pwrlvl,
 			const psci_power_state_t *state_info);
 void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
-			const psci_power_state_t *state_info,
-			unsigned int flags);
+			const psci_power_state_t *state_info);
 u_register_t psci_stat_residency(u_register_t target_cpu,
 			unsigned int power_state);
 u_register_t psci_stat_count(u_register_t target_cpu,
diff --git a/lib/psci/psci_stat.c b/lib/psci/psci_stat.c
index ecbe592..d8034a5 100644
--- a/lib/psci/psci_stat.c
+++ b/lib/psci/psci_stat.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, 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:
@@ -38,9 +38,6 @@
 #define PLAT_MAX_PWR_LVL_STATES 2
 #endif
 
-/* Ticks elapsed in one second by a signal of 1 MHz */
-#define MHZ_TICKS_PER_SEC 1000000
-
 /* Following structure is used for PSCI STAT */
 typedef struct psci_stat {
 	u_register_t residency;
@@ -62,27 +59,6 @@
 static psci_stat_t psci_non_cpu_stat[PSCI_NUM_NON_CPU_PWR_DOMAINS]
 				[PLAT_MAX_PWR_LVL_STATES];
 
-/* Register PMF PSCI service */
-PMF_REGISTER_SERVICE(psci_svc, PMF_PSCI_STAT_SVC_ID,
-	 PSCI_STAT_TOTAL_IDS, PMF_STORE_ENABLE)
-
-/* The divisor to use to convert raw timestamp into microseconds */
-u_register_t residency_div;
-
-/*
- * This macro calculates the stats residency in microseconds,
- * taking in account the wrap around condition.
- */
-#define calc_stat_residency(_pwrupts, _pwrdnts, _res)		\
-	do {							\
-		if (_pwrupts < _pwrdnts)			\
-			_res = UINT64_MAX - _pwrdnts + _pwrupts;\
-		else						\
-			_res = _pwrupts - _pwrdnts;		\
-		/* Convert timestamp into microseconds */	\
-		_res = _res/residency_div;			\
-	} while (0)
-
 /*
  * This functions returns the index into the `psci_stat_t` array given the
  * local power state and power domain level. If the platform implements the
@@ -150,44 +126,23 @@
  * It is called with caches enabled and locks acquired(for NON-CPU domain)
  ******************************************************************************/
 void psci_stats_update_pwr_up(unsigned int end_pwrlvl,
-			const psci_power_state_t *state_info,
-			unsigned int flags)
+			const psci_power_state_t *state_info)
 {
 	int parent_idx, cpu_idx = plat_my_core_pos();
 	int lvl, stat_idx;
 	plat_local_state_t local_state;
-	unsigned long long pwrup_ts = 0, pwrdn_ts = 0;
 	u_register_t residency;
 
 	assert(end_pwrlvl <= PLAT_MAX_PWR_LVL);
 	assert(state_info);
 
-	/* Initialize the residency divisor if not already initialized */
-	if (!residency_div) {
-		/* Pre-calculate divisor so that it can be directly used to
-		   convert time-stamp into microseconds */
-		residency_div = read_cntfrq_el0() / MHZ_TICKS_PER_SEC;
-		assert(residency_div);
-	}
-
-	/* Get power down time-stamp for current CPU */
-	PMF_GET_TIMESTAMP_BY_INDEX(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
-			cpu_idx, flags, pwrdn_ts);
-
-	/* In the case of 1st power on just return */
-	if (!pwrdn_ts)
-		return;
-
-	/* Get power up time-stamp for current CPU */
-	PMF_GET_TIMESTAMP_BY_INDEX(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
-			cpu_idx, flags, pwrup_ts);
-
 	/* Get the index into the stats array */
 	local_state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL];
 	stat_idx = get_stat_idx(local_state, PSCI_CPU_PWR_LVL);
 
-	/* Calculate stats residency */
-	calc_stat_residency(pwrup_ts, pwrdn_ts, residency);
+	/* Call into platform interface to calculate residency. */
+	residency = plat_psci_stat_get_residency(PSCI_CPU_PWR_LVL,
+	    state_info, cpu_idx);
 
 	/* Update CPU stats. */
 	psci_cpu_stat[cpu_idx][stat_idx].residency += residency;
@@ -207,10 +162,9 @@
 
 		assert(last_cpu_in_non_cpu_pd[parent_idx] != -1);
 
-		/* Get power down time-stamp for last CPU */
-		PMF_GET_TIMESTAMP_BY_INDEX(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
-				last_cpu_in_non_cpu_pd[parent_idx],
-				flags, pwrdn_ts);
+		/* Call into platform interface to calculate residency. */
+		residency = plat_psci_stat_get_residency(lvl, state_info,
+		    last_cpu_in_non_cpu_pd[parent_idx]);
 
 		/* Initialize back to reset value */
 		last_cpu_in_non_cpu_pd[parent_idx] = -1;
@@ -218,9 +172,6 @@
 		/* Get the index into the stats array */
 		stat_idx = get_stat_idx(local_state, lvl);
 
-		/* Calculate stats residency */
-		calc_stat_residency(pwrup_ts, pwrdn_ts, residency);
-
 		/* Update non cpu stats */
 		psci_non_cpu_stat[parent_idx][stat_idx].residency += residency;
 		psci_non_cpu_stat[parent_idx][stat_idx].count++;
diff --git a/lib/psci/psci_suspend.c b/lib/psci/psci_suspend.c
index dc2ab77..302116b 100644
--- a/lib/psci/psci_suspend.c
+++ b/lib/psci/psci_suspend.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -211,13 +211,7 @@
 	psci_plat_pm_ops->pwr_domain_suspend(state_info);
 
 #if ENABLE_PSCI_STAT
-	/*
-	 * Capture time-stamp while entering low power state.
-	 * No cache maintenance needed because caches are off
-	 * and writes are direct to main memory.
-	 */
-	PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
-		PMF_NO_CACHE_MAINT);
+	plat_psci_stat_accounting_start(state_info);
 #endif
 
 exit:
@@ -257,6 +251,10 @@
 	    PMF_NO_CACHE_MAINT);
 #endif
 
+#if ENABLE_PSCI_STAT
+	plat_psci_stat_accounting_start(state_info);
+#endif
+
 	/*
 	 * We will reach here if only retention/standby states have been
 	 * requested at multiple power levels. This means that the cpu
@@ -264,6 +262,11 @@
 	 */
 	wfi();
 
+#if ENABLE_PSCI_STAT
+	plat_psci_stat_accounting_stop(state_info);
+	psci_stats_update_pwr_up(end_pwrlvl, state_info);
+#endif
+
 #if ENABLE_RUNTIME_INSTRUMENTATION
 	PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
 	    RT_INSTR_EXIT_HW_LOW_PWR,
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
index 2312d2c..93db2d6 100644
--- a/make_helpers/build_macros.mk
+++ b/make_helpers/build_macros.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2015-2017, 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,6 +81,16 @@
     $(and $(patsubst 0,,$(value $(1))),$(patsubst 1,,$(value $(1))),$(error $(1) must be boolean))
 endef
 
+0-9 := 0 1 2 3 4 5 6 7 8 9
+
+# Function to verify that a given option $(1) contains a numeric value
+define assert_numeric
+$(if $($(1)),,$(error $(1) must not be empty))
+$(eval __numeric := $($(1)))
+$(foreach d,$(0-9),$(eval __numeric := $(subst $(d),,$(__numeric))))
+$(if $(__numeric),$(error $(1) must be numeric))
+endef
+
 # IMG_LINKERFILE defines the linker script corresponding to a BL stage
 #   $(1) = BL stage (2, 30, 31, 32, 33)
 define IMG_LINKERFILE
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 0b93dfc..b47ea46 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2016-2017, 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:
@@ -44,6 +44,10 @@
 # port can change this value if needed.
 ARM_CCI_PRODUCT_ID		:= 400
 
+# ARM Architecture major and minor versions: 8.0 by default.
+ARM_ARCH_MAJOR			:= 8
+ARM_ARCH_MINOR			:= 0
+
 # Determine the version of ARM GIC architecture to use for interrupt management
 # in EL3. The platform port can change this value if needed.
 ARM_GIC_ARCH			:= 2
diff --git a/plat/arm/board/juno/juno_security.c b/plat/arm/board/juno/juno_security.c
index 202342a..70637d6 100644
--- a/plat/arm/board/juno/juno_security.c
+++ b/plat/arm/board/juno/juno_security.c
@@ -60,16 +60,34 @@
 }
 
 /*******************************************************************************
+ * Initialize debug configuration.
+ ******************************************************************************/
+static void init_debug_cfg(void)
+{
+#if !DEBUG
+	/* Set internal drive selection for SPIDEN. */
+	mmio_write_32(SSC_REG_BASE + SSC_DBGCFG_SET,
+		1U << SPIDEN_SEL_SET_SHIFT);
+
+	/* Drive SPIDEN LOW to disable invasive debug of secure state. */
+	mmio_write_32(SSC_REG_BASE + SSC_DBGCFG_CLR,
+		1U << SPIDEN_INT_CLR_SHIFT);
+#endif
+}
+
+/*******************************************************************************
  * Initialize the secure environment.
  ******************************************************************************/
 void plat_arm_security_setup(void)
 {
+	/* Initialize debug configuration */
+	init_debug_cfg();
 	/* Initialize the TrustZone Controller */
 	arm_tzc400_setup();
 	/* Do ARM CSS internal NIC setup */
 	css_init_nic400();
 	/* Do ARM CSS SoC security setup */
 	soc_css_security_setup();
-	/* Initialize the SMMU SSD tables*/
+	/* Initialize the SMMU SSD tables */
 	init_mmu401();
 }
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index 5f30708..007108d 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, 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:
@@ -38,6 +38,7 @@
 #include <plat_arm.h>
 #include <platform_def.h>
 #include <string.h>
+#include <utils.h>
 
 /* Data structure which holds the extents of the trusted SRAM for BL2 */
 static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
@@ -123,7 +124,7 @@
 	 * Initialise the memory for all the arguments that needs to
 	 * be passed to BL31
 	 */
-	memset(&bl31_params_mem, 0, sizeof(bl2_to_bl31_params_mem_t));
+	zeromem(&bl31_params_mem, sizeof(bl2_to_bl31_params_mem_t));
 
 	/* Assign memory for TF related information */
 	bl2_to_bl31_params = &bl31_params_mem.bl31_params;
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index c2f28f9..4628a43 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2015-2017, 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:
@@ -92,6 +92,7 @@
 
 # Enable PSCI_STAT_COUNT/RESIDENCY APIs on ARM platforms
 ENABLE_PSCI_STAT		:=	1
+ENABLE_PMF			:=	1
 
 # On ARM platforms, separate the code and read-only data sections to allow
 # mapping the former as executable and the latter as execute-never.
diff --git a/plat/arm/css/common/css_bl2_setup.c b/plat/arm/css/common/css_bl2_setup.c
index 11ca342..5361d89 100644
--- a/plat/arm/css/common/css_bl2_setup.c
+++ b/plat/arm/css/common/css_bl2_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, 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:
@@ -98,7 +98,7 @@
 	 *  - restoring the SCP boot configuration.
 	 */
 	VERBOSE("BL2: Restoring SCP reset data in Trusted SRAM\n");
-	memset((void *) ARM_TRUSTED_SRAM_BASE, 0, 128);
+	zero_normalmem((void *)ARM_TRUSTED_SRAM_BASE, 128);
 	mmio_write_32(SCP_BOOT_CFG_ADDR, scp_boot_config);
 }
 #endif /* EL3_PAYLOAD_BASE */
diff --git a/plat/arm/css/drivers/scpi/css_scpi.c b/plat/arm/css/drivers/scpi/css_scpi.c
index f419abd..65ae978 100644
--- a/plat/arm/css/drivers/scpi/css_scpi.c
+++ b/plat/arm/css/drivers/scpi/css_scpi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, 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:
@@ -34,6 +34,7 @@
 #include <debug.h>
 #include <platform.h>
 #include <string.h>
+#include <utils.h>
 #include "css_mhu.h"
 #include "css_scpi.h"
 
@@ -204,7 +205,8 @@
 	scpi_secure_message_start();
 
 	/* Populate request headers */
-	cmd = memset(SCPI_CMD_HEADER_AP_TO_SCP, 0, sizeof(*cmd));
+	zeromem(SCPI_CMD_HEADER_AP_TO_SCP, sizeof(*cmd));
+	cmd = SCPI_CMD_HEADER_AP_TO_SCP;
 	cmd->id = SCPI_CMD_GET_CSS_POWER_STATE;
 
 	/*
diff --git a/plat/common/plat_psci_common.c b/plat/common/plat_psci_common.c
index 3eb6886..0e00faa 100644
--- a/plat/common/plat_psci_common.c
+++ b/plat/common/plat_psci_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, 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:
@@ -31,8 +31,125 @@
 #include <arch.h>
 #include <assert.h>
 #include <platform.h>
+#include <pmf.h>
 #include <psci.h>
 
+#if ENABLE_PSCI_STAT && ENABLE_PMF
+#pragma weak plat_psci_stat_accounting_start
+#pragma weak plat_psci_stat_accounting_stop
+#pragma weak plat_psci_stat_get_residency
+
+/* Ticks elapsed in one second by a signal of 1 MHz */
+#define MHZ_TICKS_PER_SEC 1000000
+
+/* Following are used as ID's to capture time-stamp */
+#define PSCI_STAT_ID_ENTER_LOW_PWR		0
+#define PSCI_STAT_ID_EXIT_LOW_PWR		1
+#define PSCI_STAT_TOTAL_IDS			2
+
+PMF_REGISTER_SERVICE(psci_svc, PMF_PSCI_STAT_SVC_ID, PSCI_STAT_TOTAL_IDS,
+	PMF_STORE_ENABLE)
+
+/*
+ * This function calculates the stats residency in microseconds,
+ * taking in account the wrap around condition.
+ */
+static u_register_t calc_stat_residency(unsigned long long pwrupts,
+	unsigned long long pwrdnts)
+{
+	/* The divisor to use to convert raw timestamp into microseconds. */
+	u_register_t residency_div;
+	u_register_t res;
+
+	/*
+	 * Calculate divisor so that it can be directly used to
+	 * convert time-stamp into microseconds.
+	 */
+	residency_div = read_cntfrq_el0() / MHZ_TICKS_PER_SEC;
+	assert(residency_div);
+
+	if (pwrupts < pwrdnts)
+		res = UINT64_MAX - pwrdnts + pwrupts;
+	else
+		res = pwrupts - pwrdnts;
+
+	return res / residency_div;
+}
+
+/*
+ * Capture timestamp before entering a low power state.
+ * No cache maintenance is required when capturing the timestamp.
+ * Cache maintenance may be needed when reading these timestamps.
+ */
+void plat_psci_stat_accounting_start(
+	__unused const psci_power_state_t *state_info)
+{
+	assert(state_info);
+	PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR,
+		PMF_NO_CACHE_MAINT);
+}
+
+/*
+ * Capture timestamp after exiting a low power state.
+ * No cache maintenance is required when capturing the timestamp.
+ * Cache maintenance may be needed when reading these timestamps.
+ */
+void plat_psci_stat_accounting_stop(
+	__unused const psci_power_state_t *state_info)
+{
+	assert(state_info);
+	PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR,
+		PMF_NO_CACHE_MAINT);
+}
+
+/*
+ * Calculate the residency for the given level and power state
+ * information.
+ */
+u_register_t plat_psci_stat_get_residency(unsigned int lvl,
+	const psci_power_state_t *state_info,
+	int last_cpu_idx)
+{
+	plat_local_state_t state;
+	unsigned long long pwrup_ts = 0, pwrdn_ts = 0;
+	unsigned int pmf_flags;
+
+	assert(lvl >= PSCI_CPU_PWR_LVL && lvl <= PLAT_MAX_PWR_LVL);
+	assert(state_info);
+	assert(last_cpu_idx >= 0 && last_cpu_idx <= PLATFORM_CORE_COUNT);
+
+	if (lvl == PSCI_CPU_PWR_LVL)
+		assert(last_cpu_idx == plat_my_core_pos());
+
+	/*
+	 * If power down is requested, then timestamp capture will
+	 * be with caches OFF.  Hence we have to do cache maintenance
+	 * when reading the timestamp.
+	 */
+	state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL];
+	if (is_local_state_off(state)) {
+		pmf_flags = PMF_CACHE_MAINT;
+	} else {
+		assert(is_local_state_retn(state));
+		pmf_flags = PMF_NO_CACHE_MAINT;
+	}
+
+	PMF_GET_TIMESTAMP_BY_INDEX(psci_svc,
+		PSCI_STAT_ID_ENTER_LOW_PWR,
+		last_cpu_idx,
+		pmf_flags,
+		pwrdn_ts);
+
+	PMF_GET_TIMESTAMP_BY_INDEX(psci_svc,
+		PSCI_STAT_ID_EXIT_LOW_PWR,
+		plat_my_core_pos(),
+		pmf_flags,
+		pwrup_ts);
+
+	return calc_stat_residency(pwrup_ts, pwrdn_ts);
+}
+#endif /* ENABLE_PSCI_STAT && ENABLE_PMF */
+
 /*
  * The PSCI generic code uses this API to let the platform participate in state
  * coordination during a power management operation. It compares the platform
diff --git a/plat/mediatek/mt6795/bl31.ld.S b/plat/mediatek/mt6795/bl31.ld.S
index 44510a7..472cd2e 100644
--- a/plat/mediatek/mt6795/bl31.ld.S
+++ b/plat/mediatek/mt6795/bl31.ld.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, 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:
@@ -113,7 +113,8 @@
 
     /*
      * The .bss section gets initialised to 0 at runtime.
-     * Its base address must be 16-byte aligned.
+     * Its base address should be 16-byte aligned for better performance of the
+     * zero-initialization code.
      */
     .bss (NOLOAD) : ALIGN(16) {
         __BSS_START__ = .;
diff --git a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
index 905c4c5..70a7f3a 100644
--- a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
+++ b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S
@@ -33,8 +33,25 @@
 #include <cpu_macros.S>
 #include <cortex_a57.h>
 #include <cortex_a53.h>
+#include <platform_def.h>
 #include <tegra_def.h>
 
+#define MIDR_PN_CORTEX_A57		0xD07
+
+/*******************************************************************************
+ * Implementation defined ACTLR_EL3 bit definitions
+ ******************************************************************************/
+#define ACTLR_EL3_L2ACTLR_BIT		(1 << 6)
+#define ACTLR_EL3_L2ECTLR_BIT		(1 << 5)
+#define ACTLR_EL3_L2CTLR_BIT		(1 << 4)
+#define ACTLR_EL3_CPUECTLR_BIT		(1 << 1)
+#define ACTLR_EL3_CPUACTLR_BIT		(1 << 0)
+#define ACTLR_EL3_ENABLE_ALL_ACCESS	(ACTLR_EL3_L2ACTLR_BIT | \
+					 ACTLR_EL3_L2ECTLR_BIT | \
+					 ACTLR_EL3_L2CTLR_BIT | \
+					 ACTLR_EL3_CPUECTLR_BIT | \
+					 ACTLR_EL3_CPUACTLR_BIT)
+
 	/* Global functions */
 	.globl	plat_is_my_cpu_primary
 	.globl	plat_my_core_pos
@@ -50,6 +67,8 @@
 	.globl	tegra_sec_entry_point
 	.globl	ns_image_entrypoint
 	.globl	tegra_bl31_phys_base
+	.globl	tegra_console_base
+	.globl	tegra_enable_l2_ecc_parity_prot
 
 	/* ---------------------
 	 * Common CPU init code
@@ -57,44 +76,64 @@
 	 */
 .macro	cpu_init_common
 
-#if ENABLE_L2_DYNAMIC_RETENTION
+	/* ------------------------------------------------
+	 * We enable procesor retention, L2/CPUECTLR NS
+	 * access and ECC/Parity protection for A57 CPUs
+	 * ------------------------------------------------
+	 */
+	mrs	x0, midr_el1
+	mov	x1, #(MIDR_PN_MASK << MIDR_PN_SHIFT)
+	and	x0, x0, x1
+	lsr	x0, x0, #MIDR_PN_SHIFT
+	cmp	x0, #MIDR_PN_CORTEX_A57
+	b.ne	1f
+
 	/* ---------------------------
 	 * Enable processor retention
 	 * ---------------------------
-	*/
+	 */
 	mrs	x0, L2ECTLR_EL1
 	mov	x1, #RETENTION_ENTRY_TICKS_512 << L2ECTLR_RET_CTRL_SHIFT
 	bic	x0, x0, #L2ECTLR_RET_CTRL_MASK
 	orr	x0, x0, x1
 	msr	L2ECTLR_EL1, x0
 	isb
-#endif
 
-#if ENABLE_CPU_DYNAMIC_RETENTION
 	mrs	x0, CPUECTLR_EL1
 	mov	x1, #RETENTION_ENTRY_TICKS_512 << CPUECTLR_CPU_RET_CTRL_SHIFT
 	bic	x0, x0, #CPUECTLR_CPU_RET_CTRL_MASK
 	orr	x0, x0, x1
 	msr	CPUECTLR_EL1, x0
 	isb
-#endif
 
-#if ENABLE_NS_L2_CPUECTRL_RW_ACCESS
 	/* -------------------------------------------------------
 	 * Enable L2 and CPU ECTLR RW access from non-secure world
 	 * -------------------------------------------------------
-	*/
+	 */
 	mov	x0, #ACTLR_EL3_ENABLE_ALL_ACCESS
 	msr	actlr_el3, x0
 	msr	actlr_el2, x0
 	isb
-#endif
+
+	/* -------------------------------------------------------
+	 * Enable L2 ECC and Parity Protection
+	 * -------------------------------------------------------
+	 */
+	adr	x0, tegra_enable_l2_ecc_parity_prot
+	ldr	x0, [x0]
+	cbz	x0, 1f
+	mrs	x0, L2CTLR_EL1
+	and	x1, x0, #L2_ECC_PARITY_PROTECTION_BIT
+	cbnz	x1, 1f
+	orr	x0, x0, #L2_ECC_PARITY_PROTECTION_BIT
+	msr	L2CTLR_EL1, x0
+	isb
 
 	/* --------------------------------
 	 * Enable the cycle count register
 	 * --------------------------------
 	 */
-	mrs	x0, pmcr_el0
+1:	mrs	x0, pmcr_el0
 	ubfx	x0, x0, #11, #5		// read PMCR.N field
 	mov	x1, #1
 	lsl	x0, x1, x0
@@ -158,6 +197,20 @@
 endfunc plat_get_my_entrypoint
 
 	/* -----------------------------------------------------
+	 * int platform_get_core_pos(int mpidr);
+	 *
+	 * With this function: CorePos = (ClusterId * 4) +
+	 *                                CoreId
+	 * -----------------------------------------------------
+	 */
+func platform_get_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc platform_get_core_pos
+
+	/* -----------------------------------------------------
 	 * void plat_secondary_cold_boot_setup (void);
 	 *
 	 * This function performs any platform specific actions
@@ -190,7 +243,8 @@
 	 * ---------------------------------------------
 	 */
 func plat_crash_console_init
-	mov_imm	x0, TEGRA_BOOT_UART_BASE
+	adr	x0, tegra_console_base
+	ldr	x0, [x0]
 	mov_imm	x1, TEGRA_BOOT_UART_CLK_IN_HZ
 	mov_imm	x2, TEGRA_CONSOLE_BAUDRATE
 	b	console_core_init
@@ -204,7 +258,8 @@
 	 * ---------------------------------------------
 	 */
 func plat_crash_console_putc
-	mov_imm	x1, TEGRA_BOOT_UART_BASE
+	adr	x1, tegra_console_base
+	ldr	x1, [x1]
 	b	console_core_putc
 endfunc plat_crash_console_putc
 
@@ -215,6 +270,47 @@
 	 */
 func plat_reset_handler
 
+	/* ----------------------------------------------------
+	 * Verify if we are running from BL31_BASE address
+	 * ----------------------------------------------------
+	 */
+	adr	x18, bl31_entrypoint
+	mov	x17, #BL31_BASE
+	cmp	x18, x17
+	b.eq	1f
+
+	/* ----------------------------------------------------
+	 * Copy the entire BL31 code to BL31_BASE if we are not
+	 * running from it already
+	 * ----------------------------------------------------
+	 */
+	mov	x0, x17
+	mov	x1, x18
+	mov	x2, #BL31_SIZE
+_loop16:
+	cmp	x2, #16
+	b.lt	_loop1
+	ldp	x3, x4, [x1], #16
+	stp	x3, x4, [x0], #16
+	sub	x2, x2, #16
+	b	_loop16
+	/* copy byte per byte */
+_loop1:
+	cbz	x2, _end
+	ldrb	w3, [x1], #1
+	strb	w3, [x0], #1
+	subs	x2, x2, #1
+	b.ne	_loop1
+
+	/* ----------------------------------------------------
+	 * Jump to BL31_BASE and start execution again
+	 * ----------------------------------------------------
+	 */
+_end:	mov	x0, x20
+	mov	x1, x21
+	br	x17
+1:
+
 	/* -----------------------------------
 	 * derive and save the phys_base addr
 	 * -----------------------------------
@@ -366,3 +462,17 @@
 	 */
 tegra_bl31_phys_base:
 	.quad	0
+
+	/* --------------------------------------------------
+	 * UART controller base for console init
+	 * --------------------------------------------------
+	 */
+tegra_console_base:
+	.quad	0
+
+	/* --------------------------------------------------
+	 * Enable L2 ECC and Parity Protection
+	 * --------------------------------------------------
+	 */
+tegra_enable_l2_ecc_parity_prot:
+	.quad	0
diff --git a/plat/nvidia/tegra/common/drivers/memctrl/memctrl.c b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v1.c
similarity index 88%
rename from plat/nvidia/tegra/common/drivers/memctrl/memctrl.c
rename to plat/nvidia/tegra/common/drivers/memctrl/memctrl_v1.c
index 40d1bab..c417050 100644
--- a/plat/nvidia/tegra/common/drivers/memctrl/memctrl.c
+++ b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v1.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, 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:
@@ -31,14 +31,14 @@
 #include <arch_helpers.h>
 #include <assert.h>
 #include <debug.h>
-#include <mmio.h>
 #include <memctrl.h>
+#include <memctrl_v1.h>
+#include <mmio.h>
 #include <string.h>
 #include <tegra_def.h>
+#include <utils.h>
 #include <xlat_tables.h>
 
-extern void zeromem16(void *mem, unsigned int length);
-
 #define TEGRA_GPU_RESET_REG_OFFSET	0x28c
 #define  GPU_RESET_BIT			(1 << 24)
 
@@ -55,7 +55,7 @@
 	 * Setup the Memory controller to allow only secure accesses to
 	 * the TZDRAM carveout
 	 */
-	INFO("Configuring SMMU\n");
+	INFO("Tegra Memory Controller (v1)\n");
 
 	/* allow translations for all MC engines */
 	tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_0_0,
@@ -90,6 +90,14 @@
 }
 
 /*
+ * Restore Memory Controller settings after "System Suspend"
+ */
+void tegra_memctrl_restore_settings(void)
+{
+	tegra_memctrl_setup();
+}
+
+/*
  * Secure the BL31 DRAM aperture.
  *
  * phys_base = physical base of TZDRAM aperture
@@ -107,6 +115,20 @@
 	tegra_mc_write_32(MC_SECURITY_CFG1_0, size_in_bytes >> 20);
 }
 
+/*
+ * Secure the BL31 TZRAM aperture.
+ *
+ * phys_base = physical base of TZRAM aperture
+ * size_in_bytes = size of aperture in bytes
+ */
+void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes)
+{
+	/*
+	 * The v1 hardware controller does not have any registers
+	 * for setting up the on-chip TZRAM.
+	 */
+}
+
 static void tegra_clear_videomem(uintptr_t non_overlap_area_start,
 				 unsigned long long non_overlap_area_size)
 {
@@ -114,13 +136,13 @@
 	 * Perform cache maintenance to ensure that the non-overlapping area is
 	 * zeroed out. The first invalidation of this range ensures that
 	 * possible evictions of dirty cache lines do not interfere with the
-	 * 'zeromem16' operation. Other CPUs could speculatively prefetch the
+	 * 'zeromem' operation. Other CPUs could speculatively prefetch the
 	 * main memory contents of this area between the first invalidation and
-	 * the 'zeromem16' operation. The second invalidation ensures that any
+	 * the 'zeromem' operation. The second invalidation ensures that any
 	 * such cache lines are removed as well.
 	 */
 	inv_dcache_range(non_overlap_area_start, non_overlap_area_size);
-	zeromem16((void *)non_overlap_area_start, non_overlap_area_size);
+	zeromem((void *)non_overlap_area_start, non_overlap_area_size);
 	inv_dcache_range(non_overlap_area_start, non_overlap_area_size);
 }
 
diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c
index 0fd7c82..246a03e 100644
--- a/plat/nvidia/tegra/common/tegra_bl31_setup.c
+++ b/plat/nvidia/tegra/common/tegra_bl31_setup.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:
@@ -37,14 +37,19 @@
 #include <cortex_a57.h>
 #include <cortex_a53.h>
 #include <debug.h>
+#include <denver.h>
 #include <errno.h>
 #include <memctrl.h>
 #include <mmio.h>
 #include <platform.h>
 #include <platform_def.h>
 #include <stddef.h>
+#include <string.h>
+#include <tegra_def.h>
 #include <tegra_private.h>
 
+extern void zeromem16(void *mem, unsigned int length);
+
 /*******************************************************************************
  * Declarations of linker defined symbols which will help us find the layout
  * of trusted SRAM
@@ -54,6 +59,7 @@
 extern unsigned long __BL31_END__;
 
 extern uint64_t tegra_bl31_phys_base;
+extern uint64_t tegra_console_base;
 
 /*
  * The next 3 constants identify the extents of the code, RO data region and the
@@ -77,6 +83,29 @@
 extern uint64_t ns_image_entrypoint;
 
 /*******************************************************************************
+ * The following platform setup functions are weakly defined. They
+ * provide typical implementations that will be overridden by a SoC.
+ ******************************************************************************/
+#pragma weak plat_early_platform_setup
+#pragma weak plat_get_bl31_params
+#pragma weak plat_get_bl31_plat_params
+
+void plat_early_platform_setup(void)
+{
+	; /* do nothing */
+}
+
+bl31_params_t *plat_get_bl31_params(void)
+{
+	return NULL;
+}
+
+plat_params_from_bl2_t *plat_get_bl31_plat_params(void)
+{
+	return NULL;
+}
+
+/*******************************************************************************
  * Return a pointer to the 'entry_point_info' structure of the next image for
  * security state specified. BL33 corresponds to the non-secure image type
  * while BL32 corresponds to the secure image type.
@@ -86,7 +115,8 @@
 	if (type == NON_SECURE)
 		return &bl33_image_ep_info;
 
-	if (type == SECURE)
+	/* return BL32 entry point info if it is valid */
+	if (type == SECURE && bl32_image_ep_info.pc)
 		return &bl32_image_ep_info;
 
 	return NULL;
@@ -110,28 +140,114 @@
 {
 	plat_params_from_bl2_t *plat_params =
 		(plat_params_from_bl2_t *)plat_params_from_bl2;
+#if DEBUG
+	int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
+#endif
+	image_info_t bl32_img_info = { {0} };
+	uint64_t tzdram_start, tzdram_end, bl32_start, bl32_end;
 
 	/*
-	 * Configure the UART port to be used as the console
+	 * For RESET_TO_BL31 systems, BL31 is the first bootloader to run so
+	 * there's no argument to relay from a previous bootloader. Platforms
+	 * might use custom ways to get arguments, so provide handlers which
+	 * they can override.
 	 */
-	console_init(TEGRA_BOOT_UART_BASE, TEGRA_BOOT_UART_CLK_IN_HZ,
-			TEGRA_CONSOLE_BAUDRATE);
-
-	/* Initialise crash console */
-	plat_crash_console_init();
+	if (from_bl2 == NULL)
+		from_bl2 = plat_get_bl31_params();
+	if (plat_params == NULL)
+		plat_params = plat_get_bl31_plat_params();
 
 	/*
 	 * Copy BL3-3, BL3-2 entry point information.
 	 * They are stored in Secure RAM, in BL2's address space.
 	 */
+	assert(from_bl2);
+	assert(from_bl2->bl33_ep_info);
 	bl33_image_ep_info = *from_bl2->bl33_ep_info;
-	bl32_image_ep_info = *from_bl2->bl32_ep_info;
+
+	if (from_bl2->bl32_ep_info)
+		bl32_image_ep_info = *from_bl2->bl32_ep_info;
 
 	/*
-	 * Parse platform specific parameters - TZDRAM aperture size
+	 * Parse platform specific parameters - TZDRAM aperture base and size
 	 */
-	if (plat_params)
-		plat_bl31_params_from_bl2.tzdram_size = plat_params->tzdram_size;
+	assert(plat_params);
+	plat_bl31_params_from_bl2.tzdram_base = plat_params->tzdram_base;
+	plat_bl31_params_from_bl2.tzdram_size = plat_params->tzdram_size;
+	plat_bl31_params_from_bl2.uart_id = plat_params->uart_id;
+
+	/*
+	 * It is very important that we run either from TZDRAM or TZSRAM base.
+	 * Add an explicit check here.
+	 */
+	if ((plat_bl31_params_from_bl2.tzdram_base != BL31_BASE) &&
+	    (TEGRA_TZRAM_BASE != BL31_BASE))
+		panic();
+
+	/*
+	 * Get the base address of the UART controller to be used for the
+	 * console
+	 */
+	assert(plat_params->uart_id);
+	tegra_console_base = plat_get_console_from_id(plat_params->uart_id);
+
+	/*
+	 * Configure the UART port to be used as the console
+	 */
+	assert(tegra_console_base);
+	console_init(tegra_console_base, TEGRA_BOOT_UART_CLK_IN_HZ,
+		TEGRA_CONSOLE_BAUDRATE);
+
+	/* Initialise crash console */
+	plat_crash_console_init();
+
+	/*
+	 * Do initial security configuration to allow DRAM/device access.
+	 */
+	tegra_memctrl_tzdram_setup(plat_bl31_params_from_bl2.tzdram_base,
+			plat_bl31_params_from_bl2.tzdram_size);
+
+	/*
+	 * The previous bootloader might not have placed the BL32 image
+	 * inside the TZDRAM. We check the BL32 image info to find out
+	 * the base/PC values and relocate the image if necessary.
+	 */
+	if (from_bl2->bl32_image_info) {
+
+		bl32_img_info = *from_bl2->bl32_image_info;
+
+		/* Relocate BL32 if it resides outside of the TZDRAM */
+		tzdram_start = plat_bl31_params_from_bl2.tzdram_base;
+		tzdram_end = plat_bl31_params_from_bl2.tzdram_base +
+				plat_bl31_params_from_bl2.tzdram_size;
+		bl32_start = bl32_img_info.image_base;
+		bl32_end = bl32_img_info.image_base + bl32_img_info.image_size;
+
+		assert(tzdram_end > tzdram_start);
+		assert(bl32_end > bl32_start);
+		assert(bl32_image_ep_info.pc > tzdram_start);
+		assert(bl32_image_ep_info.pc < tzdram_end);
+
+		/* relocate BL32 */
+		if (bl32_start >= tzdram_end || bl32_end <= tzdram_start) {
+
+			INFO("Relocate BL32 to TZDRAM\n");
+
+			memcpy16((void *)(uintptr_t)bl32_image_ep_info.pc,
+				 (void *)(uintptr_t)bl32_start,
+				 bl32_img_info.image_size);
+
+			/* clean up non-secure intermediate buffer */
+			zeromem16((void *)(uintptr_t)bl32_start,
+				bl32_img_info.image_size);
+		}
+	}
+
+	/* Early platform setup for Tegra SoCs */
+	plat_early_platform_setup();
+
+	INFO("BL3-1: Boot CPU: %s Processor [%lx]\n", (impl == DENVER_IMPL) ?
+		"Denver" : "ARM", read_mpidr());
 }
 
 /*******************************************************************************
@@ -141,6 +257,9 @@
 {
 	uint32_t tmp_reg;
 
+	/* Initialize the gic cpu and distributor interfaces */
+	plat_gic_setup();
+
 	/*
 	 * Initialize delay timer
 	 */
@@ -157,17 +276,26 @@
 	tegra_memctrl_setup();
 
 	/*
-	 * Do initial security configuration to allow DRAM/device access.
+	 * Set up the TZRAM memory aperture to allow only secure world
+	 * access
 	 */
-	tegra_memctrl_tzdram_setup(tegra_bl31_phys_base,
-			plat_bl31_params_from_bl2.tzdram_size);
+	tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE);
 
 	/* Set the next EL to be AArch64 */
 	tmp_reg = SCR_RES1_BITS | SCR_RW_BIT;
 	write_scr(tmp_reg);
 
-	/* Initialize the gic cpu and distributor interfaces */
-	tegra_gic_setup();
+	INFO("BL3-1: Tegra platform setup complete\n");
+}
+
+/*******************************************************************************
+ * Perform any BL3-1 platform runtime setup prior to BL3-1 cold boot exit
+ ******************************************************************************/
+void bl31_plat_runtime_setup(void)
+{
+	/* Initialize the runtime console */
+	console_init(tegra_console_base, TEGRA_BOOT_UART_CLK_IN_HZ,
+		TEGRA_CONSOLE_BAUDRATE);
 }
 
 /*******************************************************************************
@@ -185,6 +313,7 @@
 #if USE_COHERENT_MEM
 	unsigned long coh_start, coh_size;
 #endif
+	plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
 
 	/* add memory regions */
 	mmap_add_region(total_base, total_base,
@@ -194,6 +323,14 @@
 			ro_size,
 			MT_MEMORY | MT_RO | MT_SECURE);
 
+	/* map TZDRAM used by BL31 as coherent memory */
+	if (TEGRA_TZRAM_BASE == tegra_bl31_phys_base) {
+		mmap_add_region(params_from_bl2->tzdram_base,
+				params_from_bl2->tzdram_base,
+				BL31_SIZE,
+				MT_DEVICE | MT_RW | MT_SECURE);
+	}
+
 #if USE_COHERENT_MEM
 	coh_start = total_base + (BL_COHERENT_RAM_BASE - BL31_RO_BASE);
 	coh_size = BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE;
@@ -215,6 +352,8 @@
 
 	/* enable the MMU */
 	enable_mmu_el3(0);
+
+	INFO("BL3-1: Tegra: MMU enabled\n");
 }
 
 /*******************************************************************************
diff --git a/plat/nvidia/tegra/common/tegra_common.mk b/plat/nvidia/tegra/common/tegra_common.mk
index 3c07032..7f789c5 100644
--- a/plat/nvidia/tegra/common/tegra_common.mk
+++ b/plat/nvidia/tegra/common/tegra_common.mk
@@ -47,18 +47,15 @@
 COMMON_DIR		:=	plat/nvidia/tegra/common
 
 BL31_SOURCES		+=	drivers/arm/gic/gic_v2.c			\
-				drivers/arm/gic/gic_v3.c			\
 				drivers/console/aarch64/console.S		\
 				drivers/delay_timer/delay_timer.c		\
 				drivers/ti/uart/aarch64/16550_console.S		\
 				plat/common/aarch64/platform_mp_stack.S		\
-				plat/common/plat_psci_common.c			\
 				${COMMON_DIR}/aarch64/tegra_helpers.S		\
-				${COMMON_DIR}/drivers/memctrl/memctrl.c		\
 				${COMMON_DIR}/drivers/pmc/pmc.c			\
-				${COMMON_DIR}/drivers/flowctrl/flowctrl.c	\
 				${COMMON_DIR}/tegra_bl31_setup.c		\
 				${COMMON_DIR}/tegra_delay_timer.c		\
+				${COMMON_DIR}/tegra_fiq_glue.c			\
 				${COMMON_DIR}/tegra_gic.c			\
 				${COMMON_DIR}/tegra_pm.c			\
 				${COMMON_DIR}/tegra_sip_calls.c			\
diff --git a/plat/nvidia/tegra/common/tegra_fiq_glue.c b/plat/nvidia/tegra/common/tegra_fiq_glue.c
new file mode 100644
index 0000000..7fcc114
--- /dev/null
+++ b/plat/nvidia/tegra/common/tegra_fiq_glue.c
@@ -0,0 +1,162 @@
+/*
+ * 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 <assert.h>
+#include <bakery_lock.h>
+#include <bl_common.h>
+#include <context.h>
+#include <context_mgmt.h>
+#include <debug.h>
+#include <denver.h>
+#include <gic_v2.h>
+#include <interrupt_mgmt.h>
+#include <platform.h>
+#include <tegra_def.h>
+#include <tegra_private.h>
+
+DEFINE_BAKERY_LOCK(tegra_fiq_lock);
+
+/*******************************************************************************
+ * Static variables
+ ******************************************************************************/
+static uint64_t ns_fiq_handler_addr;
+static unsigned int fiq_handler_active;
+static pcpu_fiq_state_t fiq_state[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * Handler for FIQ interrupts
+ ******************************************************************************/
+static uint64_t tegra_fiq_interrupt_handler(uint32_t id,
+					  uint32_t flags,
+					  void *handle,
+					  void *cookie)
+{
+	cpu_context_t *ctx = cm_get_context(NON_SECURE);
+	el3_state_t *el3state_ctx = get_el3state_ctx(ctx);
+	int cpu = plat_my_core_pos();
+	uint32_t irq;
+
+	bakery_lock_get(&tegra_fiq_lock);
+
+	/*
+	 * The FIQ was generated when the execution was in the non-secure
+	 * world. Save the context registers to start with.
+	 */
+	cm_el1_sysregs_context_save(NON_SECURE);
+
+	/*
+	 * Save elr_el3 and spsr_el3 from the saved context, and overwrite
+	 * the context with the NS fiq_handler_addr and SPSR value.
+	 */
+	fiq_state[cpu].elr_el3 = read_ctx_reg(el3state_ctx, CTX_ELR_EL3);
+	fiq_state[cpu].spsr_el3 = read_ctx_reg(el3state_ctx, CTX_SPSR_EL3);
+
+	/*
+	 * Set the new ELR to continue execution in the NS world using the
+	 * FIQ handler registered earlier.
+	 */
+	assert(ns_fiq_handler_addr);
+	write_ctx_reg(el3state_ctx, CTX_ELR_EL3, ns_fiq_handler_addr);
+
+	/*
+	 * Mark this interrupt as complete to avoid a FIQ storm.
+	 */
+	irq = plat_ic_acknowledge_interrupt();
+	if (irq < 1022)
+		plat_ic_end_of_interrupt(irq);
+
+	bakery_lock_release(&tegra_fiq_lock);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Setup handler for FIQ interrupts
+ ******************************************************************************/
+void tegra_fiq_handler_setup(void)
+{
+	uint64_t flags;
+	int rc;
+
+	/* return if already registered */
+	if (fiq_handler_active)
+		return;
+
+	/*
+	 * Register an interrupt handler for FIQ interrupts generated for
+	 * NS interrupt sources
+	 */
+	flags = 0;
+	set_interrupt_rm_flag(flags, NON_SECURE);
+	rc = register_interrupt_type_handler(INTR_TYPE_EL3,
+				tegra_fiq_interrupt_handler,
+				flags);
+	if (rc)
+		panic();
+
+	/* handler is now active */
+	fiq_handler_active = 1;
+}
+
+/*******************************************************************************
+ * Validate and store NS world's entrypoint for FIQ interrupts
+ ******************************************************************************/
+void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint)
+{
+	ns_fiq_handler_addr = entrypoint;
+}
+
+/*******************************************************************************
+ * Handler to return the NS EL1/EL0 CPU context
+ ******************************************************************************/
+int tegra_fiq_get_intr_context(void)
+{
+	cpu_context_t *ctx = cm_get_context(NON_SECURE);
+	gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx);
+	el1_sys_regs_t *el1state_ctx = get_sysregs_ctx(ctx);
+	int cpu = plat_my_core_pos();
+	uint64_t val;
+
+	/*
+	 * We store the ELR_EL3, SPSR_EL3, SP_EL0 and SP_EL1 registers so
+	 * that el3_exit() sends these values back to the NS world.
+	 */
+	write_ctx_reg(gpregs_ctx, CTX_GPREG_X0, fiq_state[cpu].elr_el3);
+	write_ctx_reg(gpregs_ctx, CTX_GPREG_X1, fiq_state[cpu].spsr_el3);
+
+	val = read_ctx_reg(gpregs_ctx, CTX_GPREG_SP_EL0);
+	write_ctx_reg(gpregs_ctx, CTX_GPREG_X2, val);
+
+	val = read_ctx_reg(el1state_ctx, CTX_SP_EL1);
+	write_ctx_reg(gpregs_ctx, CTX_GPREG_X3, val);
+
+	return 0;
+}
diff --git a/plat/nvidia/tegra/common/tegra_gic.c b/plat/nvidia/tegra/common/tegra_gic.c
index ee12975..6864f8b 100644
--- a/plat/nvidia/tegra/common/tegra_gic.c
+++ b/plat/nvidia/tegra/common/tegra_gic.c
@@ -47,6 +47,9 @@
 	(GIC_HIGHEST_NS_PRIORITY << 16) | \
 	(GIC_HIGHEST_NS_PRIORITY << 24))
 
+static const irq_sec_cfg_t *g_irq_sec_ptr;
+static unsigned int g_num_irqs;
+
 /*******************************************************************************
  * Place the cpu interface in a state where it can never make a cpu exit wfi as
  * as result of an asserted interrupt. This is critical for powering down a cpu
@@ -110,7 +113,9 @@
  ******************************************************************************/
 static void tegra_gic_distif_setup(unsigned int gicd_base)
 {
-	unsigned int index, num_ints;
+	unsigned int index, num_ints, irq_num;
+	uint8_t target_cpus;
+	uint32_t val;
 
 	/*
 	 * Mark out non-secure interrupts. Calculate number of
@@ -128,6 +133,39 @@
 				GICD_IPRIORITYR_DEF_VAL);
 	}
 
+	/* Configure SPI secure interrupts now */
+	if (g_irq_sec_ptr) {
+
+		for (index = 0; index < g_num_irqs; index++) {
+			irq_num = (g_irq_sec_ptr + index)->irq;
+			target_cpus = (g_irq_sec_ptr + index)->target_cpus;
+
+			if (irq_num >= MIN_SPI_ID) {
+
+				/* Configure as a secure interrupt */
+				gicd_clr_igroupr(gicd_base, irq_num);
+
+				/* Configure SPI priority */
+				mmio_write_8(gicd_base + GICD_IPRIORITYR +
+					irq_num,
+					GIC_HIGHEST_SEC_PRIORITY &
+					GIC_PRI_MASK);
+
+				/* Configure as level triggered */
+				val = gicd_read_icfgr(gicd_base, irq_num);
+				val |= (3 << ((irq_num & 0xF) << 1));
+				gicd_write_icfgr(gicd_base, irq_num, val);
+
+				/* Route SPI to the target CPUs */
+				gicd_set_itargetsr(gicd_base, irq_num,
+					target_cpus);
+
+				/* Enable this interrupt */
+				gicd_set_isenabler(gicd_base, irq_num);
+			}
+		}
+	}
+
 	/*
 	 * Configure the SGI and PPI. This is done in a separated function
 	 * because each CPU is responsible for initializing its own private
@@ -139,8 +177,11 @@
 	gicd_write_ctlr(gicd_base, ENABLE_GRP0 | ENABLE_GRP1);
 }
 
-void tegra_gic_setup(void)
+void tegra_gic_setup(const irq_sec_cfg_t *irq_sec_ptr, unsigned int num_irqs)
 {
+	g_irq_sec_ptr = irq_sec_ptr;
+	g_num_irqs = num_irqs;
+
 	tegra_gic_cpuif_setup(TEGRA_GICC_BASE);
 	tegra_gic_distif_setup(TEGRA_GICD_BASE);
 }
@@ -185,12 +226,17 @@
 uint32_t tegra_gic_get_pending_interrupt_type(void)
 {
 	uint32_t id;
+	unsigned int index;
 
 	id = gicc_read_hppir(TEGRA_GICC_BASE) & INT_ID_MASK;
 
-	/* Assume that all secure interrupts are S-EL1 interrupts */
-	if (id < 1022)
-		return INTR_TYPE_S_EL1;
+	/* get the interrupt type */
+	if (id < 1022) {
+		for (index = 0; index < g_num_irqs; index++) {
+			if (id == (g_irq_sec_ptr + index)->irq)
+				return (g_irq_sec_ptr + index)->type;
+		}
+	}
 
 	if (id == GIC_SPURIOUS_INTERRUPT)
 		return INTR_TYPE_INVAL;
@@ -248,14 +294,19 @@
 uint32_t tegra_gic_get_interrupt_type(uint32_t id)
 {
 	uint32_t group;
+	unsigned int index;
 
 	group = gicd_get_igroupr(TEGRA_GICD_BASE, id);
 
-	/* Assume that all secure interrupts are S-EL1 interrupts */
-	if (group == GRP0)
-		return INTR_TYPE_S_EL1;
-	else
-		return INTR_TYPE_NS;
+	/* get the interrupt type */
+	if (group == GRP0) {
+		for (index = 0; index < g_num_irqs; index++) {
+			if (id == (g_irq_sec_ptr + index)->irq)
+				return (g_irq_sec_ptr + index)->type;
+		}
+	}
+
+	return INTR_TYPE_NS;
 }
 
 #else
diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c
index 6fb3e9c..b2703dd 100644
--- a/plat/nvidia/tegra/common/tegra_pm.c
+++ b/plat/nvidia/tegra/common/tegra_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:
@@ -54,7 +54,10 @@
 #pragma weak tegra_soc_pwr_domain_on
 #pragma weak tegra_soc_pwr_domain_off
 #pragma weak tegra_soc_pwr_domain_on_finish
+#pragma weak tegra_soc_pwr_domain_power_down_wfi
 #pragma weak tegra_soc_prepare_system_reset
+#pragma weak tegra_soc_prepare_system_off
+#pragma weak tegra_soc_get_target_pwr_state
 
 int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
 {
@@ -76,11 +79,39 @@
 	return PSCI_E_SUCCESS;
 }
 
+int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
+{
+	return PSCI_E_SUCCESS;
+}
+
 int tegra_soc_prepare_system_reset(void)
 {
 	return PSCI_E_SUCCESS;
 }
 
+__dead2 void tegra_soc_prepare_system_off(void)
+{
+	ERROR("Tegra System Off: operation not handled.\n");
+	panic();
+}
+
+plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl,
+					     const plat_local_state_t *states,
+					     unsigned int ncpu)
+{
+	plat_local_state_t target = PLAT_MAX_RET_STATE, temp;
+
+	assert(ncpu);
+
+	do {
+		temp = *states++;
+		if ((temp > target) && (temp != PLAT_MAX_OFF_STATE))
+			target = temp;
+	} while (--ncpu);
+
+	return target;
+}
+
 /*******************************************************************************
  * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
  * call to get the `power_state` parameter. This allows the platform to encode
@@ -89,12 +120,9 @@
 ******************************************************************************/
 void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state)
 {
-	/* lower affinities use PLAT_MAX_OFF_STATE */
-	for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
-		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
-
-	/* max affinity uses system suspend state id */
-	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSTATE_ID_SOC_POWERDN;
+	/* all affinities use system suspend state id */
+	for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PSTATE_ID_SOC_POWERDN;
 }
 
 /*******************************************************************************
@@ -129,7 +157,7 @@
 }
 
 /*******************************************************************************
- * Handler called when called when a power domain is about to be suspended. The
+ * Handler called when a power domain is about to be suspended. The
  * target_state encodes the power state that each level should transition to.
  ******************************************************************************/
 void tegra_pwr_domain_suspend(const psci_power_state_t *target_state)
@@ -141,6 +169,24 @@
 }
 
 /*******************************************************************************
+ * Handler called at the end of the power domain suspend sequence. The
+ * target_state encodes the power state that each level should transition to.
+ ******************************************************************************/
+__dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t
+					     *target_state)
+{
+	/* call the chip's power down handler */
+	tegra_soc_pwr_domain_power_down_wfi(target_state);
+
+	/* enter power down state */
+	wfi();
+
+	/* we can never reach here */
+	ERROR("%s: operation not handled.\n", __func__);
+	panic();
+}
+
+/*******************************************************************************
  * Handler called when a power domain has just been powered on after
  * being turned off earlier. The target_state encodes the low power state that
  * each level has woken up from.
@@ -152,7 +198,7 @@
 	/*
 	 * Initialize the GIC cpu and distributor interfaces
 	 */
-	tegra_gic_setup();
+	plat_gic_setup();
 
 	/*
 	 * Check if we are exiting from deep sleep.
@@ -161,21 +207,23 @@
 			PSTATE_ID_SOC_POWERDN) {
 
 		/*
-		 * Lock scratch registers which hold the CPU vectors.
+		 * Restore Memory Controller settings as it loses state
+		 * during system suspend.
 		 */
-		tegra_pmc_lock_cpu_vectors();
-
-		/*
-		 * SMMU configuration.
-		 */
-		tegra_memctrl_setup();
+		tegra_memctrl_restore_settings();
 
 		/*
 		 * Security configuration to allow DRAM/device access.
 		 */
 		plat_params = bl31_get_plat_params();
-		tegra_memctrl_tzdram_setup(tegra_bl31_phys_base,
+		tegra_memctrl_tzdram_setup(plat_params->tzdram_base,
 			plat_params->tzdram_size);
+
+		/*
+		 * Set up the TZRAM memory aperture to allow only secure world
+		 * access
+		 */
+		tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE);
 	}
 
 	/*
@@ -199,8 +247,9 @@
  ******************************************************************************/
 __dead2 void tegra_system_off(void)
 {
-	ERROR("Tegra System Off: operation not handled.\n");
-	panic();
+	INFO("Powering down system...\n");
+
+	tegra_soc_prepare_system_off();
 }
 
 /*******************************************************************************
@@ -208,6 +257,8 @@
  ******************************************************************************/
 __dead2 void tegra_system_reset(void)
 {
+	INFO("Restarting system...\n");
+
 	/* per-SoC system reset handler */
 	tegra_soc_prepare_system_reset();
 
@@ -223,13 +274,8 @@
 int32_t tegra_validate_power_state(unsigned int power_state,
 				   psci_power_state_t *req_state)
 {
-	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
-
 	assert(req_state);
 
-	if (pwr_lvl > PLAT_MAX_PWR_LVL)
-		return PSCI_E_INVALID_PARAMS;
-
 	return tegra_soc_validate_power_state(power_state, req_state);
 }
 
@@ -258,6 +304,7 @@
 	.pwr_domain_suspend		= tegra_pwr_domain_suspend,
 	.pwr_domain_on_finish		= tegra_pwr_domain_on_finish,
 	.pwr_domain_suspend_finish	= tegra_pwr_domain_suspend_finish,
+	.pwr_domain_pwr_down_wfi	= tegra_pwr_domain_power_down_wfi,
 	.system_off			= tegra_system_off,
 	.system_reset			= tegra_system_reset,
 	.validate_power_state		= tegra_validate_power_state,
@@ -292,3 +339,14 @@
 
 	return 0;
 }
+
+/*******************************************************************************
+ * Platform handler to calculate the proper target power level at the
+ * specified affinity level
+ ******************************************************************************/
+plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
+					     const plat_local_state_t *states,
+					     unsigned int ncpu)
+{
+	return tegra_soc_get_target_pwr_state(lvl, states, ncpu);
+}
diff --git a/plat/nvidia/tegra/common/tegra_sip_calls.c b/plat/nvidia/tegra/common/tegra_sip_calls.c
index de36a3c..ba0e1ef 100644
--- a/plat/nvidia/tegra/common/tegra_sip_calls.c
+++ b/plat/nvidia/tegra/common/tegra_sip_calls.c
@@ -32,31 +32,37 @@
 #include <arch_helpers.h>
 #include <assert.h>
 #include <bl_common.h>
-#include <context_mgmt.h>
 #include <debug.h>
 #include <errno.h>
 #include <memctrl.h>
 #include <runtime_svc.h>
 #include <tegra_private.h>
 
-#define NS_SWITCH_AARCH32	1
-#define SCR_RW_BITPOS		__builtin_ctz(SCR_RW_BIT)
-
 /*******************************************************************************
- * Tegra SiP SMCs
+ * Common Tegra SiP SMCs
  ******************************************************************************/
 #define TEGRA_SIP_NEW_VIDEOMEM_REGION		0x82000003
-#define TEGRA_SIP_AARCH_SWITCH			0x82000004
+#define TEGRA_SIP_FIQ_NS_ENTRYPOINT		0x82000005
+#define TEGRA_SIP_FIQ_NS_GET_CONTEXT		0x82000006
 
 /*******************************************************************************
- * SPSR settings for AARCH32/AARCH64 modes
+ * SoC specific SiP handler
  ******************************************************************************/
-#define SPSR32		SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, \
-			DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT)
-#define SPSR64		SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS)
+#pragma weak plat_sip_handler
+int 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)
+{
+	return -ENOTSUP;
+}
 
 /*******************************************************************************
- * This function is responsible for handling all SiP calls from the NS world
+ * This function is responsible for handling all SiP calls
  ******************************************************************************/
 uint64_t tegra_sip_handler(uint32_t smc_fid,
 			   uint64_t x1,
@@ -67,13 +73,12 @@
 			   void *handle,
 			   uint64_t flags)
 {
-	uint32_t ns;
 	int err;
 
-	/* Determine which security state this SMC originated from */
-	ns = is_caller_non_secure(flags);
-	if (!ns)
-		SMC_RET1(handle, SMC_UNK);
+	/* Check if this is a SoC specific SiP */
+	err = plat_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+	if (err == 0)
+		SMC_RET1(handle, err);
 
 	switch (smc_fid) {
 
@@ -105,29 +110,41 @@
 		SMC_RET1(handle, 0);
 		break;
 
-	case TEGRA_SIP_AARCH_SWITCH:
+	/*
+	 * The NS world registers the address of its handler to be
+	 * used for processing the FIQ. This is normally used by the
+	 * NS FIQ debugger driver to detect system hangs by programming
+	 * a watchdog timer to fire a FIQ interrupt.
+	 */
+	case TEGRA_SIP_FIQ_NS_ENTRYPOINT:
 
-		/* clean up the high bits */
-		x1 = (uint32_t)x1;
-		x2 = (uint32_t)x2;
-
-		if (!x1 || x2 > NS_SWITCH_AARCH32) {
-			ERROR("%s: invalid parameters\n", __func__);
+		if (!x1)
 			SMC_RET1(handle, SMC_UNK);
-		}
 
-		/* x1 = ns entry point */
-		cm_set_elr_spsr_el3(NON_SECURE, x1,
-			(x2 == NS_SWITCH_AARCH32) ? SPSR32 : SPSR64);
+		/*
+		 * TODO: Check if x1 contains a valid DRAM address
+		 */
 
-		/* switch NS world mode */
-		cm_write_scr_el3_bit(NON_SECURE, SCR_RW_BITPOS, !x2);
+		/* store the NS world's entrypoint */
+		tegra_fiq_set_ns_entrypoint(x1);
 
-		INFO("CPU switched to AARCH%s mode\n",
-			(x2 == NS_SWITCH_AARCH32) ? "32" : "64");
 		SMC_RET1(handle, 0);
 		break;
 
+	/*
+	 * The NS world's FIQ handler issues this SMC to get the NS EL1/EL0
+	 * CPU context when the FIQ interrupt was triggered. This allows the
+	 * NS world to understand the CPU state when the watchdog interrupt
+	 * triggered.
+	 */
+	case TEGRA_SIP_FIQ_NS_GET_CONTEXT:
+
+		/* retrieve context registers when FIQ triggered */
+		tegra_fiq_get_intr_context();
+
+		SMC_RET0(handle);
+		break;
+
 	default:
 		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
 		break;
diff --git a/plat/nvidia/tegra/include/drivers/memctrl.h b/plat/nvidia/tegra/include/drivers/memctrl.h
index 26c8057..a3f0875 100644
--- a/plat/nvidia/tegra/include/drivers/memctrl.h
+++ b/plat/nvidia/tegra/include/drivers/memctrl.h
@@ -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:
@@ -31,55 +31,10 @@
 #ifndef __MEMCTRL_H__
 #define __MEMCTRL_H__
 
-#include <mmio.h>
-#include <tegra_def.h>
-
-/* SMMU registers */
-#define MC_SMMU_CONFIG_0			0x10
-#define  MC_SMMU_CONFIG_0_SMMU_ENABLE_DISABLE	0
-#define  MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE	1
-#define MC_SMMU_TLB_CONFIG_0			0x14
-#define  MC_SMMU_TLB_CONFIG_0_RESET_VAL		0x20000010
-#define MC_SMMU_PTC_CONFIG_0			0x18
-#define  MC_SMMU_PTC_CONFIG_0_RESET_VAL		0x2000003f
-#define MC_SMMU_TLB_FLUSH_0			0x30
-#define  TLB_FLUSH_VA_MATCH_ALL			0
-#define  TLB_FLUSH_ASID_MATCH_DISABLE		0
-#define  TLB_FLUSH_ASID_MATCH_SHIFT		31
-#define  MC_SMMU_TLB_FLUSH_ALL		\
-	 (TLB_FLUSH_VA_MATCH_ALL | 	\
-	 (TLB_FLUSH_ASID_MATCH_DISABLE << TLB_FLUSH_ASID_MATCH_SHIFT))
-#define MC_SMMU_PTC_FLUSH_0			0x34
-#define  MC_SMMU_PTC_FLUSH_ALL			0
-#define MC_SMMU_ASID_SECURITY_0			0x38
-#define  MC_SMMU_ASID_SECURITY			0
-#define MC_SMMU_TRANSLATION_ENABLE_0_0		0x228
-#define MC_SMMU_TRANSLATION_ENABLE_1_0		0x22c
-#define MC_SMMU_TRANSLATION_ENABLE_2_0		0x230
-#define MC_SMMU_TRANSLATION_ENABLE_3_0		0x234
-#define MC_SMMU_TRANSLATION_ENABLE_4_0		0xb98
-#define  MC_SMMU_TRANSLATION_ENABLE		(~0)
-
-/* TZDRAM carveout configuration registers */
-#define MC_SECURITY_CFG0_0			0x70
-#define MC_SECURITY_CFG1_0			0x74
-
-/* Video Memory carveout configuration registers */
-#define MC_VIDEO_PROTECT_BASE			0x648
-#define MC_VIDEO_PROTECT_SIZE_MB		0x64c
-
-static inline uint32_t tegra_mc_read_32(uint32_t off)
-{
-	return mmio_read_32(TEGRA_MC_BASE + off);
-}
-
-static inline void tegra_mc_write_32(uint32_t off, uint32_t val)
-{
-	mmio_write_32(TEGRA_MC_BASE + off, val);
-}
-
 void tegra_memctrl_setup(void);
+void tegra_memctrl_restore_settings(void);
 void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes);
+void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes);
 void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes);
 
 #endif /* __MEMCTRL_H__ */
diff --git a/plat/nvidia/tegra/include/drivers/memctrl_v1.h b/plat/nvidia/tegra/include/drivers/memctrl_v1.h
new file mode 100644
index 0000000..e44a9ea
--- /dev/null
+++ b/plat/nvidia/tegra/include/drivers/memctrl_v1.h
@@ -0,0 +1,81 @@
+/*
+ * 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:
+ *
+ * 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 __MEMCTRLV1_H__
+#define __MEMCTRLV1_H__
+
+#include <mmio.h>
+#include <tegra_def.h>
+
+/* SMMU registers */
+#define MC_SMMU_CONFIG_0			0x10
+#define  MC_SMMU_CONFIG_0_SMMU_ENABLE_DISABLE	0
+#define  MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE	1
+#define MC_SMMU_TLB_CONFIG_0			0x14
+#define  MC_SMMU_TLB_CONFIG_0_RESET_VAL		0x20000010
+#define MC_SMMU_PTC_CONFIG_0			0x18
+#define  MC_SMMU_PTC_CONFIG_0_RESET_VAL		0x2000003f
+#define MC_SMMU_TLB_FLUSH_0			0x30
+#define  TLB_FLUSH_VA_MATCH_ALL			0
+#define  TLB_FLUSH_ASID_MATCH_DISABLE		0
+#define  TLB_FLUSH_ASID_MATCH_SHIFT		31
+#define  MC_SMMU_TLB_FLUSH_ALL		\
+	 (TLB_FLUSH_VA_MATCH_ALL | 	\
+	 (TLB_FLUSH_ASID_MATCH_DISABLE << TLB_FLUSH_ASID_MATCH_SHIFT))
+#define MC_SMMU_PTC_FLUSH_0			0x34
+#define  MC_SMMU_PTC_FLUSH_ALL			0
+#define MC_SMMU_ASID_SECURITY_0			0x38
+#define  MC_SMMU_ASID_SECURITY			0
+#define MC_SMMU_TRANSLATION_ENABLE_0_0		0x228
+#define MC_SMMU_TRANSLATION_ENABLE_1_0		0x22c
+#define MC_SMMU_TRANSLATION_ENABLE_2_0		0x230
+#define MC_SMMU_TRANSLATION_ENABLE_3_0		0x234
+#define MC_SMMU_TRANSLATION_ENABLE_4_0		0xb98
+#define  MC_SMMU_TRANSLATION_ENABLE		(~0)
+
+/* TZDRAM carveout configuration registers */
+#define MC_SECURITY_CFG0_0			0x70
+#define MC_SECURITY_CFG1_0			0x74
+
+/* Video Memory carveout configuration registers */
+#define MC_VIDEO_PROTECT_BASE			0x648
+#define MC_VIDEO_PROTECT_SIZE_MB		0x64c
+
+static inline uint32_t tegra_mc_read_32(uint32_t off)
+{
+	return mmio_read_32(TEGRA_MC_BASE + off);
+}
+
+static inline void tegra_mc_write_32(uint32_t off, uint32_t val)
+{
+	mmio_write_32(TEGRA_MC_BASE + off, val);
+}
+
+#endif /* __MEMCTRLV1_H__ */
diff --git a/plat/nvidia/tegra/include/platform_def.h b/plat/nvidia/tegra/include/platform_def.h
index cd06d93..ad245e2 100644
--- a/plat/nvidia/tegra/include/platform_def.h
+++ b/plat/nvidia/tegra/include/platform_def.h
@@ -53,12 +53,6 @@
 					 PLATFORM_CLUSTER_COUNT + 1)
 
 /*******************************************************************************
- * Platform power states
- ******************************************************************************/
-#define PLAT_MAX_RET_STATE		1
-#define PLAT_MAX_OFF_STATE		(PSTATE_ID_SOC_POWERDN + 1)
-
-/*******************************************************************************
  * Platform console related constants
  ******************************************************************************/
 #define TEGRA_CONSOLE_BAUDRATE		115200
@@ -74,7 +68,7 @@
 /*******************************************************************************
  * BL31 specific defines.
  ******************************************************************************/
-#define BL31_SIZE			0x20000
+#define BL31_SIZE			0x40000
 #define BL31_BASE			TZDRAM_BASE
 #define BL31_LIMIT			(TZDRAM_BASE + BL31_SIZE - 1)
 #define BL32_BASE			(TZDRAM_BASE + BL31_SIZE)
@@ -84,8 +78,6 @@
  * Platform specific page table and MMU setup constants
  ******************************************************************************/
 #define ADDR_SPACE_SIZE			(1ull << 32)
-#define MAX_XLAT_TABLES			3
-#define MAX_MMAP_REGIONS		8
 
 /*******************************************************************************
  * Some data must be aligned on the biggest cache line size in the platform.
diff --git a/plat/nvidia/tegra/include/t132/tegra_def.h b/plat/nvidia/tegra/include/t132/tegra_def.h
index 683c903..318f4de 100644
--- a/plat/nvidia/tegra/include/t132/tegra_def.h
+++ b/plat/nvidia/tegra/include/t132/tegra_def.h
@@ -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:
@@ -40,6 +40,15 @@
 #define PSTATE_ID_SOC_POWERDN	0xD
 
 /*******************************************************************************
+ * Platform power states (used by PSCI framework)
+ *
+ * - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID
+ * - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID
+ ******************************************************************************/
+#define PLAT_MAX_RET_STATE		1
+#define PLAT_MAX_OFF_STATE		(PSTATE_ID_SOC_POWERDN + 1)
+
+/*******************************************************************************
  * GIC memory map
  ******************************************************************************/
 #define TEGRA_GICD_BASE			0x50041000
@@ -71,6 +80,15 @@
 #define TEGRA_EVP_BASE			0x6000F000
 
 /*******************************************************************************
+ * Tegra UART controller base addresses
+ ******************************************************************************/
+#define TEGRA_UARTA_BASE		0x70006000
+#define TEGRA_UARTB_BASE		0x70006040
+#define TEGRA_UARTC_BASE		0x70006200
+#define TEGRA_UARTD_BASE		0x70006300
+#define TEGRA_UARTE_BASE		0x70006400
+
+/*******************************************************************************
  * Tegra Power Mgmt Controller constants
  ******************************************************************************/
 #define TEGRA_PMC_BASE			0x7000E400
@@ -80,4 +98,10 @@
  ******************************************************************************/
 #define TEGRA_MC_BASE			0x70019000
 
+/*******************************************************************************
+ * Tegra TZRAM constants
+ ******************************************************************************/
+#define TEGRA_TZRAM_BASE		0x7C010000
+#define TEGRA_TZRAM_SIZE		0x10000
+
 #endif /* __TEGRA_DEF_H__ */
diff --git a/plat/nvidia/tegra/include/t210/tegra_def.h b/plat/nvidia/tegra/include/t210/tegra_def.h
index 750e6e3..ce85427 100644
--- a/plat/nvidia/tegra/include/t210/tegra_def.h
+++ b/plat/nvidia/tegra/include/t210/tegra_def.h
@@ -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:
@@ -48,18 +48,13 @@
 #define PLAT_SYS_SUSPEND_STATE_ID	PSTATE_ID_SOC_POWERDN
 
 /*******************************************************************************
- * Implementation defined ACTLR_EL3 bit definitions
+ * Platform power states (used by PSCI framework)
+ *
+ * - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID
+ * - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID
  ******************************************************************************/
-#define ACTLR_EL3_L2ACTLR_BIT		(1 << 6)
-#define ACTLR_EL3_L2ECTLR_BIT		(1 << 5)
-#define ACTLR_EL3_L2CTLR_BIT		(1 << 4)
-#define ACTLR_EL3_CPUECTLR_BIT		(1 << 1)
-#define ACTLR_EL3_CPUACTLR_BIT		(1 << 0)
-#define ACTLR_EL3_ENABLE_ALL_ACCESS	(ACTLR_EL3_L2ACTLR_BIT | \
-					 ACTLR_EL3_L2ECTLR_BIT | \
-					 ACTLR_EL3_L2CTLR_BIT | \
-					 ACTLR_EL3_CPUECTLR_BIT | \
-					 ACTLR_EL3_CPUACTLR_BIT)
+#define PLAT_MAX_RET_STATE		1
+#define PLAT_MAX_OFF_STATE		(PSTATE_ID_SOC_POWERDN + 1)
 
 /*******************************************************************************
  * GIC memory map
@@ -110,6 +105,15 @@
 #define TEGRA_EVP_BASE			0x6000F000
 
 /*******************************************************************************
+ * Tegra UART controller base addresses
+ ******************************************************************************/
+#define TEGRA_UARTA_BASE		0x70006000
+#define TEGRA_UARTB_BASE		0x70006040
+#define TEGRA_UARTC_BASE		0x70006200
+#define TEGRA_UARTD_BASE		0x70006300
+#define TEGRA_UARTE_BASE		0x70006400
+
+/*******************************************************************************
  * Tegra Power Mgmt Controller constants
  ******************************************************************************/
 #define TEGRA_PMC_BASE			0x7000E400
@@ -119,4 +123,10 @@
  ******************************************************************************/
 #define TEGRA_MC_BASE			0x70019000
 
+/*******************************************************************************
+ * Tegra TZRAM constants
+ ******************************************************************************/
+#define TEGRA_TZRAM_BASE		0x7C010000
+#define TEGRA_TZRAM_SIZE		0x10000
+
 #endif /* __TEGRA_DEF_H__ */
diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h
index cf75d9f..012bfd7 100644
--- a/plat/nvidia/tegra/include/tegra_private.h
+++ b/plat/nvidia/tegra/include/tegra_private.h
@@ -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:
@@ -42,23 +42,60 @@
 #define TEGRA_DRAM_BASE		0x80000000
 #define TEGRA_DRAM_END		0x27FFFFFFF
 
+/*******************************************************************************
+ * Struct for parameters received from BL2
+ ******************************************************************************/
 typedef struct plat_params_from_bl2 {
+	/* TZ memory size */
 	uint64_t tzdram_size;
+	/* TZ memory base */
+	uint64_t tzdram_base;
+	/* UART port ID */
+	int uart_id;
 } plat_params_from_bl2_t;
 
+/*******************************************************************************
+ * Per-CPU struct describing FIQ state to be stored
+ ******************************************************************************/
+typedef struct pcpu_fiq_state {
+	uint64_t elr_el3;
+	uint64_t spsr_el3;
+} pcpu_fiq_state_t;
+
+/*******************************************************************************
+ * Struct describing per-FIQ configuration settings
+ ******************************************************************************/
+typedef struct irq_sec_cfg {
+	/* IRQ number */
+	unsigned int irq;
+	/* Target CPUs servicing this interrupt */
+	unsigned int target_cpus;
+	/* type = INTR_TYPE_S_EL1 or INTR_TYPE_EL3 */
+	uint32_t type;
+} irq_sec_cfg_t;
+
 /* Declarations for plat_psci_handlers.c */
 int32_t tegra_soc_validate_power_state(unsigned int power_state,
 		psci_power_state_t *req_state);
 
 /* Declarations for plat_setup.c */
 const mmap_region_t *plat_get_mmio_map(void);
+uint32_t plat_get_console_from_id(int id);
+void plat_gic_setup(void);
+bl31_params_t *plat_get_bl31_params(void);
+plat_params_from_bl2_t *plat_get_bl31_plat_params(void);
 
 /* Declarations for plat_secondary.c */
 void plat_secondary_setup(void);
 int plat_lock_cpu_vectors(void);
 
+/* Declarations for tegra_fiq_glue.c */
+void tegra_fiq_handler_setup(void);
+int tegra_fiq_get_intr_context(void);
+void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint);
+
 /* Declarations for tegra_gic.c */
-void tegra_gic_setup(void);
+void tegra_gic_setup(const irq_sec_cfg_t *irq_sec_ptr, unsigned int num_irqs);
 void tegra_gic_cpuif_deactivate(void);
 
 /* Declarations for tegra_security.c */
@@ -77,6 +114,7 @@
 /* Declarations for tegra_bl31_setup.c */
 plat_params_from_bl2_t *bl31_get_plat_params(void);
 int bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes);
+void plat_early_platform_setup(void);
 
 /* Declarations for tegra_delay_timer.c */
 void tegra_delay_timer_init(void);
diff --git a/plat/nvidia/tegra/platform.mk b/plat/nvidia/tegra/platform.mk
index cec7caf..b168634 100644
--- a/plat/nvidia/tegra/platform.mk
+++ b/plat/nvidia/tegra/platform.mk
@@ -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:
@@ -30,9 +30,20 @@
 
 SOC_DIR			:=	plat/nvidia/tegra/soc/${TARGET_SOC}
 
+# Enable PSCI v1.0 extended state ID format
+PSCI_EXTENDED_STATE_ID	:=	1
+
 # Disable the PSCI platform compatibility layer
 ENABLE_PLAT_COMPAT	:=	0
 
+# Disable cache non-temporal hint for A57
+A57_DISABLE_NON_TEMPORAL_HINT		:= 0
+$(eval $(call add_define,A57_DISABLE_NON_TEMPORAL_HINT))
+
+# Disable cache non-temporal hint for A53
+A53_DISABLE_NON_TEMPORAL_HINT		:= 0
+$(eval $(call add_define,A53_DISABLE_NON_TEMPORAL_HINT))
+
 include plat/nvidia/tegra/common/tegra_common.mk
 include ${SOC_DIR}/platform_${TARGET_SOC}.mk
 
diff --git a/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c
index 48a2fba..f05f3d0 100644
--- a/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c
+++ b/plat/nvidia/tegra/soc/t132/plat_psci_handlers.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:
@@ -59,36 +59,15 @@
 int32_t tegra_soc_validate_power_state(unsigned int power_state,
 					psci_power_state_t *req_state)
 {
-	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
 	int state_id = psci_get_pstate_id(power_state);
 	int cpu = read_mpidr() & MPIDR_CPU_MASK;
 
-	if (pwr_lvl > PLAT_MAX_PWR_LVL)
-		return PSCI_E_INVALID_PARAMS;
-
-	/* Sanity check the requested afflvl */
-	if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) {
-		/*
-		 * It's possible to enter standby only on affinity level 0 i.e.
-		 * a cpu on Tegra. Ignore any other affinity level.
-		 */
-		if (pwr_lvl != MPIDR_AFFLVL0)
-			return PSCI_E_INVALID_PARAMS;
-
-		/* power domain in standby state */
-		req_state->pwr_domain_state[pwr_lvl] = PLAT_MAX_RET_STATE;
-
-		return PSCI_E_SUCCESS;
-	}
-
 	/*
 	 * Sanity check the requested state id, power level and CPU number.
 	 * Currently T132 only supports SYSTEM_SUSPEND on last standing CPU
 	 * i.e. CPU 0
 	 */
-	if ((pwr_lvl != PLAT_MAX_PWR_LVL) ||
-	    (state_id != PSTATE_ID_SOC_POWERDN) ||
-	    (cpu != 0)) {
+	if ((state_id != PSTATE_ID_SOC_POWERDN) || (cpu != 0)) {
 		ERROR("unsupported state id @ power level\n");
 		return PSCI_E_INVALID_PARAMS;
 	}
@@ -128,9 +107,26 @@
 	return PSCI_E_SUCCESS;
 }
 
+int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	/*
+	 * Lock scratch registers which hold the CPU vectors
+	 */
+	tegra_pmc_lock_cpu_vectors();
+
+	return PSCI_E_SUCCESS;
+}
+
 int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
 {
 	tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
+
+	/* Disable DCO operations */
+	denver_disable_dco();
+
+	/* Power down the CPU */
+	write_actlr_el1(DENVER_CPU_STATE_POWER_DOWN);
+
 	return PSCI_E_SUCCESS;
 }
 
@@ -149,7 +145,10 @@
 	/* Program FC to enter suspend state */
 	tegra_fc_cpu_powerdn(read_mpidr());
 
-	/* Suspend DCO operations */
+	/* Disable DCO operations */
+	denver_disable_dco();
+
+	/* Program the suspend state ID */
 	write_actlr_el1(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]);
 
 	return PSCI_E_SUCCESS;
diff --git a/plat/nvidia/tegra/soc/t132/plat_setup.c b/plat/nvidia/tegra/soc/t132/plat_setup.c
index 0d66413..651bd08 100644
--- a/plat/nvidia/tegra/soc/t132/plat_setup.c
+++ b/plat/nvidia/tegra/soc/t132/plat_setup.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:
@@ -28,8 +28,11 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <xlat_tables.h>
+#include <arch_helpers.h>
+#include <bl_common.h>
 #include <tegra_def.h>
+#include <tegra_private.h>
+#include <xlat_tables.h>
 
 /*******************************************************************************
  * The Tegra power domain tree has a single system level power domain i.e. a
@@ -78,3 +81,39 @@
 {
 	return 12000000;
 }
+
+/*******************************************************************************
+ * Maximum supported UART controllers
+ ******************************************************************************/
+#define TEGRA132_MAX_UART_PORTS		5
+
+/*******************************************************************************
+ * This variable holds the UART port base addresses
+ ******************************************************************************/
+static uint32_t tegra132_uart_addresses[TEGRA132_MAX_UART_PORTS + 1] = {
+	0,	/* undefined - treated as an error case */
+	TEGRA_UARTA_BASE,
+	TEGRA_UARTB_BASE,
+	TEGRA_UARTC_BASE,
+	TEGRA_UARTD_BASE,
+	TEGRA_UARTE_BASE,
+};
+
+/*******************************************************************************
+ * Retrieve the UART controller base to be used as the console
+ ******************************************************************************/
+uint32_t plat_get_console_from_id(int id)
+{
+	if (id > TEGRA132_MAX_UART_PORTS)
+		return 0;
+
+	return tegra132_uart_addresses[id];
+}
+
+/*******************************************************************************
+ * Initialize the GIC and SGIs
+ ******************************************************************************/
+void plat_gic_setup(void)
+{
+	tegra_gic_setup(NULL, 0);
+}
diff --git a/plat/nvidia/tegra/soc/t132/plat_sip_calls.c b/plat/nvidia/tegra/soc/t132/plat_sip_calls.c
new file mode 100644
index 0000000..6c89944
--- /dev/null
+++ b/plat/nvidia/tegra/soc/t132/plat_sip_calls.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, 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 <bl_common.h>
+#include <context_mgmt.h>
+#include <debug.h>
+#include <errno.h>
+#include <tegra_private.h>
+
+#define NS_SWITCH_AARCH32	1
+#define SCR_RW_BITPOS		__builtin_ctz(SCR_RW_BIT)
+
+/*******************************************************************************
+ * Tegra132 SiP SMCs
+ ******************************************************************************/
+#define TEGRA_SIP_AARCH_SWITCH			0x82000004
+
+/*******************************************************************************
+ * SPSR settings for AARCH32/AARCH64 modes
+ ******************************************************************************/
+#define SPSR32		SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, \
+			DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT)
+#define SPSR64		SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS)
+
+/*******************************************************************************
+ * This function is responsible for handling all T132 SiP calls
+ ******************************************************************************/
+int 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)
+{
+	switch (smc_fid) {
+
+	case TEGRA_SIP_AARCH_SWITCH:
+
+		/* clean up the high bits */
+		x1 = (uint32_t)x1;
+		x2 = (uint32_t)x2;
+
+		if (!x1 || x2 > NS_SWITCH_AARCH32) {
+			ERROR("%s: invalid parameters\n", __func__);
+			return -EINVAL;
+		}
+
+		/* x1 = ns entry point */
+		cm_set_elr_spsr_el3(NON_SECURE, x1,
+			(x2 == NS_SWITCH_AARCH32) ? SPSR32 : SPSR64);
+
+		/* switch NS world mode */
+		cm_write_scr_el3_bit(NON_SECURE, SCR_RW_BITPOS, !x2);
+
+		INFO("CPU switched to AARCH%s mode\n",
+			(x2 == NS_SWITCH_AARCH32) ? "32" : "64");
+		return 0;
+
+	default:
+		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+		break;
+	}
+
+	return -ENOTSUP;
+}
diff --git a/plat/nvidia/tegra/soc/t132/platform_t132.mk b/plat/nvidia/tegra/soc/t132/platform_t132.mk
index 69d6296..6b9fce3 100644
--- a/plat/nvidia/tegra/soc/t132/platform_t132.mk
+++ b/plat/nvidia/tegra/soc/t132/platform_t132.mk
@@ -28,9 +28,6 @@
 # POSSIBILITY OF SUCH DAMAGE.
 #
 
-TEGRA_BOOT_UART_BASE		:= 0x70006300
-$(eval $(call add_define,TEGRA_BOOT_UART_BASE))
-
 TZDRAM_BASE			:= 0xF5C00000
 $(eval $(call add_define,TZDRAM_BASE))
 
@@ -40,7 +37,16 @@
 PLATFORM_MAX_CPUS_PER_CLUSTER	:= 2
 $(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER))
 
+MAX_XLAT_TABLES			:= 3
+$(eval $(call add_define,MAX_XLAT_TABLES))
+
+MAX_MMAP_REGIONS		:= 8
+$(eval $(call add_define,MAX_MMAP_REGIONS))
+
 BL31_SOURCES		+=	lib/cpus/aarch64/denver.S		\
+				${COMMON_DIR}/drivers/flowctrl/flowctrl.c	\
+				${COMMON_DIR}/drivers/memctrl/memctrl_v1.c	\
 				${SOC_DIR}/plat_psci_handlers.c		\
+				${SOC_DIR}/plat_sip_calls.c		\
 				${SOC_DIR}/plat_setup.c			\
 				${SOC_DIR}/plat_secondary.c
diff --git a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
index b184063..95fb93f 100644
--- a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c
+++ b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.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:
@@ -58,39 +58,14 @@
 int32_t tegra_soc_validate_power_state(unsigned int power_state,
 					psci_power_state_t *req_state)
 {
-	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
 	int state_id = psci_get_pstate_id(power_state);
 
-	if (pwr_lvl > PLAT_MAX_PWR_LVL) {
-		ERROR("%s: unsupported power_state (0x%x)\n", __func__,
-			power_state);
-		return PSCI_E_INVALID_PARAMS;
-	}
-
-	/* Sanity check the requested afflvl */
-	if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) {
-		/*
-		 * It's possible to enter standby only on affinity level 0 i.e.
-		 * a cpu on Tegra. Ignore any other affinity level.
-		 */
-		if (pwr_lvl != MPIDR_AFFLVL0)
-			return PSCI_E_INVALID_PARAMS;
-
-		/* power domain in standby state */
-		req_state->pwr_domain_state[pwr_lvl] = PLAT_MAX_RET_STATE;
-
-		return PSCI_E_SUCCESS;
-	}
-
 	/* Sanity check the requested state id */
 	switch (state_id) {
 	case PSTATE_ID_CORE_POWERDN:
 		/*
 		 * Core powerdown request only for afflvl 0
 		 */
-		if (pwr_lvl != MPIDR_AFFLVL0)
-			goto error;
-
 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff;
 
 		break;
@@ -100,9 +75,6 @@
 		/*
 		 * Cluster powerdown/idle request only for afflvl 1
 		 */
-		if (pwr_lvl != MPIDR_AFFLVL1)
-			goto error;
-
 		req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
 
@@ -112,9 +84,6 @@
 		/*
 		 * System powerdown request only for afflvl 2
 		 */
-		if (pwr_lvl != PLAT_MAX_PWR_LVL)
-			goto error;
-
 		for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
 			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
 
@@ -129,10 +98,6 @@
 	}
 
 	return PSCI_E_SUCCESS;
-
-error:
-	ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
-	return PSCI_E_INVALID_PARAMS;
 }
 
 int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
@@ -190,6 +155,11 @@
 			PLAT_SYS_SUSPEND_STATE_ID) {
 
 		/*
+		 * Lock scratch registers which hold the CPU vectors
+		 */
+		tegra_pmc_lock_cpu_vectors();
+
+		/*
 		 * Enable WRAP to INCR burst type conversions for
 		 * incoming requests on the AXI slave ports.
 		 */
diff --git a/plat/nvidia/tegra/soc/t210/plat_setup.c b/plat/nvidia/tegra/soc/t210/plat_setup.c
index 70a55c6..42eefe7 100644
--- a/plat/nvidia/tegra/soc/t210/plat_setup.c
+++ b/plat/nvidia/tegra/soc/t210/plat_setup.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:
@@ -28,8 +28,11 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <arch_helpers.h>
+#include <bl_common.h>
 #include <console.h>
 #include <tegra_def.h>
+#include <tegra_private.h>
 #include <xlat_tables.h>
 
 /*******************************************************************************
@@ -84,3 +87,39 @@
 {
 	return 19200000;
 }
+
+/*******************************************************************************
+ * Maximum supported UART controllers
+ ******************************************************************************/
+#define TEGRA210_MAX_UART_PORTS		5
+
+/*******************************************************************************
+ * This variable holds the UART port base addresses
+ ******************************************************************************/
+static uint32_t tegra210_uart_addresses[TEGRA210_MAX_UART_PORTS + 1] = {
+	0,	/* undefined - treated as an error case */
+	TEGRA_UARTA_BASE,
+	TEGRA_UARTB_BASE,
+	TEGRA_UARTC_BASE,
+	TEGRA_UARTD_BASE,
+	TEGRA_UARTE_BASE,
+};
+
+/*******************************************************************************
+ * Retrieve the UART controller base to be used as the console
+ ******************************************************************************/
+uint32_t plat_get_console_from_id(int id)
+{
+	if (id > TEGRA210_MAX_UART_PORTS)
+		return 0;
+
+	return tegra210_uart_addresses[id];
+}
+
+/*******************************************************************************
+ * Initialize the GIC and SGIs
+ ******************************************************************************/
+void plat_gic_setup(void)
+{
+	tegra_gic_setup(NULL, 0);
+}
diff --git a/plat/nvidia/tegra/soc/t210/platform_t210.mk b/plat/nvidia/tegra/soc/t210/platform_t210.mk
index 5001629..2c908f9 100644
--- a/plat/nvidia/tegra/soc/t210/platform_t210.mk
+++ b/plat/nvidia/tegra/soc/t210/platform_t210.mk
@@ -28,32 +28,28 @@
 # POSSIBILITY OF SUCH DAMAGE.
 #
 
-TEGRA_BOOT_UART_BASE 			:= 0x70006000
-$(eval $(call add_define,TEGRA_BOOT_UART_BASE))
-
 TZDRAM_BASE				:= 0xFDC00000
 $(eval $(call add_define,TZDRAM_BASE))
 
 ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT	:= 1
 $(eval $(call add_define,ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT))
 
-ENABLE_NS_L2_CPUECTRL_RW_ACCESS		:= 1
-$(eval $(call add_define,ENABLE_NS_L2_CPUECTRL_RW_ACCESS))
-
-ENABLE_L2_DYNAMIC_RETENTION		:= 1
-$(eval $(call add_define,ENABLE_L2_DYNAMIC_RETENTION))
-
-ENABLE_CPU_DYNAMIC_RETENTION		:= 1
-$(eval $(call add_define,ENABLE_CPU_DYNAMIC_RETENTION))
-
 PLATFORM_CLUSTER_COUNT			:= 2
 $(eval $(call add_define,PLATFORM_CLUSTER_COUNT))
 
 PLATFORM_MAX_CPUS_PER_CLUSTER		:= 4
 $(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER))
 
+MAX_XLAT_TABLES				:= 3
+$(eval $(call add_define,MAX_XLAT_TABLES))
+
+MAX_MMAP_REGIONS			:= 8
+$(eval $(call add_define,MAX_MMAP_REGIONS))
+
 BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
 				lib/cpus/aarch64/cortex_a57.S		\
+				${COMMON_DIR}/drivers/flowctrl/flowctrl.c	\
+				${COMMON_DIR}/drivers/memctrl/memctrl_v1.c	\
 				${SOC_DIR}/plat_psci_handlers.c		\
 				${SOC_DIR}/plat_setup.c			\
 				${SOC_DIR}/plat_secondary.c
diff --git a/plat/qemu/qemu_bl2_setup.c b/plat/qemu/qemu_bl2_setup.c
index dba3bee..738d671 100644
--- a/plat/qemu/qemu_bl2_setup.c
+++ b/plat/qemu/qemu_bl2_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, 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:
@@ -35,7 +35,7 @@
 #include <platform_def.h>
 #include "qemu_private.h"
 #include <string.h>
-
+#include <utils.h>
 
 /*
  * The next 2 constants identify the extents of the code & RO data region.
@@ -91,7 +91,7 @@
 	 * Initialise the memory for all the arguments that needs to
 	 * be passed to BL3-1
 	 */
-	memset(&bl31_params_mem, 0, sizeof(bl2_to_bl31_params_mem_t));
+	zeromem(&bl31_params_mem, sizeof(bl2_to_bl31_params_mem_t));
 
 	/* Assign memory for TF related information */
 	bl2_to_bl31_params = &bl31_params_mem.bl31_params;
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
index ce39d8f..7aa0d85 100644
--- a/plat/rockchip/common/include/plat_private.h
+++ b/plat/rockchip/common/include/plat_private.h
@@ -44,6 +44,7 @@
 
 extern uint32_t __bl31_sram_text_start, __bl31_sram_text_end;
 extern uint32_t __bl31_sram_data_start, __bl31_sram_data_end;
+extern uint32_t __sram_incbin_start, __sram_incbin_end;
 
 
 /******************************************************************************
diff --git a/plat/rockchip/common/pmusram/pmu_sram.c b/plat/rockchip/common/pmusram/pmu_sram.c
index 120220a..82d55ba 100644
--- a/plat/rockchip/common/pmusram/pmu_sram.c
+++ b/plat/rockchip/common/pmusram/pmu_sram.c
@@ -62,6 +62,12 @@
 	mmap_add_region((unsigned long)&__bl31_sram_data_start,
 			(unsigned long)&__bl31_sram_data_start,
 			sram_size, MT_MEMORY | MT_RW | MT_SECURE);
+
+	/* sram.incbin size */
+	sram_size = (char *)&__sram_incbin_end - (char *)&__sram_incbin_start;
+	mmap_add_region((unsigned long)&__sram_incbin_start,
+			(unsigned long)&__sram_incbin_start,
+			sram_size, MT_NON_CACHEABLE | MT_RW | MT_SECURE);
 #else
 	/* TODO: Support other SoCs, Just support RK3399 now */
 	return;
diff --git a/plat/rockchip/rk3399/drivers/dram/dcf_code.inc b/plat/rockchip/rk3399/drivers/dram/dcf_code.inc
deleted file mode 100644
index 53196a0..0000000
--- a/plat/rockchip/rk3399/drivers/dram/dcf_code.inc
+++ /dev/null
@@ -1,364 +0,0 @@
-    0x0 ,
-    0x4f8c120c ,
-    0x0 ,
-    0x4f8c1210 ,
-    0x100000 ,
-    0x1f310019 ,
-    0x0 ,
-    0xb0000001 ,
-    0x58 ,
-    0xd0000000 ,
-    0x1300 ,
-    0x1f760329 ,
-    0x0 ,
-    0xb0000001 ,
-    0x40 ,
-    0xd0000000 ,
-    0xc ,
-    0x1f760371 ,
-    0x0 ,
-    0xb0000001 ,
-    0x28 ,
-    0xd0000000 ,
-    0x400000 ,
-    0x1f900009 ,
-    0x0 ,
-    0xb0000001 ,
-    0x10 ,
-    0xd0000000 ,
-    0x1 ,
-    0x4f8c120c ,
-    0x100000 ,
-    0x1f310019 ,
-    0x0 ,
-    0xb0000001 ,
-    0x58 ,
-    0xd0000000 ,
-    0x2c00 ,
-    0x1f760329 ,
-    0x0 ,
-    0xb0000001 ,
-    0x40 ,
-    0xd0000000 ,
-    0xc0 ,
-    0x1f760371 ,
-    0x0 ,
-    0xb0000001 ,
-    0x28 ,
-    0xd0000000 ,
-    0x400000 ,
-    0x1f8f0009 ,
-    0x0 ,
-    0xb0000001 ,
-    0x10 ,
-    0xd0000000 ,
-    0x1 ,
-    0x4f8c1210 ,
-    0x0 ,
-    0x4f8c1220 ,
-    0x0 ,
-    0x4f8c121c ,
-    0x0 ,
-    0xaf8c120d ,
-    0x108 ,
-    0xd0000000 ,
-    0x2000 ,
-    0x1f900009 ,
-    0x0 ,
-    0xa0000001 ,
-    0x30 ,
-    0xd0000000 ,
-    0x0 ,
-    0x4f8c1220 ,
-    0x0 ,
-    0x4f8c121c ,
-    0x0 ,
-    0x10000001 ,
-    0x0 ,
-    0xa0000001 ,
-    0xb0 ,
-    0xd0000000 ,
-    0x8000 ,
-    0x1f900009 ,
-    0x0 ,
-    0xa0000001 ,
-    0x30 ,
-    0xd0000000 ,
-    0x1 ,
-    0x4f8c1220 ,
-    0x1 ,
-    0x4f8c121c ,
-    0x0 ,
-    0x10000001 ,
-    0x0 ,
-    0xa0000001 ,
-    0x70 ,
-    0xd0000000 ,
-    0x4000 ,
-    0x1f900009 ,
-    0x0 ,
-    0xa0000001 ,
-    0x30 ,
-    0xd0000000 ,
-    0x0 ,
-    0x4f8c1220 ,
-    0x1 ,
-    0x4f8c121c ,
-    0x0 ,
-    0x10000001 ,
-    0x0 ,
-    0xa0000001 ,
-    0x30 ,
-    0xd0000000 ,
-    0x1000 ,
-    0x1f900009 ,
-    0x0 ,
-    0xa0000001 ,
-    0x18 ,
-    0xd0000000 ,
-    0x0 ,
-    0x4f8c1220 ,
-    0x1 ,
-    0x4f8c121c ,
-    0x0 ,
-    0x10000001 ,
-    0x0 ,
-    0xa0000001 ,
-    0x100 ,
-    0xd0000000 ,
-    0x0 ,
-    0xaf8c1211 ,
-    0xf0 ,
-    0xd0000000 ,
-    0x2000 ,
-    0x1f8f0009 ,
-    0x0 ,
-    0xa0000001 ,
-    0x30 ,
-    0xd0000000 ,
-    0x0 ,
-    0x4f8c1220 ,
-    0x0 ,
-    0x4f8c121c ,
-    0x0 ,
-    0x10000001 ,
-    0x0 ,
-    0xa0000001 ,
-    0xb0 ,
-    0xd0000000 ,
-    0x8000 ,
-    0x1f8f0009 ,
-    0x0 ,
-    0xa0000001 ,
-    0x30 ,
-    0xd0000000 ,
-    0x1 ,
-    0x4f8c1220 ,
-    0x1 ,
-    0x4f8c121c ,
-    0x0 ,
-    0x10000001 ,
-    0x0 ,
-    0xa0000001 ,
-    0x70 ,
-    0xd0000000 ,
-    0x4000 ,
-    0x1f8f0009 ,
-    0x0 ,
-    0xa0000001 ,
-    0x30 ,
-    0xd0000000 ,
-    0x0 ,
-    0x4f8c1220 ,
-    0x1 ,
-    0x4f8c121c ,
-    0x0 ,
-    0x10000001 ,
-    0x0 ,
-    0xa0000001 ,
-    0x30 ,
-    0xd0000000 ,
-    0x1000 ,
-    0x1f8f0009 ,
-    0x0 ,
-    0xa0000001 ,
-    0x18 ,
-    0xd0000000 ,
-    0x0 ,
-    0x4f8c1220 ,
-    0x1 ,
-    0x4f8c121c ,
-    0x0 ,
-    0xaf8c120d ,
-    0x40 ,
-    0xd0000000 ,
-    0x80008000 ,
-    0x7f900284 ,
-    0x1 ,
-    0x0 ,
-    0x8000 ,
-    0x1f90028d ,
-    0x0 ,
-    0x60000001 ,
-    0x0 ,
-    0x10000001 ,
-    0x0 ,
-    0xa0000001 ,
-    0x38 ,
-    0xd0000000 ,
-    0x0 ,
-    0xaf8c1211 ,
-    0x28 ,
-    0xd0000000 ,
-    0x80008000 ,
-    0x7f8f0284 ,
-    0x1 ,
-    0x0 ,
-    0x8000 ,
-    0x1f8f028d ,
-    0x0 ,
-    0x60000001 ,
-    0xffffffff ,
-    0x4f77e200 ,
-    0xffffffff ,
-    0x4f77e204 ,
-    0xffffffff ,
-    0x4f77e208 ,
-    0xffffffff ,
-    0x4f77e20c ,
-    0x70007000 ,
-    0x4f77e210 ,
-    0x3fffffff ,
-    0x7f750130 ,
-    0x0 ,
-    0x2f310061 ,
-    0xc0000 ,
-    0x20000001 ,
-    0x0 ,
-    0x4f310061 ,
-    0xc0000 ,
-    0x1f310065 ,
-    0xc0000 ,
-    0xb0000001 ,
-    0x10 ,
-    0xc0000000 ,
-    0x0 ,
-    0xaf8c121d ,
-    0x48 ,
-    0xd0000000 ,
-    0x0 ,
-    0xaf8c120d ,
-    0x18 ,
-    0xd0000000 ,
-    0x80000000 ,
-    0x2f90000d ,
-    0x0 ,
-    0x4f90000d ,
-    0x0 ,
-    0xaf8c1211 ,
-    0x18 ,
-    0xd0000000 ,
-    0x80000000 ,
-    0x2f90000d ,
-    0x0 ,
-    0x4f8f000d ,
-    0x0 ,
-    0x2f8c101d ,
-    0x350005 ,
-    0x20000001 ,
-    0x0 ,
-    0x4f620001 ,
-    0x1 ,
-    0x0 ,
-    0x4 ,
-    0x1f620011 ,
-    0x0 ,
-    0x60000001 ,
-    0x3000000 ,
-    0x7f76004c ,
-    0x18 ,
-    0x0 ,
-    0x10001 ,
-    0x7f76004c ,
-    0x0 ,
-    0x2f8c1005 ,
-    0x0 ,
-    0x4f760041 ,
-    0x0 ,
-    0x2f8c1009 ,
-    0x0 ,
-    0x4f760045 ,
-    0x10000 ,
-    0x7f76004c ,
-    0x18 ,
-    0x0 ,
-    0x1 ,
-    0x0 ,
-    0x80000000 ,
-    0x1f760049 ,
-    0x0 ,
-    0x60000001 ,
-    0x3000100 ,
-    0x7f76004c ,
-    0x3e8 ,
-    0x0 ,
-    0x20002 ,
-    0x4f620000 ,
-    0x1 ,
-    0x0 ,
-    0x1 ,
-    0x1f620011 ,
-    0x0 ,
-    0x60000001 ,
-    0x0 ,
-    0xaf8c121d ,
-    0x48 ,
-    0xd0000000 ,
-    0x0 ,
-    0xaf8c120d ,
-    0x18 ,
-    0xd0000000 ,
-    0x7fffffff ,
-    0x1f90000d ,
-    0x0 ,
-    0x4f90000d ,
-    0x0 ,
-    0xaf8c1211 ,
-    0x18 ,
-    0xd0000000 ,
-    0x7fffffff ,
-    0x1f90000d ,
-    0x0 ,
-    0x4f8f000d ,
-    0xfff3ffff ,
-    0x1f310061 ,
-    0x0 ,
-    0x7f310061 ,
-    0xc0000 ,
-    0x1f310065 ,
-    0x0 ,
-    0xb0000001 ,
-    0x10 ,
-    0xc0000000 ,
-    0x0 ,
-    0x7f750130 ,
-    0x1 ,
-    0x0 ,
-    0x1 ,
-    0x0 ,
-    0x1 ,
-    0x0 ,
-    0x1 ,
-    0x0 ,
-    0x1 ,
-    0x0 ,
-    0x1 ,
-    0x0 ,
-    0x1 ,
-    0x0 ,
-    0x1 ,
-    0x0 ,
-    0x1 ,
-    0x0 ,
-    0x0 ,
-    0xe0000000 ,
diff --git a/plat/rockchip/rk3399/drivers/dram/dfs.c b/plat/rockchip/rk3399/drivers/dram/dfs.c
index 4fdd389..f589a8a 100644
--- a/plat/rockchip/rk3399/drivers/dram/dfs.c
+++ b/plat/rockchip/rk3399/drivers/dram/dfs.c
@@ -28,8 +28,10 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <arch_helpers.h>
 #include <debug.h>
 #include <mmio.h>
+#include <m0_ctl.h>
 #include <plat_private.h>
 #include "dfs.h"
 #include "dram.h"
@@ -40,31 +42,14 @@
 
 #include <delay_timer.h>
 
-#define CTL_TRAINING	(1)
-#define PI_TRAINING		(!CTL_TRAINING)
-
-#define EN_READ_GATE_TRAINING	(1)
-#define EN_CA_TRAINING		(0)
-#define EN_WRITE_LEVELING	(0)
-#define EN_READ_LEVELING	(0)
-#define EN_WDQ_LEVELING	(0)
-
-#define ENPER_CS_TRAINING_FREQ	(933)
-
-struct pll_div {
-	unsigned int mhz;
-	unsigned int refdiv;
-	unsigned int fbdiv;
-	unsigned int postdiv1;
-	unsigned int postdiv2;
-	unsigned int frac;
-	unsigned int freq;
-};
+#define ENPER_CS_TRAINING_FREQ	(666)
+#define TDFI_LAT_THRESHOLD_FREQ	(928)
+#define PHY_DLL_BYPASS_FREQ	(260)
 
 static const struct pll_div dpll_rates_table[] = {
 
 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2 */
-	{.mhz = 933, .refdiv = 3, .fbdiv = 350, .postdiv1 = 3, .postdiv2 = 1},
+	{.mhz = 928, .refdiv = 1, .fbdiv = 116, .postdiv1 = 3, .postdiv2 = 1},
 	{.mhz = 800, .refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1},
 	{.mhz = 732, .refdiv = 1, .fbdiv = 61, .postdiv1 = 2, .postdiv2 = 1},
 	{.mhz = 666, .refdiv = 1, .fbdiv = 111, .postdiv1 = 4, .postdiv2 = 1},
@@ -78,128 +63,44 @@
 struct rk3399_dram_status {
 	uint32_t current_index;
 	uint32_t index_freq[2];
+	uint32_t boot_freq;
 	uint32_t low_power_stat;
 	struct timing_related_config timing_config;
 	struct drv_odt_lp_config drv_odt_lp_cfg;
 };
 
-static struct rk3399_dram_status rk3399_dram_status;
-static struct ddr_dts_config_timing dts_parameter = {
-	.available = 0
+struct rk3399_saved_status {
+	uint32_t freq;
+	uint32_t low_power_stat;
+	uint32_t odt;
 };
 
+static struct rk3399_dram_status rk3399_dram_status;
+static struct rk3399_saved_status rk3399_suspend_status;
+static uint32_t wrdqs_delay_val[2][2][4];
+
 static struct rk3399_sdram_default_config ddr3_default_config = {
 	.bl = 8,
 	.ap = 0,
-	.dramds = 40,
-	.dramodt = 120,
 	.burst_ref_cnt = 1,
 	.zqcsi = 0
 };
 
-static struct drv_odt_lp_config ddr3_drv_odt_default_config = {
-	.ddr3_speed_bin = DDR3_DEFAULT,
-	.pd_idle = 0,
-	.sr_idle = 0,
-	.sr_mc_gate_idle = 0,
-	.srpd_lite_idle = 0,
-	.standby_idle = 0,
-
-	.ddr3_dll_dis_freq = 300,
-	.phy_dll_dis_freq = 125,
-	.odt_dis_freq = 933,
-
-	.dram_side_drv = 40,
-	.dram_side_dq_odt = 120,
-	.dram_side_ca_odt = 120,
-
-	.phy_side_ca_drv = 40,
-	.phy_side_ck_cs_drv = 40,
-	.phy_side_dq_drv = 40,
-	.phy_side_odt = 240,
-};
-
 static struct rk3399_sdram_default_config lpddr3_default_config = {
 	.bl = 8,
 	.ap = 0,
-	.dramds = 34,
-	.dramodt = 240,
 	.burst_ref_cnt = 1,
 	.zqcsi = 0
 };
 
-static struct drv_odt_lp_config lpddr3_drv_odt_default_config = {
-	.ddr3_speed_bin = DDR3_DEFAULT,
-	.pd_idle = 0,
-	.sr_idle = 0,
-	.sr_mc_gate_idle = 0,
-	.srpd_lite_idle = 0,
-	.standby_idle = 0,
-
-	.ddr3_dll_dis_freq = 300,
-	.phy_dll_dis_freq = 125,
-	.odt_dis_freq = 666,
-
-	.dram_side_drv = 40,
-	.dram_side_dq_odt = 120,
-	.dram_side_ca_odt = 120,
-
-	.phy_side_ca_drv = 40,
-	.phy_side_ck_cs_drv = 40,
-	.phy_side_dq_drv = 40,
-	.phy_side_odt = 240,
-};
-
 static struct rk3399_sdram_default_config lpddr4_default_config = {
 	.bl = 16,
 	.ap = 0,
-	.dramds = 40,
-	.dramodt = 240,
 	.caodt = 240,
 	.burst_ref_cnt = 1,
 	.zqcsi = 0
 };
 
-static struct drv_odt_lp_config lpddr4_drv_odt_default_config = {
-	.ddr3_speed_bin = DDR3_DEFAULT,
-	.pd_idle = 0,
-	.sr_idle = 0,
-	.sr_mc_gate_idle = 0,
-	.srpd_lite_idle = 0,
-	.standby_idle = 0,
-
-	.ddr3_dll_dis_freq = 300,
-	.phy_dll_dis_freq = 125,
-	.odt_dis_freq = 933,
-
-	.dram_side_drv = 60,
-	.dram_side_dq_odt = 40,
-	.dram_side_ca_odt = 40,
-
-	.phy_side_ca_drv = 40,
-	.phy_side_ck_cs_drv = 80,
-	.phy_side_dq_drv = 80,
-	.phy_side_odt = 60,
-};
-
-uint32_t dcf_code[] = {
-#include "dcf_code.inc"
-};
-
-#define DCF_START_ADDR	(SRAM_BASE + 0x1400)
-#define DCF_PARAM_ADDR	(SRAM_BASE + 0x1000)
-
-/* DCF_PAMET */
-#define PARAM_DRAM_FREQ		(0)
-#define PARAM_DPLL_CON0		(4)
-#define PARAM_DPLL_CON1		(8)
-#define PARAM_DPLL_CON2		(0xc)
-#define PARAM_DPLL_CON3		(0x10)
-#define PARAM_DPLL_CON4		(0x14)
-#define PARAM_DPLL_CON5		(0x18)
-/* equal to fn<<4 */
-#define PARAM_FREQ_SELECT	(0x1c)
-
 static uint32_t get_cs_die_capability(struct rk3399_sdram_params *sdram_config,
 		uint8_t channel, uint8_t cs)
 {
@@ -222,176 +123,79 @@
 	return (cs_cap / die);
 }
 
-static void drv_odt_lp_cfg_init(uint32_t dram_type,
-				struct ddr_dts_config_timing *dts_timing,
+static void get_dram_drv_odt_val(uint32_t dram_type,
 				struct drv_odt_lp_config *drv_config)
 {
-	if ((dts_timing) && (dts_timing->available)) {
-		drv_config->ddr3_speed_bin = dts_timing->ddr3_speed_bin;
-		drv_config->pd_idle = dts_timing->pd_idle;
-		drv_config->sr_idle = dts_timing->sr_idle;
-		drv_config->sr_mc_gate_idle = dts_timing->sr_mc_gate_idle;
-		drv_config->srpd_lite_idle = dts_timing->srpd_lite_idle;
-		drv_config->standby_idle = dts_timing->standby_idle;
-		drv_config->ddr3_dll_dis_freq = dts_timing->ddr3_dll_dis_freq;
-		drv_config->phy_dll_dis_freq = dts_timing->phy_dll_dis_freq;
-	}
+	uint32_t tmp;
+	uint32_t mr1_val, mr3_val, mr11_val;
 
 	switch (dram_type) {
 	case DDR3:
-		if ((dts_timing) && (dts_timing->available)) {
-			drv_config->odt_dis_freq =
-			    dts_timing->ddr3_odt_dis_freq;
-			drv_config->dram_side_drv = dts_timing->ddr3_drv;
-			drv_config->dram_side_dq_odt = dts_timing->ddr3_odt;
-			drv_config->phy_side_ca_drv =
-			    dts_timing->phy_ddr3_ca_drv;
-			drv_config->phy_side_ck_cs_drv =
-			    dts_timing->phy_ddr3_ca_drv;
-			drv_config->phy_side_dq_drv =
-			    dts_timing->phy_ddr3_dq_drv;
-			drv_config->phy_side_odt = dts_timing->phy_ddr3_odt;
-		} else {
-			memcpy(drv_config, &ddr3_drv_odt_default_config,
-			       sizeof(struct drv_odt_lp_config));
-		}
+		mr1_val = (mmio_read_32(CTL_REG(0, 133)) >> 16) & 0xffff;
+		tmp = ((mr1_val >> 1) & 1) | ((mr1_val >> 4) & 1);
+		if (tmp)
+			drv_config->dram_side_drv = 34;
+		else
+			drv_config->dram_side_drv = 40;
+		tmp = ((mr1_val >> 2) & 1) | ((mr1_val >> 5) & 1) |
+		      ((mr1_val >> 7) & 1);
+		if (tmp == 0)
+			drv_config->dram_side_dq_odt = 0;
+		else if (tmp == 1)
+			drv_config->dram_side_dq_odt = 60;
+		else if (tmp == 3)
+			drv_config->dram_side_dq_odt = 40;
+		else
+			drv_config->dram_side_dq_odt = 120;
 		break;
 	case LPDDR3:
-		if ((dts_timing) && (dts_timing->available)) {
-			drv_config->odt_dis_freq =
-			    dts_timing->lpddr3_odt_dis_freq;
-			drv_config->dram_side_drv = dts_timing->lpddr3_drv;
-			drv_config->dram_side_dq_odt = dts_timing->lpddr3_odt;
-			drv_config->phy_side_ca_drv =
-			    dts_timing->phy_lpddr3_ca_drv;
-			drv_config->phy_side_ck_cs_drv =
-			    dts_timing->phy_lpddr3_ca_drv;
-			drv_config->phy_side_dq_drv =
-			    dts_timing->phy_lpddr3_dq_drv;
-			drv_config->phy_side_odt = dts_timing->phy_lpddr3_odt;
+		mr3_val = mmio_read_32(CTL_REG(0, 138)) & 0xf;
+		mr11_val = (mmio_read_32(CTL_REG(0, 139)) >> 24) & 0x3;
+		if (mr3_val == 0xb)
+			drv_config->dram_side_drv = 3448;
+		else if (mr3_val == 0xa)
+			drv_config->dram_side_drv = 4048;
+		else if (mr3_val == 0x9)
+			drv_config->dram_side_drv = 3440;
+		else if (mr3_val == 0x4)
+			drv_config->dram_side_drv = 60;
+		else if (mr3_val == 0x3)
+			drv_config->dram_side_drv = 48;
+		else if (mr3_val == 0x2)
+			drv_config->dram_side_drv = 40;
+		else
+			drv_config->dram_side_drv = 34;
 
-		} else {
-			memcpy(drv_config, &lpddr3_drv_odt_default_config,
-			       sizeof(struct drv_odt_lp_config));
-		}
+		if (mr11_val == 1)
+			drv_config->dram_side_dq_odt = 60;
+		else if (mr11_val == 2)
+			drv_config->dram_side_dq_odt = 120;
+		else if (mr11_val == 0)
+			drv_config->dram_side_dq_odt = 0;
+		else
+			drv_config->dram_side_dq_odt = 240;
 		break;
 	case LPDDR4:
 	default:
-		if ((dts_timing) && (dts_timing->available)) {
-			drv_config->odt_dis_freq =
-			    dts_timing->lpddr4_odt_dis_freq;
-			drv_config->dram_side_drv = dts_timing->lpddr4_drv;
-			drv_config->dram_side_dq_odt =
-			    dts_timing->lpddr4_dq_odt;
-			drv_config->dram_side_ca_odt =
-			    dts_timing->lpddr4_ca_odt;
-			drv_config->phy_side_ca_drv =
-			    dts_timing->phy_lpddr4_ca_drv;
-			drv_config->phy_side_ck_cs_drv =
-			    dts_timing->phy_lpddr4_ck_cs_drv;
-			drv_config->phy_side_dq_drv =
-			    dts_timing->phy_lpddr4_dq_drv;
-			drv_config->phy_side_odt = dts_timing->phy_lpddr4_odt;
-		} else {
-			memcpy(drv_config, &lpddr4_drv_odt_default_config,
-			       sizeof(struct drv_odt_lp_config));
-		}
-		break;
-	}
+		mr3_val = (mmio_read_32(CTL_REG(0, 138)) >> 3) & 0x7;
+		mr11_val = (mmio_read_32(CTL_REG(0, 139)) >> 24) & 0xff;
 
-	switch (drv_config->phy_side_ca_drv) {
-	case 240:
-		drv_config->phy_side_ca_drv = PHY_DRV_ODT_240;
-		break;
-	case 120:
-		drv_config->phy_side_ca_drv = PHY_DRV_ODT_120;
-		break;
-	case 80:
-		drv_config->phy_side_ca_drv = PHY_DRV_ODT_80;
-		break;
-	case 60:
-		drv_config->phy_side_ca_drv = PHY_DRV_ODT_60;
-		break;
-	case 48:
-		drv_config->phy_side_ca_drv = PHY_DRV_ODT_48;
-		break;
-	case 40:
-		drv_config->phy_side_ca_drv = PHY_DRV_ODT_40;
-		break;
-	default:
-		drv_config->phy_side_ca_drv = PHY_DRV_ODT_34_3;
-		break;
-	};
+		if ((mr3_val == 0) || (mr3_val == 7))
+			drv_config->dram_side_drv = 40;
+		else
+			drv_config->dram_side_drv = 240 / mr3_val;
 
-	switch (drv_config->phy_side_ck_cs_drv) {
-	case 240:
-		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_240;
-		break;
-	case 120:
-		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_120;
-		break;
-	case 80:
-		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_80;
-		break;
-	case 60:
-		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_60;
-		break;
-	case 48:
-		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_48;
-		break;
-	case 40:
-		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_40;
-		break;
-	default:
-		drv_config->phy_side_ck_cs_drv = PHY_DRV_ODT_34_3;
-		break;
-	}
+		tmp = mr11_val & 0x7;
+		if ((tmp == 7) || (tmp == 0))
+			drv_config->dram_side_dq_odt = 0;
+		else
+			drv_config->dram_side_dq_odt = 240 / tmp;
 
-	switch (drv_config->phy_side_dq_drv) {
-	case 240:
-		drv_config->phy_side_dq_drv = PHY_DRV_ODT_240;
-		break;
-	case 120:
-		drv_config->phy_side_dq_drv = PHY_DRV_ODT_120;
-		break;
-	case 80:
-		drv_config->phy_side_dq_drv = PHY_DRV_ODT_80;
-		break;
-	case 60:
-		drv_config->phy_side_dq_drv = PHY_DRV_ODT_60;
-		break;
-	case 48:
-		drv_config->phy_side_dq_drv = PHY_DRV_ODT_48;
-		break;
-	case 40:
-		drv_config->phy_side_dq_drv = PHY_DRV_ODT_40;
-		break;
-	default:
-		drv_config->phy_side_dq_drv = PHY_DRV_ODT_34_3;
-		break;
-	}
-
-	switch (drv_config->phy_side_odt) {
-	case 240:
-		drv_config->phy_side_odt = PHY_DRV_ODT_240;
-		break;
-	case 120:
-		drv_config->phy_side_odt = PHY_DRV_ODT_120;
-		break;
-	case 80:
-		drv_config->phy_side_odt = PHY_DRV_ODT_80;
-		break;
-	case 60:
-		drv_config->phy_side_odt = PHY_DRV_ODT_60;
-		break;
-	case 48:
-		drv_config->phy_side_odt = PHY_DRV_ODT_48;
-		break;
-	case 40:
-		drv_config->phy_side_odt = PHY_DRV_ODT_40;
-		break;
-	default:
-		drv_config->phy_side_odt = PHY_DRV_ODT_34_3;
+		tmp = (mr11_val >> 4) & 0x7;
+		if ((tmp == 7) || (tmp == 0))
+			drv_config->dram_side_ca_odt = 0;
+		else
+			drv_config->dram_side_ca_odt = 240 / tmp;
 		break;
 	}
 }
@@ -403,8 +207,7 @@
 	uint32_t i, j;
 
 	for (i = 0; i < sdram_params->num_channels; i++) {
-		ptiming_config->dram_info[i].speed_rate =
-		    drv_config->ddr3_speed_bin;
+		ptiming_config->dram_info[i].speed_rate = DDR3_DEFAULT;
 		ptiming_config->dram_info[i].cs_cnt = sdram_params->ch[i].rank;
 		for (j = 0; j < sdram_params->ch[i].rank; j++) {
 			ptiming_config->dram_info[i].per_die_capability[j] =
@@ -432,6 +235,7 @@
 	ptiming_config->dramds = drv_config->dram_side_drv;
 	ptiming_config->dramodt = drv_config->dram_side_dq_odt;
 	ptiming_config->caodt = drv_config->dram_side_ca_odt;
+	ptiming_config->odt = (mmio_read_32(PHY_REG(0, 5)) >> 16) & 0x1;
 }
 
 struct lat_adj_pair {
@@ -928,7 +732,7 @@
 
 		/* CTL_314 TDFI_WRCSLAT_F0:RW:8:8 */
 		tmp1 = get_pi_wrlat_adj(pdram_timing, timing_config);
-		if (timing_config->freq <= ENPER_CS_TRAINING_FREQ) {
+		if (timing_config->freq <= TDFI_LAT_THRESHOLD_FREQ) {
 			if (tmp1 == 0)
 				tmp = 0;
 			else if (tmp1 < 5)
@@ -941,7 +745,7 @@
 		mmio_clrsetbits_32(CTL_REG(i, 314), 0xff << 8, tmp << 8);
 
 		/* CTL_314 TDFI_RDCSLAT_F0:RW:0:8 */
-		if ((timing_config->freq <= ENPER_CS_TRAINING_FREQ) &&
+		if ((timing_config->freq <= TDFI_LAT_THRESHOLD_FREQ) &&
 		    (pdram_timing->cl >= 5))
 			tmp = pdram_timing->cl - 5;
 		else
@@ -1178,7 +982,7 @@
 
 		/* CTL_314 TDFI_WRCSLAT_F1:RW:24:8 */
 		tmp1 = get_pi_wrlat_adj(pdram_timing, timing_config);
-		if (timing_config->freq <= ENPER_CS_TRAINING_FREQ) {
+		if (timing_config->freq <= TDFI_LAT_THRESHOLD_FREQ) {
 			if (tmp1 == 0)
 				tmp = 0;
 			else if (tmp1 < 5)
@@ -1192,7 +996,7 @@
 		mmio_clrsetbits_32(CTL_REG(i, 314), 0xff << 24, tmp << 24);
 
 		/* CTL_314 TDFI_RDCSLAT_F1:RW:16:8 */
-		if ((timing_config->freq <= ENPER_CS_TRAINING_FREQ) &&
+		if ((timing_config->freq <= TDFI_LAT_THRESHOLD_FREQ) &&
 		    (pdram_timing->cl >= 5))
 			tmp = pdram_timing->cl - 5;
 		else
@@ -1201,6 +1005,33 @@
 	}
 }
 
+static void gen_rk3399_enable_training(uint32_t ch_cnt, uint32_t nmhz)
+{
+		uint32_t i, tmp;
+
+		if (nmhz <= PHY_DLL_BYPASS_FREQ)
+			tmp = 0;
+		else
+			tmp = 1;
+
+		for (i = 0; i < ch_cnt; i++) {
+			mmio_clrsetbits_32(CTL_REG(i, 305), 1 << 16, tmp << 16);
+			mmio_clrsetbits_32(CTL_REG(i, 71), 1, tmp);
+			mmio_clrsetbits_32(CTL_REG(i, 70), 1 << 8, 1 << 8);
+		}
+}
+
+static void gen_rk3399_disable_training(uint32_t ch_cnt)
+{
+	uint32_t i;
+
+	for (i = 0; i < ch_cnt; i++) {
+		mmio_clrbits_32(CTL_REG(i, 305), 1 << 16);
+		mmio_clrbits_32(CTL_REG(i, 71), 1);
+		mmio_clrbits_32(CTL_REG(i, 70), 1 << 8);
+	}
+}
+
 static void gen_rk3399_ctl_params(struct timing_related_config *timing_config,
 				  struct dram_timing_t *pdram_timing,
 				  uint32_t fn)
@@ -1209,35 +1040,6 @@
 		gen_rk3399_ctl_params_f0(timing_config, pdram_timing);
 	else
 		gen_rk3399_ctl_params_f1(timing_config, pdram_timing);
-
-#if CTL_TRAINING
-	uint32_t i, tmp0, tmp1;
-
-	tmp0 = tmp1 = 0;
-#if EN_READ_GATE_TRAINING
-	tmp1 = 1;
-#endif
-
-#if EN_CA_TRAINING
-	tmp0 |= (1 << 8);
-#endif
-
-#if EN_WRITE_LEVELING
-	tmp0 |= (1 << 16);
-#endif
-
-#if EN_READ_LEVELING
-	tmp0 |= (1 << 24);
-#endif
-	for (i = 0; i < timing_config->ch_cnt; i++) {
-		if (tmp0 | tmp1)
-			mmio_setbits_32(CTL_REG(i, 305), 1 << 16);
-		if (tmp0)
-			mmio_setbits_32(CTL_REG(i, 70), tmp0);
-		if (tmp1)
-			mmio_setbits_32(CTL_REG(i, 71), tmp1);
-	}
-#endif
 }
 
 static void gen_rk3399_pi_params_f0(struct timing_related_config *timing_config,
@@ -1381,7 +1183,8 @@
 		mmio_clrsetbits_32(PI_REG(i, 148), 0xffff << 16,
 				   pdram_timing->mr[2] << 16);
 		/* PI_156 PI_TFC_F0:RW:0:10 */
-		mmio_clrsetbits_32(PI_REG(i, 156), 0x3ff, pdram_timing->trfc);
+		mmio_clrsetbits_32(PI_REG(i, 156), 0x3ff,
+				   pdram_timing->tfc_long);
 		/* PI_158 PI_TWR_F0:RW:24:6 */
 		mmio_clrsetbits_32(PI_REG(i, 158), 0x3f << 24,
 				   pdram_timing->twr << 24);
@@ -1452,7 +1255,7 @@
 		mmio_clrsetbits_32(PI_REG(i, 44), 0x3f, PI_ADD_LATENCY);
 		/* PI_44 PI_CASLAT_LIN_F1:RW:8:7:=0x18 */
 		mmio_clrsetbits_32(PI_REG(i, 44), 0x7f << 8,
-				   pdram_timing->cl * 2);
+				   (pdram_timing->cl * 2) << 8);
 		/* PI_47 PI_TREF_F1:RW:16:16 */
 		mmio_clrsetbits_32(PI_REG(i, 47), 0xffff << 16,
 				   pdram_timing->trefi << 16);
@@ -1561,7 +1364,7 @@
 		mmio_clrsetbits_32(PI_REG(i, 151), 0xffff, pdram_timing->mr[2]);
 		/* PI_156 PI_TFC_F1:RW:16:10 */
 		mmio_clrsetbits_32(PI_REG(i, 156), 0x3ff << 16,
-				   pdram_timing->trfc << 16);
+				   pdram_timing->tfc_long << 16);
 		/* PI_162 PI_TWR_F1:RW:8:6 */
 		mmio_clrsetbits_32(PI_REG(i, 162), 0x3f << 8,
 				   pdram_timing->twr << 8);
@@ -1605,32 +1408,6 @@
 		gen_rk3399_pi_params_f0(timing_config, pdram_timing);
 	else
 		gen_rk3399_pi_params_f1(timing_config, pdram_timing);
-
-#if PI_TRAINING
-	uint32_t i;
-
-	for (i = 0; i < timing_config->ch_cnt; i++) {
-#if EN_READ_GATE_TRAINING
-		mmio_clrsetbits_32(PI_REG(i, 80), 3 << 24, 2 << 24);
-#endif
-
-#if EN_CA_TRAINING
-		mmio_clrsetbits_32(PI_REG(i, 100), 3 << 8, 2 << 8);
-#endif
-
-#if EN_WRITE_LEVELING
-		mmio_clrsetbits_32(PI_REG(i, 60), 3 << 8, 2 << 8);
-#endif
-
-#if EN_READ_LEVELING
-		mmio_clrsetbits_32(PI_REG(i, 80), 3 << 16, 2 << 16);
-#endif
-
-#if EN_WDQ_LEVELING
-		mmio_clrsetbits_32(PI_REG(i, 124), 3 << 16, 2 << 16);
-#endif
-	}
-#endif
 }
 
 static void gen_rk3399_set_odt(uint32_t odt_en)
@@ -1652,57 +1429,92 @@
 	}
 }
 
-static void gen_rk3399_set_ds_odt(struct timing_related_config *timing_config,
-				  struct drv_odt_lp_config *drv_config)
+static void gen_rk3399_phy_dll_bypass(uint32_t mhz, uint32_t ch,
+		uint32_t index, uint32_t dram_type)
 {
-	uint32_t i, drv_odt_val;
+	uint32_t sw_master_mode = 0;
+	uint32_t rddqs_gate_delay, rddqs_latency, total_delay;
+	uint32_t i;
 
-	for (i = 0; i < timing_config->ch_cnt; i++) {
-		if (timing_config->dram_type == LPDDR4)
-			drv_odt_val = drv_config->phy_side_odt |
-				      (PHY_DRV_ODT_Hi_Z << 4) |
-				      (drv_config->phy_side_dq_drv << 8) |
-				      (drv_config->phy_side_dq_drv << 12);
-		else if (timing_config->dram_type == LPDDR3)
-			drv_odt_val = PHY_DRV_ODT_Hi_Z |
-				      (drv_config->phy_side_odt << 4) |
-				      (drv_config->phy_side_dq_drv << 8) |
-				      (drv_config->phy_side_dq_drv << 12);
-		else
-			drv_odt_val = drv_config->phy_side_odt |
-				      (drv_config->phy_side_odt << 4) |
-				      (drv_config->phy_side_dq_drv << 8) |
-				      (drv_config->phy_side_dq_drv << 12);
+	if (dram_type == DDR3)
+		total_delay = PI_PAD_DELAY_PS_VALUE;
+	else if (dram_type == LPDDR3)
+		total_delay = PI_PAD_DELAY_PS_VALUE + 2500;
+	else
+		total_delay = PI_PAD_DELAY_PS_VALUE + 1500;
+	/* total_delay + 0.55tck */
+	total_delay +=  (55 * 10000)/mhz;
+	rddqs_latency = total_delay * mhz / 1000000;
+	total_delay -= rddqs_latency * 1000000 / mhz;
+	rddqs_gate_delay = total_delay * 0x200 * mhz / 1000000;
+	if (mhz <= PHY_DLL_BYPASS_FREQ) {
+		sw_master_mode = 0xc;
+		mmio_setbits_32(PHY_REG(ch, 514), 1);
+		mmio_setbits_32(PHY_REG(ch, 642), 1);
+		mmio_setbits_32(PHY_REG(ch, 770), 1);
 
-		/* DQ drv odt set */
-		mmio_clrsetbits_32(PHY_REG(i, 6), 0xffffff, drv_odt_val);
-		mmio_clrsetbits_32(PHY_REG(i, 134), 0xffffff, drv_odt_val);
-		mmio_clrsetbits_32(PHY_REG(i, 262), 0xffffff, drv_odt_val);
-		mmio_clrsetbits_32(PHY_REG(i, 390), 0xffffff, drv_odt_val);
-		/* DQS drv odt set */
-		mmio_clrsetbits_32(PHY_REG(i, 7), 0xffffff, drv_odt_val);
-		mmio_clrsetbits_32(PHY_REG(i, 135), 0xffffff, drv_odt_val);
-		mmio_clrsetbits_32(PHY_REG(i, 263), 0xffffff, drv_odt_val);
-		mmio_clrsetbits_32(PHY_REG(i, 391), 0xffffff, drv_odt_val);
+		/* setting bypass mode slave delay */
+		for (i = 0; i < 4; i++) {
+			/* wr dq delay = -180deg + (0x60 / 4) * 20ps */
+			mmio_clrsetbits_32(PHY_REG(ch, 1 + 128 * i), 0x7ff << 8,
+					   0x4a0 << 8);
+			/* rd dqs/dq delay = (0x60 / 4) * 20ps */
+			mmio_clrsetbits_32(PHY_REG(ch, 11 + 128 * i), 0x3ff,
+					   0xa0);
+			/* rd rddqs_gate delay */
+			mmio_clrsetbits_32(PHY_REG(ch, 2 + 128 * i), 0x3ff,
+					   rddqs_gate_delay);
+			mmio_clrsetbits_32(PHY_REG(ch, 78 + 128 * i), 0xf,
+					   rddqs_latency);
+		}
+		for (i = 0; i < 3; i++)
+			/* adr delay */
+			mmio_clrsetbits_32(PHY_REG(ch, 513 + 128 * i),
+					   0x7ff << 16, 0x80 << 16);
 
-		gen_rk3399_set_odt(timing_config->odt);
-
-		/* CA drv set */
-		drv_odt_val = drv_config->phy_side_ca_drv |
-			      (drv_config->phy_side_ca_drv << 4);
-		mmio_clrsetbits_32(PHY_REG(i, 544), 0xff, drv_odt_val);
-		mmio_clrsetbits_32(PHY_REG(i, 672), 0xff, drv_odt_val);
-		mmio_clrsetbits_32(PHY_REG(i, 800), 0xff, drv_odt_val);
-
-		mmio_clrsetbits_32(PHY_REG(i, 928), 0xff, drv_odt_val);
-		mmio_clrsetbits_32(PHY_REG(i, 937), 0xff, drv_odt_val);
-		mmio_clrsetbits_32(PHY_REG(i, 935), 0xff, drv_odt_val);
-
-		drv_odt_val = drv_config->phy_side_ck_cs_drv |
-			      (drv_config->phy_side_ck_cs_drv << 4);
-		mmio_clrsetbits_32(PHY_REG(i, 929), 0xff, drv_odt_val);
-		mmio_clrsetbits_32(PHY_REG(i, 939), 0xff, drv_odt_val);
+		if ((mmio_read_32(PHY_REG(ch, 86)) & 0xc00) == 0) {
+			/*
+			 * old status is normal mode,
+			 * and saving the wrdqs slave delay
+			 */
+			for (i = 0; i < 4; i++) {
+				/* save and clear wr dqs slave delay */
+				wrdqs_delay_val[ch][index][i] = 0x3ff &
+					(mmio_read_32(PHY_REG(ch, 63 + i * 128))
+					>> 16);
+				mmio_clrsetbits_32(PHY_REG(ch, 63 + i * 128),
+						   0x03ff << 16, 0 << 16);
+				/*
+				 * in normal mode the cmd may delay 1cycle by
+				 * wrlvl and in bypass mode making dqs also
+				 * delay 1cycle.
+				 */
+				mmio_clrsetbits_32(PHY_REG(ch, 78 + i * 128),
+						   0x07 << 8, 0x1 << 8);
+			}
+		}
+	} else if (mmio_read_32(PHY_REG(ch, 86)) & 0xc00) {
+		/* old status is bypass mode and restore wrlvl resume */
+		for (i = 0; i < 4; i++) {
+			mmio_clrsetbits_32(PHY_REG(ch, 63 + i * 128),
+					   0x03ff << 16,
+					   (wrdqs_delay_val[ch][index][i] &
+					    0x3ff) << 16);
+			/* resume phy_write_path_lat_add */
+			mmio_clrbits_32(PHY_REG(ch, 78 + i * 128), 0x07 << 8);
+		}
 	}
+
+	/* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
+	mmio_clrsetbits_32(PHY_REG(ch, 86), 0xf << 8, sw_master_mode << 8);
+	mmio_clrsetbits_32(PHY_REG(ch, 214), 0xf << 8, sw_master_mode << 8);
+	mmio_clrsetbits_32(PHY_REG(ch, 342), 0xf << 8, sw_master_mode << 8);
+	mmio_clrsetbits_32(PHY_REG(ch, 470), 0xf << 8, sw_master_mode << 8);
+
+	/* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
+	mmio_clrsetbits_32(PHY_REG(ch, 547), 0xf << 16, sw_master_mode << 16);
+	mmio_clrsetbits_32(PHY_REG(ch, 675), 0xf << 16, sw_master_mode << 16);
+	mmio_clrsetbits_32(PHY_REG(ch, 803), 0xf << 16, sw_master_mode << 16);
 }
 
 static void gen_rk3399_phy_params(struct timing_related_config *timing_config,
@@ -1745,15 +1557,7 @@
 		/* DENALI_PHY_911 13bits offset_0 */
 		/* PHY_LP4_BOOT_PLL_CTRL */
 		/* DENALI_PHY_919 13bits offset_0 */
-		if (pdram_timing->mhz <= 150)
-			tmp = 3;
-		else if (pdram_timing->mhz <= 300)
-			tmp = 2;
-		else if (pdram_timing->mhz <= 600)
-			tmp = 1;
-		else
-			tmp = 0;
-		tmp = (1 << 12) | (tmp << 9) | (2 << 7) | (1 << 1);
+		tmp = (1 << 12) | (2 << 7) | (1 << 1);
 		mmio_clrsetbits_32(PHY_REG(i, 911), 0x1fff, tmp);
 		mmio_clrsetbits_32(PHY_REG(i, 919), 0x1fff, tmp);
 
@@ -1761,15 +1565,7 @@
 		/* DENALI_PHY_911 13bits offset_16 */
 		/* PHY_LP4_BOOT_PLL_CTRL_CA */
 		/* DENALI_PHY_919 13bits offset_16 */
-		if (pdram_timing->mhz <= 150)
-			tmp = 3;
-		else if (pdram_timing->mhz <= 300)
-			tmp = 2;
-		else if (pdram_timing->mhz <= 600)
-			tmp = 1;
-		else
-			tmp = 0;
-		tmp = (tmp << 9) | (2 << 7) | (1 << 5) | (1 << 1);
+		tmp = (2 << 7) | (1 << 5) | (1 << 1);
 		mmio_clrsetbits_32(PHY_REG(i, 911), 0x1fff << 16, tmp << 16);
 		mmio_clrsetbits_32(PHY_REG(i, 919), 0x1fff << 16, tmp << 16);
 
@@ -1791,7 +1587,6 @@
 				break;
 		}
 		mmio_clrsetbits_32(PHY_REG(i, 947), 0x7 << 8, tmp << 8);
-		mmio_setbits_32(PHY_REG(i, 927), (1 << 22));
 
 		if (timing_config->dram_type == DDR3) {
 			mem_delay_ps = 0;
@@ -1812,12 +1607,6 @@
 		gate_delay_ps = delay_frac_ps + 1000 - (trpre_min_ps / 2);
 		gate_delay_frac_ps = gate_delay_ps % 1000;
 		tmp = gate_delay_frac_ps * 0x200 / 1000;
-		/* PHY_RDDQS_GATE_BYPASS_SLAVE_DELAY */
-		/* DENALI_PHY_2/130/258/386 10bits offset_0 */
-		mmio_clrsetbits_32(PHY_REG(i, 2), 0x2ff, tmp);
-		mmio_clrsetbits_32(PHY_REG(i, 130), 0x2ff, tmp);
-		mmio_clrsetbits_32(PHY_REG(i, 258), 0x2ff, tmp);
-		mmio_clrsetbits_32(PHY_REG(i, 386), 0x2ff, tmp);
 		/* PHY_RDDQS_GATE_SLAVE_DELAY */
 		/* DENALI_PHY_77/205/333/461 10bits offset_16 */
 		mmio_clrsetbits_32(PHY_REG(i, 77), 0x2ff << 16, tmp << 16);
@@ -1832,12 +1621,6 @@
 		mmio_clrsetbits_32(PHY_REG(i, 138), 0xf, tmp);
 		mmio_clrsetbits_32(PHY_REG(i, 266), 0xf, tmp);
 		mmio_clrsetbits_32(PHY_REG(i, 394), 0xf, tmp);
-		/* PHY_RDDQS_LATENCY_ADJUST */
-		/* DENALI_PHY_78/206/334/462 4bits offset_0 */
-		mmio_clrsetbits_32(PHY_REG(i, 78), 0xf, tmp);
-		mmio_clrsetbits_32(PHY_REG(i, 206), 0xf, tmp);
-		mmio_clrsetbits_32(PHY_REG(i, 334), 0xf, tmp);
-		mmio_clrsetbits_32(PHY_REG(i, 462), 0xf, tmp);
 		/* PHY_GTLVL_LAT_ADJ_START */
 		/* DENALI_PHY_80/208/336/464 4bits offset_16 */
 		tmp = delay_frac_ps / 1000;
@@ -1922,6 +1705,8 @@
 			mmio_setbits_32(PHY_REG(i, 340), 0x1 << 16);
 			mmio_setbits_32(PHY_REG(i, 468), 0x1 << 16);
 		}
+		gen_rk3399_phy_dll_bypass(pdram_timing->mhz, i, fn,
+					  timing_config->dram_type);
 	}
 }
 
@@ -1944,22 +1729,6 @@
 	return i;
 }
 
-uint32_t rkclk_prepare_pll_timing(unsigned int mhz)
-{
-	unsigned int refdiv, postdiv1, fbdiv, postdiv2;
-	int index;
-
-	index = to_get_clk_index(mhz);
-	refdiv = dpll_rates_table[index].refdiv;
-	fbdiv = dpll_rates_table[index].fbdiv;
-	postdiv1 = dpll_rates_table[index].postdiv1;
-	postdiv2 = dpll_rates_table[index].postdiv2;
-	mmio_write_32(DCF_PARAM_ADDR + PARAM_DPLL_CON0, FBDIV(fbdiv));
-	mmio_write_32(DCF_PARAM_ADDR + PARAM_DPLL_CON1,
-		      POSTDIV2(postdiv2) | POSTDIV1(postdiv1) | REFDIV(refdiv));
-	return (24 * fbdiv) / refdiv / postdiv1 / postdiv2;
-}
-
 uint32_t ddr_get_rate(void)
 {
 	uint32_t refdiv, postdiv1, fbdiv, postdiv2;
@@ -2051,90 +1820,21 @@
 	}
 }
 
-static void wait_dcf_done(void)
+static void dram_low_power_config(void)
 {
-	while ((mmio_read_32(DCF_BASE + DCF_DCF_ISR) & (DCF_DONE)) == 0)
-		continue;
-}
-
-void clr_dcf_irq(void)
-{
-	/* clear dcf irq status */
-	mmio_write_32(DCF_BASE + DCF_DCF_ISR, DCF_TIMEOUT | DCF_ERR | DCF_DONE);
-}
-
-static void enable_dcf(uint32_t dcf_addr)
-{
-	/* config DCF start addr */
-	mmio_write_32(DCF_BASE + DCF_DCF_ADDR, dcf_addr);
-	/* wait dcf done */
-	while (mmio_read_32(DCF_BASE + DCF_DCF_CTRL) & 1)
-		continue;
-	/* clear dcf irq status */
-	mmio_write_32(DCF_BASE + DCF_DCF_ISR, DCF_TIMEOUT | DCF_ERR | DCF_DONE);
-	/* DCF start */
-	mmio_setbits_32(DCF_BASE + DCF_DCF_CTRL, DCF_START);
-}
-
-void dcf_code_init(void)
-{
-	memcpy((void *)DCF_START_ADDR, (void *)dcf_code, sizeof(dcf_code));
-	/* set dcf master secure */
-	mmio_write_32(SGRF_BASE + 0xe01c, ((0x3 << 0) << 16) | (0 << 0));
-	mmio_write_32(DCF_BASE + DCF_DCF_TOSET, 0x80000000);
-}
-
-static void dcf_start(uint32_t freq, uint32_t index)
-{
-	mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
-		      (0x1 << (1 + 16)) | (1 << 1));
-	mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(11),
-		      (0x1 << (0 + 16)) | (1 << 0));
-	mmio_write_32(DCF_PARAM_ADDR + PARAM_FREQ_SELECT, index << 4);
-
-	mmio_write_32(DCF_PARAM_ADDR + PARAM_DRAM_FREQ, freq);
-
-	rkclk_prepare_pll_timing(freq);
-	udelay(10);
-	mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
-		      (0x1 << (1 + 16)) | (0 << 1));
-	mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(11),
-		      (0x1 << (0 + 16)) | (0 << 0));
-	udelay(10);
-	enable_dcf(DCF_START_ADDR);
-}
-
-static void dram_low_power_config(struct drv_odt_lp_config *lp_config)
-{
-	uint32_t tmp, tmp1, i;
+	uint32_t tmp, i;
 	uint32_t ch_cnt = rk3399_dram_status.timing_config.ch_cnt;
 	uint32_t dram_type = rk3399_dram_status.timing_config.dram_type;
-	uint32_t *low_power = &rk3399_dram_status.low_power_stat;
-
-	if (dram_type == LPDDR4)
-		tmp = (lp_config->srpd_lite_idle << 16) |
-		      lp_config->pd_idle;
-	else
-		tmp = lp_config->pd_idle;
 
 	if (dram_type == DDR3)
-		tmp1 = (2 << 16) | (0x7 << 8) | 7;
+		tmp = (2 << 16) | (0x7 << 8);
 	else
-		tmp1 = (3 << 16) | (0x7 << 8) | 7;
+		tmp = (3 << 16) | (0x7 << 8);
 
-	*low_power = 0;
-
-	for (i = 0; i < ch_cnt; i++) {
-		mmio_write_32(CTL_REG(i, 102), tmp);
-		mmio_clrsetbits_32(CTL_REG(i, 103), 0xffff,
-				   (lp_config->sr_mc_gate_idle << 8) |
-				   lp_config->sr_idle);
-		mmio_clrsetbits_32(CTL_REG(i, 101), 0x70f0f, tmp1);
-		*low_power |= (7 << (8 * i));
-	}
+	for (i = 0; i < ch_cnt; i++)
+		mmio_clrsetbits_32(CTL_REG(i, 101), 0x70f0f, tmp);
 
 	/* standby idle */
-	mmio_write_32(CIC_BASE + CIC_IDLE_TH, lp_config->standby_idle);
 	mmio_write_32(CIC_BASE + CIC_CG_WAIT_TH, 0x640008);
 
 	if (ch_cnt == 2) {
@@ -2142,36 +1842,22 @@
 			      (((0x1<<4) | (0x1<<5) | (0x1<<6) |
 				(0x1<<7)) << 16) |
 			      ((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7)));
-		if (lp_config->standby_idle) {
-			tmp = 0x002a002a;
-			*low_power |= (1 << 11);
-		} else
-			tmp = 0;
-		mmio_write_32(CIC_BASE + CIC_CTRL1, tmp);
+		mmio_write_32(CIC_BASE + CIC_CTRL1, 0x002a0028);
 	}
 
 	mmio_write_32(GRF_BASE + GRF_DDRC0_CON1,
 		      (((0x1<<4) | (0x1<<5) | (0x1<<6) | (0x1<<7)) << 16) |
 		      ((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7)));
-	if (lp_config->standby_idle) {
-		tmp = 0x00150015;
-		*low_power |= (1 << 3);
-	} else
-		tmp = 0;
-	mmio_write_32(CIC_BASE + CIC_CTRL1, tmp);
+	mmio_write_32(CIC_BASE + CIC_CTRL1, 0x00150014);
 }
 
-
-static void dram_related_init(struct ddr_dts_config_timing *dts_timing)
+void dram_dfs_init(void)
 {
-	uint32_t trefi0, trefi1;
-	uint32_t i;
-
-	dcf_code_init();
+	uint32_t trefi0, trefi1, boot_freq;
 
 	/* get sdram config for os reg */
-	drv_odt_lp_cfg_init(sdram_config.dramtype, dts_timing,
-			    &rk3399_dram_status.drv_odt_lp_cfg);
+	get_dram_drv_odt_val(sdram_config.dramtype,
+			     &rk3399_dram_status.drv_odt_lp_cfg);
 	sdram_timing_cfg_init(&rk3399_dram_status.timing_config,
 			      &sdram_config,
 			      &rk3399_dram_status.drv_odt_lp_cfg);
@@ -2187,30 +1873,106 @@
 		rk3399_dram_status.index_freq[0] /= 2;
 		rk3399_dram_status.index_freq[1] /= 2;
 	}
-	rk3399_dram_status.index_freq[(rk3399_dram_status.current_index + 1)
-				      & 0x1] = 0;
+	boot_freq =
+		rk3399_dram_status.index_freq[rk3399_dram_status.current_index];
+	boot_freq = dpll_rates_table[to_get_clk_index(boot_freq)].mhz;
+	rk3399_dram_status.boot_freq = boot_freq;
+	rk3399_dram_status.index_freq[rk3399_dram_status.current_index] =
+		boot_freq;
+	rk3399_dram_status.index_freq[(rk3399_dram_status.current_index + 1) &
+				      0x1] = 0;
+	rk3399_dram_status.low_power_stat = 0;
+	/*
+	 * following register decide if NOC stall the access request
+	 * or return error when NOC being idled. when doing ddr frequency
+	 * scaling in M0 or DCF, we need to make sure noc stall the access
+	 * request, if return error cpu may data abort when ddr frequency
+	 * changing. it don't need to set this register every times,
+	 * so we init this register in function dram_dfs_init().
+	 */
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(0), 0xffffffff);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(1), 0xffffffff);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(2), 0xffffffff);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(3), 0xffffffff);
+	mmio_write_32(GRF_BASE + GRF_SOC_CON(4), 0x70007000);
 
-	/* disable all training by ctl and pi */
-	for (i = 0; i < rk3399_dram_status.timing_config.ch_cnt; i++) {
-		mmio_clrbits_32(CTL_REG(i, 70), (1 << 24) |
-				(1 << 16) | (1 << 8) | 1);
-		mmio_clrbits_32(CTL_REG(i, 71), 1);
+	/* Disable multicast */
+	mmio_clrbits_32(PHY_REG(0, 896), 1);
+	mmio_clrbits_32(PHY_REG(1, 896), 1);
 
-		mmio_clrbits_32(PI_REG(i, 60), 0x3 << 8);
-		mmio_clrbits_32(PI_REG(i, 80), (0x3 << 24) | (0x3 << 16));
-		mmio_clrbits_32(PI_REG(i, 100), 0x3 << 8);
-		mmio_clrbits_32(PI_REG(i, 124), 0x3 << 16);
+	dram_low_power_config();
+}
+
+/*
+ * arg0: bit0-7: sr_idle; bit8-15:sr_mc_gate_idle; bit16-31: standby idle
+ * arg1: bit0-11: pd_idle; bit 16-27: srpd_lite_idle
+ * arg2: bit0: if odt en
+ */
+uint32_t dram_set_odt_pd(uint32_t arg0, uint32_t arg1, uint32_t arg2)
+{
+	struct drv_odt_lp_config *lp_cfg = &rk3399_dram_status.drv_odt_lp_cfg;
+	uint32_t *low_power = &rk3399_dram_status.low_power_stat;
+	uint32_t dram_type, ch_count, pd_tmp, sr_tmp, i;
+
+	dram_type = rk3399_dram_status.timing_config.dram_type;
+	ch_count = rk3399_dram_status.timing_config.ch_cnt;
+
+	lp_cfg->sr_idle = arg0 & 0xff;
+	lp_cfg->sr_mc_gate_idle = (arg0 >> 8) & 0xff;
+	lp_cfg->standby_idle = (arg0 >> 16) & 0xffff;
+	lp_cfg->pd_idle = arg1 & 0xfff;
+	lp_cfg->srpd_lite_idle = (arg1 >> 16) & 0xfff;
+
+	rk3399_dram_status.timing_config.odt = arg2 & 0x1;
+
+	exit_low_power();
+
+	*low_power = 0;
+
+	/* pd_idle en */
+	if (lp_cfg->pd_idle)
+		*low_power |= ((1 << 0) | (1 << 8));
+	/* sr_idle en srpd_lite_idle */
+	if (lp_cfg->sr_idle | lp_cfg->srpd_lite_idle)
+		*low_power |= ((1 << 1) | (1 << 9));
+	/* sr_mc_gate_idle */
+	if (lp_cfg->sr_mc_gate_idle)
+		*low_power |= ((1 << 2) | (1 << 10));
+	/* standbyidle */
+	if (lp_cfg->standby_idle) {
+		if (rk3399_dram_status.timing_config.ch_cnt == 2)
+			*low_power |= ((1 << 3) | (1 << 11));
+		else
+			*low_power |= (1 << 3);
 	}
 
-	/* init drv odt */
-	if (rk3399_dram_status.index_freq[rk3399_dram_status.current_index] <
-		rk3399_dram_status.drv_odt_lp_cfg.odt_dis_freq)
-		rk3399_dram_status.timing_config.odt = 0;
-	else
-		rk3399_dram_status.timing_config.odt = 1;
-	gen_rk3399_set_ds_odt(&rk3399_dram_status.timing_config,
-			&rk3399_dram_status.drv_odt_lp_cfg);
-	dram_low_power_config(&rk3399_dram_status.drv_odt_lp_cfg);
+	pd_tmp = arg1;
+	if (dram_type != LPDDR4)
+		pd_tmp = arg1 & 0xfff;
+	sr_tmp = arg0 & 0xffff;
+	for (i = 0; i < ch_count; i++) {
+		mmio_write_32(CTL_REG(i, 102), pd_tmp);
+		mmio_clrsetbits_32(CTL_REG(i, 103), 0xffff, sr_tmp);
+	}
+	mmio_write_32(CIC_BASE + CIC_IDLE_TH, (arg0 >> 16) & 0xffff);
+
+	return 0;
+}
+
+static void m0_configure_ddr(struct pll_div pll_div, uint32_t ddr_index)
+{
+	/* set PARAM to M0_FUNC_DRAM */
+	mmio_write_32(M0_PARAM_ADDR + PARAM_M0_FUNC, M0_FUNC_DRAM);
+
+	mmio_write_32(M0_PARAM_ADDR + PARAM_DPLL_CON0, FBDIV(pll_div.fbdiv));
+	mmio_write_32(M0_PARAM_ADDR + PARAM_DPLL_CON1,
+		      POSTDIV2(pll_div.postdiv2) | POSTDIV1(pll_div.postdiv1) |
+		      REFDIV(pll_div.refdiv));
+
+	mmio_write_32(M0_PARAM_ADDR + PARAM_DRAM_FREQ, pll_div.mhz);
+
+	mmio_write_32(M0_PARAM_ADDR + PARAM_FREQ_SELECT, ddr_index << 4);
+	dmbst();
 }
 
 static uint32_t prepare_ddr_timing(uint32_t mhz)
@@ -2220,20 +1982,15 @@
 
 	rk3399_dram_status.timing_config.freq = mhz;
 
-	if (mhz < rk3399_dram_status.drv_odt_lp_cfg.ddr3_dll_dis_freq)
+	if (mhz < 300)
 		rk3399_dram_status.timing_config.dllbp = 1;
 	else
 		rk3399_dram_status.timing_config.dllbp = 0;
-	if (mhz < rk3399_dram_status.drv_odt_lp_cfg.odt_dis_freq) {
-		rk3399_dram_status.timing_config.odt = 0;
-	} else {
-		rk3399_dram_status.timing_config.odt = 1;
+
+	if (rk3399_dram_status.timing_config.odt == 1)
 		gen_rk3399_set_odt(1);
-	}
 
 	index = (rk3399_dram_status.current_index + 1) & 0x1;
-	if (rk3399_dram_status.index_freq[index] == mhz)
-		goto out;
 
 	/*
 	 * checking if having available gate traiing timing for
@@ -2249,8 +2006,6 @@
 			      &dram_timing, index);
 	rk3399_dram_status.index_freq[index] = mhz;
 
-
-out:
 	return index;
 }
 
@@ -2271,33 +2026,39 @@
 
 uint32_t ddr_set_rate(uint32_t hz)
 {
-	uint32_t low_power, index;
+	uint32_t low_power, index, ddr_index;
 	uint32_t mhz = hz / (1000 * 1000);
 
 	if (mhz ==
 	    rk3399_dram_status.index_freq[rk3399_dram_status.current_index])
-		goto out;
+		return mhz;
 
 	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)
+	ddr_index = prepare_ddr_timing(mhz);
+	gen_rk3399_enable_training(rk3399_dram_status.timing_config.ch_cnt,
+				   mhz);
+	if (ddr_index > 1)
 		goto out;
 
-	dcf_start(mhz, index);
-	wait_dcf_done();
+	/*
+	 * Make sure the clock is enabled. The M0 clocks should be on all of the
+	 * time during S0.
+	 */
+	m0_configure_ddr(dpll_rates_table[index], ddr_index);
+	m0_start();
+	m0_wait_done();
+	m0_stop();
+
 	if (rk3399_dram_status.timing_config.odt == 0)
 		gen_rk3399_set_odt(0);
 
-	rk3399_dram_status.current_index = index;
-
-	if (mhz < dts_parameter.auto_pd_dis_freq)
-		low_power |= rk3399_dram_status.low_power_stat;
-
+	rk3399_dram_status.current_index = ddr_index;
+	low_power = rk3399_dram_status.low_power_stat;
 	resume_low_power(low_power);
 out:
+	gen_rk3399_disable_training(rk3399_dram_status.timing_config.ch_cnt);
 	return mhz;
 }
 
@@ -2311,29 +2072,56 @@
 	return dpll_rates_table[index].mhz * 1000 * 1000;
 }
 
-uint32_t dts_timing_receive(uint32_t timing, uint32_t index)
+void ddr_prepare_for_sys_suspend(void)
 {
-	uint32_t *p = (uint32_t *) &dts_parameter;
-	static uint32_t receive_nums;
+	uint32_t mhz =
+		rk3399_dram_status.index_freq[rk3399_dram_status.current_index];
 
-	if (index < (sizeof(dts_parameter) / sizeof(uint32_t) - 1)) {
-		p[index] = (uint32_t)timing;
-		receive_nums++;
-	} else {
-		dts_parameter.available = 0;
-		return -1;
-	}
+	/*
+	 * If we're not currently at the boot (assumed highest) frequency, we
+	 * need to change frequencies to configure out current index.
+	 */
+	rk3399_suspend_status.freq = mhz;
+	exit_low_power();
+	rk3399_suspend_status.low_power_stat =
+		rk3399_dram_status.low_power_stat;
+	rk3399_suspend_status.odt = rk3399_dram_status.timing_config.odt;
+	rk3399_dram_status.low_power_stat = 0;
+	rk3399_dram_status.timing_config.odt = 1;
+	if (mhz != rk3399_dram_status.boot_freq)
+		ddr_set_rate(rk3399_dram_status.boot_freq * 1000 * 1000);
 
-	/* receive all parameter */
-	if (receive_nums  == (sizeof(dts_parameter) / sizeof(uint32_t) - 1)) {
-		dts_parameter.available = 1;
-		receive_nums = 0;
-	}
-
-	return index;
+	/*
+	 * This will configure the other index to be the same frequency as the
+	 * current one. We retrain both indices on resume, so both have to be
+	 * setup for the same frequency.
+	 */
+	prepare_ddr_timing(rk3399_dram_status.boot_freq);
 }
 
-void ddr_dfs_init(void)
+void ddr_prepare_for_sys_resume(void)
 {
-	dram_related_init(&dts_parameter);
+	/* Disable multicast */
+	mmio_clrbits_32(PHY_REG(0, 896), 1);
+	mmio_clrbits_32(PHY_REG(1, 896), 1);
+
+	/* The suspend code changes the current index, so reset it now. */
+	rk3399_dram_status.current_index =
+		(mmio_read_32(CTL_REG(0, 111)) >> 16) & 0x3;
+	rk3399_dram_status.low_power_stat =
+		rk3399_suspend_status.low_power_stat;
+	rk3399_dram_status.timing_config.odt = rk3399_suspend_status.odt;
+
+	/*
+	 * Set the saved frequency from suspend if it's different than the
+	 * current frequency.
+	 */
+	if (rk3399_suspend_status.freq !=
+	    rk3399_dram_status.index_freq[rk3399_dram_status.current_index]) {
+		ddr_set_rate(rk3399_suspend_status.freq * 1000 * 1000);
+		return;
+	}
+
+	gen_rk3399_set_odt(rk3399_dram_status.timing_config.odt);
+	resume_low_power(rk3399_dram_status.low_power_stat);
 }
diff --git a/plat/rockchip/rk3399/drivers/dram/dfs.h b/plat/rockchip/rk3399/drivers/dram/dfs.h
index 1da0903..3204ae7 100644
--- a/plat/rockchip/rk3399/drivers/dram/dfs.h
+++ b/plat/rockchip/rk3399/drivers/dram/dfs.h
@@ -48,65 +48,25 @@
 	unsigned char zqcsi;
 };
 
-struct  ddr_dts_config_timing {
-	unsigned int ddr3_speed_bin;
-	unsigned int pd_idle;
-	unsigned int sr_idle;
-	unsigned int sr_mc_gate_idle;
-	unsigned int srpd_lite_idle;
-	unsigned int standby_idle;
-	unsigned int auto_pd_dis_freq;
-	unsigned int ddr3_dll_dis_freq;
-	unsigned int phy_dll_dis_freq;
-	unsigned int ddr3_odt_dis_freq;
-	unsigned int ddr3_drv;
-	unsigned int ddr3_odt;
-	unsigned int phy_ddr3_ca_drv;
-	unsigned int phy_ddr3_dq_drv;
-	unsigned int phy_ddr3_odt;
-	unsigned int lpddr3_odt_dis_freq;
-	unsigned int lpddr3_drv;
-	unsigned int lpddr3_odt;
-	unsigned int phy_lpddr3_ca_drv;
-	unsigned int phy_lpddr3_dq_drv;
-	unsigned int phy_lpddr3_odt;
-	unsigned int lpddr4_odt_dis_freq;
-	unsigned int lpddr4_drv;
-	unsigned int lpddr4_dq_odt;
-	unsigned int lpddr4_ca_odt;
-	unsigned int phy_lpddr4_ca_drv;
-	unsigned int phy_lpddr4_ck_cs_drv;
-	unsigned int phy_lpddr4_dq_drv;
-	unsigned int phy_lpddr4_odt;
-	uint32_t available;
-};
-
 struct drv_odt_lp_config {
-	uint32_t ddr3_speed_bin;
 	uint32_t pd_idle;
 	uint32_t sr_idle;
 	uint32_t sr_mc_gate_idle;
 	uint32_t srpd_lite_idle;
 	uint32_t standby_idle;
-
-	uint32_t ddr3_dll_dis_freq;/* for ddr3 only */
-	uint32_t phy_dll_dis_freq;
-	uint32_t odt_dis_freq;
+	uint32_t odt_en;
 
 	uint32_t dram_side_drv;
 	uint32_t dram_side_dq_odt;
 	uint32_t dram_side_ca_odt;
-
-	uint32_t phy_side_ca_drv;
-	uint32_t phy_side_ck_cs_drv;
-	uint32_t phy_side_dq_drv;
-	uint32_t phy_side_odt;
 };
 
-void ddr_dfs_init(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);
-uint32_t dts_timing_receive(uint32_t timing, uint32_t index);
+uint32_t dram_set_odt_pd(uint32_t arg0, uint32_t arg1, uint32_t arg2);
+void dram_dfs_init(void);
+void ddr_prepare_for_sys_suspend(void);
+void ddr_prepare_for_sys_resume(void);
+
 #endif
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.c b/plat/rockchip/rk3399/drivers/dram/dram.c
index 5f6f0fc..1dfb3e5 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram.c
+++ b/plat/rockchip/rk3399/drivers/dram/dram.c
@@ -30,6 +30,7 @@
 
 #include <dram.h>
 #include <plat_private.h>
+#include <secure.h>
 #include <soc.h>
 #include <rk3399_def.h>
 
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.h b/plat/rockchip/rk3399/drivers/dram/dram.h
index 44dfbbd..571d51a 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram.h
+++ b/plat/rockchip/rk3399/drivers/dram/dram.h
@@ -30,111 +30,11 @@
 
 #ifndef __SOC_ROCKCHIP_RK3399_DRAM_H__
 #define __SOC_ROCKCHIP_RK3399_DRAM_H__
+
+#include <dram_regs.h>
 #include <plat_private.h>
 #include <stdint.h>
 
-#define CTL_BASE(ch)		(0xffa80000 + (ch) * 0x8000)
-#define CTL_REG(ch, n)		(CTL_BASE(ch) + (n) * 0x4)
-
-#define PI_OFFSET		0x800
-#define PI_BASE(ch)		(CTL_BASE(ch) + PI_OFFSET)
-#define PI_REG(ch, n)		(PI_BASE(ch) + (n) * 0x4)
-
-#define PHY_OFFSET		0x2000
-#define PHY_BASE(ch)		(CTL_BASE(ch) + PHY_OFFSET)
-#define PHY_REG(ch, n)		(PHY_BASE(ch) + (n) * 0x4)
-
-#define MSCH_BASE(ch)		(0xffa84000 + (ch) * 0x8000)
-#define MSCH_ID_COREID		0x0
-#define MSCH_ID_REVISIONID	0x4
-#define MSCH_DEVICECONF		0x8
-#define MSCH_DEVICESIZE		0xc
-#define MSCH_DDRTIMINGA0	0x10
-#define MSCH_DDRTIMINGB0	0x14
-#define MSCH_DDRTIMINGC0	0x18
-#define MSCH_DEVTODEV0		0x1c
-#define MSCH_DDRMODE		0x110
-#define MSCH_AGINGX0		0x1000
-
-#define CIC_CTRL0	0x0
-#define CIC_CTRL1	0x4
-#define CIC_IDLE_TH	0x8
-#define CIC_CG_WAIT_TH	0xc
-#define CIC_STATUS0	0x10
-#define CIC_STATUS1	0x14
-#define CIC_CTRL2	0x18
-#define CIC_CTRL3	0x1c
-#define CIC_CTRL4	0x20
-
-/* DENALI_CTL_00 */
-#define START			1
-
-/* DENALI_CTL_68 */
-#define PWRUP_SREFRESH_EXIT	(1 << 16)
-
-/* DENALI_CTL_274 */
-#define MEM_RST_VALID		1
-
-#define PHY_DRV_ODT_Hi_Z	0x0
-#define PHY_DRV_ODT_240		0x1
-#define PHY_DRV_ODT_120		0x8
-#define PHY_DRV_ODT_80		0x9
-#define PHY_DRV_ODT_60		0xc
-#define PHY_DRV_ODT_48		0xd
-#define PHY_DRV_ODT_40		0xe
-#define PHY_DRV_ODT_34_3	0xf
-
-/*
- * sys_reg bitfield struct
- * [31] row_3_4_ch1
- * [30] row_3_4_ch0
- * [29:28] chinfo
- * [27] rank_ch1
- * [26:25] col_ch1
- * [24] bk_ch1
- * [23:22] cs0_row_ch1
- * [21:20] cs1_row_ch1
- * [19:18] bw_ch1
- * [17:16] dbw_ch1;
- * [15:13] ddrtype
- * [12] channelnum
- * [11] rank_ch0
- * [10:9] col_ch0
- * [8] bk_ch0
- * [7:6] cs0_row_ch0
- * [5:4] cs1_row_ch0
- * [3:2] bw_ch0
- * [1:0] dbw_ch0
- */
-#define SYS_REG_ENC_ROW_3_4(n, ch)	((n) << (30 + (ch)))
-#define SYS_REG_DEC_ROW_3_4(n, ch)	(((n) >> (30 + (ch))) & 0x1)
-#define SYS_REG_ENC_CHINFO(ch)		(1 << (28 + (ch)))
-#define SYS_REG_DEC_CHINFO(n, ch)	(((n) >> (28 + (ch))) & 0x1)
-#define SYS_REG_ENC_DDRTYPE(n)		((n) << 13)
-#define SYS_REG_DEC_DDRTYPE(n)		(((n) >> 13) & 0x7)
-#define SYS_REG_ENC_NUM_CH(n)		(((n) - 1) << 12)
-#define SYS_REG_DEC_NUM_CH(n)		(1 + (((n) >> 12) & 0x1))
-#define SYS_REG_ENC_RANK(n, ch)		(((n) - 1) << (11 + (ch) * 16))
-#define SYS_REG_DEC_RANK(n, ch)		(1 + (((n) >> (11 + (ch) * 16)) & 0x1))
-#define SYS_REG_ENC_COL(n, ch)		(((n) - 9) << (9 + (ch) * 16))
-#define SYS_REG_DEC_COL(n, ch)		(9 + (((n) >> (9 + (ch) * 16)) & 0x3))
-#define SYS_REG_ENC_BK(n, ch)		(((n) == 3 ? 0 : 1) << (8 + (ch) * 16))
-#define SYS_REG_DEC_BK(n, ch)		(3 - (((n) >> (8 + (ch) * 16)) & 0x1))
-#define SYS_REG_ENC_CS0_ROW(n, ch)	(((n) - 13) << (6 + (ch) * 16))
-#define SYS_REG_DEC_CS0_ROW(n, ch)	(13 + (((n) >> (6 + (ch) * 16)) & 0x3))
-#define SYS_REG_ENC_CS1_ROW(n, ch)	(((n) - 13) << (4 + (ch) * 16))
-#define SYS_REG_DEC_CS1_ROW(n, ch)	(13 + (((n) >> (4 + (ch) * 16)) & 0x3))
-#define SYS_REG_ENC_BW(n, ch)		((2 >> (n)) << (2 + (ch) * 16))
-#define SYS_REG_DEC_BW(n, ch)		(2 >> (((n) >> (2 + (ch) * 16)) & 0x3))
-#define SYS_REG_ENC_DBW(n, ch)		((2 >> (n)) << (0 + (ch) * 16))
-#define SYS_REG_DEC_DBW(n, ch)		(2 >> (((n) >> (0 + (ch) * 16)) & 0x3))
-#define DDR_STRIDE(n)		mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(4), \
-					      (0x1f<<(10+16))|((n)<<10))
-
-#define CTL_REG_NUM		332
-#define PHY_REG_NUM		959
-#define PI_REG_NUM		200
-
 enum {
 	DDR3 = 3,
 	LPDDR2 = 5,
@@ -259,6 +159,7 @@
 	struct rk3399_ddr_pctl_regs pctl_regs;
 	struct rk3399_ddr_pi_regs pi_regs;
 	struct rk3399_ddr_publ_regs phy_regs;
+	uint32_t rx_cal_dqs[2][4];
 };
 
 extern __sramdata struct rk3399_sdram_params sdram_config;
diff --git a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c
index fbf1d39..6288de4 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c
+++ b/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, 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:
@@ -31,6 +31,7 @@
 #include <string.h>
 #include <stdint.h>
 #include <dram.h>
+#include <utils.h>
 #include "dram_spec_timing.h"
 
 static const uint8_t ddr3_cl_cwl[][7] = {
@@ -228,7 +229,7 @@
 	uint32_t ddr_capability_per_die = get_max_die_capability(timing_config);
 	uint32_t tmp;
 
-	memset((void *)pdram_timing, 0, sizeof(struct dram_timing_t));
+	zeromem((void *)pdram_timing, sizeof(struct dram_timing_t));
 	pdram_timing->mhz = nmhz;
 	pdram_timing->al = 0;
 	pdram_timing->bl = timing_config->bl;
@@ -266,21 +267,24 @@
 		break;
 	}
 
-	switch (timing_config->dramodt) {
-	case 60:
-		pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_60;
-		break;
-	case 40:
-		pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_40;
-		break;
-	case 120:
-		pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_120;
-		break;
-	case 0:
-	default:
+	if (timing_config->odt)
+		switch (timing_config->dramodt) {
+		case 60:
+			pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_60;
+			break;
+		case 40:
+			pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_40;
+			break;
+		case 120:
+			pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_120;
+			break;
+		case 0:
+		default:
+			pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_DIS;
+			break;
+		}
+	else
 		pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_DIS;
-		break;
-	}
 
 	pdram_timing->mr[2] = DDR3_MR2_CWL(pdram_timing->cwl);
 	pdram_timing->mr[3] = 0;
@@ -441,7 +445,7 @@
 	uint32_t ddr_capability_per_die = get_max_die_capability(timing_config);
 	uint32_t tmp, trp_tmp, trppb_tmp, tras_tmp, twr_tmp, bl_tmp;
 
-	memset((void *)pdram_timing, 0, sizeof(struct dram_timing_t));
+	zeromem((void *)pdram_timing, sizeof(struct dram_timing_t));
 	pdram_timing->mhz = nmhz;
 	pdram_timing->al = 0;
 	pdram_timing->bl = timing_config->bl;
@@ -663,6 +667,9 @@
 #define LPDDR3_TADR	(20) /* ns */
 #define LPDDR3_TMRZ	(3) /* ns */
 
+/* FSP */
+#define LPDDR3_TFC_LONG	(250) /* ns */
+
 /*
  * Description: depend on input parameter "timing_config",
  *		and calculate all lpddr3
@@ -678,7 +685,7 @@
 	uint32_t ddr_capability_per_die = get_max_die_capability(timing_config);
 	uint32_t tmp, trp_tmp, trppb_tmp, tras_tmp, twr_tmp, bl_tmp;
 
-	memset((void *)pdram_timing, 0, sizeof(struct dram_timing_t));
+	zeromem((void *)pdram_timing, sizeof(struct dram_timing_t));
 	pdram_timing->mhz = nmhz;
 	pdram_timing->al = 0;
 	pdram_timing->bl = timing_config->bl;
@@ -750,18 +757,21 @@
 		break;
 	}
 	pdram_timing->mr[0] = 0;
-	switch (timing_config->dramodt) {
-	case 60:
-		pdram_timing->mr11 = LPDDR3_ODT_60;
-		break;
-	case 120:
-		pdram_timing->mr11 = LPDDR3_ODT_120;
-		break;
-	case 240:
-	default:
-		pdram_timing->mr11 = LPDDR3_ODT_240;
-		break;
-	}
+	if (timing_config->odt)
+		switch (timing_config->dramodt) {
+		case 60:
+			pdram_timing->mr11 = LPDDR3_ODT_60;
+			break;
+		case 120:
+			pdram_timing->mr11 = LPDDR3_ODT_120;
+			break;
+		case 240:
+		default:
+			pdram_timing->mr11 = LPDDR3_ODT_240;
+			break;
+		}
+	else
+		pdram_timing->mr11 = LPDDR3_ODT_DIS;
 
 	pdram_timing->tinit1 = (LPDDR3_TINIT1 * nmhz + 999) / 1000;
 	pdram_timing->tinit2 = LPDDR3_TINIT2;
@@ -873,6 +883,9 @@
 	pdram_timing->tadr = (LPDDR3_TADR * nmhz + 999) / 1000;
 	pdram_timing->tmrz = (LPDDR3_TMRZ * nmhz + 999) / 1000;
 	pdram_timing->tcacd = pdram_timing->tadr + 2;
+
+	/* FSP */
+	pdram_timing->tfc_long = (LPDDR3_TFC_LONG * nmhz + 999) / 1000;
 }
 
 #define LPDDR4_TINIT1	(200000) /* 200us */
@@ -968,7 +981,7 @@
 	uint32_t ddr_capability_per_die = get_max_die_capability(timing_config);
 	uint32_t tmp, trp_tmp, trppb_tmp, tras_tmp;
 
-	memset((void *)pdram_timing, 0, sizeof(struct dram_timing_t));
+	zeromem((void *)pdram_timing, sizeof(struct dram_timing_t));
 	pdram_timing->mhz = nmhz;
 	pdram_timing->al = 0;
 	pdram_timing->bl = timing_config->bl;
@@ -1112,47 +1125,52 @@
 		break;
 	}
 	pdram_timing->mr[0] = 0;
-	switch (timing_config->dramodt) {
-	case 240:
-		tmp = LPDDR4_DQODT_240;
-		break;
-	case 120:
-		tmp = LPDDR4_DQODT_120;
-		break;
-	case 80:
-		tmp = LPDDR4_DQODT_80;
-		break;
-	case 60:
-		tmp = LPDDR4_DQODT_60;
-		break;
-	case 48:
-		tmp = LPDDR4_DQODT_48;
-		break;
-	case 40:
-	default:
-		tmp = LPDDR4_DQODT_40;
-		break;
-	}
-	switch (timing_config->caodt) {
-	case 240:
-		pdram_timing->mr11 = LPDDR4_CAODT_240 | tmp;
-		break;
-	case 120:
-		pdram_timing->mr11 = LPDDR4_CAODT_120 | tmp;
-		break;
-	case 80:
-		pdram_timing->mr11 = LPDDR4_CAODT_80 | tmp;
-		break;
-	case 60:
-		pdram_timing->mr11 = LPDDR4_CAODT_60 | tmp;
-		break;
-	case 48:
-		pdram_timing->mr11 = LPDDR4_CAODT_48 | tmp;
-		break;
-	case 40:
-	default:
-		pdram_timing->mr11 = LPDDR4_CAODT_40 | tmp;
-		break;
+	if (timing_config->odt) {
+		switch (timing_config->dramodt) {
+		case 240:
+			tmp = LPDDR4_DQODT_240;
+			break;
+		case 120:
+			tmp = LPDDR4_DQODT_120;
+			break;
+		case 80:
+			tmp = LPDDR4_DQODT_80;
+			break;
+		case 60:
+			tmp = LPDDR4_DQODT_60;
+			break;
+		case 48:
+			tmp = LPDDR4_DQODT_48;
+			break;
+		case 40:
+		default:
+			tmp = LPDDR4_DQODT_40;
+			break;
+		}
+
+		switch (timing_config->caodt) {
+		case 240:
+			pdram_timing->mr11 = LPDDR4_CAODT_240 | tmp;
+			break;
+		case 120:
+			pdram_timing->mr11 = LPDDR4_CAODT_120 | tmp;
+			break;
+		case 80:
+			pdram_timing->mr11 = LPDDR4_CAODT_80 | tmp;
+			break;
+		case 60:
+			pdram_timing->mr11 = LPDDR4_CAODT_60 | tmp;
+			break;
+		case 48:
+			pdram_timing->mr11 = LPDDR4_CAODT_48 | tmp;
+			break;
+		case 40:
+		default:
+			pdram_timing->mr11 = LPDDR4_CAODT_40 | tmp;
+			break;
+		}
+	} else {
+		pdram_timing->mr11 = LPDDR4_CAODT_DIS | tmp;
 	}
 
 	pdram_timing->tinit1 = (LPDDR4_TINIT1 * nmhz + 999) / 1000;
diff --git a/plat/rockchip/rk3399/drivers/dram/suspend.c b/plat/rockchip/rk3399/drivers/dram/suspend.c
index f408d67..42cbf98 100644
--- a/plat/rockchip/rk3399/drivers/dram/suspend.c
+++ b/plat/rockchip/rk3399/drivers/dram/suspend.c
@@ -34,6 +34,7 @@
 #include <dram.h>
 #include <pmu_regs.h>
 #include <rk3399_def.h>
+#include <secure.h>
 #include <soc.h>
 #include <suspend.h>
 
@@ -571,14 +572,15 @@
 	sram_regcpy(PHY_REG(ch, 768), (uintptr_t)&params_phy[768], 38);
 }
 
-static __sramfunc int dram_switch_to_phy_index1(
+static __sramfunc int dram_switch_to_next_index(
 		struct rk3399_sdram_params *sdram_params)
 {
 	uint32_t ch, ch_count;
+	uint32_t fn = ((mmio_read_32(CTL_REG(0, 111)) >> 16) + 1) & 0x1;
 
 	mmio_write_32(CIC_BASE + CIC_CTRL0,
 		      (((0x3 << 4) | (1 << 2) | 1) << 16) |
-		      (1 << 4) | (1 << 2) | 1);
+		      (fn << 4) | (1 << 2) | 1);
 	while (!(mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 2)))
 		;
 
@@ -591,7 +593,7 @@
 	/* LPDDR4 f2 cann't do training, all training will fail */
 	for (ch = 0; ch < ch_count; ch++) {
 		mmio_clrsetbits_32(PHY_REG(ch, 896), (0x3 << 8) | 1,
-				   1 << 8);
+				   fn << 8);
 
 		/* data_training failed */
 		if (data_training(ch, sdram_params, PI_FULL_TRAINING))
@@ -609,6 +611,7 @@
 		struct rk3399_sdram_params *sdram_params)
 {
 	uint32_t count;
+	uint32_t byte;
 
 	mmio_setbits_32(CTL_REG(0, 68), PWRUP_SREFRESH_EXIT);
 	mmio_setbits_32(CTL_REG(1, 68), PWRUP_SREFRESH_EXIT);
@@ -640,6 +643,12 @@
 		}
 
 		mmio_clrbits_32(CTL_REG(0, 68), PWRUP_SREFRESH_EXIT);
+
+		/* Restore the PHY_RX_CAL_DQS value */
+		for (byte = 0; byte < 4; byte++)
+			mmio_clrsetbits_32(PHY_REG(0, 57 + 128 * byte),
+					   0xfff << 16,
+					   sdram_params->rx_cal_dqs[0][byte]);
 	}
 	if (channel_mask & (1 << 1)) {
 		count = 0;
@@ -653,6 +662,12 @@
 		}
 
 		mmio_clrbits_32(CTL_REG(1, 68), PWRUP_SREFRESH_EXIT);
+
+		/* Restore the PHY_RX_CAL_DQS value */
+		for (byte = 0; byte < 4; byte++)
+			mmio_clrsetbits_32(PHY_REG(1, 57 + 128 * byte),
+					   0xfff << 16,
+					   sdram_params->rx_cal_dqs[1][byte]);
 	}
 
 	return 0;
@@ -665,7 +680,7 @@
 	uint32_t *params_pi;
 	uint32_t *params_phy;
 	uint32_t refdiv, postdiv2, postdiv1, fbdiv;
-	uint32_t tmp;
+	uint32_t tmp, ch, byte;
 
 	params_ctl = sdram_params->pctl_regs.denali_ctl;
 	params_pi = sdram_params->pi_regs.denali_pi;
@@ -705,6 +720,12 @@
 	sram_regcpy((uintptr_t)&params_phy[768], PHY_REG(0, 768), 38);
 	sram_regcpy((uintptr_t)&params_phy[896], PHY_REG(0, 896), 63);
 
+	for (ch = 0; ch < sdram_params->num_channels; ch++) {
+		for (byte = 0; byte < 4; byte++)
+			sdram_params->rx_cal_dqs[ch][byte] = (0xfff << 16) &
+				mmio_read_32(PHY_REG(ch, 57 + byte * 128));
+	}
+
 	/* set DENALI_PHY_957_DATA.PHY_DLL_RST_EN = 0x1 */
 	params_phy[957] &= ~(0x3 << 24);
 	params_phy[957] |= 1 << 24;
@@ -754,5 +775,5 @@
 	dram_all_config(sdram_params);
 
 	/* Switch to index 1 and prepare for DDR frequency switch. */
-	dram_switch_to_phy_index1(sdram_params);
+	dram_switch_to_next_index(sdram_params);
 }
diff --git a/plat/rockchip/rk3399/drivers/m0/Makefile b/plat/rockchip/rk3399/drivers/m0/Makefile
index c9454fe..b2dac4a 100644
--- a/plat/rockchip/rk3399/drivers/m0/Makefile
+++ b/plat/rockchip/rk3399/drivers/m0/Makefile
@@ -46,32 +46,29 @@
 
 .SUFFIXES:
 
-INCLUDES		+= -Iinclude/
+INCLUDES		+= -Iinclude/ \
+			   -I../../include/shared/
 
 # NOTE: Add C source files here
 C_SOURCES		:= src/startup.c \
-			   src/main.c
+			   src/main.c	\
+			   src/suspend.c \
+			   src/dram.c	\
+			   src/stopwatch.c
 
 # Flags definition
-CFLAGS			:= -g
-ASFLAGS			:= -g -Wa,--gdwarf-2
-
-ASFLAGS			+= -mcpu=$(ARCH) -mthumb -Wall -ffunction-sections -O3
-CFLAGS			+= -mcpu=$(ARCH) -mthumb -Wall -ffunction-sections -O3
-
-LDFLAGS			:= -mcpu=$(ARCH) -mthumb -g -nostartfiles -nostdlib -O3
-LDFLAGS			+= -Wl,--gc-sections -Wl,--build-id=none
+COMMON_FLAGS		:= -g -mcpu=$(ARCH) -mthumb -Wall -O3 -nostdlib -mfloat-abi=soft
+CFLAGS			:= -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-common
+ASFLAGS			:= -Wa,--gdwarf-2
+LDFLAGS			:= -Wl,--gc-sections -Wl,--build-id=none
 
 # Cross tool
 CC			:= ${M0_CROSS_COMPILE}gcc
 CPP			:= ${M0_CROSS_COMPILE}cpp
-AS			:= ${M0_CROSS_COMPILE}gcc
 AR			:= ${M0_CROSS_COMPILE}ar
-LD			:= ${M0_CROSS_COMPILE}ld
 OC			:= ${M0_CROSS_COMPILE}objcopy
 OD			:= ${M0_CROSS_COMPILE}objdump
 NM			:= ${M0_CROSS_COMPILE}nm
-PP			:= ${M0_CROSS_COMPILE}gcc -E ${CFLAGS}
 
 # NOTE: The line continuation '\' is required in the next define otherwise we
 # end up with a line-feed characer at the end of the last c filename.
@@ -83,10 +80,11 @@
 
 SOURCES 		:= $(C_SOURCES)
 OBJS 			:= $(addprefix $(BUILD)/,$(call SOURCES_TO_OBJS,$(SOURCES)))
-LINKERFILE		:= src/rk3399m0.ld
+LINKERFILE		:= $(BUILD)/$(PLAT_M0).ld
 MAPFILE			:= $(BUILD)/$(PLAT_M0).map
 ELF 			:= $(BUILD)/$(PLAT_M0).elf
 BIN 			:= $(BUILD)/$(PLAT_M0).bin
+LINKERFILE_SRC		:= src/$(PLAT_M0).ld.S
 
 # Function definition related compilation
 define MAKE_C
@@ -95,7 +93,7 @@
 
 $(OBJ) : $(2)
 	@echo "  CC      $$<"
-	$$(Q)$$(CC) $$(CFLAGS) $$(INCLUDES) -MMD -MT $$@ -c $$< -o $$@
+	$$(Q)$$(CC) $$(COMMON_FLAGS) $$(CFLAGS) $$(INCLUDES) -MMD -MT $$@ -c $$< -o $$@
 endef
 
 define MAKE_S
@@ -103,7 +101,7 @@
 
 $(OBJ) : $(2)
 	@echo "  AS      $$<"
-	$$(Q)$$(AS) $$(ASFLAGS) -c $$< -o $$@
+	$$(Q)$$(CC) -x assembler-with-cpp $$(COMMON_FLAGS) $$(ASFLAGS) -c $$< -o $$@
 endef
 
 define MAKE_OBJS
@@ -118,13 +116,15 @@
 	$(and $(REMAIN),$(error Unexpected source files present: $(REMAIN)))
 endef
 
-.PHONY: all
-all: $(BIN)
+.DEFAULT_GOAL := $(BIN)
+
+$(LINKERFILE): $(LINKERFILE_SRC)
+	$(CC) $(COMMON_FLAGS) $(INCLUDES) -P -E -D__LINKER__ -MMD -MF $@.d -MT $@ -o $@ $<
+-include $(LINKERFILE).d
 
 $(ELF) : $(OBJS) $(LINKERFILE)
 	@echo "  LD      $@"
-	$(Q)$(CC) -o $@ $(LDFLAGS) -Wl,-Map=$(MAPFILE) -Wl,-T$(LINKERFILE) \
-		$(OBJS)
+	$(Q)$(CC) -o $@ $(COMMON_FLAGS) $(LDFLAGS) -Wl,-Map=$(MAPFILE) -Wl,-T$(LINKERFILE) $(OBJS)
 
 $(BIN) : $(ELF)
 	@echo "  BIN     $@"
diff --git a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h b/plat/rockchip/rk3399/drivers/m0/include/addressmap.h
similarity index 84%
rename from plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
rename to plat/rockchip/rk3399/drivers/m0/include/addressmap.h
index 78b350a..715d8c1 100644
--- a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
+++ b/plat/rockchip/rk3399/drivers/m0/include/addressmap.h
@@ -28,13 +28,12 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef __RK3399M0_H__
-#define __RK3399M0_H__
+#ifndef __ROCKCHIP_RK3399_M0_INCLUDE_SHARED_ADDRESSMAP_H__
+#define __ROCKCHIP_RK3399_M0_INCLUDE_SHARED_ADDRESSMAP_H__
 
-/* pmu_fw.c */
-extern char rk3399m0_bin[];
-extern char rk3399m0_bin_end[];
+#include <addressmap_shared.h>
 
-#define M0_BINCODE_BASE ((uintptr_t)rk3399m0_bin)
+/* Registers base address for M0 */
+#define MMIO_BASE			0x40000000
 
-#endif /* __RK3399M0_H__ */
+#endif /* __ROCKCHIP_RK3399_M0_INCLUDE_SHARED_ADDRESSMAP_H__ */
diff --git a/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h b/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h
index 7ea40fa..b6ea3e8 100644
--- a/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h
+++ b/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h
@@ -31,11 +31,28 @@
 #ifndef __RK3399_MCU_H__
 #define __RK3399_MCU_H__
 
-#define readl(c)	({unsigned int __v =	\
-				(*(volatile unsigned int *)(c)); __v; })
-#define writel(v, c)	((*(volatile unsigned int *) (c)) = (v))
+#include <addressmap.h>
 
-#define MCU_BASE	0x40000000
-#define PMU_BASE	(MCU_BASE + 0x07310000)
+typedef unsigned int uint32_t;
+
+#define mmio_read_32(c)	({unsigned int __v = \
+				(*(volatile unsigned int *)(c)); __v; })
+#define mmio_write_32(c, v)	((*(volatile unsigned int *)(c)) = (v))
+
+#define mmio_clrbits_32(addr, clear) \
+		mmio_write_32(addr, (mmio_read_32(addr) & ~(clear)))
+#define mmio_setbits_32(addr, set) \
+		mmio_write_32(addr, (mmio_read_32(addr)) | (set))
+#define mmio_clrsetbits_32(addr, clear, set) \
+		mmio_write_32(addr, (mmio_read_32(addr) & ~(clear)) | (set))
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+void handle_suspend(void);
+void handle_dram(void);
+void stopwatch_init_usecs_expire(unsigned int usecs);
+int stopwatch_expired(void);
+void stopwatch_reset(void);
 
 #endif /* __RK3399_MCU_H__ */
diff --git a/plat/rockchip/rk3399/drivers/m0/src/dram.c b/plat/rockchip/rk3399/drivers/m0/src/dram.c
new file mode 100644
index 0000000..bd46843
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/dram.c
@@ -0,0 +1,103 @@
+/*
+ * 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 <dram_regs.h>
+#include <m0_param.h>
+#include <pmu_bits.h>
+#include <pmu_regs.h>
+#include "misc_regs.h"
+#include "rk3399_mcu.h"
+
+static uint32_t gatedis_con0;
+
+static void idle_port(void)
+{
+	gatedis_con0 = mmio_read_32(PMUCRU_BASE + PMU_CRU_GATEDIS_CON0);
+	mmio_write_32(PMUCRU_BASE + PMU_CRU_GATEDIS_CON0, 0x3fffffff);
+
+	mmio_setbits_32(PMU_BASE + PMU_BUS_IDLE_REQ,
+			(1 << PMU_IDLE_REQ_MSCH0) | (1 << PMU_IDLE_REQ_MSCH1));
+	while ((mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) &
+		((1 << PMU_IDLE_ST_MSCH1) | (1 << PMU_IDLE_ST_MSCH0))) !=
+		((1 << PMU_IDLE_ST_MSCH1) | (1 << PMU_IDLE_ST_MSCH0)))
+		continue;
+}
+
+static void deidle_port(void)
+{
+	mmio_clrbits_32(PMU_BASE + PMU_BUS_IDLE_REQ,
+			(1 << PMU_IDLE_REQ_MSCH0) | (1 << PMU_IDLE_REQ_MSCH1));
+	while (mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) &
+	       ((1 << PMU_IDLE_ST_MSCH1) | (1 << PMU_IDLE_ST_MSCH0)))
+		continue;
+
+	/* document is wrong, PMU_CRU_GATEDIS_CON0 do not need set MASK BIT */
+	mmio_write_32(PMUCRU_BASE + PMU_CRU_GATEDIS_CON0, gatedis_con0);
+}
+
+static void ddr_set_pll(void)
+{
+	mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_MODE(PLL_SLOW_MODE));
+
+	mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_POWER_DOWN(1));
+	mmio_write_32(CRU_BASE + CRU_DPLL_CON0,
+		      mmio_read_32(PARAM_ADDR + PARAM_DPLL_CON0));
+	mmio_write_32(CRU_BASE + CRU_DPLL_CON1,
+		      mmio_read_32(PARAM_ADDR + PARAM_DPLL_CON1));
+	mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_POWER_DOWN(0));
+
+	while ((mmio_read_32(CRU_BASE + CRU_DPLL_CON2) & (1u << 31)) == 0)
+		continue;
+
+	mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_MODE(PLL_NORMAL_MODE));
+}
+
+void handle_dram(void)
+{
+	mmio_setbits_32(PHY_REG(0, 927), (1 << 22));
+	mmio_setbits_32(PHY_REG(1, 927), (1 << 22));
+	idle_port();
+
+	mmio_write_32(CIC_BASE + CIC_CTRL0,
+		      (((0x3 << 4) | (1 << 2) | 1) << 16) |
+		      (1 << 2) | 1 |
+		      mmio_read_32(PARAM_ADDR + PARAM_FREQ_SELECT));
+	while ((mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 2)) == 0)
+		continue;
+
+	ddr_set_pll();
+	mmio_write_32(CIC_BASE + CIC_CTRL0, 0x20002);
+	while ((mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 0)) == 0)
+		continue;
+
+	deidle_port();
+	mmio_clrbits_32(PHY_REG(0, 927), (1 << 22));
+	mmio_clrbits_32(PHY_REG(1, 927), (1 << 22));
+}
diff --git a/plat/rockchip/rk3399/drivers/m0/src/main.c b/plat/rockchip/rk3399/drivers/m0/src/main.c
index 2e583c7..95659c4 100644
--- a/plat/rockchip/rk3399/drivers/m0/src/main.c
+++ b/plat/rockchip/rk3399/drivers/m0/src/main.c
@@ -28,44 +28,24 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <m0_param.h>
 #include "rk3399_mcu.h"
 
-#define PMU_PWRMODE_CON		0x20
-#define PMU_POWER_ST		0x78
-
-#define M0_SCR			0xe000ed10  /* System Control Register (SCR) */
-
-#define SCR_SLEEPDEEP_SHIFT	(1 << 2)
-
-static void system_wakeup(void)
+__attribute__((noreturn)) void main(void)
 {
-	unsigned int status_value;
-	unsigned int mode_con;
-
-	while (1) {
-		status_value = readl(PMU_BASE + PMU_POWER_ST);
-		if (status_value) {
-			mode_con = readl(PMU_BASE + PMU_PWRMODE_CON);
-			writel(mode_con & (~0x01),
-			       PMU_BASE + PMU_PWRMODE_CON);
-			return;
-		}
+	switch (mmio_read_32(PARAM_ADDR + PARAM_M0_FUNC)) {
+	case M0_FUNC_SUSPEND:
+		handle_suspend();
+		break;
+	case M0_FUNC_DRAM:
+		handle_dram();
+		break;
+	default:
+		break;
 	}
-}
 
-int main(void)
-{
-	unsigned int reg_src;
-
-	system_wakeup();
-
-	reg_src = readl(M0_SCR);
-
-	/* m0 enter deep sleep mode */
-	writel(reg_src | SCR_SLEEPDEEP_SHIFT, M0_SCR);
+	mmio_write_32(PARAM_ADDR + PARAM_M0_DONE, M0_DONE_FLAG);
 
 	for (;;)
-		__asm volatile("wfi");
-
-	return 0;
+		__asm__ volatile ("wfi");
 }
diff --git a/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld b/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld.S
similarity index 93%
rename from plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld
rename to plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld.S
index 0b7b124..cb224f0 100644
--- a/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld
+++ b/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld.S
@@ -28,12 +28,16 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <m0_param.h>
+
 OUTPUT_FORMAT("elf32-littlearm")
 
 SECTIONS {
 	.m0_bin 0 : {
 		KEEP(*(.isr_vector))
 		ASSERT(. == 0xc0, "ISR vector has the wrong size.");
+		ASSERT(. == PARAM_ADDR, "M0 params should go right behind ISR table.");
+		. += PARAM_M0_SIZE;
 		*(.text*)
 		*(.rodata*)
 		*(.data*)
diff --git a/plat/rockchip/rk3399/drivers/m0/src/stopwatch.c b/plat/rockchip/rk3399/drivers/m0/src/stopwatch.c
new file mode 100644
index 0000000..4f4a961
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/m0/src/stopwatch.c
@@ -0,0 +1,98 @@
+/*
+ * 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 <m0_param.h>
+#include "rk3399_mcu.h"
+
+/* use 24MHz SysTick */
+#define US_TO_CYCLE(US)	(US * 24)
+
+#define SYST_CST	0xe000e010
+/* enable counter */
+#define ENABLE		(1 << 0)
+/* count down to 0 does not cause SysTick exception to pend */
+#define TICKINT		(1 << 1)
+/* core clock used for SysTick */
+#define CLKSOURCE	(1 << 2)
+
+#define COUNTFLAG	(1 << 16)
+#define SYST_RVR	0xe000e014
+#define MAX_VALUE	0xffffff
+#define MAX_USECS	(MAX_VALUE / US_TO_CYCLE(1))
+#define SYST_CVR	0xe000e018
+#define SYST_CALIB	0xe000e01c
+
+unsigned int remaining_usecs;
+
+static inline void stopwatch_set_usecs(void)
+{
+	unsigned int cycle;
+	unsigned int usecs = MIN(MAX_USECS, remaining_usecs);
+
+	remaining_usecs -= usecs;
+	cycle = US_TO_CYCLE(usecs);
+	mmio_write_32(SYST_RVR, cycle);
+	mmio_write_32(SYST_CVR, 0);
+
+	mmio_write_32(SYST_CST, ENABLE | TICKINT | CLKSOURCE);
+}
+
+void stopwatch_init_usecs_expire(unsigned int usecs)
+{
+	/*
+	 * Enter an inifite loop if the stopwatch is in use. This will allow the
+	 * state to be analyzed with a debugger.
+	 */
+	if (mmio_read_32(SYST_CST) & ENABLE)
+		while (1)
+			;
+
+	remaining_usecs = usecs;
+	stopwatch_set_usecs();
+}
+
+int stopwatch_expired(void)
+{
+	int val = mmio_read_32(SYST_CST);
+	if ((val & COUNTFLAG) || !(val & ENABLE)) {
+		if (!remaining_usecs)
+			return 1;
+
+		stopwatch_set_usecs();
+	}
+
+	return 0;
+}
+
+void stopwatch_reset(void)
+{
+	mmio_clrbits_32(SYST_CST, ENABLE);
+	remaining_usecs = 0;
+}
diff --git a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h b/plat/rockchip/rk3399/drivers/m0/src/suspend.c
similarity index 77%
copy from plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
copy to plat/rockchip/rk3399/drivers/m0/src/suspend.c
index 78b350a..71be71d 100644
--- a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
+++ b/plat/rockchip/rk3399/drivers/m0/src/suspend.c
@@ -28,13 +28,25 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef __RK3399M0_H__
-#define __RK3399M0_H__
+#include <pmu_regs.h>
+#include "rk3399_mcu.h"
 
-/* pmu_fw.c */
-extern char rk3399m0_bin[];
-extern char rk3399m0_bin_end[];
+#define M0_SCR			0xe000ed10  /* System Control Register (SCR) */
 
-#define M0_BINCODE_BASE ((uintptr_t)rk3399m0_bin)
+#define SCR_SLEEPDEEP_SHIFT	(1 << 2)
 
-#endif /* __RK3399M0_H__ */
+void handle_suspend(void)
+{
+	unsigned int status_value;
+
+	while (1) {
+		status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST);
+		if (status_value) {
+			mmio_clrbits_32(PMU_BASE + PMU_PWRMODE_CON, 0x01);
+			return;
+		}
+	}
+
+	/* m0 enter deep sleep mode */
+	mmio_setbits_32(M0_SCR, SCR_SLEEPDEEP_SHIFT);
+}
diff --git a/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c
new file mode 100644
index 0000000..6bdd04b
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c
@@ -0,0 +1,121 @@
+/*
+ * 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 <assert.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <mmio.h>
+#include <m0_ctl.h>
+#include <plat_private.h>
+#include <rk3399_def.h>
+#include <secure.h>
+#include <soc.h>
+
+void m0_init(void)
+{
+	/* secure config for M0 */
+	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(0), WMSK_BIT(7));
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6), WMSK_BIT(12));
+
+	/* set the execute address for M0 */
+	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(3),
+		      BITS_WITH_WMASK((M0_BINCODE_BASE >> 12) & 0xffff,
+				      0xffff, 0));
+	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(7),
+		      BITS_WITH_WMASK((M0_BINCODE_BASE >> 28) & 0xf,
+				      0xf, 0));
+
+	/* document is wrong, PMU_CRU_GATEDIS_CON0 do not need set MASK BIT */
+	mmio_setbits_32(PMUCRU_BASE + PMUCRU_GATEDIS_CON0, 0x02);
+
+	/*
+	 * To switch the parent to xin24M and div == 1,
+	 *
+	 * We need to close most of the PLLs and clocks except the OSC 24MHz
+	 * durning suspend, and this should be enough to supplies the ddrfreq,
+	 * For the simple handle, we just keep the fixed 24MHz to supply the
+	 * suspend and ddrfreq directly.
+	 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKSEL_CON0,
+		      BIT_WITH_WMSK(15) | BITS_WITH_WMASK(0x0, 0x1f, 8));
+
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2, WMSK_BIT(5));
+}
+
+void m0_start(void)
+{
+	/* enable clocks for M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2,
+		      BITS_WITH_WMASK(0x0, 0xf, 0));
+
+	/* clean the PARAM_M0_DONE flag, mean that M0 will start working */
+	mmio_write_32(M0_PARAM_ADDR + PARAM_M0_DONE, 0);
+	dmbst();
+
+	mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
+		      BITS_WITH_WMASK(0x0, 0x4, 0));
+
+	udelay(5);
+	/* start M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
+		      BITS_WITH_WMASK(0x0, 0x20, 0));
+	dmbst();
+}
+
+void m0_stop(void)
+{
+	/* stop M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
+		      BITS_WITH_WMASK(0x24, 0x24, 0));
+
+	/* disable clocks for M0 */
+	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2,
+		      BITS_WITH_WMASK(0xf, 0xf, 0));
+}
+
+void m0_wait_done(void)
+{
+	do {
+		/*
+		 * Don't starve the M0 for access to SRAM, so delay before
+		 * reading the PARAM_M0_DONE value again.
+		 */
+		udelay(5);
+		dsb();
+	} while (mmio_read_32(M0_PARAM_ADDR + PARAM_M0_DONE) != M0_DONE_FLAG);
+
+	/*
+	 * Let the M0 settle into WFI before we leave. This is so we don't reset
+	 * the M0 in a bad spot which can cause problems with the M0.
+	 */
+	udelay(10);
+	dsb();
+}
diff --git a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h
similarity index 83%
copy from plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
copy to plat/rockchip/rk3399/drivers/pmu/m0_ctl.h
index 78b350a..c21caab 100644
--- a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
+++ b/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h
@@ -28,13 +28,20 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef __RK3399M0_H__
-#define __RK3399M0_H__
+#ifndef __M0_CTL_H__
+#define __M0_CTL_H__
+
+#include <m0_param.h>
+
+#define M0_BINCODE_BASE 	((uintptr_t)rk3399m0_bin)
+#define M0_PARAM_ADDR		(M0_BINCODE_BASE + PARAM_ADDR)
 
 /* pmu_fw.c */
 extern char rk3399m0_bin[];
 extern char rk3399m0_bin_end[];
 
-#define M0_BINCODE_BASE ((uintptr_t)rk3399m0_bin)
-
-#endif /* __RK3399M0_H__ */
+extern void m0_init(void);
+extern void m0_start(void);
+extern void m0_stop(void);
+extern void m0_wait_done(void);
+#endif /* __M0_CTL_H__ */
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
index 5bb29b3..31b4f07 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -33,21 +33,23 @@
 #include <bakery_lock.h>
 #include <debug.h>
 #include <delay_timer.h>
+#include <dfs.h>
 #include <errno.h>
 #include <gpio.h>
 #include <mmio.h>
+#include <m0_ctl.h>
 #include <platform.h>
 #include <platform_def.h>
 #include <plat_params.h>
 #include <plat_private.h>
 #include <rk3399_def.h>
 #include <pmu_sram.h>
+#include <secure.h>
 #include <soc.h>
 #include <pmu.h>
 #include <pmu_com.h>
 #include <pwm.h>
 #include <bl31.h>
-#include <rk3399m0.h>
 #include <suspend.h>
 
 DEFINE_BAKERY_LOCK(rockchip_pd_lock);
@@ -1066,36 +1068,10 @@
 	}
 }
 
-static void m0_clock_init(void)
+static void m0_configure_suspend(void)
 {
-	/* enable clocks for M0 */
-	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2,
-		      BITS_WITH_WMASK(0x0, 0x2f, 0));
-
-	/* switch the parent to xin24M and div == 1 */
-	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKSEL_CON0,
-		      BIT_WITH_WMSK(15) | BITS_WITH_WMASK(0x0, 0x1f, 8));
-
-	/* start M0 */
-	mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
-		      BITS_WITH_WMASK(0x0, 0x24, 0));
-
-	/* gating disable for M0 */
-	mmio_write_32(PMUCRU_BASE + PMUCRU_GATEDIS_CON0, BIT_WITH_WMSK(1));
-}
-
-static void m0_reset(void)
-{
-	/* stop M0 */
-	mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0,
-		      BITS_WITH_WMASK(0x24, 0x24, 0));
-
-	/* recover gating bit for M0 */
-	mmio_write_32(PMUCRU_BASE + PMUCRU_GATEDIS_CON0, WMSK_BIT(1));
-
-	/* disable clocks for M0 */
-	mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2,
-		      BITS_WITH_WMASK(0x2f, 0x2f, 0));
+	/* set PARAM to M0_FUNC_SUSPEND */
+	mmio_write_32(M0_PARAM_ADDR + PARAM_M0_FUNC, M0_FUNC_SUSPEND);
 }
 
 int rockchip_soc_sys_pwr_dm_suspend(void)
@@ -1103,6 +1079,7 @@
 	uint32_t wait_cnt = 0;
 	uint32_t status = 0;
 
+	ddr_prepare_for_sys_suspend();
 	dmc_save();
 	pmu_scu_b_pwrdn();
 
@@ -1118,11 +1095,12 @@
 
 	sys_slp_config();
 
-	m0_clock_init();
+	m0_configure_suspend();
+	m0_start();
 
 	pmu_sgrf_rst_hld();
 
-	mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
 		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
 		      CPU_BOOT_ADDR_WMASK);
 
@@ -1174,7 +1152,7 @@
 	udelay(300);
 	enable_dvfs_plls();
 
-	secure_watchdog_restore();
+	secure_watchdog_enable();
 
 	/* restore clk_ddrc_bpll_src_en gate */
 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3),
@@ -1190,7 +1168,7 @@
 	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),
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
 		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
 		      CPU_BOOT_ADDR_WMASK);
 
@@ -1242,8 +1220,9 @@
 				BIT(PMU_CLR_GIC));
 
 	plat_rockchip_gic_cpuif_enable();
+	m0_stop();
 
-	m0_reset();
+	ddr_prepare_for_sys_resume();
 
 	return 0;
 }
@@ -1312,7 +1291,7 @@
 	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
 
 	/* config cpu's warm boot address */
-	mmio_write_32(SGRF_BASE + SGRF_SOC_CON0_1(1),
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
 		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
 		      CPU_BOOT_ADDR_WMASK);
 	mmio_write_32(PMU_BASE + PMU_NOC_AUTO_ENA, NOC_AUTO_ENABLE);
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.h b/plat/rockchip/rk3399/drivers/pmu/pmu.h
index 22c8c63..08d55a8 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.h
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.h
@@ -31,6 +31,7 @@
 #ifndef __PMU_H__
 #define __PMU_H__
 
+#include <pmu_bits.h>
 #include <pmu_regs.h>
 #include <soc.h>
 
@@ -67,693 +68,6 @@
 #define CKECK_WFI_MSK		0x10
 #define CKECK_WFEI_MSK		0x11
 
-enum pmu_powerdomain_id {
-	PD_CPUL0 = 0,
-	PD_CPUL1,
-	PD_CPUL2,
-	PD_CPUL3,
-	PD_CPUB0,
-	PD_CPUB1,
-	PD_SCUL,
-	PD_SCUB,
-	PD_TCPD0,
-	PD_TCPD1,
-	PD_CCI,
-	PD_PERILP,
-	PD_PERIHP,
-	PD_CENTER,
-	PD_VIO,
-	PD_GPU,
-	PD_VCODEC,
-	PD_VDU,
-	PD_RGA,
-	PD_IEP,
-	PD_VO,
-	PD_ISP0 = 22,
-	PD_ISP1,
-	PD_HDCP,
-	PD_GMAC,
-	PD_EMMC,
-	PD_USB3,
-	PD_EDP,
-	PD_GIC,
-	PD_SD,
-	PD_SDIOAUDIO,
-	PD_END
-};
-
-enum powerdomain_state {
-	PMU_POWER_ON = 0,
-	PMU_POWER_OFF,
-};
-
-enum pmu_bus_id {
-	BUS_ID_GPU = 0,
-	BUS_ID_PERILP,
-	BUS_ID_PERIHP,
-	BUS_ID_VCODEC,
-	BUS_ID_VDU,
-	BUS_ID_RGA,
-	BUS_ID_IEP,
-	BUS_ID_VOPB,
-	BUS_ID_VOPL,
-	BUS_ID_ISP0,
-	BUS_ID_ISP1,
-	BUS_ID_HDCP,
-	BUS_ID_USB3,
-	BUS_ID_PERILPM0,
-	BUS_ID_CENTER,
-	BUS_ID_CCIM0,
-	BUS_ID_CCIM1,
-	BUS_ID_VIO,
-	BUS_ID_MSCH0,
-	BUS_ID_MSCH1,
-	BUS_ID_ALIVE,
-	BUS_ID_PMU,
-	BUS_ID_EDP,
-	BUS_ID_GMAC,
-	BUS_ID_EMMC,
-	BUS_ID_CENTER1,
-	BUS_ID_PMUM0,
-	BUS_ID_GIC,
-	BUS_ID_SD,
-	BUS_ID_SDIOAUDIO,
-};
-
-enum pmu_bus_state {
-	BUS_ACTIVE,
-	BUS_IDLE,
-};
-
-/* pmu_cpuapm bit */
-enum pmu_cores_pm_by_wfi {
-	core_pm_en = 0,
-	core_pm_int_wakeup_en,
-	core_pm_resv,
-	core_pm_sft_wakeup_en
-};
-
-enum pmu_wkup_cfg0 {
-	PMU_GPIO0A_POSE_WKUP_EN = 0,
-	PMU_GPIO0B_POSE_WKUP_EN = 8,
-	PMU_GPIO0C_POSE_WKUP_EN = 16,
-	PMU_GPIO0D_POSE_WKUP_EN = 24,
-};
-
-enum pmu_wkup_cfg1 {
-	PMU_GPIO0A_NEGEDGE_WKUP_EN = 0,
-	PMU_GPIO0B_NEGEDGE_WKUP_EN = 7,
-	PMU_GPIO0C_NEGEDGE_WKUP_EN = 16,
-	PMU_GPIO0D_NEGEDGE_WKUP_EN = 24,
-};
-
-enum pmu_wkup_cfg2 {
-	PMU_GPIO1A_POSE_WKUP_EN = 0,
-	PMU_GPIO1B_POSE_WKUP_EN = 7,
-	PMU_GPIO1C_POSE_WKUP_EN = 16,
-	PMU_GPIO1D_POSE_WKUP_EN = 24,
-};
-
-enum pmu_wkup_cfg3 {
-	PMU_GPIO1A_NEGEDGE_WKUP_EN = 0,
-	PMU_GPIO1B_NEGEDGE_WKUP_EN = 7,
-	PMU_GPIO1C_NEGEDGE_WKUP_EN = 16,
-	PMU_GPIO1D_NEGEDGE_WKUP_EN = 24,
-};
-
-/* pmu_wkup_cfg4 */
-enum pmu_wkup_cfg4 {
-	PMU_CLUSTER_L_WKUP_EN = 0,
-	PMU_CLUSTER_B_WKUP_EN,
-	PMU_GPIO_WKUP_EN,
-	PMU_SDIO_WKUP_EN,
-
-	PMU_SDMMC_WKUP_EN,
-	PMU_TIMER_WKUP_EN = 6,
-	PMU_USBDEV_WKUP_EN,
-
-	PMU_SFT_WKUP_EN,
-	PMU_M0_WDT_WKUP_EN,
-	PMU_TIMEOUT_WKUP_EN,
-	PMU_PWM_WKUP_EN,
-
-	PMU_PCIE_WKUP_EN = 13,
-};
-
-enum pmu_pwrdn_con {
-	PMU_A53_L0_PWRDWN_EN = 0,
-	PMU_A53_L1_PWRDWN_EN,
-	PMU_A53_L2_PWRDWN_EN,
-	PMU_A53_L3_PWRDWN_EN,
-
-	PMU_A72_B0_PWRDWN_EN,
-	PMU_A72_B1_PWRDWN_EN,
-	PMU_SCU_L_PWRDWN_EN,
-	PMU_SCU_B_PWRDWN_EN,
-
-	PMU_TCPD0_PWRDWN_EN,
-	PMU_TCPD1_PWRDWN_EN,
-	PMU_CCI_PWRDWN_EN,
-	PMU_PERILP_PWRDWN_EN,
-
-	PMU_PERIHP_PWRDWN_EN,
-	PMU_CENTER_PWRDWN_EN,
-	PMU_VIO_PWRDWN_EN,
-	PMU_GPU_PWRDWN_EN,
-
-	PMU_VCODEC_PWRDWN_EN,
-	PMU_VDU_PWRDWN_EN,
-	PMU_RGA_PWRDWN_EN,
-	PMU_IEP_PWRDWN_EN,
-
-	PMU_VO_PWRDWN_EN,
-	PMU_ISP0_PWRDWN_EN = 22,
-	PMU_ISP1_PWRDWN_EN,
-
-	PMU_HDCP_PWRDWN_EN,
-	PMU_GMAC_PWRDWN_EN,
-	PMU_EMMC_PWRDWN_EN,
-	PMU_USB3_PWRDWN_EN,
-
-	PMU_EDP_PWRDWN_EN,
-	PMU_GIC_PWRDWN_EN,
-	PMU_SD_PWRDWN_EN,
-	PMU_SDIOAUDIO_PWRDWN_EN,
-};
-
-enum pmu_pwrdn_st {
-	PMU_A53_L0_PWRDWN_ST = 0,
-	PMU_A53_L1_PWRDWN_ST,
-	PMU_A53_L2_PWRDWN_ST,
-	PMU_A53_L3_PWRDWN_ST,
-
-	PMU_A72_B0_PWRDWN_ST,
-	PMU_A72_B1_PWRDWN_ST,
-	PMU_SCU_L_PWRDWN_ST,
-	PMU_SCU_B_PWRDWN_ST,
-
-	PMU_TCPD0_PWRDWN_ST,
-	PMU_TCPD1_PWRDWN_ST,
-	PMU_CCI_PWRDWN_ST,
-	PMU_PERILP_PWRDWN_ST,
-
-	PMU_PERIHP_PWRDWN_ST,
-	PMU_CENTER_PWRDWN_ST,
-	PMU_VIO_PWRDWN_ST,
-	PMU_GPU_PWRDWN_ST,
-
-	PMU_VCODEC_PWRDWN_ST,
-	PMU_VDU_PWRDWN_ST,
-	PMU_RGA_PWRDWN_ST,
-	PMU_IEP_PWRDWN_ST,
-
-	PMU_VO_PWRDWN_ST,
-	PMU_ISP0_PWRDWN_ST = 22,
-	PMU_ISP1_PWRDWN_ST,
-
-	PMU_HDCP_PWRDWN_ST,
-	PMU_GMAC_PWRDWN_ST,
-	PMU_EMMC_PWRDWN_ST,
-	PMU_USB3_PWRDWN_ST,
-
-	PMU_EDP_PWRDWN_ST,
-	PMU_GIC_PWRDWN_ST,
-	PMU_SD_PWRDWN_ST,
-	PMU_SDIOAUDIO_PWRDWN_ST,
-
-};
-
-enum pmu_pll_con {
-	PMU_PLL_PD_CFG = 0,
-	PMU_SFT_PLL_PD = 8,
-};
-
-enum pmu_pwermode_con {
-	PMU_PWR_MODE_EN = 0,
-	PMU_WKUP_RST_EN,
-	PMU_INPUT_CLAMP_EN,
-	PMU_OSC_DIS,
-
-	PMU_ALIVE_USE_LF,
-	PMU_PMU_USE_LF,
-	PMU_POWER_OFF_REQ_CFG,
-	PMU_CHIP_PD_EN,
-
-	PMU_PLL_PD_EN,
-	PMU_CPU0_PD_EN,
-	PMU_L2_FLUSH_EN,
-	PMU_L2_IDLE_EN,
-
-	PMU_SCU_PD_EN,
-	PMU_CCI_PD_EN,
-	PMU_PERILP_PD_EN,
-	PMU_CENTER_PD_EN,
-
-	PMU_SREF0_ENTER_EN,
-	PMU_DDRC0_GATING_EN,
-	PMU_DDRIO0_RET_EN,
-	PMU_DDRIO0_RET_DE_REQ,
-
-	PMU_SREF1_ENTER_EN,
-	PMU_DDRC1_GATING_EN,
-	PMU_DDRIO1_RET_EN,
-	PMU_DDRIO1_RET_DE_REQ,
-
-	PMU_CLK_CENTER_SRC_GATE_EN = 26,
-	PMU_CLK_PERILP_SRC_GATE_EN,
-
-	PMU_CLK_CORE_SRC_GATE_EN,
-	PMU_DDRIO_RET_HW_DE_REQ,
-	PMU_SLP_OUTPUT_CFG,
-	PMU_MAIN_CLUSTER,
-};
-
-enum pmu_sft_con {
-	PMU_WKUP_SFT = 0,
-	PMU_INPUT_CLAMP_CFG,
-	PMU_OSC_DIS_CFG,
-	PMU_PMU_LF_EN_CFG,
-
-	PMU_ALIVE_LF_EN_CFG,
-	PMU_24M_EN_CFG,
-	PMU_DBG_PWRUP_L0_CFG,
-	PMU_WKUP_SFT_M0,
-
-	PMU_DDRCTL0_C_SYSREQ_CFG,
-	PMU_DDR0_IO_RET_CFG,
-
-	PMU_DDRCTL1_C_SYSREQ_CFG = 12,
-	PMU_DDR1_IO_RET_CFG,
-	DBG_PWRUP_B0_CFG = 15,
-
-	DBG_NOPWERDWN_L0_EN,
-	DBG_NOPWERDWN_L1_EN,
-	DBG_NOPWERDWN_L2_EN,
-	DBG_NOPWERDWN_L3_EN,
-
-	DBG_PWRUP_REQ_L_EN = 20,
-	CLUSTER_L_CLK_SRC_GATING_CFG,
-	L2_FLUSH_REQ_CLUSTER_L,
-	ACINACTM_CLUSTER_L_CFG,
-
-	DBG_NO_PWERDWN_B0_EN,
-	DBG_NO_PWERDWN_B1_EN,
-
-	DBG_PWRUP_REQ_B_EN = 28,
-	CLUSTER_B_CLK_SRC_GATING_CFG,
-	L2_FLUSH_REQ_CLUSTER_B,
-	ACINACTM_CLUSTER_B_CFG,
-};
-
-enum pmu_int_con {
-	PMU_PMU_INT_EN = 0,
-	PMU_PWRMD_WKUP_INT_EN,
-	PMU_WKUP_GPIO0_NEG_INT_EN,
-	PMU_WKUP_GPIO0_POS_INT_EN,
-	PMU_WKUP_GPIO1_NEG_INT_EN,
-	PMU_WKUP_GPIO1_POS_INT_EN,
-};
-
-enum pmu_int_st {
-	PMU_PWRMD_WKUP_INT_ST = 1,
-	PMU_WKUP_GPIO0_NEG_INT_ST,
-	PMU_WKUP_GPIO0_POS_INT_ST,
-	PMU_WKUP_GPIO1_NEG_INT_ST,
-	PMU_WKUP_GPIO1_POS_INT_ST,
-};
-
-enum pmu_gpio0_pos_int_con {
-	PMU_GPIO0A_POS_INT_EN = 0,
-	PMU_GPIO0B_POS_INT_EN = 8,
-	PMU_GPIO0C_POS_INT_EN = 16,
-	PMU_GPIO0D_POS_INT_EN = 24,
-};
-
-enum pmu_gpio0_neg_int_con {
-	PMU_GPIO0A_NEG_INT_EN = 0,
-	PMU_GPIO0B_NEG_INT_EN = 8,
-	PMU_GPIO0C_NEG_INT_EN = 16,
-	PMU_GPIO0D_NEG_INT_EN = 24,
-};
-
-enum pmu_gpio1_pos_int_con {
-	PMU_GPIO1A_POS_INT_EN = 0,
-	PMU_GPIO1B_POS_INT_EN = 8,
-	PMU_GPIO1C_POS_INT_EN = 16,
-	PMU_GPIO1D_POS_INT_EN = 24,
-};
-
-enum pmu_gpio1_neg_int_con {
-	PMU_GPIO1A_NEG_INT_EN = 0,
-	PMU_GPIO1B_NEG_INT_EN = 8,
-	PMU_GPIO1C_NEG_INT_EN = 16,
-	PMU_GPIO1D_NEG_INT_EN = 24,
-};
-
-enum pmu_gpio0_pos_int_st {
-	PMU_GPIO0A_POS_INT_ST = 0,
-	PMU_GPIO0B_POS_INT_ST = 8,
-	PMU_GPIO0C_POS_INT_ST = 16,
-	PMU_GPIO0D_POS_INT_ST = 24,
-};
-
-enum pmu_gpio0_neg_int_st {
-	PMU_GPIO0A_NEG_INT_ST = 0,
-	PMU_GPIO0B_NEG_INT_ST = 8,
-	PMU_GPIO0C_NEG_INT_ST = 16,
-	PMU_GPIO0D_NEG_INT_ST = 24,
-};
-
-enum pmu_gpio1_pos_int_st {
-	PMU_GPIO1A_POS_INT_ST = 0,
-	PMU_GPIO1B_POS_INT_ST = 8,
-	PMU_GPIO1C_POS_INT_ST = 16,
-	PMU_GPIO1D_POS_INT_ST = 24,
-};
-
-enum pmu_gpio1_neg_int_st {
-	PMU_GPIO1A_NEG_INT_ST = 0,
-	PMU_GPIO1B_NEG_INT_ST = 8,
-	PMU_GPIO1C_NEG_INT_ST = 16,
-	PMU_GPIO1D_NEG_INT_ST = 24,
-};
-
-/* pmu power down configure register 0x0050 */
-enum pmu_pwrdn_inten {
-	PMU_A53_L0_PWR_SWITCH_INT_EN = 0,
-	PMU_A53_L1_PWR_SWITCH_INT_EN,
-	PMU_A53_L2_PWR_SWITCH_INT_EN,
-	PMU_A53_L3_PWR_SWITCH_INT_EN,
-
-	PMU_A72_B0_PWR_SWITCH_INT_EN,
-	PMU_A72_B1_PWR_SWITCH_INT_EN,
-	PMU_SCU_L_PWR_SWITCH_INT_EN,
-	PMU_SCU_B_PWR_SWITCH_INT_EN,
-
-	PMU_TCPD0_PWR_SWITCH_INT_EN,
-	PMU_TCPD1_PWR_SWITCH_INT_EN,
-	PMU_CCI_PWR_SWITCH_INT_EN,
-	PMU_PERILP_PWR_SWITCH_INT_EN,
-
-	PMU_PERIHP_PWR_SWITCH_INT_EN,
-	PMU_CENTER_PWR_SWITCH_INT_EN,
-	PMU_VIO_PWR_SWITCH_INT_EN,
-	PMU_GPU_PWR_SWITCH_INT_EN,
-
-	PMU_VCODEC_PWR_SWITCH_INT_EN,
-	PMU_VDU_PWR_SWITCH_INT_EN,
-	PMU_RGA_PWR_SWITCH_INT_EN,
-	PMU_IEP_PWR_SWITCH_INT_EN,
-
-	PMU_VO_PWR_SWITCH_INT_EN,
-	PMU_ISP0_PWR_SWITCH_INT_EN = 22,
-	PMU_ISP1_PWR_SWITCH_INT_EN,
-
-	PMU_HDCP_PWR_SWITCH_INT_EN,
-	PMU_GMAC_PWR_SWITCH_INT_EN,
-	PMU_EMMC_PWR_SWITCH_INT_EN,
-	PMU_USB3_PWR_SWITCH_INT_EN,
-
-	PMU_EDP_PWR_SWITCH_INT_EN,
-	PMU_GIC_PWR_SWITCH_INT_EN,
-	PMU_SD_PWR_SWITCH_INT_EN,
-	PMU_SDIOAUDIO_PWR_SWITCH_INT_EN,
-};
-
-enum pmu_wkup_status {
-	PMU_WKUP_BY_CLSTER_L_INT = 0,
-	PMU_WKUP_BY_CLSTER_b_INT,
-	PMU_WKUP_BY_GPIO_INT,
-	PMU_WKUP_BY_SDIO_DET,
-
-	PMU_WKUP_BY_SDMMC_DET,
-	PMU_WKUP_BY_TIMER = 6,
-	PMU_WKUP_BY_USBDEV_DET,
-
-	PMU_WKUP_BY_M0_SFT,
-	PMU_WKUP_BY_M0_WDT_INT,
-	PMU_WKUP_BY_TIMEOUT,
-	PMU_WKUP_BY_PWM,
-
-	PMU_WKUP_BY_PCIE = 13,
-};
-
-enum pmu_bus_clr {
-	PMU_CLR_GPU = 0,
-	PMU_CLR_PERILP,
-	PMU_CLR_PERIHP,
-	PMU_CLR_VCODEC,
-
-	PMU_CLR_VDU,
-	PMU_CLR_RGA,
-	PMU_CLR_IEP,
-	PMU_CLR_VOPB,
-
-	PMU_CLR_VOPL,
-	PMU_CLR_ISP0,
-	PMU_CLR_ISP1,
-	PMU_CLR_HDCP,
-
-	PMU_CLR_USB3,
-	PMU_CLR_PERILPM0,
-	PMU_CLR_CENTER,
-	PMU_CLR_CCIM1,
-
-	PMU_CLR_CCIM0,
-	PMU_CLR_VIO,
-	PMU_CLR_MSCH0,
-	PMU_CLR_MSCH1,
-
-	PMU_CLR_ALIVE,
-	PMU_CLR_PMU,
-	PMU_CLR_EDP,
-	PMU_CLR_GMAC,
-
-	PMU_CLR_EMMC,
-	PMU_CLR_CENTER1,
-	PMU_CLR_PMUM0,
-	PMU_CLR_GIC,
-
-	PMU_CLR_SD,
-	PMU_CLR_SDIOAUDIO,
-};
-
-/* PMU bus idle request register */
-enum pmu_bus_idle_req {
-	PMU_IDLE_REQ_GPU = 0,
-	PMU_IDLE_REQ_PERILP,
-	PMU_IDLE_REQ_PERIHP,
-	PMU_IDLE_REQ_VCODEC,
-
-	PMU_IDLE_REQ_VDU,
-	PMU_IDLE_REQ_RGA,
-	PMU_IDLE_REQ_IEP,
-	PMU_IDLE_REQ_VOPB,
-
-	PMU_IDLE_REQ_VOPL,
-	PMU_IDLE_REQ_ISP0,
-	PMU_IDLE_REQ_ISP1,
-	PMU_IDLE_REQ_HDCP,
-
-	PMU_IDLE_REQ_USB3,
-	PMU_IDLE_REQ_PERILPM0,
-	PMU_IDLE_REQ_CENTER,
-	PMU_IDLE_REQ_CCIM0,
-
-	PMU_IDLE_REQ_CCIM1,
-	PMU_IDLE_REQ_VIO,
-	PMU_IDLE_REQ_MSCH0,
-	PMU_IDLE_REQ_MSCH1,
-
-	PMU_IDLE_REQ_ALIVE,
-	PMU_IDLE_REQ_PMU,
-	PMU_IDLE_REQ_EDP,
-	PMU_IDLE_REQ_GMAC,
-
-	PMU_IDLE_REQ_EMMC,
-	PMU_IDLE_REQ_CENTER1,
-	PMU_IDLE_REQ_PMUM0,
-	PMU_IDLE_REQ_GIC,
-
-	PMU_IDLE_REQ_SD,
-	PMU_IDLE_REQ_SDIOAUDIO,
-};
-
-/* pmu bus idle status register */
-enum pmu_bus_idle_st {
-	PMU_IDLE_ST_GPU = 0,
-	PMU_IDLE_ST_PERILP,
-	PMU_IDLE_ST_PERIHP,
-	PMU_IDLE_ST_VCODEC,
-
-	PMU_IDLE_ST_VDU,
-	PMU_IDLE_ST_RGA,
-	PMU_IDLE_ST_IEP,
-	PMU_IDLE_ST_VOPB,
-
-	PMU_IDLE_ST_VOPL,
-	PMU_IDLE_ST_ISP0,
-	PMU_IDLE_ST_ISP1,
-	PMU_IDLE_ST_HDCP,
-
-	PMU_IDLE_ST_USB3,
-	PMU_IDLE_ST_PERILPM0,
-	PMU_IDLE_ST_CENTER,
-	PMU_IDLE_ST_CCIM0,
-
-	PMU_IDLE_ST_CCIM1,
-	PMU_IDLE_ST_VIO,
-	PMU_IDLE_ST_MSCH0,
-	PMU_IDLE_ST_MSCH1,
-
-	PMU_IDLE_ST_ALIVE,
-	PMU_IDLE_ST_PMU,
-	PMU_IDLE_ST_EDP,
-	PMU_IDLE_ST_GMAC,
-
-	PMU_IDLE_ST_EMMC,
-	PMU_IDLE_ST_CENTER1,
-	PMU_IDLE_ST_PMUM0,
-	PMU_IDLE_ST_GIC,
-
-	PMU_IDLE_ST_SD,
-	PMU_IDLE_ST_SDIOAUDIO,
-};
-
-enum pmu_bus_idle_ack {
-	PMU_IDLE_ACK_GPU = 0,
-	PMU_IDLE_ACK_PERILP,
-	PMU_IDLE_ACK_PERIHP,
-	PMU_IDLE_ACK_VCODEC,
-
-	PMU_IDLE_ACK_VDU,
-	PMU_IDLE_ACK_RGA,
-	PMU_IDLE_ACK_IEP,
-	PMU_IDLE_ACK_VOPB,
-
-	PMU_IDLE_ACK_VOPL,
-	PMU_IDLE_ACK_ISP0,
-	PMU_IDLE_ACK_ISP1,
-	PMU_IDLE_ACK_HDCP,
-
-	PMU_IDLE_ACK_USB3,
-	PMU_IDLE_ACK_PERILPM0,
-	PMU_IDLE_ACK_CENTER,
-	PMU_IDLE_ACK_CCIM0,
-
-	PMU_IDLE_ACK_CCIM1,
-	PMU_IDLE_ACK_VIO,
-	PMU_IDLE_ACK_MSCH0,
-	PMU_IDLE_ACK_MSCH1,
-
-	PMU_IDLE_ACK_ALIVE,
-	PMU_IDLE_ACK_PMU,
-	PMU_IDLE_ACK_EDP,
-	PMU_IDLE_ACK_GMAC,
-
-	PMU_IDLE_ACK_EMMC,
-	PMU_IDLE_ACK_CENTER1,
-	PMU_IDLE_ACK_PMUM0,
-	PMU_IDLE_ACK_GIC,
-
-	PMU_IDLE_ACK_SD,
-	PMU_IDLE_ACK_SDIOAUDIO,
-};
-
-enum pmu_cci500_con {
-	PMU_PREQ_CCI500_CFG_SW = 0,
-	PMU_CLR_PREQ_CCI500_HW,
-	PMU_PSTATE_CCI500_0,
-	PMU_PSTATE_CCI500_1,
-
-	PMU_PSTATE_CCI500_2,
-	PMU_QREQ_CCI500_CFG_SW,
-	PMU_CLR_QREQ_CCI500_HW,
-	PMU_QGATING_CCI500_CFG,
-
-	PMU_PREQ_CCI500_CFG_SW_WMSK = 16,
-	PMU_CLR_PREQ_CCI500_HW_WMSK,
-	PMU_PSTATE_CCI500_0_WMSK,
-	PMU_PSTATE_CCI500_1_WMSK,
-
-	PMU_PSTATE_CCI500_2_WMSK,
-	PMU_QREQ_CCI500_CFG_SW_WMSK,
-	PMU_CLR_QREQ_CCI500_HW_WMSK,
-	PMU_QGATING_CCI500_CFG_WMSK,
-};
-
-enum pmu_adb400_con {
-	PMU_PWRDWN_REQ_CXCS_SW = 0,
-	PMU_PWRDWN_REQ_CORE_L_SW,
-	PMU_PWRDWN_REQ_CORE_L_2GIC_SW,
-	PMU_PWRDWN_REQ_GIC2_CORE_L_SW,
-
-	PMU_PWRDWN_REQ_CORE_B_SW,
-	PMU_PWRDWN_REQ_CORE_B_2GIC_SW,
-	PMU_PWRDWN_REQ_GIC2_CORE_B_SW,
-
-	PMU_CLR_CXCS_HW = 8,
-	PMU_CLR_CORE_L_HW,
-	PMU_CLR_CORE_L_2GIC_HW,
-	PMU_CLR_GIC2_CORE_L_HW,
-
-	PMU_CLR_CORE_B_HW,
-	PMU_CLR_CORE_B_2GIC_HW,
-	PMU_CLR_GIC2_CORE_B_HW,
-
-	PMU_PWRDWN_REQ_CXCS_SW_WMSK = 16,
-	PMU_PWRDWN_REQ_CORE_L_SW_WMSK,
-	PMU_PWRDWN_REQ_CORE_L_2GIC_SW_WMSK,
-	PMU_PWRDWN_REQ_GIC2_CORE_L_SW_WMSK,
-
-	PMU_PWRDWN_REQ_CORE_B_SW_WMSK,
-	PMU_PWRDWN_REQ_CORE_B_2GIC_SW_WMSK,
-	PMU_PWRDWN_REQ_GIC2_CORE_B_SW_WMSK,
-
-	PMU_CLR_CXCS_HW_WMSK = 24,
-	PMU_CLR_CORE_L_HW_WMSK,
-	PMU_CLR_CORE_L_2GIC_HW_WMSK,
-	PMU_CLR_GIC2_CORE_L_HW_WMSK,
-
-	PMU_CLR_CORE_B_HW_WMSK,
-	PMU_CLR_CORE_B_2GIC_HW_WMSK,
-	PMU_CLR_GIC2_CORE_B_HW_WMSK,
-};
-
-enum pmu_adb400_st {
-	PMU_PWRDWN_REQ_CXCS_SW_ST = 0,
-	PMU_PWRDWN_REQ_CORE_L_SW_ST,
-	PMU_PWRDWN_REQ_CORE_L_2GIC_SW_ST,
-	PMU_PWRDWN_REQ_GIC2_CORE_L_SW_ST,
-
-	PMU_PWRDWN_REQ_CORE_B_SW_ST,
-	PMU_PWRDWN_REQ_CORE_B_2GIC_SW_ST,
-	PMU_PWRDWN_REQ_GIC2_CORE_B_SW_ST,
-
-	PMU_CLR_CXCS_HW_ST = 8,
-	PMU_CLR_CORE_L_HW_ST,
-	PMU_CLR_CORE_L_2GIC_HW_ST,
-	PMU_CLR_GIC2_CORE_L_HW_ST,
-
-	PMU_CLR_CORE_B_HW_ST,
-	PMU_CLR_CORE_B_2GIC_HW_ST,
-	PMU_CLR_GIC2_CORE_B_HW_ST,
-};
-
-enum pmu_pwrdn_con1 {
-	PMU_VD_SCU_L_PWRDN_EN = 0,
-	PMU_VD_SCU_B_PWRDN_EN,
-	PMU_VD_CENTER_PWRDN_EN,
-};
-
-enum pmu_core_pwr_st {
-	L2_FLUSHDONE_CLUSTER_L = 0,
-	STANDBY_BY_WFIL2_CLUSTER_L,
-
-	L2_FLUSHDONE_CLUSTER_B = 10,
-	STANDBY_BY_WFIL2_CLUSTER_B,
-};
-
 /* Specific features required  */
 #define AP_PWROFF		0x0a
 
diff --git a/plat/rockchip/rk3399/drivers/secure/secure.c b/plat/rockchip/rk3399/drivers/secure/secure.c
new file mode 100644
index 0000000..d3c8cb8
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/secure/secure.c
@@ -0,0 +1,173 @@
+/*
+ * 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 <assert.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <plat_private.h>
+#include <secure.h>
+#include <soc.h>
+
+static void sgrf_ddr_rgn_global_bypass(uint32_t bypass)
+{
+	if (bypass)
+		/* set bypass (non-secure regions) for whole ddr regions */
+		mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16),
+			      SGRF_DDR_RGN_BYPS);
+	else
+		/* cancel bypass for whole ddr regions */
+		mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16),
+			      SGRF_DDR_RGN_NO_BYPS);
+}
+
+/**
+ * There are 8 + 1 regions for DDR secure control:
+ * DDR_RGN_0 ~ DDR_RGN_7: Per DDR_RGNs grain size is 1MB
+ * DDR_RGN_X - the memories of exclude DDR_RGN_0 ~ DDR_RGN_7
+ *
+ * DDR_RGN_0 - start address of the RGN0
+ * DDR_RGN_8 - end address of the RGN0
+ * DDR_RGN_1 - start address of the RGN1
+ * DDR_RGN_9 - end address of the RGN1
+ * ...
+ * DDR_RGN_7 - start address of the RGN7
+ * DDR_RGN_15 - end address of the RGN7
+ * DDR_RGN_16 - bit 0 ~ 7 is bitmap for RGN0~7 secure,0: disable, 1: enable
+ *              bit 8 is setting for RGNx, the rest of the memory and region
+ *                which excludes RGN0~7, 0: disable, 1: enable
+ *              bit 9, the global secure configuration via bypass, 0: disable
+ *                bypass, 1: enable bypass
+ *
+ * @rgn - the DDR regions 0 ~ 7 which are can be configured.
+ * The @st_mb and @ed_mb indicate the start and end addresses for which to set
+ * the security, and the unit is megabyte. When the st_mb == 0, ed_mb == 0, the
+ * address range 0x0 ~ 0xfffff is secure.
+ *
+ * For example, if we would like to set the range [0, 32MB) is security via
+ * DDR_RGN0, then rgn == 0, st_mb == 0, ed_mb == 31.
+ */
+static void sgrf_ddr_rgn_config(uint32_t rgn,
+				uintptr_t st, uintptr_t ed)
+{
+	uintptr_t st_mb, ed_mb;
+
+	assert(rgn <= 7);
+	assert(st < ed);
+
+	/* check aligned 1MB */
+	assert(st % SIZE_M(1) == 0);
+	assert(ed % SIZE_M(1) == 0);
+
+	st_mb = st / SIZE_M(1);
+	ed_mb = ed / SIZE_M(1);
+
+	/* set ddr region addr start */
+	mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(rgn),
+		      BITS_WITH_WMASK(st_mb, SGRF_DDR_RGN_0_16_WMSK, 0));
+
+	/* set ddr region addr end */
+	mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(rgn + 8),
+		      BITS_WITH_WMASK((ed_mb - 1), SGRF_DDR_RGN_0_16_WMSK, 0));
+
+	mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16),
+		      BIT_WITH_WMSK(rgn));
+}
+
+void secure_watchdog_disable(void)
+{
+	/**
+	 * Disable CA53 and CM0 wdt pclk
+	 * BIT[8]: ca53 wdt pclk, 0: enable 1: disable
+	 * BIT[10]: cm0 wdt pclk, 0: enable 1: disable
+	 */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3),
+		      BIT_WITH_WMSK(PCLK_WDT_CA53_GATE_SHIFT) |
+		      BIT_WITH_WMSK(PCLK_WDT_CM0_GATE_SHIFT));
+}
+
+void secure_watchdog_enable(void)
+{
+	/**
+	 * Enable CA53 and CM0 wdt pclk
+	 * BIT[8]: ca53 wdt pclk, 0: enable 1: disable
+	 * BIT[10]: cm0 wdt pclk, 0: enable 1: disable
+	 */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3),
+		      WMSK_BIT(PCLK_WDT_CA53_GATE_SHIFT) |
+		      WMSK_BIT(PCLK_WDT_CM0_GATE_SHIFT));
+}
+
+void secure_timer_init(void)
+{
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_END_COUNT0, 0xffffffff);
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_END_COUNT1, 0xffffffff);
+
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_INIT_COUNT0, 0x0);
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_INIT_COUNT0, 0x0);
+
+	/* auto reload & enable the timer */
+	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_CONTROL_REG,
+		      TIMER_EN | TIMER_FMODE);
+}
+
+void secure_sgrf_init(void)
+{
+	/* security config for master */
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(5),
+		      REG_SOC_WMSK | SGRF_SOC_ALLMST_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6),
+		      REG_SOC_WMSK | SGRF_SOC_ALLMST_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(7),
+		      REG_SOC_WMSK | SGRF_SOC_ALLMST_NS);
+
+	/* security config for slave */
+	mmio_write_32(SGRF_BASE + SGRF_PMU_SLV_CON0_1(0),
+		      SGRF_PMU_SLV_S_CFGED |
+		      SGRF_PMU_SLV_CRYPTO1_NS);
+	mmio_write_32(SGRF_BASE + SGRF_PMU_SLV_CON0_1(1),
+		      SGRF_SLV_S_WMSK | SGRF_PMUSRAM_S);
+	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(0),
+		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(1),
+		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(2),
+		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(3),
+		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
+	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(4),
+		      SGRF_SLV_S_WMSK | SGRF_INTSRAM_S);
+}
+
+void secure_sgrf_ddr_rgn_init(void)
+{
+	sgrf_ddr_rgn_config(0, TZRAM_BASE, TZRAM_SIZE);
+	sgrf_ddr_rgn_global_bypass(0);
+}
diff --git a/plat/rockchip/rk3399/drivers/secure/secure.h b/plat/rockchip/rk3399/drivers/secure/secure.h
new file mode 100644
index 0000000..12a875c
--- /dev/null
+++ b/plat/rockchip/rk3399/drivers/secure/secure.h
@@ -0,0 +1,128 @@
+/*
+ * 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_ROCKCHIP_RK3399_DRIVER_SECURE_H__
+#define __PLAT_ROCKCHIP_RK3399_DRIVER_SECURE_H__
+
+/**************************************************
+ * sgrf reg, offset
+ **************************************************/
+#define SGRF_SOC_CON0_1(n)		(0xc000 + (n) * 4)
+#define SGRF_SOC_CON3_7(n)		(0xe00c + ((n) - 3) * 4)
+#define SGRF_SOC_CON8_15(n)		(0x8020 + ((n) - 8) * 4)
+#define SGRF_SOC_CON(n) 		(n < 3 ? SGRF_SOC_CON0_1(n) :\
+						(n < 8 ? SGRF_SOC_CON3_7(n) :\
+							 SGRF_SOC_CON8_15(n)))
+
+#define SGRF_PMU_SLV_CON0_1(n)		(0xc240 + ((n) - 0) * 4)
+#define SGRF_SLV_SECURE_CON0_4(n)	(0xe3c0 + ((n) - 0) * 4)
+#define SGRF_DDRRGN_CON0_16(n)		((n) * 4)
+#define SGRF_DDRRGN_CON20_34(n)		(0x50 + ((n) - 20) * 4)
+
+/* All of master in ns */
+#define SGRF_SOC_ALLMST_NS		0xffff
+
+/* security config for slave */
+#define SGRF_SLV_S_WMSK			0xffff0000
+#define SGRF_SLV_S_ALL_NS		0x0
+
+/* security config pmu slave ip */
+/* All of slaves  is ns */
+#define SGRF_PMU_SLV_S_NS		BIT_WITH_WMSK(0)
+/* slaves secure attr is configed */
+#define SGRF_PMU_SLV_S_CFGED		WMSK_BIT(0)
+#define SGRF_PMU_SLV_CRYPTO1_NS		WMSK_BIT(1)
+
+#define SGRF_PMUSRAM_S			BIT(8)
+
+#define SGRF_INTSRAM_S			BIT(13)
+
+/* ddr region */
+#define SGRF_DDR_RGN_0_16_WMSK		0x0fff  /* DDR RGN 0~16 size mask */
+
+#define SGRF_DDR_RGN_DPLL_CLK		BIT_WITH_WMSK(15) /* DDR PLL output clock */
+#define SGRF_DDR_RGN_RTC_CLK		BIT_WITH_WMSK(14) /* 32K clock for DDR PLL */
+
+/* All security of the DDR RGNs are bypass */
+#define SGRF_DDR_RGN_BYPS		BIT_WITH_WMSK(9)
+/* All security of the DDR RGNs are not bypass */
+#define SGRF_DDR_RGN_NO_BYPS		WMSK_BIT(9)
+
+/* The MST access the ddr rgn n with secure attribution */
+#define SGRF_L_MST_S_DDR_RGN(n)		BIT_WITH_WMSK((n))
+/* bits[16:8]*/
+#define SGRF_H_MST_S_DDR_RGN(n)		BIT_WITH_WMSK((n) + 8)
+
+#define SGRF_PMU_CON0			0x0c100
+#define SGRF_PMU_CON(n)   		(SGRF_PMU_CON0 + (n) * 4)
+
+/**************************************************
+ * secure timer
+ **************************************************/
+/* chanal0~5 */
+#define STIMER0_CHN_BASE(n)		(STIME_BASE + 0x20 * (n))
+/* chanal6~11 */
+#define STIMER1_CHN_BASE(n)		(STIME_BASE + 0x8000 + 0x20 * (n))
+
+ /* low 32 bits */
+#define TIMER_END_COUNT0		0x00
+ /* high 32 bits */
+#define TIMER_END_COUNT1		0x04
+
+#define TIMER_CURRENT_VALUE0		0x08
+#define TIMER_CURRENT_VALUE1		0x0C
+
+ /* low 32 bits */
+#define TIMER_INIT_COUNT0		0x10
+ /* high 32 bits */
+#define TIMER_INIT_COUNT1		0x14
+
+#define TIMER_INTSTATUS			0x18
+#define TIMER_CONTROL_REG		0x1c
+
+#define TIMER_EN			0x1
+
+#define TIMER_FMODE			(0x0 << 1)
+#define TIMER_RMODE			(0x1 << 1)
+
+/**************************************************
+ * secure WDT
+ **************************************************/
+#define PCLK_WDT_CA53_GATE_SHIFT	8
+#define PCLK_WDT_CM0_GATE_SHIFT		10
+
+/* export secure operating APIs */
+void secure_watchdog_disable(void);
+void secure_watchdog_enable(void);
+void secure_timer_init(void);
+void secure_sgrf_init(void);
+void secure_sgrf_ddr_rgn_init(void);
+
+#endif /* __PLAT_ROCKCHIP_RK3399_DRIVER_SECURE_H__ */
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.c b/plat/rockchip/rk3399/drivers/soc/soc.c
index c769b73..ec5470e 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.c
+++ b/plat/rockchip/rk3399/drivers/soc/soc.c
@@ -29,19 +29,22 @@
  */
 
 #include <arch_helpers.h>
+#include <assert.h>
 #include <debug.h>
 #include <delay_timer.h>
+#include <dfs.h>
+#include <dram.h>
 #include <mmio.h>
+#include <m0_ctl.h>
 #include <platform_def.h>
 #include <plat_private.h>
-#include <dram.h>
 #include <rk3399_def.h>
-#include <rk3399m0.h>
+#include <secure.h>
 #include <soc.h>
 
 /* Table of regions to map using the MMU.  */
 const mmap_region_t plat_rk_mmap[] = {
-	MAP_REGION_FLAT(RK3399_DEV_RNG0_BASE, RK3399_DEV_RNG0_SIZE,
+	MAP_REGION_FLAT(DEV_RNG0_BASE, DEV_RNG0_SIZE,
 			MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE,
 			MT_MEMORY | MT_RW | MT_SECURE),
@@ -61,158 +64,8 @@
 	PLATFORM_CLUSTER1_CORE_COUNT
 };
 
-void secure_timer_init(void)
-{
-	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_END_COUNT0, 0xffffffff);
-	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_END_COUNT1, 0xffffffff);
-
-	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_INIT_COUNT0, 0x0);
-	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_INIT_COUNT0, 0x0);
-
-	/* auto reload & enable the timer */
-	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_CONTROL_REG,
-		      TIMER_EN | TIMER_FMODE);
-}
-
-void sgrf_init(void)
-{
-	/* security config for master */
-	mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(5),
-		      SGRF_SOC_CON_WMSK | SGRF_SOC_ALLMST_NS);
-	mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(6),
-		      SGRF_SOC_CON_WMSK | SGRF_SOC_ALLMST_NS);
-	mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(7),
-		      SGRF_SOC_CON_WMSK | SGRF_SOC_ALLMST_NS);
-
-	/* security config for slave */
-	mmio_write_32(SGRF_BASE + SGRF_PMU_SLV_CON0_1(0),
-		      SGRF_PMU_SLV_S_CFGED |
-		      SGRF_PMU_SLV_CRYPTO1_NS);
-	mmio_write_32(SGRF_BASE + SGRF_PMU_SLV_CON0_1(1),
-		      SGRF_PMU_SLV_CON1_CFG);
-	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(0),
-		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
-	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(1),
-		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
-	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(2),
-		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
-	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(3),
-		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
-	mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(4),
-		      SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS);
-
-	/* security config for ddr memery */
-	mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16),
-		      SGRF_DDR_RGN_BYPS);
-}
-
-static void dma_secure_cfg(uint32_t secure)
-{
-	if (secure) {
-		/* rgn0 secure for dmac0 and dmac1 */
-		mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON20_34(22),
-			      SGRF_L_MST_S_DDR_RGN(0) | /* dmac0 */
-			      SGRF_H_MST_S_DDR_RGN(0) /* dmac1 */
-			      );
-
-		/* set dmac0 boot, under secure state */
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(8),
-			      SGRF_DMAC_CFG_S);
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(9),
-			      SGRF_DMAC_CFG_S);
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(10),
-			      SGRF_DMAC_CFG_S);
-
-		/* dmac0 soft reset */
-		mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
-			      CRU_DMAC0_RST);
-		udelay(5);
-		mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
-			      CRU_DMAC0_RST_RLS);
-
-		/* set dmac1 boot, under secure state */
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(11),
-			      SGRF_DMAC_CFG_S);
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(12),
-			      SGRF_DMAC_CFG_S);
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(13),
-			      SGRF_DMAC_CFG_S);
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(14),
-			      SGRF_DMAC_CFG_S);
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(15),
-			      SGRF_DMAC_CFG_S);
-
-		/* dmac1 soft reset */
-		mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
-			      CRU_DMAC1_RST);
-		udelay(5);
-		mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
-			      CRU_DMAC1_RST_RLS);
-	} else {
-		/* rgn non-secure for dmac0 and dmac1 */
-		mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON20_34(22),
-			      DMAC1_RGN_NS | DMAC0_RGN_NS);
-
-		/* set dmac0 boot, under non-secure state */
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(8),
-			      DMAC0_BOOT_CFG_NS);
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(9),
-			      DMAC0_BOOT_PERIPH_NS);
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(10),
-			      DMAC0_BOOT_ADDR_NS);
-
-		/* dmac0 soft reset */
-		mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
-			      CRU_DMAC0_RST);
-		udelay(5);
-		mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
-			      CRU_DMAC0_RST_RLS);
-
-		/* set dmac1 boot, under non-secure state */
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(11),
-			      DMAC1_BOOT_CFG_NS);
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(12),
-			      DMAC1_BOOT_PERIPH_L_NS);
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(13),
-			      DMAC1_BOOT_ADDR_NS);
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(14),
-			      DMAC1_BOOT_PERIPH_H_NS);
-		mmio_write_32(SGRF_BASE + SGRF_SOC_CON8_15(15),
-			      DMAC1_BOOT_IRQ_NS);
-
-		/* dmac1 soft reset */
-		mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
-			      CRU_DMAC1_RST);
-		udelay(5);
-		mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(10),
-			      CRU_DMAC1_RST_RLS);
-	}
-}
-
-/* pll suspend */
-struct deepsleep_data_s slp_data;
-
-void secure_watchdog_disable(void)
-{
-	slp_data.sgrf_con[3] = mmio_read_32(SGRF_BASE + SGRF_SOC_CON3_7(3));
-
-	/* disable CA53 wdt pclk */
-	mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(3),
-		      BITS_WITH_WMASK(WDT_CA53_DIS, WDT_CA53_1BIT_MASK,
-				      PCLK_WDT_CA53_GATE_SHIFT));
-	/* disable CM0 wdt pclk */
-	mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(3),
-		      BITS_WITH_WMASK(WDT_CM0_DIS, WDT_CM0_1BIT_MASK,
-				      PCLK_WDT_CM0_GATE_SHIFT));
-}
-
-void secure_watchdog_restore(void)
-{
-	mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(3),
-		      slp_data.sgrf_con[3] |
-		      WMSK_BIT(PCLK_WDT_CA53_GATE_SHIFT) |
-		      WMSK_BIT(PCLK_WDT_CM0_GATE_SHIFT));
-}
+/* sleep data for pll suspend */
+static struct deepsleep_data_s slp_data;
 
 static void set_pll_slow_mode(uint32_t pll_id)
 {
@@ -433,7 +286,7 @@
 			CRU_PMU_WDTRST_MSK | CRU_PMU_FIRST_SFTRST_MSK);
 }
 
-void  __dead2 soc_global_soft_reset(void)
+void __dead2 soc_global_soft_reset(void)
 {
 	set_pll_slow_mode(VPLL_ID);
 	set_pll_slow_mode(NPLL_ID);
@@ -455,27 +308,14 @@
 		;
 }
 
-static void soc_m0_init(void)
-{
-	/* secure config for pmu M0 */
-	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(0), WMSK_BIT(7));
-
-	/* set the execute address for M0 */
-	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(3),
-		      BITS_WITH_WMASK((M0_BINCODE_BASE >> 12) & 0xffff,
-				      0xffff, 0));
-	mmio_write_32(SGRF_BASE + SGRF_PMU_CON(7),
-		      BITS_WITH_WMASK((M0_BINCODE_BASE >> 28) & 0xf,
-				      0xf, 0));
-}
-
 void plat_rockchip_soc_init(void)
 {
 	secure_timer_init();
-	dma_secure_cfg(0);
-	sgrf_init();
+	secure_sgrf_init();
+	secure_sgrf_ddr_rgn_init();
 	soc_global_soft_reset_init();
 	plat_rockchip_gpio_init();
-	soc_m0_init();
+	m0_init();
 	dram_init();
+	dram_dfs_init();
 }
diff --git a/plat/rockchip/rk3399/drivers/soc/soc.h b/plat/rockchip/rk3399/drivers/soc/soc.h
index 28590f2..da16adb 100644
--- a/plat/rockchip/rk3399/drivers/soc/soc.h
+++ b/plat/rockchip/rk3399/drivers/soc/soc.h
@@ -75,7 +75,6 @@
 #define REG_SOC_WMSK			0xffff0000
 #define CLK_GATE_MASK			0x01
 
-#define SGRF_SOC_COUNT		0x17
 #define PMUCRU_GATE_COUNT	0x03
 #define CRU_GATE_COUNT		0x23
 #define PMUCRU_GATE_CON(n)	(0x100 + (n) * 4)
@@ -108,13 +107,20 @@
 	PMU_RST_NOT_BY_SFT = BIT(3),
 };
 
+struct pll_div {
+	uint32_t mhz;
+	uint32_t refdiv;
+	uint32_t fbdiv;
+	uint32_t postdiv1;
+	uint32_t postdiv2;
+	uint32_t frac;
+	uint32_t freq;
+};
+
 struct deepsleep_data_s {
 	uint32_t plls_con[END_PLL_ID][PLL_CON_COUNT];
-	uint32_t pmucru_clksel_con[PMUCRU_CLKSEL_CONUT];
-	uint32_t cru_clksel_con[CRU_CLKSEL_COUNT];
 	uint32_t cru_gate_con[CRU_GATE_COUNT];
 	uint32_t pmucru_gate_con[PMUCRU_GATE_COUNT];
-	uint32_t sgrf_con[SGRF_SOC_COUNT];
 };
 
 /**************************************************
@@ -147,50 +153,6 @@
 #define CYCL_32K_CNT_MS(ms)	(ms * 32)
 
 /**************************************************
- * secure timer
- **************************************************/
-
-/* chanal0~5 */
-#define STIMER0_CHN_BASE(n)	(STIME_BASE + 0x20 * (n))
-/* chanal6~11 */
-#define STIMER1_CHN_BASE(n)	(STIME_BASE + 0x8000 + 0x20 * (n))
-
- /* low 32 bits */
-#define TIMER_END_COUNT0	0x00
- /* high 32 bits */
-#define TIMER_END_COUNT1	0x04
-
-#define TIMER_CURRENT_VALUE0	0x08
-#define TIMER_CURRENT_VALUE1	0x0C
-
- /* low 32 bits */
-#define TIMER_INIT_COUNT0	0x10
- /* high 32 bits */
-#define TIMER_INIT_COUNT1	0x14
-
-#define TIMER_INTSTATUS		0x18
-#define TIMER_CONTROL_REG	0x1c
-
-#define TIMER_EN			0x1
-
-#define TIMER_FMODE		(0x0 << 1)
-#define TIMER_RMODE		(0x1 << 1)
-
-/**************************************************
- * secure WDT
- **************************************************/
-#define WDT_CM0_EN		0x0
-#define WDT_CM0_DIS		0x1
-#define WDT_CA53_EN		0x0
-#define WDT_CA53_DIS		0x1
-
-#define PCLK_WDT_CA53_GATE_SHIFT	8
-#define PCLK_WDT_CM0_GATE_SHIFT		10
-
-#define WDT_CA53_1BIT_MASK	0x1
-#define WDT_CM0_1BIT_MASK	0x1
-
-/**************************************************
  * cru reg, offset
  **************************************************/
 #define CRU_SOFTRST_CON(n)	(0x400 + (n) * 4)
@@ -231,63 +193,6 @@
 #define PCLK_GPIO0_GATE_SHIFT		3
 #define PCLK_GPIO1_GATE_SHIFT		4
 
-/**************************************************
- * sgrf reg, offset
- **************************************************/
-#define SGRF_SOC_CON0_1(n)		(0xc000 + (n) * 4)
-#define SGRF_SOC_CON3_7(n)		(0xe00c + ((n) - 3) * 4)
-#define SGRF_SOC_CON8_15(n)		(0x8020 + ((n) - 8) * 4)
-#define SGRF_PMU_SLV_CON0_1(n)		(0xc240 + ((n) - 0) * 4)
-#define SGRF_SLV_SECURE_CON0_4(n)	(0xe3c0 + ((n) - 0) * 4)
-#define SGRF_DDRRGN_CON0_16(n)		((n) * 4)
-#define SGRF_DDRRGN_CON20_34(n)		(0x50 + ((n) - 20) * 4)
-
-/* security config for master */
-#define SGRF_SOC_CON_WMSK		0xffff0000
-/* All of master in ns */
-#define SGRF_SOC_ALLMST_NS		0xffff
-
-/* security config for slave */
-#define SGRF_SLV_S_WMSK			0xffff0000
-#define SGRF_SLV_S_ALL_NS		0x0
-
-/* security config pmu slave ip */
-/* All of slaves  is ns */
-#define SGRF_PMU_SLV_S_NS		BIT_WITH_WMSK(0)
-/* slaves secure attr is configed */
-#define SGRF_PMU_SLV_S_CFGED		WMSK_BIT(0)
-#define SGRF_PMU_SLV_CRYPTO1_NS		WMSK_BIT(1)
-
-#define SGRF_PMUSRAM_S			BIT(8)
-
-#define SGRF_PMU_SLV_CON1_CFG		(SGRF_SLV_S_WMSK | \
-					SGRF_PMUSRAM_S)
-/* ddr region */
-#define SGRF_DDR_RGN_DPLL_CLK	BIT_WITH_WMSK(15) /* DDR PLL output clock */
-#define SGRF_DDR_RGN_RTC_CLK	BIT_WITH_WMSK(14) /* 32K clock for DDR PLL */
-#define SGRF_DDR_RGN_BYPS	BIT_WITH_WMSK(9) /* All of ddr rgn  is ns */
-
-/* The MST access the ddr rgn n with secure attribution */
-#define SGRF_L_MST_S_DDR_RGN(n)	BIT_WITH_WMSK((n))
-/* bits[16:8]*/
-#define SGRF_H_MST_S_DDR_RGN(n)	BIT_WITH_WMSK((n) + 8)
-
-/* dmac to periph s or ns*/
-#define SGRF_DMAC_CFG_S		0xffff0000
-
-#define DMAC1_RGN_NS			0xff000000
-#define DMAC0_RGN_NS			0x00ff0000
-
-#define DMAC0_BOOT_CFG_NS		0xfffffff8
-#define DMAC0_BOOT_PERIPH_NS		0xffff0fff
-#define DMAC0_BOOT_ADDR_NS		0xffff0000
-
-#define DMAC1_BOOT_CFG_NS		0xffff0008
-#define DMAC1_BOOT_PERIPH_L_NS		0xffff0fff
-#define DMAC1_BOOT_ADDR_NS		0xffff0000
-#define DMAC1_BOOT_PERIPH_H_NS		0xffffffff
-#define DMAC1_BOOT_IRQ_NS		0xffffffff
-
 #define CPU_BOOT_ADDR_WMASK	0xffff0000
 #define CPU_BOOT_ADDR_ALIGN	16
 
@@ -312,17 +217,13 @@
 #define GRF_DDRC0_CON1		0xe384
 #define GRF_DDRC1_CON0		0xe388
 #define GRF_DDRC1_CON1		0xe38c
+#define GRF_SOC_CON_BASE	0xe200
+#define GRF_SOC_CON(n)		(GRF_SOC_CON_BASE + (n) * 4)
 
 #define PMUCRU_CLKSEL_CON0	0x0080
 #define PMUCRU_CLKGATE_CON2	0x0108
 #define PMUCRU_SOFTRST_CON0	0x0110
 #define PMUCRU_GATEDIS_CON0 0x0130
-
-#define SGRF_SOC_CON6     0x0e018
-#define SGRF_PERILP_CON0	0x08100
-#define SGRF_PERILP_CON(n)	(SGRF_PERILP_CON0 + (n) * 4)
-#define SGRF_PMU_CON0	0x0c100
-#define SGRF_PMU_CON(n)   (SGRF_PMU_CON0 + (n) * 4)
 #define PMUCRU_SOFTRST_CON(n)   (PMUCRU_SOFTRST_CON0 + (n) * 4)
 
 /*
@@ -346,10 +247,8 @@
 		      CRU_PMU_SGRF_RST_HOLD);
 }
 
-/* funciton*/
+/* export related and operating SoC APIs */
 void __dead2 soc_global_soft_reset(void);
-void secure_watchdog_disable();
-void secure_watchdog_restore();
 void disable_dvfs_plls(void);
 void disable_nodvfs_plls(void);
 void enable_dvfs_plls(void);
@@ -360,5 +259,5 @@
 void clk_gate_con_save(void);
 void clk_gate_con_disable(void);
 void clk_gate_con_restore(void);
-void sgrf_init(void);
+
 #endif /* __SOC_H__ */
diff --git a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h b/plat/rockchip/rk3399/include/addressmap.h
similarity index 80%
copy from plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
copy to plat/rockchip/rk3399/include/addressmap.h
index 78b350a..da514e7 100644
--- a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
+++ b/plat/rockchip/rk3399/include/addressmap.h
@@ -28,13 +28,16 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef __RK3399M0_H__
-#define __RK3399M0_H__
+#ifndef __ROCKCHIP_RK3399_INCLUDE_ADDRESSMAP_H__
+#define __ROCKCHIP_RK3399_INCLUDE_ADDRESSMAP_H__
 
-/* pmu_fw.c */
-extern char rk3399m0_bin[];
-extern char rk3399m0_bin_end[];
+#include <addressmap_shared.h>
 
-#define M0_BINCODE_BASE ((uintptr_t)rk3399m0_bin)
+/* Registers base address */
+#define MMIO_BASE		0xF8000000
 
-#endif /* __RK3399M0_H__ */
+/* Aggregate of all devices in the first GB */
+#define DEV_RNG0_BASE		MMIO_BASE
+#define DEV_RNG0_SIZE		SIZE_M(125)
+
+#endif /* __ROCKCHIP_RK3399_INCLUDE_ADDRESSMAP_H__ */
diff --git a/plat/rockchip/rk3399/include/platform_def.h b/plat/rockchip/rk3399/include/platform_def.h
index 5ccc532..da0bb18 100644
--- a/plat/rockchip/rk3399/include/platform_def.h
+++ b/plat/rockchip/rk3399/include/platform_def.h
@@ -32,6 +32,7 @@
 #define __PLATFORM_DEF_H__
 
 #include <arch.h>
+#include <bl31_param.h>
 #include <common_def.h>
 #include <rk3399_def.h>
 
@@ -89,22 +90,6 @@
 #define PLAT_MAX_OFF_STATE		2
 
 /*******************************************************************************
- * Platform memory map related constants
- ******************************************************************************/
-/* TF txet, ro, rw, Size: 512KB */
-#define TZRAM_BASE		(0x0)
-#define TZRAM_SIZE		(0x80000)
-
-/*******************************************************************************
- * BL31 specific defines.
- ******************************************************************************/
-/*
- * Put BL3-1 at the top of the Trusted RAM
- */
-#define BL31_BASE		(TZRAM_BASE + 0x10000)
-#define BL31_LIMIT	(TZRAM_BASE + TZRAM_SIZE)
-
-/*******************************************************************************
  * Platform specific page table and MMU setup constants
  ******************************************************************************/
 #define ADDR_SPACE_SIZE		(1ull << 32)
@@ -138,7 +123,7 @@
 #define PLAT_RK_G1S_IRQS		RK3399_G1S_IRQS
 #define PLAT_RK_G0_IRQS			RK3399_G0_IRQS
 
-#define PLAT_RK_UART_BASE		RK3399_UART2_BASE
+#define PLAT_RK_UART_BASE		UART2_BASE
 #define PLAT_RK_UART_CLOCK		RK3399_UART_CLOCK
 #define PLAT_RK_UART_BAUDRATE		RK3399_BAUDRATE
 
diff --git a/plat/rockchip/rk3399/include/shared/addressmap_shared.h b/plat/rockchip/rk3399/include/shared/addressmap_shared.h
new file mode 100644
index 0000000..7f6c075
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/addressmap_shared.h
@@ -0,0 +1,122 @@
+/*
+ * 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 __ROCKCHIP_RK3399_INCLUDE_SHARED_ADDRESSMAP_SHARED_H__
+#define __ROCKCHIP_RK3399_INCLUDE_SHARED_ADDRESSMAP_SHARED_H__
+
+#define SIZE_K(n)		((n) * 1024)
+#define SIZE_M(n)		((n) * 1024 * 1024)
+
+/*
+ * The parts of the shared defined registers address with AP and M0,
+ * let's note and mark the previous defines like this:
+ */
+#define GIC500_BASE		(MMIO_BASE + 0x06E00000)
+#define UART0_BASE		(MMIO_BASE + 0x07180000)
+#define UART1_BASE		(MMIO_BASE + 0x07190000)
+#define UART2_BASE		(MMIO_BASE + 0x071A0000)
+#define UART3_BASE		(MMIO_BASE + 0x071B0000)
+
+#define PMU_BASE		(MMIO_BASE + 0x07310000)
+#define PMUGRF_BASE		(MMIO_BASE + 0x07320000)
+#define SGRF_BASE		(MMIO_BASE + 0x07330000)
+#define PMUSRAM_BASE		(MMIO_BASE + 0x073B0000)
+#define PWM_BASE		(MMIO_BASE + 0x07420000)
+
+#define CIC_BASE		(MMIO_BASE + 0x07620000)
+#define PD_BUS0_BASE		(MMIO_BASE + 0x07650000)
+#define DCF_BASE		(MMIO_BASE + 0x076A0000)
+#define GPIO0_BASE		(MMIO_BASE + 0x07720000)
+#define GPIO1_BASE		(MMIO_BASE + 0x07730000)
+#define PMUCRU_BASE		(MMIO_BASE + 0x07750000)
+#define CRU_BASE		(MMIO_BASE + 0x07760000)
+#define GRF_BASE		(MMIO_BASE + 0x07770000)
+#define GPIO2_BASE		(MMIO_BASE + 0x07780000)
+#define GPIO3_BASE		(MMIO_BASE + 0x07788000)
+#define GPIO4_BASE		(MMIO_BASE + 0x07790000)
+#define STIME_BASE		(MMIO_BASE + 0x07860000)
+#define SRAM_BASE		(MMIO_BASE + 0x078C0000)
+#define SERVICE_NOC_0_BASE	(MMIO_BASE + 0x07A50000)
+#define DDRC0_BASE		(MMIO_BASE + 0x07A80000)
+#define SERVICE_NOC_1_BASE	(MMIO_BASE + 0x07A84000)
+#define DDRC1_BASE		(MMIO_BASE + 0x07A88000)
+#define SERVICE_NOC_2_BASE	(MMIO_BASE + 0x07A8C000)
+#define SERVICE_NOC_3_BASE	(MMIO_BASE + 0x07A90000)
+#define CCI500_BASE		(MMIO_BASE + 0x07B00000)
+#define COLD_BOOT_BASE		(MMIO_BASE + 0x07FF0000)
+
+/* Registers size */
+#define GIC500_SIZE		SIZE_M(2)
+#define UART0_SIZE		SIZE_K(64)
+#define UART1_SIZE		SIZE_K(64)
+#define UART2_SIZE		SIZE_K(64)
+#define UART3_SIZE		SIZE_K(64)
+#define PMU_SIZE		SIZE_K(64)
+#define PMUGRF_SIZE		SIZE_K(64)
+#define SGRF_SIZE		SIZE_K(64)
+#define PMUSRAM_SIZE		SIZE_K(64)
+#define PMUSRAM_RSIZE		SIZE_K(8)
+#define PWM_SIZE		SIZE_K(64)
+#define CIC_SIZE		SIZE_K(4)
+#define DCF_SIZE		SIZE_K(4)
+#define GPIO0_SIZE		SIZE_K(64)
+#define GPIO1_SIZE		SIZE_K(64)
+#define PMUCRU_SIZE		SIZE_K(64)
+#define CRU_SIZE		SIZE_K(64)
+#define GRF_SIZE		SIZE_K(64)
+#define GPIO2_SIZE		SIZE_K(32)
+#define GPIO3_SIZE		SIZE_K(32)
+#define GPIO4_SIZE		SIZE_K(32)
+#define STIME_SIZE		SIZE_K(64)
+#define SRAM_SIZE		SIZE_K(192)
+#define SERVICE_NOC_0_SIZE	SIZE_K(192)
+#define DDRC0_SIZE		SIZE_K(32)
+#define SERVICE_NOC_1_SIZE	SIZE_K(16)
+#define DDRC1_SIZE		SIZE_K(32)
+#define SERVICE_NOC_2_SIZE	SIZE_K(16)
+#define SERVICE_NOC_3_SIZE	SIZE_K(448)
+#define CCI500_SIZE		SIZE_M(1)
+#define PD_BUS0_SIZE		SIZE_K(448)
+
+/* DDR Registers address */
+#define CTL_BASE(ch)		(DDRC0_BASE + (ch) * 0x8000)
+#define CTL_REG(ch, n)		(CTL_BASE(ch) + (n) * 0x4)
+
+#define PI_OFFSET		0x800
+#define PI_BASE(ch)		(CTL_BASE(ch) + PI_OFFSET)
+#define PI_REG(ch, n)		(PI_BASE(ch) + (n) * 0x4)
+
+#define PHY_OFFSET		0x2000
+#define PHY_BASE(ch)		(CTL_BASE(ch) + PHY_OFFSET)
+#define PHY_REG(ch, n)		(PHY_BASE(ch) + (n) * 0x4)
+
+#define MSCH_BASE(ch)		(SERVICE_NOC_1_BASE + (ch) * 0x8000)
+
+#endif /* __ROCKCHIP_RK3399_INCLUDE_SHARED_ADDRESSMAP_SHARED_H__ */
diff --git a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h b/plat/rockchip/rk3399/include/shared/bl31_param.h
similarity index 65%
copy from plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
copy to plat/rockchip/rk3399/include/shared/bl31_param.h
index 78b350a..fd53af4 100644
--- a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
+++ b/plat/rockchip/rk3399/include/shared/bl31_param.h
@@ -28,13 +28,23 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef __RK3399M0_H__
-#define __RK3399M0_H__
+#ifndef __PLAT_ROCKCHIP_RK3399_INCLUDE_SHARED_BL31_PARAM_H__
+#define __PLAT_ROCKCHIP_RK3399_INCLUDE_SHARED_BL31_PARAM_H__
 
-/* pmu_fw.c */
-extern char rk3399m0_bin[];
-extern char rk3399m0_bin_end[];
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+/* TF text, ro, rw, Size: 1MB */
+#define TZRAM_BASE		(0x0)
+#define TZRAM_SIZE		(0x100000)
 
-#define M0_BINCODE_BASE ((uintptr_t)rk3399m0_bin)
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL3-1 at the top of the Trusted RAM
+ */
+#define BL31_BASE		(TZRAM_BASE + 0x1000)
+#define BL31_LIMIT		(TZRAM_BASE + TZRAM_SIZE)
 
-#endif /* __RK3399M0_H__ */
+#endif /*__PLAT_ROCKCHIP_RK3399_INCLUDE_SHARED_BL31_PARAM_H__*/
diff --git a/plat/rockchip/rk3399/include/shared/dram_regs.h b/plat/rockchip/rk3399/include/shared/dram_regs.h
new file mode 100644
index 0000000..21af8a5
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/dram_regs.h
@@ -0,0 +1,124 @@
+/*
+ * 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 __DRAM_REGS_H__
+#define __DRAM_REGS_H__
+
+#define CTL_REG_NUM		332
+#define PHY_REG_NUM		959
+#define PI_REG_NUM		200
+
+#define MSCH_ID_COREID		0x0
+#define MSCH_ID_REVISIONID	0x4
+#define MSCH_DEVICECONF		0x8
+#define MSCH_DEVICESIZE		0xc
+#define MSCH_DDRTIMINGA0	0x10
+#define MSCH_DDRTIMINGB0	0x14
+#define MSCH_DDRTIMINGC0	0x18
+#define MSCH_DEVTODEV0		0x1c
+#define MSCH_DDRMODE		0x110
+#define MSCH_AGINGX0		0x1000
+
+#define CIC_CTRL0		0x0
+#define CIC_CTRL1		0x4
+#define CIC_IDLE_TH		0x8
+#define CIC_CG_WAIT_TH		0xc
+#define CIC_STATUS0		0x10
+#define CIC_STATUS1		0x14
+#define CIC_CTRL2		0x18
+#define CIC_CTRL3		0x1c
+#define CIC_CTRL4		0x20
+
+/* DENALI_CTL_00 */
+#define START			1
+
+/* DENALI_CTL_68 */
+#define PWRUP_SREFRESH_EXIT	(1 << 16)
+
+/* DENALI_CTL_274 */
+#define MEM_RST_VALID		1
+
+#define PHY_DRV_ODT_Hi_Z	0x0
+#define PHY_DRV_ODT_240		0x1
+#define PHY_DRV_ODT_120		0x8
+#define PHY_DRV_ODT_80		0x9
+#define PHY_DRV_ODT_60		0xc
+#define PHY_DRV_ODT_48		0xd
+#define PHY_DRV_ODT_40		0xe
+#define PHY_DRV_ODT_34_3	0xf
+
+/*
+ * sys_reg bitfield struct
+ * [31] row_3_4_ch1
+ * [30] row_3_4_ch0
+ * [29:28] chinfo
+ * [27] rank_ch1
+ * [26:25] col_ch1
+ * [24] bk_ch1
+ * [23:22] cs0_row_ch1
+ * [21:20] cs1_row_ch1
+ * [19:18] bw_ch1
+ * [17:16] dbw_ch1;
+ * [15:13] ddrtype
+ * [12] channelnum
+ * [11] rank_ch0
+ * [10:9] col_ch0
+ * [8] bk_ch0
+ * [7:6] cs0_row_ch0
+ * [5:4] cs1_row_ch0
+ * [3:2] bw_ch0
+ * [1:0] dbw_ch0
+ */
+#define SYS_REG_ENC_ROW_3_4(n, ch)	((n) << (30 + (ch)))
+#define SYS_REG_DEC_ROW_3_4(n, ch)	(((n) >> (30 + (ch))) & 0x1)
+#define SYS_REG_ENC_CHINFO(ch)		(1 << (28 + (ch)))
+#define SYS_REG_DEC_CHINFO(n, ch)	(((n) >> (28 + (ch))) & 0x1)
+#define SYS_REG_ENC_DDRTYPE(n)		((n) << 13)
+#define SYS_REG_DEC_DDRTYPE(n)		(((n) >> 13) & 0x7)
+#define SYS_REG_ENC_NUM_CH(n)		(((n) - 1) << 12)
+#define SYS_REG_DEC_NUM_CH(n)		(1 + (((n) >> 12) & 0x1))
+#define SYS_REG_ENC_RANK(n, ch)		(((n) - 1) << (11 + (ch) * 16))
+#define SYS_REG_DEC_RANK(n, ch)		(1 + (((n) >> (11 + (ch) * 16)) & 0x1))
+#define SYS_REG_ENC_COL(n, ch)		(((n) - 9) << (9 + (ch) * 16))
+#define SYS_REG_DEC_COL(n, ch)		(9 + (((n) >> (9 + (ch) * 16)) & 0x3))
+#define SYS_REG_ENC_BK(n, ch)		(((n) == 3 ? 0 : 1) << (8 + (ch) * 16))
+#define SYS_REG_DEC_BK(n, ch)		(3 - (((n) >> (8 + (ch) * 16)) & 0x1))
+#define SYS_REG_ENC_CS0_ROW(n, ch)	(((n) - 13) << (6 + (ch) * 16))
+#define SYS_REG_DEC_CS0_ROW(n, ch)	(13 + (((n) >> (6 + (ch) * 16)) & 0x3))
+#define SYS_REG_ENC_CS1_ROW(n, ch)	(((n) - 13) << (4 + (ch) * 16))
+#define SYS_REG_DEC_CS1_ROW(n, ch)	(13 + (((n) >> (4 + (ch) * 16)) & 0x3))
+#define SYS_REG_ENC_BW(n, ch)		((2 >> (n)) << (2 + (ch) * 16))
+#define SYS_REG_DEC_BW(n, ch)		(2 >> (((n) >> (2 + (ch) * 16)) & 0x3))
+#define SYS_REG_ENC_DBW(n, ch)		((2 >> (n)) << (0 + (ch) * 16))
+#define SYS_REG_DEC_DBW(n, ch)		(2 >> (((n) >> (0 + (ch) * 16)) & 0x3))
+#define DDR_STRIDE(n)		mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(4), \
+					      (0x1f<<(10+16))|((n)<<10))
+
+#endif /* __DRAM_REGS_H__ */
diff --git a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h b/plat/rockchip/rk3399/include/shared/m0_param.h
similarity index 73%
copy from plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
copy to plat/rockchip/rk3399/include/shared/m0_param.h
index 78b350a..46755e1 100644
--- a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
+++ b/plat/rockchip/rk3399/include/shared/m0_param.h
@@ -28,13 +28,29 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef __RK3399M0_H__
-#define __RK3399M0_H__
+#ifndef __M0_PARAM_H__
+#define __M0_PARAM_H__
 
-/* pmu_fw.c */
-extern char rk3399m0_bin[];
-extern char rk3399m0_bin_end[];
+#ifndef __LINKER__
+enum {
+	M0_FUNC_SUSPEND = 0,
+	M0_FUNC_DRAM	= 1,
+};
+#endif /* __LINKER__ */
 
-#define M0_BINCODE_BASE ((uintptr_t)rk3399m0_bin)
+#define PARAM_ADDR		0xc0
 
-#endif /* __RK3399M0_H__ */
+#define PARAM_M0_FUNC		0x00
+#define PARAM_DRAM_FREQ		0x04
+#define PARAM_DPLL_CON0		0x08
+#define PARAM_DPLL_CON1		0x0c
+#define PARAM_DPLL_CON2		0x10
+#define PARAM_DPLL_CON3		0x14
+#define PARAM_DPLL_CON4		0x18
+#define PARAM_DPLL_CON5		0x1c
+#define PARAM_FREQ_SELECT	0x20
+#define PARAM_M0_DONE		0x24
+#define PARAM_M0_SIZE		0x28
+#define M0_DONE_FLAG		0xf59ec39a
+
+#endif /*__M0_PARAM_H__*/
diff --git a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h b/plat/rockchip/rk3399/include/shared/misc_regs.h
similarity index 72%
copy from plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
copy to plat/rockchip/rk3399/include/shared/misc_regs.h
index 78b350a..3e0a362 100644
--- a/plat/rockchip/rk3399/drivers/pmu/rk3399m0.h
+++ b/plat/rockchip/rk3399/include/shared/misc_regs.h
@@ -28,13 +28,24 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef __RK3399M0_H__
-#define __RK3399M0_H__
+#ifndef __ROCKCHIP_RK3399_INCLUDE_SHARED_MISC_REGS_H__
+#define __ROCKCHIP_RK3399_INCLUDE_SHARED_MISC_REGS_H__
 
-/* pmu_fw.c */
-extern char rk3399m0_bin[];
-extern char rk3399m0_bin_end[];
+/* CRU */
+#define CRU_DPLL_CON0		0x40
+#define CRU_DPLL_CON1		0x44
+#define CRU_DPLL_CON2		0x48
+#define CRU_DPLL_CON3		0x4c
+#define CRU_DPLL_CON4		0x50
+#define CRU_DPLL_CON5		0x54
 
-#define M0_BINCODE_BASE ((uintptr_t)rk3399m0_bin)
+/* CRU_PLL_CON3 */
+#define PLL_SLOW_MODE		0
+#define PLL_NORMAL_MODE		1
+#define PLL_MODE(n)		((0x3 << (8 + 16)) | ((n) << 8))
+#define PLL_POWER_DOWN(n)	((0x1 << (0 + 16)) | ((n) << 0))
 
-#endif /* __RK3399M0_H__ */
+/* PMU CRU */
+#define PMU_CRU_GATEDIS_CON0	0x130
+
+#endif /* __ROCKCHIP_RK3399_INCLUDE_SHARED_MISC_REGS_H__ */
diff --git a/plat/rockchip/rk3399/include/shared/pmu_bits.h b/plat/rockchip/rk3399/include/shared/pmu_bits.h
new file mode 100644
index 0000000..59d7107
--- /dev/null
+++ b/plat/rockchip/rk3399/include/shared/pmu_bits.h
@@ -0,0 +1,721 @@
+/*
+ * 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 __PMU_BITS_H__
+#define __PMU_BITS_H__
+
+enum pmu_powerdomain_id {
+	PD_CPUL0 = 0,
+	PD_CPUL1,
+	PD_CPUL2,
+	PD_CPUL3,
+	PD_CPUB0,
+	PD_CPUB1,
+	PD_SCUL,
+	PD_SCUB,
+	PD_TCPD0,
+	PD_TCPD1,
+	PD_CCI,
+	PD_PERILP,
+	PD_PERIHP,
+	PD_CENTER,
+	PD_VIO,
+	PD_GPU,
+	PD_VCODEC,
+	PD_VDU,
+	PD_RGA,
+	PD_IEP,
+	PD_VO,
+	PD_ISP0 = 22,
+	PD_ISP1,
+	PD_HDCP,
+	PD_GMAC,
+	PD_EMMC,
+	PD_USB3,
+	PD_EDP,
+	PD_GIC,
+	PD_SD,
+	PD_SDIOAUDIO,
+	PD_END
+};
+
+enum powerdomain_state {
+	PMU_POWER_ON = 0,
+	PMU_POWER_OFF,
+};
+
+enum pmu_bus_id {
+	BUS_ID_GPU = 0,
+	BUS_ID_PERILP,
+	BUS_ID_PERIHP,
+	BUS_ID_VCODEC,
+	BUS_ID_VDU,
+	BUS_ID_RGA,
+	BUS_ID_IEP,
+	BUS_ID_VOPB,
+	BUS_ID_VOPL,
+	BUS_ID_ISP0,
+	BUS_ID_ISP1,
+	BUS_ID_HDCP,
+	BUS_ID_USB3,
+	BUS_ID_PERILPM0,
+	BUS_ID_CENTER,
+	BUS_ID_CCIM0,
+	BUS_ID_CCIM1,
+	BUS_ID_VIO,
+	BUS_ID_MSCH0,
+	BUS_ID_MSCH1,
+	BUS_ID_ALIVE,
+	BUS_ID_PMU,
+	BUS_ID_EDP,
+	BUS_ID_GMAC,
+	BUS_ID_EMMC,
+	BUS_ID_CENTER1,
+	BUS_ID_PMUM0,
+	BUS_ID_GIC,
+	BUS_ID_SD,
+	BUS_ID_SDIOAUDIO,
+};
+
+enum pmu_bus_state {
+	BUS_ACTIVE,
+	BUS_IDLE,
+};
+
+/* pmu_cpuapm bit */
+enum pmu_cores_pm_by_wfi {
+	core_pm_en = 0,
+	core_pm_int_wakeup_en,
+	core_pm_resv,
+	core_pm_sft_wakeup_en
+};
+
+enum pmu_wkup_cfg0 {
+	PMU_GPIO0A_POSE_WKUP_EN = 0,
+	PMU_GPIO0B_POSE_WKUP_EN = 8,
+	PMU_GPIO0C_POSE_WKUP_EN = 16,
+	PMU_GPIO0D_POSE_WKUP_EN = 24,
+};
+
+enum pmu_wkup_cfg1 {
+	PMU_GPIO0A_NEGEDGE_WKUP_EN = 0,
+	PMU_GPIO0B_NEGEDGE_WKUP_EN = 7,
+	PMU_GPIO0C_NEGEDGE_WKUP_EN = 16,
+	PMU_GPIO0D_NEGEDGE_WKUP_EN = 24,
+};
+
+enum pmu_wkup_cfg2 {
+	PMU_GPIO1A_POSE_WKUP_EN = 0,
+	PMU_GPIO1B_POSE_WKUP_EN = 7,
+	PMU_GPIO1C_POSE_WKUP_EN = 16,
+	PMU_GPIO1D_POSE_WKUP_EN = 24,
+};
+
+enum pmu_wkup_cfg3 {
+	PMU_GPIO1A_NEGEDGE_WKUP_EN = 0,
+	PMU_GPIO1B_NEGEDGE_WKUP_EN = 7,
+	PMU_GPIO1C_NEGEDGE_WKUP_EN = 16,
+	PMU_GPIO1D_NEGEDGE_WKUP_EN = 24,
+};
+
+/* pmu_wkup_cfg4 */
+enum pmu_wkup_cfg4 {
+	PMU_CLUSTER_L_WKUP_EN = 0,
+	PMU_CLUSTER_B_WKUP_EN,
+	PMU_GPIO_WKUP_EN,
+	PMU_SDIO_WKUP_EN,
+
+	PMU_SDMMC_WKUP_EN,
+	PMU_TIMER_WKUP_EN = 6,
+	PMU_USBDEV_WKUP_EN,
+
+	PMU_SFT_WKUP_EN,
+	PMU_M0_WDT_WKUP_EN,
+	PMU_TIMEOUT_WKUP_EN,
+	PMU_PWM_WKUP_EN,
+
+	PMU_PCIE_WKUP_EN = 13,
+};
+
+enum pmu_pwrdn_con {
+	PMU_A53_L0_PWRDWN_EN = 0,
+	PMU_A53_L1_PWRDWN_EN,
+	PMU_A53_L2_PWRDWN_EN,
+	PMU_A53_L3_PWRDWN_EN,
+
+	PMU_A72_B0_PWRDWN_EN,
+	PMU_A72_B1_PWRDWN_EN,
+	PMU_SCU_L_PWRDWN_EN,
+	PMU_SCU_B_PWRDWN_EN,
+
+	PMU_TCPD0_PWRDWN_EN,
+	PMU_TCPD1_PWRDWN_EN,
+	PMU_CCI_PWRDWN_EN,
+	PMU_PERILP_PWRDWN_EN,
+
+	PMU_PERIHP_PWRDWN_EN,
+	PMU_CENTER_PWRDWN_EN,
+	PMU_VIO_PWRDWN_EN,
+	PMU_GPU_PWRDWN_EN,
+
+	PMU_VCODEC_PWRDWN_EN,
+	PMU_VDU_PWRDWN_EN,
+	PMU_RGA_PWRDWN_EN,
+	PMU_IEP_PWRDWN_EN,
+
+	PMU_VO_PWRDWN_EN,
+	PMU_ISP0_PWRDWN_EN = 22,
+	PMU_ISP1_PWRDWN_EN,
+
+	PMU_HDCP_PWRDWN_EN,
+	PMU_GMAC_PWRDWN_EN,
+	PMU_EMMC_PWRDWN_EN,
+	PMU_USB3_PWRDWN_EN,
+
+	PMU_EDP_PWRDWN_EN,
+	PMU_GIC_PWRDWN_EN,
+	PMU_SD_PWRDWN_EN,
+	PMU_SDIOAUDIO_PWRDWN_EN,
+};
+
+enum pmu_pwrdn_st {
+	PMU_A53_L0_PWRDWN_ST = 0,
+	PMU_A53_L1_PWRDWN_ST,
+	PMU_A53_L2_PWRDWN_ST,
+	PMU_A53_L3_PWRDWN_ST,
+
+	PMU_A72_B0_PWRDWN_ST,
+	PMU_A72_B1_PWRDWN_ST,
+	PMU_SCU_L_PWRDWN_ST,
+	PMU_SCU_B_PWRDWN_ST,
+
+	PMU_TCPD0_PWRDWN_ST,
+	PMU_TCPD1_PWRDWN_ST,
+	PMU_CCI_PWRDWN_ST,
+	PMU_PERILP_PWRDWN_ST,
+
+	PMU_PERIHP_PWRDWN_ST,
+	PMU_CENTER_PWRDWN_ST,
+	PMU_VIO_PWRDWN_ST,
+	PMU_GPU_PWRDWN_ST,
+
+	PMU_VCODEC_PWRDWN_ST,
+	PMU_VDU_PWRDWN_ST,
+	PMU_RGA_PWRDWN_ST,
+	PMU_IEP_PWRDWN_ST,
+
+	PMU_VO_PWRDWN_ST,
+	PMU_ISP0_PWRDWN_ST = 22,
+	PMU_ISP1_PWRDWN_ST,
+
+	PMU_HDCP_PWRDWN_ST,
+	PMU_GMAC_PWRDWN_ST,
+	PMU_EMMC_PWRDWN_ST,
+	PMU_USB3_PWRDWN_ST,
+
+	PMU_EDP_PWRDWN_ST,
+	PMU_GIC_PWRDWN_ST,
+	PMU_SD_PWRDWN_ST,
+	PMU_SDIOAUDIO_PWRDWN_ST,
+
+};
+
+enum pmu_pll_con {
+	PMU_PLL_PD_CFG = 0,
+	PMU_SFT_PLL_PD = 8,
+};
+
+enum pmu_pwermode_con {
+	PMU_PWR_MODE_EN = 0,
+	PMU_WKUP_RST_EN,
+	PMU_INPUT_CLAMP_EN,
+	PMU_OSC_DIS,
+
+	PMU_ALIVE_USE_LF,
+	PMU_PMU_USE_LF,
+	PMU_POWER_OFF_REQ_CFG,
+	PMU_CHIP_PD_EN,
+
+	PMU_PLL_PD_EN,
+	PMU_CPU0_PD_EN,
+	PMU_L2_FLUSH_EN,
+	PMU_L2_IDLE_EN,
+
+	PMU_SCU_PD_EN,
+	PMU_CCI_PD_EN,
+	PMU_PERILP_PD_EN,
+	PMU_CENTER_PD_EN,
+
+	PMU_SREF0_ENTER_EN,
+	PMU_DDRC0_GATING_EN,
+	PMU_DDRIO0_RET_EN,
+	PMU_DDRIO0_RET_DE_REQ,
+
+	PMU_SREF1_ENTER_EN,
+	PMU_DDRC1_GATING_EN,
+	PMU_DDRIO1_RET_EN,
+	PMU_DDRIO1_RET_DE_REQ,
+
+	PMU_CLK_CENTER_SRC_GATE_EN = 26,
+	PMU_CLK_PERILP_SRC_GATE_EN,
+
+	PMU_CLK_CORE_SRC_GATE_EN,
+	PMU_DDRIO_RET_HW_DE_REQ,
+	PMU_SLP_OUTPUT_CFG,
+	PMU_MAIN_CLUSTER,
+};
+
+enum pmu_sft_con {
+	PMU_WKUP_SFT = 0,
+	PMU_INPUT_CLAMP_CFG,
+	PMU_OSC_DIS_CFG,
+	PMU_PMU_LF_EN_CFG,
+
+	PMU_ALIVE_LF_EN_CFG,
+	PMU_24M_EN_CFG,
+	PMU_DBG_PWRUP_L0_CFG,
+	PMU_WKUP_SFT_M0,
+
+	PMU_DDRCTL0_C_SYSREQ_CFG,
+	PMU_DDR0_IO_RET_CFG,
+
+	PMU_DDRCTL1_C_SYSREQ_CFG = 12,
+	PMU_DDR1_IO_RET_CFG,
+	DBG_PWRUP_B0_CFG = 15,
+
+	DBG_NOPWERDWN_L0_EN,
+	DBG_NOPWERDWN_L1_EN,
+	DBG_NOPWERDWN_L2_EN,
+	DBG_NOPWERDWN_L3_EN,
+
+	DBG_PWRUP_REQ_L_EN = 20,
+	CLUSTER_L_CLK_SRC_GATING_CFG,
+	L2_FLUSH_REQ_CLUSTER_L,
+	ACINACTM_CLUSTER_L_CFG,
+
+	DBG_NO_PWERDWN_B0_EN,
+	DBG_NO_PWERDWN_B1_EN,
+
+	DBG_PWRUP_REQ_B_EN = 28,
+	CLUSTER_B_CLK_SRC_GATING_CFG,
+	L2_FLUSH_REQ_CLUSTER_B,
+	ACINACTM_CLUSTER_B_CFG,
+};
+
+enum pmu_int_con {
+	PMU_PMU_INT_EN = 0,
+	PMU_PWRMD_WKUP_INT_EN,
+	PMU_WKUP_GPIO0_NEG_INT_EN,
+	PMU_WKUP_GPIO0_POS_INT_EN,
+	PMU_WKUP_GPIO1_NEG_INT_EN,
+	PMU_WKUP_GPIO1_POS_INT_EN,
+};
+
+enum pmu_int_st {
+	PMU_PWRMD_WKUP_INT_ST = 1,
+	PMU_WKUP_GPIO0_NEG_INT_ST,
+	PMU_WKUP_GPIO0_POS_INT_ST,
+	PMU_WKUP_GPIO1_NEG_INT_ST,
+	PMU_WKUP_GPIO1_POS_INT_ST,
+};
+
+enum pmu_gpio0_pos_int_con {
+	PMU_GPIO0A_POS_INT_EN = 0,
+	PMU_GPIO0B_POS_INT_EN = 8,
+	PMU_GPIO0C_POS_INT_EN = 16,
+	PMU_GPIO0D_POS_INT_EN = 24,
+};
+
+enum pmu_gpio0_neg_int_con {
+	PMU_GPIO0A_NEG_INT_EN = 0,
+	PMU_GPIO0B_NEG_INT_EN = 8,
+	PMU_GPIO0C_NEG_INT_EN = 16,
+	PMU_GPIO0D_NEG_INT_EN = 24,
+};
+
+enum pmu_gpio1_pos_int_con {
+	PMU_GPIO1A_POS_INT_EN = 0,
+	PMU_GPIO1B_POS_INT_EN = 8,
+	PMU_GPIO1C_POS_INT_EN = 16,
+	PMU_GPIO1D_POS_INT_EN = 24,
+};
+
+enum pmu_gpio1_neg_int_con {
+	PMU_GPIO1A_NEG_INT_EN = 0,
+	PMU_GPIO1B_NEG_INT_EN = 8,
+	PMU_GPIO1C_NEG_INT_EN = 16,
+	PMU_GPIO1D_NEG_INT_EN = 24,
+};
+
+enum pmu_gpio0_pos_int_st {
+	PMU_GPIO0A_POS_INT_ST = 0,
+	PMU_GPIO0B_POS_INT_ST = 8,
+	PMU_GPIO0C_POS_INT_ST = 16,
+	PMU_GPIO0D_POS_INT_ST = 24,
+};
+
+enum pmu_gpio0_neg_int_st {
+	PMU_GPIO0A_NEG_INT_ST = 0,
+	PMU_GPIO0B_NEG_INT_ST = 8,
+	PMU_GPIO0C_NEG_INT_ST = 16,
+	PMU_GPIO0D_NEG_INT_ST = 24,
+};
+
+enum pmu_gpio1_pos_int_st {
+	PMU_GPIO1A_POS_INT_ST = 0,
+	PMU_GPIO1B_POS_INT_ST = 8,
+	PMU_GPIO1C_POS_INT_ST = 16,
+	PMU_GPIO1D_POS_INT_ST = 24,
+};
+
+enum pmu_gpio1_neg_int_st {
+	PMU_GPIO1A_NEG_INT_ST = 0,
+	PMU_GPIO1B_NEG_INT_ST = 8,
+	PMU_GPIO1C_NEG_INT_ST = 16,
+	PMU_GPIO1D_NEG_INT_ST = 24,
+};
+
+/* pmu power down configure register 0x0050 */
+enum pmu_pwrdn_inten {
+	PMU_A53_L0_PWR_SWITCH_INT_EN = 0,
+	PMU_A53_L1_PWR_SWITCH_INT_EN,
+	PMU_A53_L2_PWR_SWITCH_INT_EN,
+	PMU_A53_L3_PWR_SWITCH_INT_EN,
+
+	PMU_A72_B0_PWR_SWITCH_INT_EN,
+	PMU_A72_B1_PWR_SWITCH_INT_EN,
+	PMU_SCU_L_PWR_SWITCH_INT_EN,
+	PMU_SCU_B_PWR_SWITCH_INT_EN,
+
+	PMU_TCPD0_PWR_SWITCH_INT_EN,
+	PMU_TCPD1_PWR_SWITCH_INT_EN,
+	PMU_CCI_PWR_SWITCH_INT_EN,
+	PMU_PERILP_PWR_SWITCH_INT_EN,
+
+	PMU_PERIHP_PWR_SWITCH_INT_EN,
+	PMU_CENTER_PWR_SWITCH_INT_EN,
+	PMU_VIO_PWR_SWITCH_INT_EN,
+	PMU_GPU_PWR_SWITCH_INT_EN,
+
+	PMU_VCODEC_PWR_SWITCH_INT_EN,
+	PMU_VDU_PWR_SWITCH_INT_EN,
+	PMU_RGA_PWR_SWITCH_INT_EN,
+	PMU_IEP_PWR_SWITCH_INT_EN,
+
+	PMU_VO_PWR_SWITCH_INT_EN,
+	PMU_ISP0_PWR_SWITCH_INT_EN = 22,
+	PMU_ISP1_PWR_SWITCH_INT_EN,
+
+	PMU_HDCP_PWR_SWITCH_INT_EN,
+	PMU_GMAC_PWR_SWITCH_INT_EN,
+	PMU_EMMC_PWR_SWITCH_INT_EN,
+	PMU_USB3_PWR_SWITCH_INT_EN,
+
+	PMU_EDP_PWR_SWITCH_INT_EN,
+	PMU_GIC_PWR_SWITCH_INT_EN,
+	PMU_SD_PWR_SWITCH_INT_EN,
+	PMU_SDIOAUDIO_PWR_SWITCH_INT_EN,
+};
+
+enum pmu_wkup_status {
+	PMU_WKUP_BY_CLSTER_L_INT = 0,
+	PMU_WKUP_BY_CLSTER_b_INT,
+	PMU_WKUP_BY_GPIO_INT,
+	PMU_WKUP_BY_SDIO_DET,
+
+	PMU_WKUP_BY_SDMMC_DET,
+	PMU_WKUP_BY_TIMER = 6,
+	PMU_WKUP_BY_USBDEV_DET,
+
+	PMU_WKUP_BY_M0_SFT,
+	PMU_WKUP_BY_M0_WDT_INT,
+	PMU_WKUP_BY_TIMEOUT,
+	PMU_WKUP_BY_PWM,
+
+	PMU_WKUP_BY_PCIE = 13,
+};
+
+enum pmu_bus_clr {
+	PMU_CLR_GPU = 0,
+	PMU_CLR_PERILP,
+	PMU_CLR_PERIHP,
+	PMU_CLR_VCODEC,
+
+	PMU_CLR_VDU,
+	PMU_CLR_RGA,
+	PMU_CLR_IEP,
+	PMU_CLR_VOPB,
+
+	PMU_CLR_VOPL,
+	PMU_CLR_ISP0,
+	PMU_CLR_ISP1,
+	PMU_CLR_HDCP,
+
+	PMU_CLR_USB3,
+	PMU_CLR_PERILPM0,
+	PMU_CLR_CENTER,
+	PMU_CLR_CCIM1,
+
+	PMU_CLR_CCIM0,
+	PMU_CLR_VIO,
+	PMU_CLR_MSCH0,
+	PMU_CLR_MSCH1,
+
+	PMU_CLR_ALIVE,
+	PMU_CLR_PMU,
+	PMU_CLR_EDP,
+	PMU_CLR_GMAC,
+
+	PMU_CLR_EMMC,
+	PMU_CLR_CENTER1,
+	PMU_CLR_PMUM0,
+	PMU_CLR_GIC,
+
+	PMU_CLR_SD,
+	PMU_CLR_SDIOAUDIO,
+};
+
+/* PMU bus idle request register */
+enum pmu_bus_idle_req {
+	PMU_IDLE_REQ_GPU = 0,
+	PMU_IDLE_REQ_PERILP,
+	PMU_IDLE_REQ_PERIHP,
+	PMU_IDLE_REQ_VCODEC,
+
+	PMU_IDLE_REQ_VDU,
+	PMU_IDLE_REQ_RGA,
+	PMU_IDLE_REQ_IEP,
+	PMU_IDLE_REQ_VOPB,
+
+	PMU_IDLE_REQ_VOPL,
+	PMU_IDLE_REQ_ISP0,
+	PMU_IDLE_REQ_ISP1,
+	PMU_IDLE_REQ_HDCP,
+
+	PMU_IDLE_REQ_USB3,
+	PMU_IDLE_REQ_PERILPM0,
+	PMU_IDLE_REQ_CENTER,
+	PMU_IDLE_REQ_CCIM0,
+
+	PMU_IDLE_REQ_CCIM1,
+	PMU_IDLE_REQ_VIO,
+	PMU_IDLE_REQ_MSCH0,
+	PMU_IDLE_REQ_MSCH1,
+
+	PMU_IDLE_REQ_ALIVE,
+	PMU_IDLE_REQ_PMU,
+	PMU_IDLE_REQ_EDP,
+	PMU_IDLE_REQ_GMAC,
+
+	PMU_IDLE_REQ_EMMC,
+	PMU_IDLE_REQ_CENTER1,
+	PMU_IDLE_REQ_PMUM0,
+	PMU_IDLE_REQ_GIC,
+
+	PMU_IDLE_REQ_SD,
+	PMU_IDLE_REQ_SDIOAUDIO,
+};
+
+/* pmu bus idle status register */
+enum pmu_bus_idle_st {
+	PMU_IDLE_ST_GPU = 0,
+	PMU_IDLE_ST_PERILP,
+	PMU_IDLE_ST_PERIHP,
+	PMU_IDLE_ST_VCODEC,
+
+	PMU_IDLE_ST_VDU,
+	PMU_IDLE_ST_RGA,
+	PMU_IDLE_ST_IEP,
+	PMU_IDLE_ST_VOPB,
+
+	PMU_IDLE_ST_VOPL,
+	PMU_IDLE_ST_ISP0,
+	PMU_IDLE_ST_ISP1,
+	PMU_IDLE_ST_HDCP,
+
+	PMU_IDLE_ST_USB3,
+	PMU_IDLE_ST_PERILPM0,
+	PMU_IDLE_ST_CENTER,
+	PMU_IDLE_ST_CCIM0,
+
+	PMU_IDLE_ST_CCIM1,
+	PMU_IDLE_ST_VIO,
+	PMU_IDLE_ST_MSCH0,
+	PMU_IDLE_ST_MSCH1,
+
+	PMU_IDLE_ST_ALIVE,
+	PMU_IDLE_ST_PMU,
+	PMU_IDLE_ST_EDP,
+	PMU_IDLE_ST_GMAC,
+
+	PMU_IDLE_ST_EMMC,
+	PMU_IDLE_ST_CENTER1,
+	PMU_IDLE_ST_PMUM0,
+	PMU_IDLE_ST_GIC,
+
+	PMU_IDLE_ST_SD,
+	PMU_IDLE_ST_SDIOAUDIO,
+};
+
+enum pmu_bus_idle_ack {
+	PMU_IDLE_ACK_GPU = 0,
+	PMU_IDLE_ACK_PERILP,
+	PMU_IDLE_ACK_PERIHP,
+	PMU_IDLE_ACK_VCODEC,
+
+	PMU_IDLE_ACK_VDU,
+	PMU_IDLE_ACK_RGA,
+	PMU_IDLE_ACK_IEP,
+	PMU_IDLE_ACK_VOPB,
+
+	PMU_IDLE_ACK_VOPL,
+	PMU_IDLE_ACK_ISP0,
+	PMU_IDLE_ACK_ISP1,
+	PMU_IDLE_ACK_HDCP,
+
+	PMU_IDLE_ACK_USB3,
+	PMU_IDLE_ACK_PERILPM0,
+	PMU_IDLE_ACK_CENTER,
+	PMU_IDLE_ACK_CCIM0,
+
+	PMU_IDLE_ACK_CCIM1,
+	PMU_IDLE_ACK_VIO,
+	PMU_IDLE_ACK_MSCH0,
+	PMU_IDLE_ACK_MSCH1,
+
+	PMU_IDLE_ACK_ALIVE,
+	PMU_IDLE_ACK_PMU,
+	PMU_IDLE_ACK_EDP,
+	PMU_IDLE_ACK_GMAC,
+
+	PMU_IDLE_ACK_EMMC,
+	PMU_IDLE_ACK_CENTER1,
+	PMU_IDLE_ACK_PMUM0,
+	PMU_IDLE_ACK_GIC,
+
+	PMU_IDLE_ACK_SD,
+	PMU_IDLE_ACK_SDIOAUDIO,
+};
+
+enum pmu_cci500_con {
+	PMU_PREQ_CCI500_CFG_SW = 0,
+	PMU_CLR_PREQ_CCI500_HW,
+	PMU_PSTATE_CCI500_0,
+	PMU_PSTATE_CCI500_1,
+
+	PMU_PSTATE_CCI500_2,
+	PMU_QREQ_CCI500_CFG_SW,
+	PMU_CLR_QREQ_CCI500_HW,
+	PMU_QGATING_CCI500_CFG,
+
+	PMU_PREQ_CCI500_CFG_SW_WMSK = 16,
+	PMU_CLR_PREQ_CCI500_HW_WMSK,
+	PMU_PSTATE_CCI500_0_WMSK,
+	PMU_PSTATE_CCI500_1_WMSK,
+
+	PMU_PSTATE_CCI500_2_WMSK,
+	PMU_QREQ_CCI500_CFG_SW_WMSK,
+	PMU_CLR_QREQ_CCI500_HW_WMSK,
+	PMU_QGATING_CCI500_CFG_WMSK,
+};
+
+enum pmu_adb400_con {
+	PMU_PWRDWN_REQ_CXCS_SW = 0,
+	PMU_PWRDWN_REQ_CORE_L_SW,
+	PMU_PWRDWN_REQ_CORE_L_2GIC_SW,
+	PMU_PWRDWN_REQ_GIC2_CORE_L_SW,
+
+	PMU_PWRDWN_REQ_CORE_B_SW,
+	PMU_PWRDWN_REQ_CORE_B_2GIC_SW,
+	PMU_PWRDWN_REQ_GIC2_CORE_B_SW,
+
+	PMU_CLR_CXCS_HW = 8,
+	PMU_CLR_CORE_L_HW,
+	PMU_CLR_CORE_L_2GIC_HW,
+	PMU_CLR_GIC2_CORE_L_HW,
+
+	PMU_CLR_CORE_B_HW,
+	PMU_CLR_CORE_B_2GIC_HW,
+	PMU_CLR_GIC2_CORE_B_HW,
+
+	PMU_PWRDWN_REQ_CXCS_SW_WMSK = 16,
+	PMU_PWRDWN_REQ_CORE_L_SW_WMSK,
+	PMU_PWRDWN_REQ_CORE_L_2GIC_SW_WMSK,
+	PMU_PWRDWN_REQ_GIC2_CORE_L_SW_WMSK,
+
+	PMU_PWRDWN_REQ_CORE_B_SW_WMSK,
+	PMU_PWRDWN_REQ_CORE_B_2GIC_SW_WMSK,
+	PMU_PWRDWN_REQ_GIC2_CORE_B_SW_WMSK,
+
+	PMU_CLR_CXCS_HW_WMSK = 24,
+	PMU_CLR_CORE_L_HW_WMSK,
+	PMU_CLR_CORE_L_2GIC_HW_WMSK,
+	PMU_CLR_GIC2_CORE_L_HW_WMSK,
+
+	PMU_CLR_CORE_B_HW_WMSK,
+	PMU_CLR_CORE_B_2GIC_HW_WMSK,
+	PMU_CLR_GIC2_CORE_B_HW_WMSK,
+};
+
+enum pmu_adb400_st {
+	PMU_PWRDWN_REQ_CXCS_SW_ST = 0,
+	PMU_PWRDWN_REQ_CORE_L_SW_ST,
+	PMU_PWRDWN_REQ_CORE_L_2GIC_SW_ST,
+	PMU_PWRDWN_REQ_GIC2_CORE_L_SW_ST,
+
+	PMU_PWRDWN_REQ_CORE_B_SW_ST,
+	PMU_PWRDWN_REQ_CORE_B_2GIC_SW_ST,
+	PMU_PWRDWN_REQ_GIC2_CORE_B_SW_ST,
+
+	PMU_CLR_CXCS_HW_ST = 8,
+	PMU_CLR_CORE_L_HW_ST,
+	PMU_CLR_CORE_L_2GIC_HW_ST,
+	PMU_CLR_GIC2_CORE_L_HW_ST,
+
+	PMU_CLR_CORE_B_HW_ST,
+	PMU_CLR_CORE_B_2GIC_HW_ST,
+	PMU_CLR_GIC2_CORE_B_HW_ST,
+};
+
+enum pmu_pwrdn_con1 {
+	PMU_VD_SCU_L_PWRDN_EN = 0,
+	PMU_VD_SCU_B_PWRDN_EN,
+	PMU_VD_CENTER_PWRDN_EN,
+};
+
+enum pmu_core_pwr_st {
+	L2_FLUSHDONE_CLUSTER_L = 0,
+	STANDBY_BY_WFIL2_CLUSTER_L,
+
+	L2_FLUSHDONE_CLUSTER_B = 10,
+	STANDBY_BY_WFIL2_CLUSTER_B,
+};
+
+#endif /* __PMU_BITS_H__ */
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu_regs.h b/plat/rockchip/rk3399/include/shared/pmu_regs.h
similarity index 100%
rename from plat/rockchip/rk3399/drivers/pmu/pmu_regs.h
rename to plat/rockchip/rk3399/include/shared/pmu_regs.h
diff --git a/plat/rockchip/rk3399/plat_sip_calls.c b/plat/rockchip/rk3399/plat_sip_calls.c
index 6f5a4bd..7cf3957 100644
--- a/plat/rockchip/rk3399/plat_sip_calls.c
+++ b/plat/rockchip/rk3399/plat_sip_calls.c
@@ -44,24 +44,20 @@
 #define DRAM_GET_RATE		0x05
 #define DRAM_CLR_IRQ		0x06
 #define DRAM_SET_PARAM		0x07
+#define DRAM_SET_ODT_PD		0x08
 
-uint32_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, uint64_t arg2)
 {
 	switch (id) {
-	case DRAM_INIT:
-		ddr_dfs_init();
-		break;
 	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 DRAM_CLR_IRQ:
-		clr_dcf_irq();
-		break;
-	case DRAM_SET_PARAM:
-		dts_timing_receive((uint32_t)arg0, (uint32_t)arg1);
+	case DRAM_SET_ODT_PD:
+		dram_set_odt_pd(arg0, arg1, arg2);
 		break;
 	default:
 		break;
@@ -81,7 +77,7 @@
 {
 	switch (smc_fid) {
 	case RK_SIP_DDR_CFG:
-		SMC_RET1(handle, ddr_smc_handler(x1, x2, x3));
+		SMC_RET1(handle, ddr_smc_handler(x1, x2, x3, x4));
 	default:
 		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
 		SMC_RET1(handle, SMC_UNK);
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
index 3628dc3..c72119c 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -28,63 +28,67 @@
 # POSSIBILITY OF SUCH DAMAGE.
 #
 
-RK_PLAT         :=      plat/rockchip
-RK_PLAT_SOC     :=      ${RK_PLAT}/${PLAT}
-RK_PLAT_COMMON  :=      ${RK_PLAT}/common
+RK_PLAT		:=	plat/rockchip
+RK_PLAT_SOC	:=	${RK_PLAT}/${PLAT}
+RK_PLAT_COMMON	:=	${RK_PLAT}/common
 
-PLAT_INCLUDES           :=	-I${RK_PLAT_COMMON}/				\
-                                -I${RK_PLAT_COMMON}/include/			\
-                                -I${RK_PLAT_COMMON}/pmusram			\
-                                -I${RK_PLAT_COMMON}/drivers/pmu/			\
-				-I${RK_PLAT_SOC}/				\
-                                -I${RK_PLAT_SOC}/drivers/pmu/                   \
-				-I${RK_PLAT_SOC}/drivers/pwm/			\
-                                -I${RK_PLAT_SOC}/drivers/soc/                   \
-                                -I${RK_PLAT_SOC}/drivers/dram/			\
-                                -I${RK_PLAT_SOC}/include/                       \
+PLAT_INCLUDES		:=	-I${RK_PLAT_COMMON}/			\
+				-I${RK_PLAT_COMMON}/include/		\
+				-I${RK_PLAT_COMMON}/pmusram		\
+				-I${RK_PLAT_COMMON}/drivers/pmu/	\
+				-I${RK_PLAT_SOC}/			\
+				-I${RK_PLAT_SOC}/drivers/pmu/		\
+				-I${RK_PLAT_SOC}/drivers/pwm/		\
+				-I${RK_PLAT_SOC}/drivers/secure/	\
+				-I${RK_PLAT_SOC}/drivers/soc/		\
+				-I${RK_PLAT_SOC}/drivers/dram/		\
+				-I${RK_PLAT_SOC}/include/		\
+				-I${RK_PLAT_SOC}/include/shared/	\
 
-RK_GIC_SOURCES          :=      drivers/arm/gic/common/gic_common.c     \
-                                drivers/arm/gic/v3/gicv3_main.c         \
-                                drivers/arm/gic/v3/gicv3_helpers.c      \
-                                plat/common/plat_gicv3.c                \
-                                ${RK_PLAT}/common/rockchip_gicv3.c
+RK_GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/v3/gicv3_helpers.c	\
+				plat/common/plat_gicv3.c		\
+				${RK_PLAT}/common/rockchip_gicv3.c
 
-PLAT_BL_COMMON_SOURCES  :=	lib/xlat_tables/xlat_tables_common.c		\
-				lib/xlat_tables/aarch64/xlat_tables.c		\
-                                plat/common/aarch64/plat_common.c               \
+PLAT_BL_COMMON_SOURCES	:=	lib/xlat_tables/xlat_tables_common.c	\
+				lib/xlat_tables/aarch64/xlat_tables.c	\
+				plat/common/aarch64/plat_common.c	\
 				plat/common/plat_psci_common.c
 
-BL31_SOURCES            +=      ${RK_GIC_SOURCES}                               \
-                                drivers/arm/cci/cci.c                           \
-                                drivers/console/aarch64/console.S		\
-                                drivers/ti/uart/aarch64/16550_console.S		\
-                                drivers/delay_timer/delay_timer.c               \
-                                drivers/delay_timer/generic_delay_timer.c	\
-				drivers/gpio/gpio.c				\
-                                lib/cpus/aarch64/cortex_a53.S                   \
-                                lib/cpus/aarch64/cortex_a72.S                   \
-                                plat/common/aarch64/platform_mp_stack.S         \
-                                ${RK_PLAT_COMMON}/aarch64/plat_helpers.S        \
-                                ${RK_PLAT_COMMON}/bl31_plat_setup.c             \
-                                ${RK_PLAT_COMMON}/params_setup.c                \
-                                ${RK_PLAT_COMMON}/pmusram/pmu_sram_cpus_on.S	\
-				${RK_PLAT_COMMON}/pmusram/pmu_sram.c		\
-                                ${RK_PLAT_COMMON}/plat_pm.c                     \
-                                ${RK_PLAT_COMMON}/plat_topology.c               \
-                                ${RK_PLAT_COMMON}/aarch64/platform_common.c        \
-				${RK_PLAT_COMMON}/rockchip_sip_svc.c		\
-				${RK_PLAT_SOC}/plat_sip_calls.c			\
-				${RK_PLAT_SOC}/drivers/gpio/rk3399_gpio.c	\
-                                ${RK_PLAT_SOC}/drivers/pmu/pmu.c                \
-                                ${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c             \
-				${RK_PLAT_SOC}/drivers/pwm/pwm.c	\
-                                ${RK_PLAT_SOC}/drivers/soc/soc.c		\
-				${RK_PLAT_SOC}/drivers/dram/dfs.c		\
-                                ${RK_PLAT_SOC}/drivers/dram/suspend.c           \
-				${RK_PLAT_SOC}/drivers/dram/dram.c		\
-				${RK_PLAT_SOC}/drivers/dram/dram_spec_timing.c
+BL31_SOURCES	+=	${RK_GIC_SOURCES}				\
+			drivers/arm/cci/cci.c				\
+			drivers/console/aarch64/console.S		\
+			drivers/ti/uart/aarch64/16550_console.S		\
+			drivers/delay_timer/delay_timer.c		\
+			drivers/delay_timer/generic_delay_timer.c	\
+			drivers/gpio/gpio.c				\
+			lib/cpus/aarch64/cortex_a53.S			\
+			lib/cpus/aarch64/cortex_a72.S			\
+			plat/common/aarch64/platform_mp_stack.S		\
+			${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
+			${RK_PLAT_COMMON}/bl31_plat_setup.c		\
+			${RK_PLAT_COMMON}/params_setup.c		\
+			${RK_PLAT_COMMON}/pmusram/pmu_sram_cpus_on.S	\
+			${RK_PLAT_COMMON}/pmusram/pmu_sram.c		\
+			${RK_PLAT_COMMON}/plat_pm.c			\
+			${RK_PLAT_COMMON}/plat_topology.c		\
+			${RK_PLAT_COMMON}/aarch64/platform_common.c	\
+			${RK_PLAT_COMMON}/rockchip_sip_svc.c		\
+			${RK_PLAT_SOC}/plat_sip_calls.c			\
+			${RK_PLAT_SOC}/drivers/gpio/rk3399_gpio.c	\
+			${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
+			${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c		\
+			${RK_PLAT_SOC}/drivers/pmu/m0_ctl.c		\
+			${RK_PLAT_SOC}/drivers/pwm/pwm.c		\
+			${RK_PLAT_SOC}/drivers/secure/secure.c		\
+			${RK_PLAT_SOC}/drivers/soc/soc.c		\
+			${RK_PLAT_SOC}/drivers/dram/dfs.c		\
+			${RK_PLAT_SOC}/drivers/dram/dram.c		\
+			${RK_PLAT_SOC}/drivers/dram/dram_spec_timing.c	\
+			${RK_PLAT_SOC}/drivers/dram/suspend.c
 
-ENABLE_PLAT_COMPAT      :=      0
+ENABLE_PLAT_COMPAT	:=	0
 
 $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
 
diff --git a/plat/rockchip/rk3399/rk3399_def.h b/plat/rockchip/rk3399/rk3399_def.h
index fdf93fd..a24176d 100644
--- a/plat/rockchip/rk3399/rk3399_def.h
+++ b/plat/rockchip/rk3399/rk3399_def.h
@@ -31,122 +31,18 @@
 #ifndef __PLAT_DEF_H__
 #define __PLAT_DEF_H__
 
-#define RK3399_PRIMARY_CPU	0x0
+#include <addressmap.h>
+
+#define RK3399_PRIMARY_CPU		0x0
 
 /* Special value used to verify platform parameters from BL2 to BL3-1 */
-#define RK_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
-
-#define SIZE_K(n)	((n) * 1024)
-#define SIZE_M(n)	((n) * 1024 * 1024)
-
-/* Register base address and size */
-#define MMIO_BASE		0xfe000000
-
-#define GIC500_BASE		(MMIO_BASE + 0xe00000)
-#define GIC500_SIZE		SIZE_M(2)
-
-#define PMU_BASE		(MMIO_BASE + 0x1310000)
-#define PMU_SIZE		SIZE_K(64)
-
-#define PMUGRF_BASE		(MMIO_BASE + 0x1320000)
-#define PMUGRF_SIZE		SIZE_K(64)
-
-#define SGRF_BASE		(MMIO_BASE + 0x1330000)
-#define SGRF_SIZE		SIZE_K(64)
-
-#define PMUSRAM_BASE		(MMIO_BASE + 0x13b0000)
-#define PMUSRAM_SIZE		SIZE_K(64)
-#define PMUSRAM_RSIZE		SIZE_K(8)
-
-#define PWM_BASE		(MMIO_BASE + 0x1420000)
-#define PWM_SIZE		SIZE_K(64)
-
-#define CIC_BASE		(MMIO_BASE + 0x1620000)
-#define CIC_SIZE		SIZE_K(4)
-
-#define DCF_BASE		(MMIO_BASE + 0x16a0000)
-#define DCF_SIZE		SIZE_K(4)
-
-#define GPIO0_BASE		(MMIO_BASE + 0x1720000)
-#define GPIO0_SIZE		SIZE_K(64)
-
-#define GPIO1_BASE		(MMIO_BASE + 0x1730000)
-#define GPIO1_SIZE		SIZE_K(64)
-
-#define CRUS_BASE		(MMIO_BASE + 0x1750000)
-#define CRUS_SIZE		SIZE_K(128)
-
-#define GRF_BASE		(MMIO_BASE + 0x1770000)
-#define GRF_SIZE		SIZE_K(64)
-
-#define GPIO2_BASE		(MMIO_BASE + 0x1780000)
-#define GPIO2_SIZE		SIZE_K(32)
-
-#define GPIO3_BASE		(MMIO_BASE + 0x1788000)
-#define GPIO3_SIZE		SIZE_K(32)
-
-#define GPIO4_BASE		(MMIO_BASE + 0x1790000)
-#define GPIO4_SIZE		SIZE_K(32)
-
-#define STIME_BASE		(MMIO_BASE + 0x1860000)
-#define STIME_SIZE		SIZE_K(64)
-
-#define SRAM_BASE		(MMIO_BASE + 0x18c0000)
-#define SRAM_SIZE		SIZE_K(192)
-
-#define SERVICE_NOC_0_BASE	(MMIO_BASE + 0x1a50000)
-#define NOC_0_SIZE		SIZE_K(192)
-
-#define DDRC0_BASE		(MMIO_BASE + 0x1a80000)
-#define DDRC0_SIZE		SIZE_K(32)
-
-#define SERVICE_NOC_1_BASE	(MMIO_BASE + 0x1a84000)
-#define NOC_1_SIZE		SIZE_K(16)
-
-#define DDRC1_BASE		(MMIO_BASE + 0x1a88000)
-#define DDRC1_SIZE		SIZE_K(32)
-
-#define SERVICE_NOC_2_BASE	(MMIO_BASE + 0x1a8c000)
-#define NOC_2_SIZE		SIZE_K(16)
-
-#define SERVICE_NOC_3_BASE	(MMIO_BASE + 0x1a90000)
-#define NOC_3_SIZE		SIZE_K(448)
-
-#define CCI500_BASE		(MMIO_BASE + 0x1b00000)
-#define CCI500_SIZE		SIZE_M(1)
-
-#define DDR_PI_OFFSET		0x800
-#define DDR_PHY_OFFSET		0x2000
-
-#define DDRC0_PI_BASE		(DDRC0_BASE + DDR_PI_OFFSET)
-#define DDRC0_PHY_BASE		(DDRC0_BASE + DDR_PHY_OFFSET)
-#define DDRC1_PI_BASE		(DDRC1_BASE + DDR_PI_OFFSET)
-#define DDRC1_PHY_BASE		(DDRC1_BASE + DDR_PHY_OFFSET)
-
-/* Aggregate of all devices in the first GB */
-#define RK3399_DEV_RNG0_BASE	MMIO_BASE
-#define RK3399_DEV_RNG0_SIZE	0x1d00000
-
-/*
- * include i2c pmu/audio, pwm0-3 rkpwm0-3 uart_dbg,mailbox scr
- * 0xff650000 -0xff6c0000
- */
-#define PD_BUS0_BASE		(MMIO_BASE + 0x1650000)
-#define PD_BUS0_SIZE		SIZE_K(448)
-
-#define PMUCRU_BASE		(MMIO_BASE + 0x1750000)
-#define CRU_BASE		(MMIO_BASE + 0x1760000)
-
-#define COLD_BOOT_BASE		(MMIO_BASE + 0x1ff0000)
+#define RK_BL31_PLAT_PARAM_VAL		0x0f1e2d3c4b5a6978ULL
 
 /**************************************************************************
  * UART related constants
  **************************************************************************/
-#define RK3399_UART2_BASE	(0xff1a0000)
-#define RK3399_UART2_SIZE	SIZE_K(64)
-
-#define RK3399_BAUDRATE		(115200)
-#define RK3399_UART_CLOCK	(24000000)
+#define RK3399_BAUDRATE			115200
+#define RK3399_UART_CLOCK		24000000
 
 /******************************************************************************
  * System counter frequency related constants
@@ -154,8 +50,8 @@
 #define SYS_COUNTER_FREQ_IN_TICKS	24000000
 
 /* Base rockchip_platform compatible GIC memory map */
-#define BASE_GICD_BASE		(GIC500_BASE)
-#define BASE_GICR_BASE		(GIC500_BASE + SIZE_M(1))
+#define BASE_GICD_BASE			(GIC500_BASE)
+#define BASE_GICR_BASE			(GIC500_BASE + SIZE_M(1))
 
 /*****************************************************************************
  * CCI-400 related constants
@@ -176,6 +72,7 @@
 #define ARM_IRQ_SEC_SGI_5		13
 #define ARM_IRQ_SEC_SGI_6		14
 #define ARM_IRQ_SEC_SGI_7		15
+
 /*
  * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
  * terminology. On a GICv2 system or mode, the lists will be merged and treated
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.c b/plat/xilinx/zynqmp/pm_service/pm_client.c
index e102b4f..0fe17b5 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_client.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_client.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -40,6 +40,7 @@
 #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"
@@ -188,7 +189,7 @@
 	uint8_t pm_wakeup_nodes_set[NODE_MAX];
 	uintptr_t isenabler1 = BASE_GICD_BASE + GICD_ISENABLER + 4;
 
-	memset(&pm_wakeup_nodes_set, 0, sizeof(pm_wakeup_nodes_set));
+	zeromem(&pm_wakeup_nodes_set, sizeof(pm_wakeup_nodes_set));
 
 	for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) {
 		uint32_t base_irq = reg_num << ISENABLER_SHIFT;
diff --git a/services/spd/opteed/opteed_common.c b/services/spd/opteed/opteed_common.c
index 2f20b7c..910f900 100644
--- a/services/spd/opteed/opteed_common.c
+++ b/services/spd/opteed/opteed_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -33,6 +33,7 @@
 #include <bl_common.h>
 #include <context_mgmt.h>
 #include <string.h>
+#include <utils.h>
 #include "opteed_private.h"
 
 /*******************************************************************************
@@ -73,7 +74,7 @@
 						      DAIF_FIQ_BIT |
 							DAIF_IRQ_BIT |
 							DAIF_ABT_BIT);
-	memset(&optee_entry_point->args, 0, sizeof(optee_entry_point->args));
+	zeromem(&optee_entry_point->args, sizeof(optee_entry_point->args));
 }
 
 /*******************************************************************************
diff --git a/services/spd/trusty/trusty.c b/services/spd/trusty/trusty.c
index 78a68ba..b21ce71 100644
--- a/services/spd/trusty/trusty.c
+++ b/services/spd/trusty/trusty.c
@@ -395,7 +395,7 @@
 DECLARE_RT_SVC(
 	trusty_std,
 
-	OEN_TOS_START,
+	OEN_TAP_START,
 	SMC_ENTITY_SECURE_MONITOR,
 	SMC_TYPE_STD,
 	NULL,
diff --git a/services/spd/tspd/tspd_common.c b/services/spd/tspd/tspd_common.c
index 3dcefea..70959d7 100644
--- a/services/spd/tspd/tspd_common.c
+++ b/services/spd/tspd/tspd_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, 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:
@@ -35,6 +35,7 @@
 #include <debug.h>
 #include <string.h>
 #include <tsp.h>
+#include <utils.h>
 #include "tspd_private.h"
 
 /*******************************************************************************
@@ -78,7 +79,7 @@
 	tsp_entry_point->spsr = SPSR_64(MODE_EL1,
 					MODE_SP_ELX,
 					DISABLE_ALL_EXCEPTIONS);
-	memset(&tsp_entry_point->args, 0, sizeof(tsp_entry_point->args));
+	zeromem(&tsp_entry_point->args, sizeof(tsp_entry_point->args));
 }
 
 /*******************************************************************************
diff --git a/services/spd/tspd/tspd_main.c b/services/spd/tspd/tspd_main.c
index 2850e70..ff515cc 100644
--- a/services/spd/tspd/tspd_main.c
+++ b/services/spd/tspd/tspd_main.c
@@ -612,15 +612,26 @@
 			break;
 		}
 
+		assert(handle == cm_get_context(NON_SECURE));
+		cm_el1_sysregs_context_save(NON_SECURE);
+
 		/* Abort the preempted SMC request */
-		if (!tspd_abort_preempted_smc(tsp_ctx))
+		if (!tspd_abort_preempted_smc(tsp_ctx)) {
 			/*
 			 * If there was no preempted SMC to abort, return
 			 * SMC_UNK.
+			 *
+			 * Restoring the NON_SECURE context is not necessary as
+			 * the synchronous entry did not take place if the
+			 * return code of tspd_abort_preempted_smc is zero.
 			 */
-			SMC_RET1(handle, SMC_UNK);
+			cm_set_next_eret_context(NON_SECURE);
+			break;
+		}
 
-		break;
+		cm_el1_sysregs_context_restore(NON_SECURE);
+		cm_set_next_eret_context(NON_SECURE);
+		SMC_RET0(handle);
 
 		/*
 		 * Request from non secure world to resume the preempted
diff --git a/tools/cert_create/include/key.h b/tools/cert_create/include/key.h
index f60997f..433f72c 100644
--- a/tools/cert_create/include/key.h
+++ b/tools/cert_create/include/key.h
@@ -73,6 +73,7 @@
 /* Exported API */
 int key_init(void);
 key_t *key_get_by_opt(const char *opt);
+int key_new(key_t *key);
 int key_create(key_t *key, int type);
 int key_load(key_t *key, unsigned int *err_code);
 int key_store(key_t *key);
diff --git a/tools/cert_create/src/cert.c b/tools/cert_create/src/cert.c
index a559832..375c66b 100644
--- a/tools/cert_create/src/cert.c
+++ b/tools/cert_create/src/cert.c
@@ -103,10 +103,10 @@
 	cert_t *issuer_cert = &certs[cert->issuer];
 	EVP_PKEY *ikey = keys[issuer_cert->key].key;
 	X509 *issuer = issuer_cert->x;
-	X509 *x = NULL;
-	X509_EXTENSION *ex = NULL;
-	X509_NAME *name = NULL;
-	ASN1_INTEGER *sno = NULL;
+	X509 *x;
+	X509_EXTENSION *ex;
+	X509_NAME *name;
+	ASN1_INTEGER *sno;
 	int i, num;
 
 	/* Create the certificate structure */
@@ -202,7 +202,7 @@
 
 cert_t *cert_get_by_opt(const char *opt)
 {
-	cert_t *cert = NULL;
+	cert_t *cert;
 	unsigned int i;
 
 	for (i = 0; i < num_certs; i++) {
diff --git a/tools/cert_create/src/ext.c b/tools/cert_create/src/ext.c
index 3f56edb..a50919e 100644
--- a/tools/cert_create/src/ext.c
+++ b/tools/cert_create/src/ext.c
@@ -181,13 +181,13 @@
 X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md,
 		unsigned char *buf, size_t len)
 {
-	X509_EXTENSION *ex = NULL;
-	ASN1_OCTET_STRING *octet = NULL;
-	HASH *hash = NULL;
-	ASN1_OBJECT *algorithm = NULL;
-	X509_ALGOR *x509_algor = NULL;
+	X509_EXTENSION *ex;
+	ASN1_OCTET_STRING *octet;
+	HASH *hash;
+	ASN1_OBJECT *algorithm;
+	X509_ALGOR *x509_algor;
 	unsigned char *p = NULL;
-	int sz = -1;
+	int sz;
 
 	/* OBJECT_IDENTIFIER with hash algorithm */
 	algorithm = OBJ_nid2obj(md->type);
@@ -254,16 +254,15 @@
  */
 X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value)
 {
-	X509_EXTENSION *ex = NULL;
-	ASN1_INTEGER *counter = NULL;
+	X509_EXTENSION *ex;
+	ASN1_INTEGER *counter;
 	unsigned char *p = NULL;
-	int sz = -1;
+	int sz;
 
 	/* Encode counter */
 	counter = ASN1_INTEGER_new();
 	ASN1_INTEGER_set(counter, value);
-	sz = i2d_ASN1_INTEGER(counter, NULL);
-	i2d_ASN1_INTEGER(counter, &p);
+	sz = i2d_ASN1_INTEGER(counter, &p);
 
 	/* Create the extension */
 	ex = ext_new(nid, crit, p, sz);
@@ -292,9 +291,9 @@
  */
 X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k)
 {
-	X509_EXTENSION *ex = NULL;
-	unsigned char *p = NULL;
-	int sz = -1;
+	X509_EXTENSION *ex;
+	unsigned char *p;
+	int sz;
 
 	/* Encode key */
 	BIO *mem = BIO_new(BIO_s_mem());
@@ -316,7 +315,7 @@
 
 ext_t *ext_get_by_opt(const char *opt)
 {
-	ext_t *ext = NULL;
+	ext_t *ext;
 	unsigned int i;
 
 	/* Sequential search. This is not a performance concern since the number
diff --git a/tools/cert_create/src/key.c b/tools/cert_create/src/key.c
index a7ee759..ce0e4da 100644
--- a/tools/cert_create/src/key.c
+++ b/tools/cert_create/src/key.c
@@ -49,7 +49,7 @@
 /*
  * Create a new key container
  */
-static int key_new(key_t *key)
+int key_new(key_t *key)
 {
 	/* Create key pair container */
 	key->key = EVP_PKEY_new();
@@ -62,7 +62,7 @@
 
 static int key_create_rsa(key_t *key)
 {
-	RSA *rsa = NULL;
+	RSA *rsa;
 
 	rsa = RSA_generate_key(RSA_KEY_BITS, RSA_F4, NULL, NULL);
 	if (rsa == NULL) {
@@ -83,7 +83,7 @@
 #ifndef OPENSSL_NO_EC
 static int key_create_ecdsa(key_t *key)
 {
-	EC_KEY *ec = NULL;
+	EC_KEY *ec;
 
 	ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
 	if (ec == NULL) {
@@ -123,11 +123,6 @@
 		return 0;
 	}
 
-	/* Create OpenSSL key container */
-	if (!key_new(key)) {
-		return 0;
-	}
-
 	if (key_create_fn[type]) {
 		return key_create_fn[type](key);
 	}
@@ -137,14 +132,8 @@
 
 int key_load(key_t *key, unsigned int *err_code)
 {
-	FILE *fp = NULL;
-	EVP_PKEY *k = NULL;
-
-	/* Create OpenSSL key container */
-	if (!key_new(key)) {
-		*err_code = KEY_ERR_MALLOC;
-		return 0;
-	}
+	FILE *fp;
+	EVP_PKEY *k;
 
 	if (key->fn) {
 		/* Load key from file */
@@ -173,7 +162,7 @@
 
 int key_store(key_t *key)
 {
-	FILE *fp = NULL;
+	FILE *fp;
 
 	if (key->fn) {
 		fp = fopen(key->fn, "w");
@@ -196,7 +185,6 @@
 {
 	cmd_opt_t cmd_opt;
 	key_t *key;
-	int rc = 0;
 	unsigned int i;
 
 	for (i = 0; i < num_keys; i++) {
@@ -211,12 +199,12 @@
 		}
 	}
 
-	return rc;
+	return 0;
 }
 
 key_t *key_get_by_opt(const char *opt)
 {
-	key_t *key = NULL;
+	key_t *key;
 	unsigned int i;
 
 	/* Sequential search. This is not a performance concern since the number
diff --git a/tools/cert_create/src/main.c b/tools/cert_create/src/main.c
index c58f41d..c9c9622 100644
--- a/tools/cert_create/src/main.c
+++ b/tools/cert_create/src/main.c
@@ -134,7 +134,6 @@
 	printf("\t%s [OPTIONS]\n\n", cmd);
 
 	printf("Available options:\n");
-	i = 0;
 	opt = long_opt;
 	while (opt->name) {
 		p = line;
@@ -261,12 +260,12 @@
 
 int main(int argc, char *argv[])
 {
-	STACK_OF(X509_EXTENSION) * sk = NULL;
-	X509_EXTENSION *cert_ext = NULL;
-	ext_t *ext = NULL;
-	key_t *key = NULL;
-	cert_t *cert = NULL;
-	FILE *file = NULL;
+	STACK_OF(X509_EXTENSION) * sk;
+	X509_EXTENSION *cert_ext;
+	ext_t *ext;
+	key_t *key;
+	cert_t *cert;
+	FILE *file;
 	int i, j, ext_nid, nvctr;
 	int c, opt_idx = 0;
 	const struct option *cmd_opt;
@@ -367,6 +366,11 @@
 
 	/* Load private keys from files (or generate new ones) */
 	for (i = 0 ; i < num_keys ; i++) {
+		if (!key_new(&keys[i])) {
+			ERROR("Failed to allocate key container\n");
+			exit(1);
+		}
+
 		/* First try to load the key from disk */
 		if (key_load(&keys[i], &err_code)) {
 			/* Key loaded successfully */
@@ -374,11 +378,7 @@
 		}
 
 		/* Key not loaded. Check the error code */
-		if (err_code == KEY_ERR_MALLOC) {
-			/* Cannot allocate memory. Abort. */
-			ERROR("Malloc error while loading '%s'\n", keys[i].fn);
-			exit(1);
-		} else if (err_code == KEY_ERR_LOAD) {
+		if (err_code == KEY_ERR_LOAD) {
 			/* File exists, but it does not contain a valid private
 			 * key. Abort. */
 			ERROR("Error loading '%s'\n", keys[i].fn);
diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c
index 865aeae..f3f831b 100644
--- a/tools/fiptool/fiptool.c
+++ b/tools/fiptool/fiptool.c
@@ -52,8 +52,6 @@
 #define OPT_PLAT_TOC_FLAGS 1
 #define OPT_ALIGN 2
 
-static image_desc_t *lookup_image_desc_from_uuid(const uuid_t *uuid);
-static image_t *lookup_image_from_uuid(const uuid_t *uuid);
 static int info_cmd(int argc, char *argv[]);
 static void info_usage(void);
 static int create_cmd(int argc, char *argv[]);
@@ -822,11 +820,9 @@
 	printf("\n");
 	printf("Options:\n");
 	printf("  --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
-	printf("  --blob uuid=...,file=...\tAdd an image with the given UUID "
-	    "pointed to by file.\n");
-	printf("  --plat-toc-flags <value>\t16-bit platform specific flag field "
-	    "occupying bits 32-47 in 64-bit ToC header.\n");
-	fputc('\n', stderr);
+	printf("  --blob uuid=...,file=...\tAdd an image with the given UUID pointed to by file.\n");
+	printf("  --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n");
+	printf("\n");
 	printf("Specific images are packed with the following options:\n");
 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
@@ -938,12 +934,10 @@
 	printf("\n");
 	printf("Options:\n");
 	printf("  --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
-	printf("  --blob uuid=...,file=...\tAdd or update an image "
-	    "with the given UUID pointed to by file.\n");
+	printf("  --blob uuid=...,file=...\tAdd or update an image with the given UUID pointed to by file.\n");
 	printf("  --out FIP_FILENAME\t\tSet an alternative output FIP file.\n");
-	printf("  --plat-toc-flags <value>\t16-bit platform specific flag field "
-	    "occupying bits 32-47 in 64-bit ToC header.\n");
-	fputc('\n', stderr);
+	printf("  --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n");
+	printf("\n");
 	printf("Specific images are packed with the following options:\n");
 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
@@ -1076,17 +1070,15 @@
 	printf("fiptool unpack [opts] FIP_FILENAME\n");
 	printf("\n");
 	printf("Options:\n");
-	printf("  --blob uuid=...,file=...\tUnpack an image with the given UUID "
-	    "to file.\n");
-	printf("  --force\t\t\tIf the output file already exists, use --force to "
-	    "overwrite it.\n");
+	printf("  --blob uuid=...,file=...\tUnpack an image with the given UUID to file.\n");
+	printf("  --force\t\t\tIf the output file already exists, use --force to overwrite it.\n");
 	printf("  --out path\t\t\tSet the output directory path.\n");
-	fputc('\n', stderr);
+	printf("\n");
 	printf("Specific images are unpacked with the following options:\n");
 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
 		    toc_entry->name);
-	fputc('\n', stderr);
+	printf("\n");
 	printf("If no options are provided, all images will be unpacked.\n");
 	exit(1);
 }
@@ -1207,10 +1199,9 @@
 	printf("Options:\n");
 	printf("  --align <value>\tEach image is aligned to <value> (default: 1).\n");
 	printf("  --blob uuid=...\tRemove an image with the given UUID.\n");
-	printf("  --force\t\tIf the output FIP file already exists, use --force to "
-	    "overwrite it.\n");
+	printf("  --force\t\tIf the output FIP file already exists, use --force to overwrite it.\n");
 	printf("  --out FIP_FILENAME\tSet an alternative output FIP file.\n");
-	fputc('\n', stderr);
+	printf("\n");
 	printf("Specific images are removed with the following options:\n");
 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
 		printf("  --%-16s\t%s\n", toc_entry->cmdline_name,
@@ -1258,7 +1249,7 @@
 	printf("usage: fiptool [--verbose] <command> [<args>]\n");
 	printf("Global options supported:\n");
 	printf("  --verbose\tEnable verbose output for all commands.\n");
-	fputc('\n', stderr);
+	printf("\n");
 	printf("Commands supported:\n");
 	printf("  info\t\tList images contained in FIP.\n");
 	printf("  create\tCreate a new FIP with the given images.\n");