Merge pull request #654 from rockchip-linux/rk3399-suspend-resume

rockchip: support the suspend/resume for rk3399
diff --git a/Makefile b/Makefile
index ab9b1ad..800312c 100644
--- a/Makefile
+++ b/Makefile
@@ -104,6 +104,13 @@
 SPIN_ON_BL1_EXIT		:= 0
 # Build PL011 UART driver in minimal generic UART mode
 PL011_GENERIC_UART		:= 0
+# Flag to enable Performance Measurement Framework
+ENABLE_PMF			:= 0
+# Flag to enable PSCI STATs functionality
+ENABLE_PSCI_STAT	:= 0
+# Whether code and read-only data should be put on separate memory pages.
+# The platform Makefile is free to override this value.
+SEPARATE_CODE_AND_RODATA	:= 0
 
 
 ################################################################################
@@ -373,6 +380,10 @@
         endif
 endif
 
+# Make sure PMF is enabled if PSCI STAT is enabled.
+ifeq (${ENABLE_PSCI_STAT},1)
+ENABLE_PMF			:= 1
+endif
 
 ################################################################################
 # Auxiliary tools (fip_create, cert_create, etc)
@@ -410,6 +421,9 @@
 $(eval $(call assert_boolean,ENABLE_PLAT_COMPAT))
 $(eval $(call assert_boolean,SPIN_ON_BL1_EXIT))
 $(eval $(call assert_boolean,PL011_GENERIC_UART))
+$(eval $(call assert_boolean,ENABLE_PMF))
+$(eval $(call assert_boolean,ENABLE_PSCI_STAT))
+$(eval $(call assert_boolean,SEPARATE_CODE_AND_RODATA))
 
 
 ################################################################################
@@ -437,6 +451,9 @@
 $(eval $(call add_define,ENABLE_PLAT_COMPAT))
 $(eval $(call add_define,SPIN_ON_BL1_EXIT))
 $(eval $(call add_define,PL011_GENERIC_UART))
+$(eval $(call add_define,ENABLE_PMF))
+$(eval $(call add_define,ENABLE_PSCI_STAT))
+$(eval $(call add_define,SEPARATE_CODE_AND_RODATA))
 # Define the EL3_PAYLOAD_BASE flag only if it is provided.
 ifdef EL3_PAYLOAD_BASE
         $(eval $(call add_define,EL3_PAYLOAD_BASE))
@@ -448,7 +465,6 @@
         endif
 endif
 
-
 ################################################################################
 # Include BL specific makefiles
 ################################################################################
diff --git a/bl1/bl1.ld.S b/bl1/bl1.ld.S
index df9a799..b9554d1 100644
--- a/bl1/bl1.ld.S
+++ b/bl1/bl1.ld.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-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:
@@ -45,6 +45,43 @@
     ASSERT(. == ALIGN(4096),
            "BL1_RO_BASE address is not aligned on a page boundary.")
 
+#if SEPARATE_CODE_AND_RODATA
+    .text . : {
+        __TEXT_START__ = .;
+        *bl1_entrypoint.o(.text*)
+        *(.text*)
+        *(.vectors)
+        . = NEXT(4096);
+        __TEXT_END__ = .;
+     } >ROM
+
+    .rodata . : {
+        __RODATA_START__ = .;
+        *(.rodata*)
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __PARSER_LIB_DESCS_START__ = .;
+        KEEP(*(.img_parser_lib_descs))
+        __PARSER_LIB_DESCS_END__ = .;
+
+        /*
+         * Ensure 8-byte alignment for cpu_ops so that its fields are also
+         * aligned. Also ensure cpu_ops inclusion.
+         */
+        . = ALIGN(8);
+        __CPU_OPS_START__ = .;
+        KEEP(*(cpu_ops))
+        __CPU_OPS_END__ = .;
+
+        /*
+         * No need to pad out the .rodata section to a page boundary. Next is
+         * the .data section, which can mapped in ROM with the same memory
+         * attributes as the .rodata section.
+         */
+        __RODATA_END__ = .;
+    } >ROM
+#else
     ro . : {
         __RO_START__ = .;
         *bl1_entrypoint.o(.text*)
@@ -69,6 +106,7 @@
         *(.vectors)
         __RO_END__ = .;
     } >ROM
+#endif
 
     ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
            "cpu_ops not defined for this platform.")
@@ -139,12 +177,14 @@
 
     __DATA_ROM_START__ = LOADADDR(.data);
     __DATA_SIZE__ = SIZEOF(.data);
+
     /*
      * The .data section is the last PROGBITS section so its end marks the end
-     * of the read-only part of BL1's binary.
+     * of BL1's actual content in Trusted ROM.
      */
-    ASSERT(__DATA_ROM_START__ + __DATA_SIZE__ <= BL1_RO_LIMIT,
-           "BL1's RO section has exceeded its limit.")
+    __BL1_ROM_END__ =  __DATA_ROM_START__ + __DATA_SIZE__;
+    ASSERT(__BL1_ROM_END__ <= BL1_RO_LIMIT,
+           "BL1's ROM content has exceeded its limit.")
 
     __BSS_SIZE__ = SIZEOF(.bss);
 
diff --git a/bl1/bl1_private.h b/bl1/bl1_private.h
index 283bbb9..79dde73 100644
--- a/bl1/bl1_private.h
+++ b/bl1/bl1_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-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,8 +35,11 @@
 
 /*******************************************************************************
  * Declarations of linker defined symbols which will tell us where BL1 lives
- * in Trusted RAM
+ * in Trusted ROM and RAM
  ******************************************************************************/
+extern uint64_t __BL1_ROM_END__;
+#define BL1_ROM_END (uint64_t)(&__BL1_ROM_END__)
+
 extern uint64_t __BL1_RAM_START__;
 extern uint64_t __BL1_RAM_END__;
 #define BL1_RAM_BASE (uint64_t)(&__BL1_RAM_START__)
diff --git a/bl2/bl2.ld.S b/bl2/bl2.ld.S
index a660bda..fa694de 100644
--- a/bl2/bl2.ld.S
+++ b/bl2/bl2.ld.S
@@ -45,6 +45,30 @@
     ASSERT(. == ALIGN(4096),
            "BL2_BASE address is not aligned on a page boundary.")
 
+#if SEPARATE_CODE_AND_RODATA
+    .text . : {
+        __TEXT_START__ = .;
+        *bl2_entrypoint.o(.text*)
+        *(.text*)
+        *(.vectors)
+        . = NEXT(4096);
+        __TEXT_END__ = .;
+     } >RAM
+
+    .rodata . : {
+        __RODATA_START__ = .;
+        *(.rodata*)
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __PARSER_LIB_DESCS_START__ = .;
+        KEEP(*(.img_parser_lib_descs))
+        __PARSER_LIB_DESCS_END__ = .;
+
+        . = NEXT(4096);
+        __RODATA_END__ = .;
+    } >RAM
+#else
     ro . : {
         __RO_START__ = .;
         *bl2_entrypoint.o(.text*)
@@ -67,6 +91,7 @@
         . = NEXT(4096);
         __RO_END__ = .;
     } >RAM
+#endif
 
     /*
      * Define a linker symbol to mark start of the RW memory area for this
diff --git a/bl2u/bl2u.ld.S b/bl2u/bl2u.ld.S
index ec12077..d72589f 100644
--- a/bl2u/bl2u.ld.S
+++ b/bl2u/bl2u.ld.S
@@ -45,6 +45,23 @@
     ASSERT(. == ALIGN(4096),
            "BL2U_BASE address is not aligned on a page boundary.")
 
+#if SEPARATE_CODE_AND_RODATA
+    .text . : {
+        __TEXT_START__ = .;
+        *bl2u_entrypoint.o(.text*)
+        *(.text*)
+        *(.vectors)
+        . = NEXT(4096);
+        __TEXT_END__ = .;
+     } >RAM
+
+    .rodata . : {
+        __RODATA_START__ = .;
+        *(.rodata*)
+        . = NEXT(4096);
+        __RODATA_END__ = .;
+    } >RAM
+#else
     ro . : {
         __RO_START__ = .;
         *bl2u_entrypoint.o(.text*)
@@ -61,6 +78,7 @@
         . = NEXT(4096);
         __RO_END__ = .;
     } >RAM
+#endif
 
     /*
      * Define a linker symbol to mark start of the RW memory area for this
diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S
index dc6e7a4..743e65c 100644
--- a/bl31/bl31.ld.S
+++ b/bl31/bl31.ld.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-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:
@@ -46,6 +46,47 @@
     ASSERT(. == ALIGN(4096),
            "BL31_BASE address is not aligned on a page boundary.")
 
+#if SEPARATE_CODE_AND_RODATA
+    .text . : {
+        __TEXT_START__ = .;
+        *bl31_entrypoint.o(.text*)
+        *(.text*)
+        *(.vectors)
+        . = NEXT(4096);
+        __TEXT_END__ = .;
+    } >RAM
+
+    .rodata . : {
+        __RODATA_START__ = .;
+        *(.rodata*)
+
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __RT_SVC_DESCS_START__ = .;
+        KEEP(*(rt_svc_descs))
+        __RT_SVC_DESCS_END__ = .;
+
+#if ENABLE_PMF
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __PMF_SVC_DESCS_START__ = .;
+        KEEP(*(pmf_svc_descs))
+        __PMF_SVC_DESCS_END__ = .;
+#endif /* ENABLE_PMF */
+
+        /*
+         * Ensure 8-byte alignment for cpu_ops so that its fields are also
+         * aligned. Also ensure cpu_ops inclusion.
+         */
+        . = ALIGN(8);
+        __CPU_OPS_START__ = .;
+        KEEP(*(cpu_ops))
+        __CPU_OPS_END__ = .;
+
+        . = NEXT(4096);
+        __RODATA_END__ = .;
+    } >RAM
+#else
     ro . : {
         __RO_START__ = .;
         *bl31_entrypoint.o(.text*)
@@ -58,6 +99,14 @@
         KEEP(*(rt_svc_descs))
         __RT_SVC_DESCS_END__ = .;
 
+#if ENABLE_PMF
+        /* Ensure 8-byte alignment for descriptors and ensure inclusion */
+        . = ALIGN(8);
+        __PMF_SVC_DESCS_START__ = .;
+        KEEP(*(pmf_svc_descs))
+        __PMF_SVC_DESCS_END__ = .;
+#endif /* ENABLE_PMF */
+
         /*
          * Ensure 8-byte alignment for cpu_ops so that its fields are also
          * aligned. Also ensure cpu_ops inclusion.
@@ -77,6 +126,7 @@
         . = NEXT(4096);
         __RO_END__ = .;
     } >RAM
+#endif
 
     ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
            "cpu_ops not defined for this platform.")
@@ -132,6 +182,24 @@
         "PLAT_PERCPU_BAKERY_LOCK_SIZE does not match bakery lock requirements");
 #endif
 #endif
+
+#if ENABLE_PMF
+        /*
+         * Time-stamps are stored in normal .bss memory
+         *
+         * The compiler will allocate enough memory for one CPU's time-stamps,
+         * the remaining memory for other CPU's is allocated by the
+         * linker script
+         */
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __PMF_TIMESTAMP_START__ = .;
+        KEEP(*(pmf_timestamp_array))
+        . = ALIGN(CACHE_WRITEBACK_GRANULE);
+        __PMF_PERCPU_TIMESTAMP_END__ = .;
+        __PERCPU_TIMESTAMP_SIZE__ = ABSOLUTE(. - __PMF_TIMESTAMP_START__);
+        . = . + (__PERCPU_TIMESTAMP_SIZE__ * (PLATFORM_CORE_COUNT - 1));
+        __PMF_TIMESTAMP_END__ = .;
+#endif /* ENABLE_PMF */
         __BSS_END__ = .;
     } >RAM
 
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index 0f14bfa..8a7fccb 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-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,6 +59,14 @@
 BL31_SOURCES		+=	lib/locks/bakery/bakery_lock_normal.c
 endif
 
+ifeq (${ENABLE_PMF}, 1)
+BL31_SOURCES		+=	lib/pmf/pmf_main.c
+endif
+
+ifeq (${ENABLE_PSCI_STAT}, 1)
+BL31_SOURCES		+=	services/std_svc/psci/psci_stat.c
+endif
+
 BL31_LINKERFILE		:=	bl31/bl31.ld.S
 
 # Flag used to indicate if Crash reporting via console should be included
diff --git a/bl32/tsp/tsp.ld.S b/bl32/tsp/tsp.ld.S
index 9c7ed38..7e24f66 100644
--- a/bl32/tsp/tsp.ld.S
+++ b/bl32/tsp/tsp.ld.S
@@ -46,6 +46,23 @@
     ASSERT(. == ALIGN(4096),
            "BL32_BASE address is not aligned on a page boundary.")
 
+#if SEPARATE_CODE_AND_RODATA
+    .text . : {
+        __TEXT_START__ = .;
+        *tsp_entrypoint.o(.text*)
+        *(.text*)
+        *(.vectors)
+        . = NEXT(4096);
+        __TEXT_END__ = .;
+    } >RAM
+
+    .rodata . : {
+        __RODATA_START__ = .;
+        *(.rodata*)
+        . = NEXT(4096);
+        __RODATA_END__ = .;
+    } >RAM
+#else
     ro . : {
         __RO_START__ = .;
         *tsp_entrypoint.o(.text*)
@@ -61,6 +78,7 @@
         . = NEXT(4096);
         __RO_END__ = .;
     } >RAM
+#endif
 
     /*
      * Define a linker symbol to mark start of the RW memory area for this
diff --git a/bl32/tsp/tsp_main.c b/bl32/tsp/tsp_main.c
index 359b9e1..d03f7e2 100644
--- a/bl32/tsp/tsp_main.c
+++ b/bl32/tsp/tsp_main.c
@@ -56,12 +56,12 @@
 work_statistics_t tsp_stats[PLATFORM_CORE_COUNT];
 
 /*******************************************************************************
- * The BL32 memory footprint starts with an RO sections and ends
- * with the linker symbol __BL32_END__. Use it to find the memory size
+ * The TSP memory footprint starts at address BL32_BASE and ends with the
+ * linker symbol __BL32_END__. Use these addresses to compute the TSP image
+ * size.
  ******************************************************************************/
-#define BL32_TOTAL_BASE (unsigned long)(&__RO_START__)
-
 #define BL32_TOTAL_LIMIT (unsigned long)(&__BL32_END__)
+#define BL32_TOTAL_SIZE (BL32_TOTAL_LIMIT - (unsigned long) BL32_BASE)
 
 static tsp_args_t *set_smc_args(uint64_t arg0,
 			     uint64_t arg1,
@@ -102,9 +102,8 @@
 {
 	NOTICE("TSP: %s\n", version_string);
 	NOTICE("TSP: %s\n", build_message);
-	INFO("TSP: Total memory base : 0x%lx\n", BL32_TOTAL_BASE);
-	INFO("TSP: Total memory size : 0x%lx bytes\n",
-			 BL32_TOTAL_LIMIT - BL32_TOTAL_BASE);
+	INFO("TSP: Total memory base : 0x%lx\n", (unsigned long) BL32_BASE);
+	INFO("TSP: Total memory size : 0x%lx bytes\n", BL32_TOTAL_SIZE);
 
 	uint32_t linear_id = plat_my_core_pos();
 
diff --git a/common/context_mgmt.c b/common/context_mgmt.c
index 586d42a..3ccbd03 100644
--- a/common/context_mgmt.c
+++ b/common/context_mgmt.c
@@ -126,7 +126,7 @@
 
 	/*
 	 * Set up SCTLR_ELx for the target exception level:
-	 * EE bit is taken from the entrpoint attributes
+	 * EE bit is taken from the entrypoint attributes
 	 * M, C and I bits must be zero (as required by PSCI specification)
 	 *
 	 * The target exception level is based on the spsr mode requested.
diff --git a/docs/firmware-design.md b/docs/firmware-design.md
index 87bdb88..b99a283 100644
--- a/docs/firmware-design.md
+++ b/docs/firmware-design.md
@@ -718,8 +718,8 @@
 |`CPU_HW_STATE`         | No      |                                           |
 |`SYSTEM_SUSPEND`       | Yes*    |                                           |
 |`PSCI_SET_SUSPEND_MODE`| No      |                                           |
-|`PSCI_STAT_RESIDENCY`  | No      |                                           |
-|`PSCI_STAT_COUNT`      | No      |                                           |
+|`PSCI_STAT_RESIDENCY`  | Yes*    |                                           |
+|`PSCI_STAT_COUNT`      | Yes*    |                                           |
 
 *Note : These PSCI APIs require platform power management hooks to be
 registered with the generic PSCI code to be supported.
@@ -1052,10 +1052,10 @@
 All PROGBITS sections are grouped together at the beginning of the image,
 followed by all NOBITS sections. This is true for all Trusted Firmware images
 and it is governed by the linker scripts. This ensures that the raw binary
-images are as small as possible. If a NOBITS section would sneak in between
-PROGBITS sections then the resulting binary file would contain a bunch of zero
-bytes at the location of this NOBITS section, making the image unnecessarily
-bigger. Smaller images allow faster loading from the FIP to the main memory.
+images are as small as possible. If a NOBITS section was inserted in between
+PROGBITS sections then the resulting binary file would contain zero bytes in
+place of this NOBITS section, making the image unnecessarily bigger. Smaller
+images allow faster loading from the FIP to the main memory.
 
 ### Linker scripts and symbols
 
@@ -1110,47 +1110,48 @@
 
 #### Common linker symbols
 
-Early setup code needs to know the extents of the BSS section to zero-initialise
-it before executing any C code. The following linker symbols are defined for
-this purpose:
+All BL images share the following requirements:
 
-* `__BSS_START__` This address must be aligned on a 16-byte boundary.
-* `__BSS_SIZE__`
+*   The BSS section must be zero-initialised before executing any C code.
+*   The coherent memory section (if enabled) must be zero-initialised as well.
+*   The MMU setup code needs to know the extents of the coherent and read-only
+    memory regions to set the right memory attributes. When
+    `SEPARATE_CODE_AND_RODATA=1`, it needs to know more specifically how the
+    read-only memory region is divided between code and data.
 
-Similarly, the coherent memory section (if enabled) must be zero-initialised.
-Also, the MMU setup code needs to know the extents of this section to set the
-right memory attributes for it. The following linker symbols are defined for
-this purpose:
+The following linker symbols are defined for this purpose:
 
-* `__COHERENT_RAM_START__` This address must be aligned on a page-size boundary.
-* `__COHERENT_RAM_END__` This address must be aligned on a page-size boundary.
-* `__COHERENT_RAM_UNALIGNED_SIZE__`
+*   `__BSS_START__`          Must be aligned on a 16-byte boundary.
+*   `__BSS_SIZE__`
+*   `__COHERENT_RAM_START__` Must be aligned on a page-size boundary.
+*   `__COHERENT_RAM_END__`   Must be aligned on a page-size boundary.
+*   `__COHERENT_RAM_UNALIGNED_SIZE__`
+*   `__RO_START__`
+*   `__RO_END__`
+*   `__TEXT_START__`
+*   `__TEXT_END__`
+*   `__RODATA_START__`
+*   `__RODATA_END__`
 
 #### BL1's linker symbols
 
-BL1's early setup code needs to know the extents of the .data section to
-relocate it from ROM to RAM before executing any C code. The following linker
-symbols are defined for this purpose:
+BL1 being the ROM image, it has additional requirements. BL1 resides in ROM and
+it is entirely executed in place but it needs some read-write memory for its
+mutable data. Its `.data` section (i.e. its allocated read-write data) must be
+relocated from ROM to RAM before executing any C code.
 
-* `__DATA_ROM_START__` This address must be aligned on a 16-byte boundary.
-* `__DATA_RAM_START__` This address must be aligned on a 16-byte boundary.
-* `__DATA_SIZE__`
+The following additional linker symbols are defined for BL1:
 
-BL1's platform setup code needs to know the extents of its read-write data
-region to figure out its memory layout. The following linker symbols are defined
-for this purpose:
-
-* `__BL1_RAM_START__` This is the start address of BL1 RW data.
-* `__BL1_RAM_END__` This is the end address of BL1 RW data.
-
-#### BL2's, BL31's and TSP's linker symbols
-
-BL2, BL31 and TSP need to know the extents of their read-only section to set
-the right memory attributes for this memory region in their MMU setup code. The
-following linker symbols are defined for this purpose:
+*   `__BL1_ROM_END__`    End address of BL1's ROM contents, covering its code
+                         and `.data` section in ROM.
+*   `__DATA_ROM_START__` Start address of the `.data` section in ROM. Must be
+                         aligned on a 16-byte boundary.
+*   `__DATA_RAM_START__` Address in RAM where the `.data` section should be
+                         copied over. Must be aligned on a 16-byte boundary.
+*   `__DATA_SIZE__`      Size of the `.data` section (in ROM or RAM).
+*   `__BL1_RAM_START__`  Start address of BL1 read-write data.
+*   `__BL1_RAM_END__`    End address of BL1 read-write data.
 
-* `__RO_START__`
-* `__RO_END__`
 
 ### How to choose the right base addresses for each bootloader stage image
 
diff --git a/docs/plat/xilinx-zynqmp.md b/docs/plat/xilinx-zynqmp.md
index 997d9a9..09546b0 100644
--- a/docs/plat/xilinx-zynqmp.md
+++ b/docs/plat/xilinx-zynqmp.md
@@ -21,14 +21,21 @@
 ```
 
 # ZynqMP platform specific build options
-*   `ZYNQMP_ATF_LOCATION`: Specifies the location of the bl31 binary. Options:
-    -   `tsram` : bl31 will be located in OCM (default)
-    -   `tdram` : bl31 will be located in DRAM (address: 0x30000000)
+*   `ZYNQMP_ATF_MEM_BASE`: Specifies the base address of the bl31 binary.
+*   `ZYNQMP_ATF_MEM_SIZE`: Specifies the size of the memory region of the bl31 binary.
+*   `ZYNQMP_BL32_MEM_BASE`: Specifies the base address of the bl32 binary.
+*   `ZYNQMP_BL32_MEM_SIZE`: Specifies the size of the memory region of the bl32 binary.
+
+*   `ZYNQMP_CONSOLE`: Select the console driver. Options:
+    -   `cadence`, `cadence0`: Cadence UART 0
+    -   `cadence1`           : Cadence UART 1
 
-*   `ZYNQMP_TSP_RAM_LOCATION`: Specifies the location of the bl32 binary and
-    secure payload dispatcher. Options:
-    -   `tsram` : bl32/spd will be located in OCM (default)
-    -   `tdram` : bl32/spd will be located in DRAM (address: 0x30000000)
+# FSBL->ATF Parameter Passing
+The FSBL populates a data structure with image information for the ATF. The ATF
+uses that data to hand off to the loaded images. The address of the handoff data
+structure is passed in the ```PMU_GLOBAL.GLOBAL_GEN_STORAGE6``` register. The
+register is free to be used by other software once the ATF is bringing up
+further firmware images.
 
 # Power Domain Tree
 The following power domain tree represents the power domain model used by the
diff --git a/docs/porting-guide.md b/docs/porting-guide.md
index 759761e..23033d5 100644
--- a/docs/porting-guide.md
+++ b/docs/porting-guide.md
@@ -189,9 +189,20 @@
     Defines the local power state corresponding to the deepest retention state
     possible at every power domain level in the platform. This macro should be
     a value less than PLAT_MAX_OFF_STATE and greater than 0. It is used by the
-    PSCI implementation to distuiguish between retention and power down local
+    PSCI implementation to distinguish between retention and power down local
     power states within PSCI_CPU_SUSPEND call.
 
+*   **#define : PLAT_MAX_PWR_LVL_STATES**
+
+    Defines the maximum number of local power states per power domain level
+    that the platform supports. The default value of this macro is 2 since
+    most platforms just support a maximum of two local power states at each
+    power domain level (power-down and retention). If the platform needs to
+    account for more local power states, then it must redefine this macro.
+
+    Currently, this macro is used by the Generic PSCI implementation to size
+    the array used for PSCI_STAT_COUNT/RESIDENCY accounting.
+
 *   **#define : BL1_RO_BASE**
 
     Defines the base address in secure ROM where BL1 originally lives. Must be
@@ -1792,6 +1803,34 @@
 `pwr_domain_suspend()` will be invoked with the coordinated target state to
 enter system suspend.
 
+#### plat_psci_ops.get_pwr_lvl_state_idx()
+
+This is an optional function and, if implemented, is invoked by the PSCI
+implementation to convert the `local_state` (first argument) at a specified
+`pwr_lvl` (second argument) to an index between 0 and
+`PLAT_MAX_PWR_LVL_STATES` - 1. This function is only needed if the platform
+supports more than two local power states at each power domain level, that is
+`PLAT_MAX_PWR_LVL_STATES` is greater than 2, and needs to account for these
+local power states.
+
+#### plat_psci_ops.translate_power_state_by_mpidr()
+
+This is an optional function and, if implemented, verifies the `power_state`
+(second argument) parameter of the PSCI API corresponding to a target power
+domain. The target power domain is identified by using both `MPIDR` (first
+argument) and the power domain level encoded in `power_state`. The power domain
+level specific local states are to be extracted from `power_state` and be
+populated in the `output_state` (third argument) array.  The functionality
+is similar to the `validate_power_state` function described above and is
+envisaged to be used in case the validity of `power_state` depend on the
+targeted power domain. If the `power_state` is invalid for the targeted power
+domain, the platform must return PSCI_E_INVALID_PARAMS as error. If this
+function is not implemented, then the generic implementation relies on
+`validate_power_state` function to translate the `power_state`.
+
+This function can also be used in case the platform wants to support local
+power state encoding for `power_state` parameter of PSCI_STAT_COUNT/RESIDENCY
+APIs as described in Section 5.18 of [PSCI].
 
 3.6  Interrupt Management framework (in BL31)
 ----------------------------------------------
diff --git a/docs/user-guide.md b/docs/user-guide.md
index 0bdedf9..41a272f 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -408,6 +408,14 @@
 *   `HANDLE_EA_EL3_FIRST`: When defined External Aborts and SError Interrupts
     will be always trapped in EL3 i.e. in BL31 at runtime.
 
+*   `ENABLE_PMF`: Boolean option to enable support for optional Performance
+     Measurement Framework(PMF). Default is 0.
+
+*   `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.
+
 #### ARM development platform specific build options
 
 *   `ARM_TSP_RAM_LOCATION`: location of the TSP binary. Options:
diff --git a/drivers/arm/gic/arm_gic.c b/drivers/arm/gic/arm_gic.c
index ecd5a93..82c5448 100644
--- a/drivers/arm/gic/arm_gic.c
+++ b/drivers/arm/gic/arm_gic.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -205,10 +205,14 @@
 
 	assert(g_irq_sec_ptr);
 	sec_ppi_sgi_mask = 0;
+
+	/* Ensure all SGIs and PPIs are Group0 to begin with */
+	gicd_write_igroupr(g_gicd_base, 0, 0);
+
 	for (index = 0; index < g_num_irqs; index++) {
 		irq_num = g_irq_sec_ptr[index];
 		if (irq_num < MIN_SPI_ID) {
-			/* We have an SGI or a PPI. They are Group0 at reset */
+			/* We have an SGI or a PPI */
 			sec_ppi_sgi_mask |= 1U << irq_num;
 			gicd_set_ipriorityr(g_gicd_base, irq_num,
 				GIC_HIGHEST_SEC_PRIORITY);
diff --git a/include/bl31/services/psci.h b/include/bl31/services/psci.h
index 95e7780..20aa52e 100644
--- a/include/bl31/services/psci.h
+++ b/include/bl31/services/psci.h
@@ -80,6 +80,10 @@
 #define PSCI_FEATURES			0x8400000A
 #define PSCI_SYSTEM_SUSPEND_AARCH32	0x8400000E
 #define PSCI_SYSTEM_SUSPEND_AARCH64	0xc400000E
+#define PSCI_STAT_RESIDENCY_AARCH32	0x84000010
+#define PSCI_STAT_RESIDENCY_AARCH64	0xc4000010
+#define PSCI_STAT_COUNT_AARCH32		0x84000011
+#define PSCI_STAT_COUNT_AARCH64		0xc4000011
 
 /* Macro to help build the psci capabilities bitfield */
 #define define_psci_cap(x)		(1 << (x & 0x1f))
@@ -87,7 +91,11 @@
 /*
  * Number of PSCI calls (above) implemented
  */
+#if ENABLE_PSCI_STAT
+#define PSCI_NUM_CALLS			22
+#else
 #define PSCI_NUM_CALLS			18
+#endif
 
 /*******************************************************************************
  * PSCI Migrate and friends
@@ -274,6 +282,11 @@
 	int (*validate_ns_entrypoint)(uintptr_t ns_entrypoint);
 	void (*get_sys_suspend_power_state)(
 				    psci_power_state_t *req_state);
+	int (*get_pwr_lvl_state_idx)(plat_local_state_t pwr_domain_state,
+				    int pwrlvl);
+	int (*translate_power_state_by_mpidr)(u_register_t mpidr,
+				    unsigned int power_state,
+				    psci_power_state_t *output_state);
 } plat_psci_ops_t;
 
 /*******************************************************************************
diff --git a/include/common/asm_macros.S b/include/common/asm_macros.S
index d4bd11e..bd8bb70 100644
--- a/include/common/asm_macros.S
+++ b/include/common/asm_macros.S
@@ -148,17 +148,33 @@
 #endif
 
 	/*
+	 * Helper assembler macro to count trailing zeros. The output is
+	 * populated in the `TZ_COUNT` symbol.
+	 */
+	.macro count_tz _value, _tz_count
+	.if \_value
+	  count_tz "(\_value >> 1)", "(\_tz_count + 1)"
+	.else
+	  .equ TZ_COUNT, (\_tz_count - 1)
+	.endif
+	.endm
+
+	/*
 	 * This macro declares an array of 1 or more stacks, properly
 	 * aligned and in the requested section
 	 */
-#define STACK_ALIGN	6
+#define DEFAULT_STACK_ALIGN	(1 << 6)   /* In case the caller doesnt provide alignment */
 
-	.macro declare_stack _name, _section, _size, _count
-	.if ((\_size & ((1 << STACK_ALIGN) - 1)) <> 0)
+	.macro declare_stack _name, _section, _size, _count, _align=DEFAULT_STACK_ALIGN
+	count_tz \_align, 0
+	.if (\_align - (1 << TZ_COUNT))
+	  .error "Incorrect stack alignment specified (Must be a power of 2)."
+	.endif
+	.if ((\_size & ((1 << TZ_COUNT) - 1)) <> 0)
 	  .error "Stack size not correctly aligned"
 	.endif
 	.section    \_section, "aw", %nobits
-	.align STACK_ALIGN
+	.align TZ_COUNT
 	\_name:
 	.space ((\_count) * (\_size)), 0
 	.endm
diff --git a/include/common/bl_common.h b/include/common/bl_common.h
index f13dc31..646a817 100644
--- a/include/common/bl_common.h
+++ b/include/common/bl_common.h
@@ -137,15 +137,22 @@
 #include <cassert.h>
 #include <stdint.h>
 #include <stddef.h>
-
-#define ARRAY_SIZE(a)	(sizeof(a) / sizeof((a)[0]))
+#include <utils.h> /* To retain compatibility */
 
 /*
  * Declarations of linker defined symbols to help determine memory layout of
  * BL images
  */
+#if SEPARATE_CODE_AND_RODATA
+extern unsigned long __TEXT_START__;
+extern unsigned long __TEXT_END__;
+extern unsigned long __RODATA_START__;
+extern unsigned long __RODATA_END__;
+#else
 extern unsigned long __RO_START__;
 extern unsigned long __RO_END__;
+#endif
+
 #if IMAGE_BL2
 extern unsigned long __BL2_END__;
 #elif IMAGE_BL2U
diff --git a/include/lib/cpus/aarch64/cortex_a53.h b/include/lib/cpus/aarch64/cortex_a53.h
index 169d8f4..6976b80 100644
--- a/include/lib/cpus/aarch64/cortex_a53.h
+++ b/include/lib/cpus/aarch64/cortex_a53.h
@@ -57,6 +57,11 @@
 #define CPUECTLR_FPU_RET_CTRL_MASK	(0x7 << CPUECTLR_FPU_RET_CTRL_SHIFT)
 
 /*******************************************************************************
+ * CPU Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CPUMERRSR_EL1			S3_1_C15_C2_2	/* Instruction def. */
+
+/*******************************************************************************
  * CPU Auxiliary Control register specific definitions.
  ******************************************************************************/
 #define CPUACTLR_EL1			S3_1_C15_C2_0	/* Instruction def. */
@@ -79,4 +84,9 @@
 #define L2ECTLR_RET_CTRL_SHIFT		0
 #define L2ECTLR_RET_CTRL_MASK		(0x7 << L2ECTLR_RET_CTRL_SHIFT)
 
+/*******************************************************************************
+ * L2 Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define L2MERRSR_EL1			S3_1_C15_C2_3	/* Instruction def. */
+
 #endif /* __CORTEX_A53_H__ */
diff --git a/include/lib/cpus/aarch64/cortex_a57.h b/include/lib/cpus/aarch64/cortex_a57.h
index ac4ae57..c5a218b 100644
--- a/include/lib/cpus/aarch64/cortex_a57.h
+++ b/include/lib/cpus/aarch64/cortex_a57.h
@@ -57,6 +57,11 @@
 #define CPUECTLR_CPU_RET_CTRL_MASK	(0x7 << CPUECTLR_CPU_RET_CTRL_SHIFT)
 
 /*******************************************************************************
+ * CPU Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CPUMERRSR_EL1			S3_1_C15_C2_2	/* Instruction def. */
+
+/*******************************************************************************
  * CPU Auxiliary Control register specific definitions.
  ******************************************************************************/
 #define CPUACTLR_EL1			S3_1_C15_C2_0	/* Instruction def. */
@@ -90,4 +95,9 @@
 #define L2ECTLR_RET_CTRL_SHIFT		0
 #define L2ECTLR_RET_CTRL_MASK		(0x7 << L2ECTLR_RET_CTRL_SHIFT)
 
+/*******************************************************************************
+ * L2 Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define L2MERRSR_EL1			S3_1_C15_C2_3	/* Instruction def. */
+
 #endif /* __CORTEX_A57_H__ */
diff --git a/include/lib/cpus/aarch64/cortex_a72.h b/include/lib/cpus/aarch64/cortex_a72.h
index fa10ca9..01edf43 100644
--- a/include/lib/cpus/aarch64/cortex_a72.h
+++ b/include/lib/cpus/aarch64/cortex_a72.h
@@ -45,6 +45,11 @@
 #define CPUECTLR_L2_DPFTCH_DIST_MASK	(0x3 << 32)
 
 /*******************************************************************************
+ * CPU Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CPUMERRSR_EL1			S3_1_C15_C2_2	/* Instruction def. */
+
+/*******************************************************************************
  * CPU Auxiliary Control register specific definitions.
  ******************************************************************************/
 #define CPUACTLR_EL1			S3_1_C15_C2_0	/* Instruction def. */
@@ -65,4 +70,9 @@
 #define L2_TAG_RAM_LATENCY_2_CYCLES	0x1
 #define L2_TAG_RAM_LATENCY_3_CYCLES	0x2
 
+/*******************************************************************************
+ * L2 Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define L2MERRSR_EL1			S3_1_C15_C2_3	/* Instruction def. */
+
 #endif /* __CORTEX_A72_H__ */
diff --git a/include/lib/cpus/aarch64/cortex_a73.h b/include/lib/cpus/aarch64/cortex_a73.h
index 2ad0467..13e114a 100644
--- a/include/lib/cpus/aarch64/cortex_a73.h
+++ b/include/lib/cpus/aarch64/cortex_a73.h
@@ -41,4 +41,9 @@
 
 #define CORTEX_A73_CPUECTLR_SMP_BIT	(1 << 6)
 
+/*******************************************************************************
+ * L2 Memory Error Syndrome register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A73_L2MERRSR_EL1		S3_1_C15_C2_3   /* Instruction def. */
+
 #endif /* __CORTEX_A73_H__ */
diff --git a/include/lib/pmf.h b/include/lib/pmf.h
new file mode 100644
index 0000000..5f953b5
--- /dev/null
+++ b/include/lib/pmf.h
@@ -0,0 +1,199 @@
+/*
+ * 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 __PMF_H__
+#define __PMF_H__
+
+#include <cassert.h>
+#include <pmf_helpers.h>
+
+/*
+ * Constants used for/by PMF services.
+ */
+#define PMF_ARM_TIF_IMPL_ID	(0x41000000)
+#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)
+
+/*
+ * Flags passed to PMF_REGISTER_SERVICE
+ */
+#define PMF_STORE_ENABLE	(1 << 0)
+#define PMF_DUMP_ENABLE		(1 << 1)
+
+/*
+ * Flags passed to PMF_GET_TIMESTAMP_XXX
+ * and PMF_CAPTURE_TIMESTAMP
+ */
+#define PMF_CACHE_MAINT		(1 << 0)
+#define PMF_NO_CACHE_MAINT	0
+
+/*
+ * Defines for PMF SMC function ids.
+ */
+#define PMF_SMC_GET_TIMESTAMP_32	0x82000010
+#define PMF_SMC_GET_TIMESTAMP_64	0xC2000010
+#define PMF_NUM_SMC_CALLS		2
+
+/*
+ * The macros below are used to identify
+ * PMF calls from the SMC function ID.
+ */
+#define PMF_FID_MASK	0xffe0u
+#define PMF_FID_VALUE	0u
+#define is_pmf_fid(_fid)	(((_fid) & PMF_FID_MASK) == PMF_FID_VALUE)
+
+/* Following are the supported PMF service IDs */
+#define PMF_PSCI_STAT_SVC_ID	0
+
+#if ENABLE_PMF
+/*
+ * Convenience macros for capturing time-stamp.
+ */
+#define PMF_DECLARE_CAPTURE_TIMESTAMP(_name)			\
+	void pmf_capture_timestamp_with_cache_maint_ ## _name(	\
+				unsigned int tid,		\
+				unsigned long long ts);		\
+	void pmf_capture_timestamp_ ## _name(			\
+				unsigned int tid,		\
+				unsigned long long ts);
+
+#define PMF_CAPTURE_TIMESTAMP(_name, _tid, _flags)			\
+	do {								\
+		unsigned long long ts = read_cntpct_el0();		\
+		if ((_flags) & PMF_CACHE_MAINT)				\
+			pmf_capture_timestamp_with_cache_maint_ ## _name((_tid), ts);\
+		else							\
+			pmf_capture_timestamp_ ## _name((_tid), ts);	\
+	} while (0)
+
+#define PMF_CAPTURE_AND_GET_TIMESTAMP(_name, _tid, _flags, _tsval)	\
+	do {								\
+		(_tsval) = read_cntpct_el0();				\
+		CASSERT(sizeof(_tsval) == sizeof(unsigned long long), invalid_tsval_size);\
+		if ((_flags) & PMF_CACHE_MAINT)				\
+			pmf_capture_timestamp_with_cache_maint_ ## _name((_tid), (_tsval));\
+		else							\
+			pmf_capture_timestamp_ ## _name((_tid), (_tsval));\
+	} while (0)
+
+#define PMF_WRITE_TIMESTAMP(_name, _tid, _flags, _wrval)		\
+	do {								\
+		CASSERT(sizeof(_wrval) == sizeof(unsigned long long), invalid_wrval_size);\
+		if ((_flags) & PMF_CACHE_MAINT)				\
+			pmf_capture_timestamp_with_cache_maint_ ## _name((_tid), (_wrval));\
+		else							\
+			pmf_capture_timestamp_ ## _name((_tid), (_wrval));\
+	} while (0)
+
+/*
+ * Convenience macros for retrieving time-stamp.
+ */
+#define PMF_DECLARE_GET_TIMESTAMP(_name)			\
+	unsigned long long pmf_get_timestamp_by_index_ ## _name(\
+		unsigned int tid,				\
+		unsigned int cpuid,				\
+		unsigned int flags);				\
+	unsigned long long pmf_get_timestamp_by_mpidr_ ## _name(\
+		unsigned int tid,				\
+		u_register_t mpidr,				\
+		unsigned int flags);
+
+#define PMF_GET_TIMESTAMP_BY_MPIDR(_name, _tid, _mpidr, _flags, _tsval)\
+	_tsval = pmf_get_timestamp_by_mpidr_ ## _name(_tid, _mpidr, _flags)
+
+#define PMF_GET_TIMESTAMP_BY_INDEX(_name, _tid, _cpuid, _flags, _tsval)\
+	_tsval = pmf_get_timestamp_by_index_ ## _name(_tid, _cpuid, _flags)
+
+/* Convenience macros to register a PMF service.*/
+/*
+ * This macro is used to register a PMF Service. It allocates PMF memory
+ * and defines default service-specific PMF functions.
+ */
+#define PMF_REGISTER_SERVICE(_name, _svcid, _totalid, _flags)	\
+	PMF_ALLOCATE_TIMESTAMP_MEMORY(_name, _totalid)		\
+	PMF_DEFINE_CAPTURE_TIMESTAMP(_name, _flags)		\
+	PMF_DEFINE_GET_TIMESTAMP(_name)
+
+/*
+ * This macro is used to register a PMF service, including an
+ * SMC interface to that service.
+ */
+#define PMF_REGISTER_SERVICE_SMC(_name, _svcid, _totalid, _flags)\
+	PMF_REGISTER_SERVICE(_name, _svcid, _totalid, _flags)	\
+	PMF_DEFINE_SERVICE_DESC(_name, PMF_ARM_TIF_IMPL_ID,	\
+			_svcid, _totalid, NULL,			\
+			pmf_get_timestamp_by_mpidr_ ## _name)
+
+/*
+ * This macro is used to register a PMF service that has an SMC interface
+ * but provides its own service-specific PMF functions.
+ */
+#define PMF_REGISTER_SERVICE_SMC_OWN(_name, _implid, _svcid, _totalid,	\
+		 _init, _getts)						\
+	PMF_DEFINE_SERVICE_DESC(_name, _implid, _svcid, _totalid,	\
+		 _init, _getts)
+
+#else
+
+#define PMF_REGISTER_SERVICE(_name, _svcid, _totalid, _flags)
+#define PMF_REGISTER_SERVICE_SMC(_name, _svcid, _totalid, _flags)
+#define PMF_REGISTER_SERVICE_SMC_OWN(_name, _implid, _svcid, _totalid,	\
+				_init, _getts)
+#define PMF_DECLARE_CAPTURE_TIMESTAMP(_name)
+#define PMF_DECLARE_GET_TIMESTAMP(_name)
+#define PMF_CAPTURE_TIMESTAMP(_name, _tid, _flags)
+#define PMF_GET_TIMESTAMP_BY_MPIDR(_name, _tid, _mpidr, _flags, _tsval)
+#define PMF_GET_TIMESTAMP_BY_INDEX(_name, _tid, _cpuid, _flags, _tsval)
+
+#endif /* ENABLE_PMF */
+
+/*******************************************************************************
+ * Function & variable prototypes
+ ******************************************************************************/
+/* PMF common functions */
+int pmf_get_timestamp_smc(unsigned int tid,
+		u_register_t mpidr,
+		unsigned int flags,
+		unsigned long long *ts);
+int pmf_setup(void);
+uintptr_t pmf_smc_handler(unsigned int smc_fid,
+		u_register_t x1,
+		u_register_t x2,
+		u_register_t x3,
+		u_register_t x4,
+		void *cookie,
+		void *handle,
+		u_register_t flags);
+
+#endif /* __PMF_H__ */
diff --git a/include/lib/pmf_helpers.h b/include/lib/pmf_helpers.h
new file mode 100644
index 0000000..1b8c507
--- /dev/null
+++ b/include/lib/pmf_helpers.h
@@ -0,0 +1,166 @@
+/*
+ * 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 __PMF_HELPERS_H__
+#define __PMF_HELPERS_H__
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <platform.h>
+#include <pmf.h>
+#include <stdint.h>
+#include <stddef.h>
+
+/*
+ * Prototype for PMF service functions.
+ */
+typedef int (*pmf_svc_init_t)(void);
+typedef unsigned long long (*pmf_svc_get_ts_t)(unsigned int tid,
+		 u_register_t mpidr,
+		 unsigned int flags);
+
+/*
+ * This is the definition of PMF service desc.
+ */
+typedef struct pmf_svc_desc {
+	/* Structure version information */
+	param_header_t h;
+
+	/* Name of the PMF service */
+	const char *name;
+
+	/* PMF service config: Implementer id, Service id and total id*/
+	unsigned int svc_config;
+
+	/* PMF service initialization handler */
+	pmf_svc_init_t init;
+
+	/* PMF service time-stamp retrieval handler */
+	pmf_svc_get_ts_t get_ts;
+} pmf_svc_desc_t;
+
+/*
+ * Convenience macro to allocate memory for a PMF service.
+ */
+#define PMF_ALLOCATE_TIMESTAMP_MEMORY(_name, _total_id)			\
+	static unsigned long long pmf_ts_mem_ ## _name[_total_id]	\
+	__section("pmf_timestamp_array") __used;
+
+/*
+ * Convenience macro to validate tid index for the given TS array.
+ */
+#define PMF_VALIDATE_TID(_name, _tid)	\
+	assert((_tid & PMF_TID_MASK) < (ARRAY_SIZE(pmf_ts_mem_ ## _name)))
+
+/*
+ * Convenience macros for capturing time-stamp.
+ */
+#define PMF_DEFINE_CAPTURE_TIMESTAMP(_name, _flags)			\
+	void pmf_capture_timestamp_ ## _name(				\
+			unsigned int tid,				\
+			unsigned long long ts)				\
+	{								\
+		CASSERT(_flags, select_proper_config);			\
+		PMF_VALIDATE_TID(_name, tid);				\
+		uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name;	\
+		if ((_flags) & PMF_STORE_ENABLE)			\
+			__pmf_store_timestamp(base_addr, tid, ts);	\
+		if ((_flags) & PMF_DUMP_ENABLE)				\
+			__pmf_dump_timestamp(tid, ts);			\
+	}								\
+	void pmf_capture_timestamp_with_cache_maint_ ## _name(		\
+			unsigned int tid,				\
+			unsigned long long ts)				\
+	{								\
+		CASSERT(_flags, select_proper_config);			\
+		PMF_VALIDATE_TID(_name, tid);				\
+		uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name;	\
+		if ((_flags) & PMF_STORE_ENABLE)			\
+			__pmf_store_timestamp_with_cache_maint(base_addr, tid, ts);\
+		if ((_flags) & PMF_DUMP_ENABLE)				\
+			__pmf_dump_timestamp(tid, ts);			\
+	}
+
+/*
+ * Convenience macros for retrieving time-stamp.
+ */
+#define PMF_DEFINE_GET_TIMESTAMP(_name)					\
+	unsigned long long pmf_get_timestamp_by_index_ ## _name(	\
+		unsigned int tid, unsigned int cpuid, unsigned int flags)\
+	{								\
+		PMF_VALIDATE_TID(_name, tid);				\
+		uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name;	\
+		return __pmf_get_timestamp(base_addr, tid, cpuid, flags);\
+	}								\
+	unsigned long long pmf_get_timestamp_by_mpidr_ ## _name(	\
+		unsigned int tid, u_register_t mpidr, unsigned int flags)\
+	{								\
+		PMF_VALIDATE_TID(_name, tid);				\
+		uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name;	\
+		return __pmf_get_timestamp(base_addr, tid,		\
+			plat_core_pos_by_mpidr(mpidr), flags);		\
+	}
+
+/*
+ * Convenience macro to register a PMF service.
+ * This is needed for services that require SMC handling.
+ */
+#define PMF_DEFINE_SERVICE_DESC(_name, _implid, _svcid, _totalid,	\
+		_init, _getts_by_mpidr) 				\
+	static const pmf_svc_desc_t __pmf_desc_ ## _name 		\
+	__section("pmf_svc_descs") __used = {		 		\
+		.h.type = PARAM_EP, 					\
+		.h.version = VERSION_1, 				\
+		.h.size = sizeof(pmf_svc_desc_t),			\
+		.h.attr = 0,						\
+		.name = #_name, 					\
+		.svc_config = ((((_implid) << PMF_IMPL_ID_SHIFT) &	\
+						PMF_IMPL_ID_MASK) |	\
+				(((_svcid) << PMF_SVC_ID_SHIFT) &	\
+						PMF_SVC_ID_MASK) |	\
+				(((_totalid) << PMF_TID_SHIFT) &	\
+						PMF_TID_MASK)),		\
+		.init = _init,						\
+		.get_ts = _getts_by_mpidr				\
+	};
+
+/* PMF internal functions */
+void __pmf_dump_timestamp(unsigned int tid, unsigned long long ts);
+void __pmf_store_timestamp(uintptr_t base_addr,
+		unsigned int tid,
+		unsigned long long ts);
+void __pmf_store_timestamp_with_cache_maint(uintptr_t base_addr,
+		unsigned int tid,
+		unsigned long long ts);
+unsigned long long __pmf_get_timestamp(uintptr_t base_addr,
+		unsigned int tid,
+		unsigned int cpuid,
+		unsigned int flags);
+#endif /* __PMF_HELPERS_H__ */
diff --git a/include/lib/utils.h b/include/lib/utils.h
new file mode 100644
index 0000000..9cc5468
--- /dev/null
+++ b/include/lib/utils.h
@@ -0,0 +1,58 @@
+/*
+ * 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 __UTILS_H__
+#define __UTILS_H__
+
+/* Compute the number of elements in the given array */
+#define ARRAY_SIZE(a)				\
+	(sizeof(a) / sizeof((a)[0]))
+
+#define IS_POWER_OF_TWO(x)			\
+	(((x) & ((x) - 1)) == 0)
+
+/*
+ * The round_up() macro rounds up a value to the given boundary in a
+ * type-agnostic yet type-safe manner. The boundary must be a power of two.
+ * In other words, it computes the smallest multiple of boundary which is
+ * greater than or equal to value.
+ *
+ * round_down() is similar but rounds the value down instead.
+ */
+#define round_boundary(value, boundary)		\
+	((__typeof__(value))((boundary) - 1))
+
+#define round_up(value, boundary)		\
+	((((value) - 1) | round_boundary(value, boundary)) + 1)
+
+#define round_down(value, boundary)		\
+	((value) & ~round_boundary(value, boundary))
+
+#endif /* __UTILS_H__ */
diff --git a/include/lib/xlat_tables.h b/include/lib/xlat_tables.h
index 7d57521..b51a1de 100644
--- a/include/lib/xlat_tables.h
+++ b/include/lib/xlat_tables.h
@@ -134,6 +134,8 @@
 #define MT_PERM_SHIFT	3
 /* Security state (SECURE/NS) */
 #define MT_SEC_SHIFT	4
+/* Access permissions for instruction execution (EXECUTE/EXECUTE_NEVER) */
+#define MT_EXECUTE_SHIFT	5
 
 /*
  * Memory mapping attributes
@@ -155,8 +157,21 @@
 
 	MT_SECURE	= 0 << MT_SEC_SHIFT,
 	MT_NS		= 1 << MT_SEC_SHIFT,
+
+	/*
+	 * Access permissions for instruction execution are only relevant for
+	 * normal read-only memory, i.e. MT_MEMORY | MT_RO. They are ignored
+	 * (and potentially overridden) otherwise:
+	 *  - Device memory is always marked as execute-never.
+	 *  - Read-write normal memory is always marked as execute-never.
+	 */
+	MT_EXECUTE		= 0 << MT_EXECUTE_SHIFT,
+	MT_EXECUTE_NEVER	= 1 << MT_EXECUTE_SHIFT,
 } mmap_attr_t;
 
+#define MT_CODE		(MT_MEMORY | MT_RO | MT_EXECUTE)
+#define MT_RO_DATA	(MT_MEMORY | MT_RO | MT_EXECUTE_NEVER)
+
 /*
  * Structure for specifying a single region of memory.
  */
diff --git a/include/plat/arm/board/common/v2m_def.h b/include/plat/arm/board/common/v2m_def.h
index 888792e..7cee4e8 100644
--- a/include/plat/arm/board/common/v2m_def.h
+++ b/include/plat/arm/board/common/v2m_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:
@@ -119,13 +119,26 @@
 #define V2M_SP810_CTRL_TIM2_SEL		(1 << 19)
 #define V2M_SP810_CTRL_TIM3_SEL		(1 << 21)
 
+/*
+ * The flash can be mapped either as read-only or read-write.
+ *
+ * If it is read-write then it should also be mapped as device memory because
+ * NOR flash programming involves sending a fixed, ordered sequence of commands.
+ *
+ * If it is read-only then it should also be mapped as:
+ * - Normal memory, because reading from NOR flash is transparent, it is like
+ *   reading from RAM.
+ * - Non-executable by default. If some parts of the flash need to be executable
+ *   then platform code is responsible for re-mapping the appropriate portion
+ *   of it as executable.
+ */
 #define V2M_MAP_FLASH0_RW		MAP_REGION_FLAT(V2M_FLASH0_BASE,\
 						V2M_FLASH0_SIZE,	\
 						MT_DEVICE | MT_RW | MT_SECURE)
 
 #define V2M_MAP_FLASH0_RO		MAP_REGION_FLAT(V2M_FLASH0_BASE,\
 						V2M_FLASH0_SIZE,	\
-						MT_MEMORY | MT_RO | MT_SECURE)
+						MT_RO_DATA | MT_SECURE)
 
 #define V2M_MAP_IOFPGA			MAP_REGION_FLAT(V2M_IOFPGA_BASE,\
 						V2M_IOFPGA_SIZE,		\
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index 2fe0a69..06912eb 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -31,10 +31,10 @@
 #define __PLAT_ARM_H__
 
 #include <bakery_lock.h>
-#include <bl_common.h>
 #include <cassert.h>
 #include <cpu_data.h>
 #include <stdint.h>
+#include <utils.h>
 #include <xlat_tables.h>
 
 #define ARM_CASSERT_MMAP						\
@@ -45,20 +45,12 @@
 /*
  * Utility functions common to ARM standard platforms
  */
-
-void arm_configure_mmu_el1(unsigned long total_base,
-			unsigned long total_size,
-			unsigned long ro_start,
-			unsigned long ro_limit
-#if USE_COHERENT_MEM
-			, unsigned long coh_start,
-			unsigned long coh_limit
-#endif
-);
-void arm_configure_mmu_el3(unsigned long total_base,
+void arm_setup_page_tables(unsigned long total_base,
 			unsigned long total_size,
-			unsigned long ro_start,
-			unsigned long ro_limit
+			unsigned long code_start,
+			unsigned long code_limit,
+			unsigned long rodata_start,
+			unsigned long rodata_limit
 #if USE_COHERENT_MEM
 			, unsigned long coh_start,
 			unsigned long coh_limit
diff --git a/include/plat/common/common_def.h b/include/plat/common/common_def.h
index 9fac9fa..d6b7772 100644
--- a/include/plat/common/common_def.h
+++ b/include/plat/common/common_def.h
@@ -80,5 +80,44 @@
 	.ep_info.pc = BL2_BASE,				\
 }
 
-#endif /* __COMMON_DEF_H__ */
+/*
+ * The following constants identify the extents of the code & read-only data
+ * regions. These addresses are used by the MMU setup code and therefore they
+ * must be page-aligned.
+ *
+ * When the code and read-only data are mapped as a single atomic section
+ * (i.e. when SEPARATE_CODE_AND_RODATA=0) then we treat the whole section as
+ * code by specifying the read-only data section as empty.
+ *
+ * BL1 is different than the other images in the sense that its read-write data
+ * originally lives in Trusted ROM and needs to be relocated in Trusted SRAM at
+ * run-time. Therefore, the read-write data in ROM can be mapped with the same
+ * memory attributes as the read-only data region. For this reason, BL1 uses
+ * different macros.
+ *
+ * Note that BL1_ROM_END is not necessarily aligned on a page boundary as it
+ * just points to the end of BL1's actual content in Trusted ROM. Therefore it
+ * needs to be rounded up to the next page size in order to map the whole last
+ * page of it with the right memory attributes.
+ */
+#if SEPARATE_CODE_AND_RODATA
+#define BL_CODE_BASE		(unsigned long)(&__TEXT_START__)
+#define BL_CODE_LIMIT		(unsigned long)(&__TEXT_END__)
+#define BL_RO_DATA_BASE		(unsigned long)(&__RODATA_START__)
+#define BL_RO_DATA_LIMIT	(unsigned long)(&__RODATA_END__)
+
+#define BL1_CODE_LIMIT		BL_CODE_LIMIT
+#define BL1_RO_DATA_BASE	(unsigned long)(&__RODATA_START__)
+#define BL1_RO_DATA_LIMIT	round_up(BL1_ROM_END, PAGE_SIZE)
+#else
+#define BL_CODE_BASE		(unsigned long)(&__RO_START__)
+#define BL_CODE_LIMIT		(unsigned long)(&__RO_END__)
+#define BL_RO_DATA_BASE		0
+#define BL_RO_DATA_LIMIT	0
 
+#define BL1_CODE_LIMIT		round_up(BL1_ROM_END, PAGE_SIZE)
+#define BL1_RO_DATA_BASE	0
+#define BL1_RO_DATA_LIMIT	0
+#endif /* SEPARATE_CODE_AND_RODATA */
+
+#endif /* __COMMON_DEF_H__ */
diff --git a/lib/cpus/aarch64/cortex_a53.S b/lib/cpus/aarch64/cortex_a53.S
index bb56516..ed546e7 100644
--- a/lib/cpus/aarch64/cortex_a53.S
+++ b/lib/cpus/aarch64/cortex_a53.S
@@ -234,11 +234,13 @@
 	 */
 .section .rodata.cortex_a53_regs, "aS"
 cortex_a53_regs:  /* The ascii list of register names to be reported */
-	.asciz	"cpuectlr_el1", ""
+	.asciz	"cpuectlr_el1", "cpumerrsr_el1", "l2merrsr_el1", ""
 
 func cortex_a53_cpu_reg_dump
 	adr	x6, cortex_a53_regs
 	mrs	x8, CPUECTLR_EL1
+	mrs	x9, CPUMERRSR_EL1
+	mrs	x10, L2MERRSR_EL1
 	ret
 endfunc cortex_a53_cpu_reg_dump
 
diff --git a/lib/cpus/aarch64/cortex_a57.S b/lib/cpus/aarch64/cortex_a57.S
index 60929a0..d6b181d 100644
--- a/lib/cpus/aarch64/cortex_a57.S
+++ b/lib/cpus/aarch64/cortex_a57.S
@@ -477,11 +477,13 @@
 	 */
 .section .rodata.cortex_a57_regs, "aS"
 cortex_a57_regs:  /* The ascii list of register names to be reported */
-	.asciz	"cpuectlr_el1", ""
+	.asciz	"cpuectlr_el1", "cpumerrsr_el1", "l2merrsr_el1", ""
 
 func cortex_a57_cpu_reg_dump
 	adr	x6, cortex_a57_regs
 	mrs	x8, CPUECTLR_EL1
+	mrs	x9, CPUMERRSR_EL1
+	mrs	x10, L2MERRSR_EL1
 	ret
 endfunc cortex_a57_cpu_reg_dump
 
diff --git a/lib/cpus/aarch64/cortex_a72.S b/lib/cpus/aarch64/cortex_a72.S
index eb37f2c..9f04fb7 100644
--- a/lib/cpus/aarch64/cortex_a72.S
+++ b/lib/cpus/aarch64/cortex_a72.S
@@ -231,11 +231,13 @@
 	 */
 .section .rodata.cortex_a72_regs, "aS"
 cortex_a72_regs:  /* The ascii list of register names to be reported */
-	.asciz	"cpuectlr_el1", ""
+	.asciz	"cpuectlr_el1", "cpumerrsr_el1", "l2merrsr_el1", ""
 
 func cortex_a72_cpu_reg_dump
 	adr	x6, cortex_a72_regs
 	mrs	x8, CPUECTLR_EL1
+	mrs	x9, CPUMERRSR_EL1
+	mrs	x10, L2MERRSR_EL1
 	ret
 endfunc cortex_a72_cpu_reg_dump
 
diff --git a/lib/cpus/aarch64/cortex_a73.S b/lib/cpus/aarch64/cortex_a73.S
index 70b4c6a..e1615db 100644
--- a/lib/cpus/aarch64/cortex_a73.S
+++ b/lib/cpus/aarch64/cortex_a73.S
@@ -144,11 +144,12 @@
 	 */
 .section .rodata.cortex_a73_regs, "aS"
 cortex_a73_regs:  /* The ascii list of register names to be reported */
-	.asciz	"cpuectlr_el1", ""
+	.asciz	"cpuectlr_el1", "l2merrsr_el1", ""
 
 func cortex_a73_cpu_reg_dump
 	adr	x6, cortex_a73_regs
 	mrs	x8, CORTEX_A73_CPUECTLR_EL1
+	mrs	x9, CORTEX_A73_L2MERRSR_EL1
 	ret
 endfunc cortex_a73_cpu_reg_dump
 
diff --git a/lib/pmf/pmf_main.c b/lib/pmf/pmf_main.c
new file mode 100644
index 0000000..7ce1a9d
--- /dev/null
+++ b/lib/pmf/pmf_main.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <arch.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <platform.h>
+#include <pmf.h>
+#include <string.h>
+
+/*******************************************************************************
+ * The 'pmf_svc_descs' array holds the PMF service descriptors exported by
+ * services by placing them in the 'pmf_svc_descs' linker section.
+ * The 'pmf_svc_descs_indices' array holds the index of a descriptor in the
+ * 'pmf_svc_descs' array. The TIF[15:10] bits in the time-stamp id are used
+ * to get an index into the 'pmf_svc_descs_indices' array. This gives the
+ * index of the descriptor in the 'pmf_svc_descs' array  which contains the
+ * service function pointers.
+ ******************************************************************************/
+extern uintptr_t __PMF_SVC_DESCS_START__;
+extern uintptr_t __PMF_SVC_DESCS_END__;
+#define PMF_SVC_DESCS_START		((uintptr_t)(&__PMF_SVC_DESCS_START__))
+#define PMF_SVC_DESCS_END		((uintptr_t)(&__PMF_SVC_DESCS_END__))
+extern void *__PERCPU_TIMESTAMP_SIZE__;
+#define PMF_PERCPU_TIMESTAMP_SIZE	((uintptr_t)&__PERCPU_TIMESTAMP_SIZE__)
+extern uintptr_t __PMF_TIMESTAMP_START__;
+#define PMF_TIMESTAMP_ARRAY_START	((uintptr_t)&__PMF_TIMESTAMP_START__)
+extern uintptr_t __PMF_TIMESTAMP_END__;
+#define PMF_TIMESTAMP_ARRAY_END		((uintptr_t)&__PMF_TIMESTAMP_END__)
+
+#define PMF_SVC_DESCS_MAX		10
+
+/*
+ * This is used to traverse through registered PMF services.
+ */
+static pmf_svc_desc_t *pmf_svc_descs;
+
+/*
+ * This array is used to store registered PMF services in sorted order.
+ */
+static int pmf_svc_descs_indices[PMF_SVC_DESCS_MAX];
+
+/*
+ * This is used to track total number of successfully registered PMF services.
+ */
+static int pmf_num_services;
+
+/*
+ * This is the main PMF function that initialize registered
+ * PMF services and also sort them in ascending order.
+ */
+int pmf_setup(void)
+{
+	int rc, ii, jj = 0;
+	int pmf_svc_descs_num, temp_val;
+
+	/* If no PMF services are registered then simply bail out */
+	pmf_svc_descs_num = (PMF_SVC_DESCS_END - PMF_SVC_DESCS_START)/
+				 sizeof(pmf_svc_desc_t);
+	if (pmf_svc_descs_num == 0)
+		return 0;
+
+	assert(pmf_svc_descs_num < PMF_SVC_DESCS_MAX);
+
+	pmf_svc_descs = (pmf_svc_desc_t *) PMF_SVC_DESCS_START;
+	for (ii = 0; ii < pmf_svc_descs_num; ii++) {
+
+		assert(pmf_svc_descs[ii].get_ts);
+
+		/*
+		 * Call the initialization routine for this
+		 * PMF service, if it is defined.
+		 */
+		if (pmf_svc_descs[ii].init) {
+			rc = pmf_svc_descs[ii].init();
+			if (rc) {
+				WARN("Could not initialize PMF"
+					"service %s - skipping \n",
+					pmf_svc_descs[ii].name);
+				continue;
+			}
+		}
+
+		/* Update the pmf_svc_descs_indices array */
+		pmf_svc_descs_indices[jj++] = ii;
+	}
+
+	pmf_num_services = jj;
+
+	/*
+	 * Sort the successfully registered PMF services
+	 * according to service ID
+	 */
+	for (ii = 1; ii < pmf_num_services; ii++) {
+		for (jj = 0; jj < (pmf_num_services - ii); jj++) {
+			if ((pmf_svc_descs[jj].svc_config & PMF_SVC_ID_MASK) >
+				(pmf_svc_descs[jj + 1].svc_config &
+						PMF_SVC_ID_MASK)) {
+				temp_val = pmf_svc_descs_indices[jj];
+				pmf_svc_descs_indices[jj] =
+						pmf_svc_descs_indices[jj+1];
+				pmf_svc_descs_indices[jj+1] = temp_val;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This function implements binary search to find registered
+ * PMF service based on Service ID provided in `tid` argument.
+ */
+static pmf_svc_desc_t *get_service(unsigned int tid)
+{
+	int low = 0;
+	int mid;
+	int high = pmf_num_services;
+	unsigned int svc_id = tid & PMF_SVC_ID_MASK;
+	int index;
+	unsigned int desc_svc_id;
+
+	if (pmf_num_services == 0)
+		return NULL;
+
+	assert(pmf_svc_descs);
+
+	do {
+		mid = (low + high) / 2;
+		index = pmf_svc_descs_indices[mid];
+
+		desc_svc_id = pmf_svc_descs[index].svc_config & PMF_SVC_ID_MASK;
+		if (svc_id < desc_svc_id)
+			high = mid - 1;
+		if (svc_id > desc_svc_id)
+			low = mid + 1;
+	} while ((svc_id != desc_svc_id) && (low <= high));
+
+	/*
+	 * Make sure the Service found supports the tid range.
+	 */
+	if ((svc_id == desc_svc_id) && ((tid & PMF_TID_MASK) <
+		(pmf_svc_descs[index].svc_config & PMF_TID_MASK)))
+		return (pmf_svc_desc_t *)&pmf_svc_descs[index];
+
+	return NULL;
+}
+
+/*
+ * This function gets the time-stamp value for the PMF services
+ * registered for SMC interface based on `tid` and `mpidr`.
+ */
+int pmf_get_timestamp_smc(unsigned int tid,
+		u_register_t mpidr,
+		unsigned int flags,
+		unsigned long long *ts_value)
+{
+	pmf_svc_desc_t *svc_desc;
+	assert(ts_value);
+
+	/* Search for registered service. */
+	svc_desc = get_service(tid);
+
+	if ((svc_desc == NULL) || (plat_core_pos_by_mpidr(mpidr) < 0)) {
+		*ts_value = 0;
+		return -EINVAL;
+	} else {
+		/* Call the service time-stamp handler. */
+		*ts_value = svc_desc->get_ts(tid, mpidr, flags);
+		return 0;
+	}
+}
+
+/*
+ * This function can be used to dump `ts` value for given `tid`.
+ * Assumption is that the console is already initialized.
+ */
+void __pmf_dump_timestamp(unsigned int tid, unsigned long long ts)
+{
+	tf_printf("PMF:cpu %u	tid %u	ts %llu\n",
+		plat_my_core_pos(), tid, ts);
+}
+
+/*
+ * This function calculate the address identified by
+ * `base_addr`, `tid` and `cpuid`.
+ */
+static inline uintptr_t calc_ts_addr(uintptr_t base_addr,
+		unsigned int tid,
+		unsigned int cpuid)
+{
+	assert(cpuid < PLATFORM_CORE_COUNT);
+	assert(base_addr >= PMF_TIMESTAMP_ARRAY_START);
+	assert(base_addr < ((PMF_TIMESTAMP_ARRAY_START +
+		PMF_PERCPU_TIMESTAMP_SIZE) - ((tid & PMF_TID_MASK) *
+		sizeof(unsigned long long))));
+
+	base_addr += ((cpuid * PMF_PERCPU_TIMESTAMP_SIZE) +
+		((tid & PMF_TID_MASK) * sizeof(unsigned long long)));
+
+	return base_addr;
+}
+
+/*
+ * This function stores the `ts` value to the storage identified by
+ * `base_addr`, `tid` and current cpu id.
+ * Note: The timestamp addresses are cache line aligned per cpu
+ * and only the owning CPU would ever write into it.
+ */
+void __pmf_store_timestamp(uintptr_t base_addr,
+			unsigned int tid,
+			unsigned long long ts)
+{
+	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
+				 tid, plat_my_core_pos());
+	*ts_addr = ts;
+}
+
+/*
+ * This is the cached version of `pmf_store_my_timestamp`
+ * Note: The timestamp addresses are cache line aligned per cpu
+ * and only the owning CPU would ever write into it.
+ */
+void __pmf_store_timestamp_with_cache_maint(uintptr_t base_addr,
+			unsigned int tid,
+			unsigned long long ts)
+{
+	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
+				 tid, plat_my_core_pos());
+	*ts_addr = ts;
+	flush_dcache_range((uintptr_t)ts_addr, sizeof(unsigned long long));
+}
+
+/*
+ * This function retrieves the `ts` value from the storage identified by
+ * `base_addr`, `tid` and `cpuid`.
+ * Note: The timestamp addresses are cache line aligned per cpu.
+ */
+unsigned long long __pmf_get_timestamp(uintptr_t base_addr,
+			unsigned int tid,
+			unsigned int cpuid,
+			unsigned int flags)
+{
+	assert(cpuid < PLATFORM_CORE_COUNT);
+	unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr,
+				tid, cpuid);
+
+	if (flags & PMF_CACHE_MAINT)
+		inv_dcache_range((uintptr_t)ts_addr, sizeof(unsigned long long));
+
+	return *ts_addr;
+}
diff --git a/lib/pmf/pmf_smc.c b/lib/pmf/pmf_smc.c
new file mode 100644
index 0000000..14190b7
--- /dev/null
+++ b/lib/pmf/pmf_smc.c
@@ -0,0 +1,91 @@
+/*
+ * 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 <assert.h>
+#include <debug.h>
+#include <platform.h>
+#include <pmf.h>
+#include <smcc_helpers.h>
+
+/*
+ * This function is responsible for handling all PMF SMC calls.
+ */
+uintptr_t pmf_smc_handler(unsigned int smc_fid,
+			u_register_t x1,
+			u_register_t x2,
+			u_register_t x3,
+			u_register_t x4,
+			void *cookie,
+			void *handle,
+			u_register_t flags)
+{
+	int rc;
+	unsigned long long ts_value;
+
+	if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {
+
+		x1 = (uint32_t)x1;
+		x2 = (uint32_t)x2;
+		x3 = (uint32_t)x3;
+
+		switch (smc_fid) {
+		case PMF_SMC_GET_TIMESTAMP_32:
+			/*
+			 * Return error code and the captured
+			 * time-stamp to the caller.
+			 * x0 --> error code.
+			 * x1 - x2 --> time-stamp value.
+			 */
+			rc = pmf_get_timestamp_smc(x1, x2, x3, &ts_value);
+			SMC_RET3(handle, rc, (uint32_t)ts_value,
+					(uint32_t)(ts_value >> 32));
+
+		default:
+			break;
+		}
+	} else {
+		switch (smc_fid) {
+		case PMF_SMC_GET_TIMESTAMP_64:
+			/*
+			 * Return error code and the captured
+			 * time-stamp to the caller.
+			 * x0 --> error code.
+			 * x1 --> time-stamp value.
+			 */
+			rc = pmf_get_timestamp_smc(x1, x2, x3, &ts_value);
+			SMC_RET2(handle, rc, ts_value);
+
+		default:
+			break;
+		}
+	}
+
+	WARN("Unimplemented PMF Call: 0x%x \n", smc_fid);
+	SMC_RET1(handle, SMC_UNK);
+}
diff --git a/lib/xlat_tables/aarch64/xlat_tables.c b/lib/xlat_tables/aarch64/xlat_tables.c
index 051e46a..19eb7d5 100644
--- a/lib/xlat_tables/aarch64/xlat_tables.c
+++ b/lib/xlat_tables/aarch64/xlat_tables.c
@@ -33,11 +33,10 @@
 #include <assert.h>
 #include <cassert.h>
 #include <platform_def.h>
+#include <utils.h>
 #include <xlat_tables.h>
 #include "../xlat_tables_private.h"
 
-#define IS_POWER_OF_TWO(x)	(((x) & ((x) - 1)) == 0)
-
 /*
  * The virtual address space size must be a power of two (as set in TCR.T0SZ).
  * As we start the initial lookup at level 1, it must also be between 2 GB and
diff --git a/lib/xlat_tables/xlat_tables_common.c b/lib/xlat_tables/xlat_tables_common.c
index fd10084..71e3efc 100644
--- a/lib/xlat_tables/xlat_tables_common.c
+++ b/lib/xlat_tables/xlat_tables_common.c
@@ -31,11 +31,11 @@
 #include <arch.h>
 #include <arch_helpers.h>
 #include <assert.h>
-#include <bl_common.h>
 #include <cassert.h>
 #include <debug.h>
 #include <platform_def.h>
 #include <string.h>
+#include <utils.h>
 #include <xlat_tables.h>
 
 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE
@@ -194,37 +194,66 @@
 static uint64_t mmap_desc(unsigned attr, unsigned long long addr_pa,
 							int level)
 {
-	uint64_t desc = addr_pa;
+	uint64_t desc;
 	int mem_type;
 
-	desc |= level == 3 ? TABLE_DESC : BLOCK_DESC;
-
-	desc |= attr & MT_NS ? LOWER_ATTRS(NS) : 0;
-
-	desc |= attr & MT_RW ? LOWER_ATTRS(AP_RW) : LOWER_ATTRS(AP_RO);
-
+	desc = addr_pa;
+	desc |= (level == 3) ? TABLE_DESC : BLOCK_DESC;
+	desc |= (attr & MT_NS) ? LOWER_ATTRS(NS) : 0;
+	desc |= (attr & MT_RW) ? LOWER_ATTRS(AP_RW) : LOWER_ATTRS(AP_RO);
 	desc |= LOWER_ATTRS(ACCESS_FLAG);
 
+	/*
+	 * Deduce shareability domain and executability of the memory region
+	 * from the memory type.
+	 *
+	 * Data accesses to device memory and non-cacheable normal memory are
+	 * coherent for all observers in the system, and correspondingly are
+	 * always treated as being Outer Shareable. Therefore, for these 2 types
+	 * of memory, it is not strictly needed to set the shareability field
+	 * in the translation tables.
+	 */
 	mem_type = MT_TYPE(attr);
-	if (mem_type == MT_MEMORY) {
-		desc |= LOWER_ATTRS(ATTR_IWBWA_OWBWA_NTR_INDEX | ISH);
-		if (attr & MT_RW)
-			desc |= UPPER_ATTRS(XN);
-	} else if (mem_type == MT_NON_CACHEABLE) {
-		desc |= LOWER_ATTRS(ATTR_NON_CACHEABLE_INDEX | OSH);
-		if (attr & MT_RW)
-			desc |= UPPER_ATTRS(XN);
-	} else {
-		assert(mem_type == MT_DEVICE);
+	if (mem_type == MT_DEVICE) {
 		desc |= LOWER_ATTRS(ATTR_DEVICE_INDEX | OSH);
+		/*
+		 * Always map device memory as execute-never.
+		 * This is to avoid the possibility of a speculative instruction
+		 * fetch, which could be an issue if this memory region
+		 * corresponds to a read-sensitive peripheral.
+		 */
 		desc |= UPPER_ATTRS(XN);
+	} else { /* Normal memory */
+		/*
+		 * Always map read-write normal memory as execute-never.
+		 * (Trusted Firmware doesn't self-modify its code, therefore
+		 * R/W memory is reserved for data storage, which must not be
+		 * executable.)
+		 * Note that setting the XN bit here is for consistency only.
+		 * The enable_mmu_elx() function sets the SCTLR_EL3.WXN bit,
+		 * which makes any writable memory region to be treated as
+		 * execute-never, regardless of the value of the XN bit in the
+		 * translation table.
+		 *
+		 * For read-only memory, rely on the MT_EXECUTE/MT_EXECUTE_NEVER
+		 * attribute to figure out the value of the XN bit.
+		 */
+		if ((attr & MT_RW) || (attr & MT_EXECUTE_NEVER))
+			desc |= UPPER_ATTRS(XN);
+
+		if (mem_type == MT_MEMORY) {
+			desc |= LOWER_ATTRS(ATTR_IWBWA_OWBWA_NTR_INDEX | ISH);
+		} else {
+			assert(mem_type == MT_NON_CACHEABLE);
+			desc |= LOWER_ATTRS(ATTR_NON_CACHEABLE_INDEX | OSH);
+		}
 	}
 
 	debug_print((mem_type == MT_MEMORY) ? "MEM" :
 		((mem_type == MT_NON_CACHEABLE) ? "NC" : "DEV"));
 	debug_print(attr & MT_RW ? "-RW" : "-RO");
 	debug_print(attr & MT_NS ? "-NS" : "-S");
-
+	debug_print(attr & MT_EXECUTE_NEVER ? "-XN" : "-EXEC");
 	return desc;
 }
 
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
index c963b7a..165e3aa 100644
--- a/make_helpers/build_macros.mk
+++ b/make_helpers/build_macros.mk
@@ -68,6 +68,13 @@
     DEFINES			+=	-D$(1)$(if $(value $(1)),=$(value $(1)),)
 endef
 
+# Convenience function for adding build definitions
+# $(eval $(call add_define_val,FOO,BAR)) will have:
+# -DFOO=BAR
+define add_define_val
+    DEFINES			+=	-D$(1)=$(2)
+endef
+
 # Convenience function for verifying option has a boolean value
 # $(eval $(call assert_boolean,FOO)) will assert FOO is 0 or 1
 define assert_boolean
diff --git a/plat/arm/board/common/board_css_common.c b/plat/arm/board/common/board_css_common.c
index 62253f8..69b744d 100644
--- a/plat/arm/board/common/board_css_common.c
+++ b/plat/arm/board/common/board_css_common.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:
@@ -31,9 +31,9 @@
 #include <plat_arm.h>
 
 /*
- * Table of regions for different BL stages to map using the MMU.
- * This doesn't include Trusted RAM as the 'mem_layout' argument passed to
- * arm_configure_mmu_elx() will give the available subset of that,
+ * Table of memory regions for different BL stages to map using the MMU.
+ * This doesn't include Trusted SRAM as arm_setup_page_tables() already
+ * takes care of mapping it.
  */
 #if IMAGE_BL1
 const mmap_region_t plat_arm_mmap[] = {
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index 0f557af..002cff6 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -66,9 +66,12 @@
 
 
 /*
- * Table of regions for various BL stages to map using the MMU.
- * This doesn't include TZRAM as the 'mem_layout' argument passed to
- * arm_configure_mmu_elx() will give the available subset of that,
+ * Table of memory regions for various BL stages to map using the MMU.
+ * This doesn't include Trusted SRAM as arm_setup_page_tables() already
+ * takes care of mapping it.
+ *
+ * The flash needs to be mapped as writable in order to erase the FIP's Table of
+ * Contents in case of unrecoverable error (see plat_error_handler()).
  */
 #if IMAGE_BL1
 const mmap_region_t plat_arm_mmap[] = {
diff --git a/plat/arm/board/juno/juno_pm.c b/plat/arm/board/juno/juno_pm.c
index 4b956d2..cbf994a 100644
--- a/plat/arm/board/juno/juno_pm.c
+++ b/plat/arm/board/juno/juno_pm.c
@@ -59,6 +59,19 @@
 	return rc;
 }
 
+/*
+ * Custom `translate_power_state_by_mpidr` handler for Juno. Unlike in the
+ * `juno_validate_power_state`, we do not down-grade the system power
+ * domain level request in `power_state` as it will be used to query the
+ * PSCI_STAT_COUNT/RESIDENCY at the system power domain level.
+ */
+static int juno_translate_power_state_by_mpidr(u_register_t mpidr,
+		unsigned int power_state,
+		psci_power_state_t *output_state)
+{
+	return arm_validate_power_state(power_state, output_state);
+}
+
 /*******************************************************************************
  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
  * platform will take care of registering the handlers with PSCI.
@@ -74,5 +87,6 @@
 	.system_reset			= css_system_reset,
 	.validate_power_state		= juno_validate_power_state,
 	.validate_ns_entrypoint		= arm_validate_ns_entrypoint,
-	.get_sys_suspend_power_state	= css_get_sys_suspend_power_state
+	.get_sys_suspend_power_state	= css_get_sys_suspend_power_state,
+	.translate_power_state_by_mpidr = juno_translate_power_state_by_mpidr
 };
diff --git a/plat/arm/common/aarch64/arm_common.c b/plat/arm/common/aarch64/arm_common.c
index c4cc80e..7c0b93d 100644
--- a/plat/arm/common/aarch64/arm_common.c
+++ b/plat/arm/common/aarch64/arm_common.c
@@ -50,57 +50,67 @@
 #pragma weak plat_get_syscnt_freq
 #endif
 
-/*******************************************************************************
- * Macro generating the code for the function setting up the pagetables as per
- * the platform memory map & initialize the mmu, for the given exception level
- ******************************************************************************/
+/*
+ * Set up the page tables for the generic and platform-specific memory regions.
+ * The extents of the generic memory regions are specified by the function
+ * arguments and consist of:
+ * - Trusted SRAM seen by the BL image;
+ * - Code section;
+ * - Read-only data section;
+ * - Coherent memory region, if applicable.
+ */
+void arm_setup_page_tables(unsigned long total_base,
+			   unsigned long total_size,
+			   unsigned long code_start,
+			   unsigned long code_limit,
+			   unsigned long rodata_start,
+			   unsigned long rodata_limit
 #if USE_COHERENT_MEM
-#define DEFINE_CONFIGURE_MMU_EL(_el)					\
-	void arm_configure_mmu_el##_el(unsigned long total_base,	\
-				   unsigned long total_size,		\
-				   unsigned long ro_start,		\
-				   unsigned long ro_limit,		\
-				   unsigned long coh_start,		\
-				   unsigned long coh_limit)		\
-	{								\
-		mmap_add_region(total_base, total_base,			\
-				total_size,				\
-				MT_MEMORY | MT_RW | MT_SECURE);		\
-		mmap_add_region(ro_start, ro_start,			\
-				ro_limit - ro_start,			\
-				MT_MEMORY | MT_RO | MT_SECURE);		\
-		mmap_add_region(coh_start, coh_start,			\
-				coh_limit - coh_start,			\
-				MT_DEVICE | MT_RW | MT_SECURE);		\
-		mmap_add(plat_arm_get_mmap());				\
-		init_xlat_tables();					\
-									\
-		enable_mmu_el##_el(0);					\
-	}
-#else
-#define DEFINE_CONFIGURE_MMU_EL(_el)					\
-	void arm_configure_mmu_el##_el(unsigned long total_base,	\
-				   unsigned long total_size,		\
-				   unsigned long ro_start,		\
-				   unsigned long ro_limit)		\
-	{								\
-		mmap_add_region(total_base, total_base,			\
-				total_size,				\
-				MT_MEMORY | MT_RW | MT_SECURE);		\
-		mmap_add_region(ro_start, ro_start,			\
-				ro_limit - ro_start,			\
-				MT_MEMORY | MT_RO | MT_SECURE);		\
-		mmap_add(plat_arm_get_mmap());				\
-		init_xlat_tables();					\
-									\
-		enable_mmu_el##_el(0);					\
-	}
+			   ,
+			   unsigned long coh_start,
+			   unsigned long coh_limit
 #endif
+			   )
+{
+	/*
+	 * Map the Trusted SRAM with appropriate memory attributes.
+	 * Subsequent mappings will adjust the attributes for specific regions.
+	 */
+	VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n",
+		(void *) total_base, (void *) (total_base + total_size));
+	mmap_add_region(total_base, total_base,
+			total_size,
+			MT_MEMORY | MT_RW | MT_SECURE);
 
-/* Define EL1 and EL3 variants of the function initialising the MMU */
-DEFINE_CONFIGURE_MMU_EL(1)
-DEFINE_CONFIGURE_MMU_EL(3)
+	/* Re-map the code section */
+	VERBOSE("Code region: %p - %p\n",
+		(void *) code_start, (void *) code_limit);
+	mmap_add_region(code_start, code_start,
+			code_limit - code_start,
+			MT_CODE | MT_SECURE);
+
+	/* Re-map the read-only data section */
+	VERBOSE("Read-only data region: %p - %p\n",
+		(void *) rodata_start, (void *) rodata_limit);
+	mmap_add_region(rodata_start, rodata_start,
+			rodata_limit - rodata_start,
+			MT_RO_DATA | MT_SECURE);
+
+#if USE_COHERENT_MEM
+	/* Re-map the coherent memory region */
+	VERBOSE("Coherent region: %p - %p\n",
+		(void *) coh_start, (void *) coh_limit);
+	mmap_add_region(coh_start, coh_start,
+			coh_limit - coh_start,
+			MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+
+	/* Now (re-)map the platform-specific memory regions */
+	mmap_add(plat_arm_get_mmap());
 
+	/* Create the page tables to reflect the above mappings */
+	init_xlat_tables();
+}
 
 uintptr_t plat_get_ns_image_entrypoint(void)
 {
diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c
index 951f48a..c94f0cd 100644
--- a/plat/arm/common/arm_bl1_setup.c
+++ b/plat/arm/common/arm_bl1_setup.c
@@ -35,6 +35,8 @@
 #include <platform_def.h>
 #include <plat_arm.h>
 #include <sp805.h>
+#include <utils.h>
+#include <xlat_tables.h>
 #include "../../../bl1/bl1_private.h"
 
 
@@ -118,15 +120,18 @@
  *****************************************************************************/
 void arm_bl1_plat_arch_setup(void)
 {
-	arm_configure_mmu_el3(bl1_tzram_layout.total_base,
+	arm_setup_page_tables(bl1_tzram_layout.total_base,
 			      bl1_tzram_layout.total_size,
-			      BL1_RO_BASE,
-			      BL1_RO_LIMIT
+			      BL_CODE_BASE,
+			      BL1_CODE_LIMIT,
+			      BL1_RO_DATA_BASE,
+			      BL1_RO_DATA_LIMIT
 #if USE_COHERENT_MEM
 			      , BL1_COHERENT_RAM_BASE,
 			      BL1_COHERENT_RAM_LIMIT
 #endif
 			     );
+	enable_mmu_el3(0);
 }
 
 void bl1_plat_arch_setup(void)
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index 681dc8a..b6afaa7 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -36,16 +36,6 @@
 #include <plat_arm.h>
 #include <string.h>
 
-
-/*
- * The next 2 constants identify the extents of the code & RO data region.
- * These addresses are used by the MMU setup code and therefore they must be
- * page-aligned.  It is the responsibility of the linker script to ensure that
- * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses.
- */
-#define BL2_RO_BASE (unsigned long)(&__RO_START__)
-#define BL2_RO_LIMIT (unsigned long)(&__RO_END__)
-
 #if USE_COHERENT_MEM
 /*
  * The next 2 constants identify the extents of the coherent memory region.
@@ -234,15 +224,18 @@
  ******************************************************************************/
 void arm_bl2_plat_arch_setup(void)
 {
-	arm_configure_mmu_el1(bl2_tzram_layout.total_base,
+	arm_setup_page_tables(bl2_tzram_layout.total_base,
 			      bl2_tzram_layout.total_size,
-			      BL2_RO_BASE,
-			      BL2_RO_LIMIT
+			      BL_CODE_BASE,
+			      BL_CODE_LIMIT,
+			      BL_RO_DATA_BASE,
+			      BL_RO_DATA_LIMIT
 #if USE_COHERENT_MEM
 			      , BL2_COHERENT_RAM_BASE,
 			      BL2_COHERENT_RAM_LIMIT
 #endif
 			      );
+	enable_mmu_el1(0);
 }
 
 void bl2_plat_arch_setup(void)
diff --git a/plat/arm/common/arm_bl2u_setup.c b/plat/arm/common/arm_bl2u_setup.c
index 5b7354b..de7d0c2 100644
--- a/plat/arm/common/arm_bl2u_setup.c
+++ b/plat/arm/common/arm_bl2u_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:
@@ -36,16 +36,6 @@
 #include <plat_arm.h>
 #include <string.h>
 
-
-/*
- * The next 2 constants identify the extents of the code & RO data region.
- * These addresses are used by the MMU setup code and therefore they must be
- * page-aligned.  It is the responsibility of the linker script to ensure that
- * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses.
- */
-#define BL2U_RO_BASE (unsigned long)(&__RO_START__)
-#define BL2U_RO_LIMIT (unsigned long)(&__RO_END__)
-
 #if USE_COHERENT_MEM
 /*
  * The next 2 constants identify the extents of the coherent memory region.
@@ -102,16 +92,19 @@
  ******************************************************************************/
 void arm_bl2u_plat_arch_setup(void)
 {
-	arm_configure_mmu_el1(BL2U_RO_LIMIT,
+	arm_setup_page_tables(BL2U_BASE,
 			      BL31_LIMIT,
-			      BL2U_RO_BASE,
-			      BL2U_RO_LIMIT
+			      BL_CODE_BASE,
+			      BL_CODE_LIMIT,
+			      BL_RO_DATA_BASE,
+			      BL_RO_DATA_LIMIT
 #if USE_COHERENT_MEM
 			      ,
 			      BL2U_COHERENT_RAM_BASE,
 			      BL2U_COHERENT_RAM_LIMIT
 #endif
 		);
+	enable_mmu_el1(0);
 }
 
 void bl2u_plat_arch_setup(void)
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index 8eb6818..87cafce 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -38,16 +38,6 @@
 #include <plat_arm.h>
 #include <platform.h>
 
-
-/*
- * The next 3 constants identify the extents of the code, RO data region and the
- * limit of the BL31 image.  These addresses are used by the MMU setup code and
- * therefore they must be page-aligned.  It is the responsibility of the linker
- * script to ensure that __RO_START__, __RO_END__ & __BL31_END__ linker symbols
- * refer to page-aligned addresses.
- */
-#define BL31_RO_BASE (unsigned long)(&__RO_START__)
-#define BL31_RO_LIMIT (unsigned long)(&__RO_END__)
 #define BL31_END (unsigned long)(&__BL31_END__)
 
 #if USE_COHERENT_MEM
@@ -246,20 +236,25 @@
 }
 
 /*******************************************************************************
- * Perform the very early platform specific architectural setup here. At the
- * moment this is only intializes the mmu in a quick and dirty way.
+ * Perform the very early platform specific architectural setup shared between
+ * ARM standard platforms. This only does basic initialization. Later
+ * architectural setup (bl31_arch_setup()) does not do anything platform
+ * specific.
  ******************************************************************************/
 void arm_bl31_plat_arch_setup(void)
 {
-	arm_configure_mmu_el3(BL31_RO_BASE,
-			      (BL31_END - BL31_RO_BASE),
-			      BL31_RO_BASE,
-			      BL31_RO_LIMIT
+	arm_setup_page_tables(BL31_BASE,
+			      BL31_END - BL31_BASE,
+			      BL_CODE_BASE,
+			      BL_CODE_LIMIT,
+			      BL_RO_DATA_BASE,
+			      BL_RO_DATA_LIMIT
 #if USE_COHERENT_MEM
 			      , BL31_COHERENT_RAM_BASE,
 			      BL31_COHERENT_RAM_LIMIT
 #endif
 			      );
+	enable_mmu_el3(0);
 }
 
 void bl31_plat_arch_setup(void)
diff --git a/plat/arm/common/arm_cci.c b/plat/arm/common/arm_cci.c
index 41054c2..40cfb48 100644
--- a/plat/arm/common/arm_cci.c
+++ b/plat/arm/common/arm_cci.c
@@ -32,6 +32,7 @@
 #include <cci.h>
 #include <plat_arm.h>
 #include <platform_def.h>
+#include <utils.h>
 
 static const int cci_map[] = {
 	PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX,
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 0b28861..9e5ddea 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -82,6 +82,14 @@
 $(eval $(call assert_boolean,ARM_BL31_IN_DRAM))
 $(eval $(call add_define,ARM_BL31_IN_DRAM))
 
+# Enable PSCI_STAT_COUNT/RESIDENCY APIs on ARM platforms
+ENABLE_PSCI_STAT = 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.
+SEPARATE_CODE_AND_RODATA	:=	1
+
+
 PLAT_INCLUDES		+=	-Iinclude/common/tbbr				\
 				-Iinclude/plat/arm/common			\
 				-Iinclude/plat/arm/common/aarch64
diff --git a/plat/arm/common/arm_io_storage.c b/plat/arm/common/arm_io_storage.c
index 153fdfe..42435a7 100644
--- a/plat/arm/common/arm_io_storage.c
+++ b/plat/arm/common/arm_io_storage.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,7 +28,6 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 #include <assert.h>
-#include <bl_common.h>		/* For ARRAY_SIZE */
 #include <debug.h>
 #include <firmware_image_package.h>
 #include <io_driver.h>
@@ -37,6 +36,7 @@
 #include <io_storage.h>
 #include <platform_def.h>
 #include <string.h>
+#include <utils.h>
 
 /* IO devices */
 static const io_dev_connector_t *fip_dev_con;
diff --git a/plat/arm/common/tsp/arm_tsp_setup.c b/plat/arm/common/tsp/arm_tsp_setup.c
index 2a67fd1..09029f4 100644
--- a/plat/arm/common/tsp/arm_tsp_setup.c
+++ b/plat/arm/common/tsp/arm_tsp_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:
@@ -35,16 +35,6 @@
 #include <platform_tsp.h>
 #include <plat_arm.h>
 
-
-/*
- * The next 3 constants identify the extents of the code & RO data region and
- * the limit of the BL32 image. These addresses are used by the MMU setup code
- * and therefore they must be page-aligned.  It is the responsibility of the
- * linker script to ensure that __RO_START__, __RO_END__ & & __BL32_END__
- * linker symbols refer to page-aligned addresses.
- */
-#define BL32_RO_BASE (unsigned long)(&__RO_START__)
-#define BL32_RO_LIMIT (unsigned long)(&__RO_END__)
 #define BL32_END (unsigned long)(&__BL32_END__)
 
 #if USE_COHERENT_MEM
@@ -98,13 +88,16 @@
  ******************************************************************************/
 void tsp_plat_arch_setup(void)
 {
-	arm_configure_mmu_el1(BL32_RO_BASE,
-			      (BL32_END - BL32_RO_BASE),
-			      BL32_RO_BASE,
-			      BL32_RO_LIMIT
+	arm_setup_page_tables(BL32_BASE,
+			      (BL32_END - BL32_BASE),
+			      BL_CODE_BASE,
+			      BL_CODE_LIMIT,
+			      BL_RO_DATA_BASE,
+			      BL_RO_DATA_LIMIT
 #if USE_COHERENT_MEM
 			      , BL32_COHERENT_RAM_BASE,
 			      BL32_COHERENT_RAM_LIMIT
 #endif
 			      );
+	enable_mmu_el1(0);
 }
diff --git a/plat/common/aarch64/platform_mp_stack.S b/plat/common/aarch64/platform_mp_stack.S
index c719019..a077f65 100644
--- a/plat/common/aarch64/platform_mp_stack.S
+++ b/plat/common/aarch64/platform_mp_stack.S
@@ -193,4 +193,5 @@
 	 * -----------------------------------------------------
 	 */
 declare_stack platform_normal_stacks, tzfw_normal_stacks, \
-		PLATFORM_STACK_SIZE, PLATFORM_CORE_COUNT
+		PLATFORM_STACK_SIZE, PLATFORM_CORE_COUNT, \
+		CACHE_WRITEBACK_GRANULE
diff --git a/plat/common/aarch64/platform_up_stack.S b/plat/common/aarch64/platform_up_stack.S
index c01534a..24b3a71 100644
--- a/plat/common/aarch64/platform_up_stack.S
+++ b/plat/common/aarch64/platform_up_stack.S
@@ -99,4 +99,4 @@
 	 * -----------------------------------------------------
 	 */
 declare_stack platform_normal_stacks, tzfw_normal_stacks, \
-		PLATFORM_STACK_SIZE, 1
+		PLATFORM_STACK_SIZE, 1, CACHE_WRITEBACK_GRANULE
diff --git a/plat/mediatek/mt8173/aarch64/platform_common.c b/plat/mediatek/mt8173/aarch64/platform_common.c
index 365df1b..70639ed 100644
--- a/plat/mediatek/mt8173/aarch64/platform_common.c
+++ b/plat/mediatek/mt8173/aarch64/platform_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-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:
@@ -34,6 +34,7 @@
 #include <debug.h>
 #include <mt8173_def.h>
 #include <platform_def.h>
+#include <utils.h>
 #include <xlat_tables.h>
 
 static const int cci_map[] = {
diff --git a/plat/mediatek/mt8173/plat_mt_gic.c b/plat/mediatek/mt8173/plat_mt_gic.c
index c9bdaa9..402a0f4 100644
--- a/plat/mediatek/mt8173/plat_mt_gic.c
+++ b/plat/mediatek/mt8173/plat_mt_gic.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-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,6 +30,7 @@
 #include <arm_gic.h>
 #include <bl_common.h>
 #include <mt8173_def.h>
+#include <utils.h>
 
 const unsigned int mt_irq_sec_array[] = {
 	MT_IRQ_SEC_SGI_0,
diff --git a/plat/rockchip/common/aarch64/platform_common.c b/plat/rockchip/common/aarch64/platform_common.c
index 6e9dab7..40cd29e 100644
--- a/plat/rockchip/common/aarch64/platform_common.c
+++ b/plat/rockchip/common/aarch64/platform_common.c
@@ -37,6 +37,7 @@
 #include <xlat_tables.h>
 #include <platform_def.h>
 #include <plat_private.h>
+#include <utils.h>
 
 #ifdef PLAT_RK_CCI_BASE
 static const int cci_map[] = {
diff --git a/plat/rockchip/common/include/rockchip_sip_svc.h b/plat/rockchip/common/include/rockchip_sip_svc.h
new file mode 100644
index 0000000..9e31082
--- /dev/null
+++ b/plat/rockchip/common/include/rockchip_sip_svc.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ *
+ * 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_SIP_SVC_H__
+#define __ROCKCHIP_SIP_SVC_H__
+
+/* SMC function IDs for SiP Service queries */
+#define SIP_SVC_CALL_COUNT		0x8200ff00
+#define SIP_SVC_UID			0x8200ff01
+#define SIP_SVC_VERSION			0x8200ff03
+
+/* rockchip SiP Service Calls version numbers */
+#define RK_SIP_SVC_VERSION_MAJOR	0x0
+#define RK_SIP_SVC_VERSION_MINOR	0x1
+
+/* Number of ROCKCHIP SiP Calls implemented */
+#define RK_COMMON_SIP_NUM_CALLS		0x3
+
+enum {
+	RK_SIP_E_SUCCESS = 0,
+	RK_SIP_E_INVALID_PARAM = -1
+};
+
+#endif
diff --git a/plat/rockchip/common/rockchip_gicv2.c b/plat/rockchip/common/rockchip_gicv2.c
index 3e1fa91..c2dca1f 100644
--- a/plat/rockchip/common/rockchip_gicv2.c
+++ b/plat/rockchip/common/rockchip_gicv2.c
@@ -31,6 +31,7 @@
 #include <bl_common.h>
 #include <gicv2.h>
 #include <platform_def.h>
+#include <utils.h>
 
 /******************************************************************************
  * The following functions are defined as weak to allow a platform to override
diff --git a/plat/rockchip/common/rockchip_gicv3.c b/plat/rockchip/common/rockchip_gicv3.c
index d197aba..7730896 100644
--- a/plat/rockchip/common/rockchip_gicv3.c
+++ b/plat/rockchip/common/rockchip_gicv3.c
@@ -32,6 +32,7 @@
 #include <gicv3.h>
 #include <platform.h>
 #include <platform_def.h>
+#include <utils.h>
 
 /******************************************************************************
  * The following functions are defined as weak to allow a platform to override
diff --git a/plat/rockchip/common/rockchip_sip_svc.c b/plat/rockchip/common/rockchip_sip_svc.c
new file mode 100644
index 0000000..cbc9105
--- /dev/null
+++ b/plat/rockchip/common/rockchip_sip_svc.c
@@ -0,0 +1,104 @@
+/*
+ * 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 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 <assert.h>
+#include <debug.h>
+#include <mmio.h>
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+#include <runtime_svc.h>
+#include <uuid.h>
+
+/* Rockchip SiP Service UUID */
+DEFINE_SVC_UUID(rk_sip_svc_uid,
+		0xe86fc7e2, 0x313e, 0x11e6, 0xb7, 0x0d,
+		0x8f, 0x88, 0xee, 0x74, 0x7b, 0x72);
+
+#pragma weak rockchip_plat_sip_handler
+uint64_t rockchip_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)
+{
+	ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+	SMC_RET1(handle, SMC_UNK);
+}
+
+/*
+ * This function is responsible for handling all SiP calls from the NS world
+ */
+uint64_t sip_smc_handler(uint32_t smc_fid,
+			 uint64_t x1,
+			 uint64_t x2,
+			 uint64_t x3,
+			 uint64_t x4,
+			 void *cookie,
+			 void *handle,
+			 uint64_t flags)
+{
+	uint32_t ns;
+
+	/* Determine which security state this SMC originated from */
+	ns = is_caller_non_secure(flags);
+	if (!ns)
+		SMC_RET1(handle, SMC_UNK);
+
+	switch (smc_fid) {
+	case SIP_SVC_CALL_COUNT:
+		/* Return the number of Rockchip SiP Service Calls. */
+		SMC_RET1(handle,
+			 RK_COMMON_SIP_NUM_CALLS + RK_PLAT_SIP_NUM_CALLS);
+
+	case SIP_SVC_UID:
+		/* Return UID to the caller */
+		SMC_UUID_RET(handle, rk_sip_svc_uid);
+		break;
+
+	case SIP_SVC_VERSION:
+		/* Return the version of current implementation */
+		SMC_RET2(handle, RK_SIP_SVC_VERSION_MAJOR,
+			RK_SIP_SVC_VERSION_MINOR);
+		break;
+
+	default:
+		return rockchip_plat_sip_handler(smc_fid, x1, x2, x3, x4,
+			cookie, handle, flags);
+	}
+}
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	rockchip_sip_svc,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	NULL,
+	sip_smc_handler
+);
diff --git a/plat/rockchip/rk3368/include/plat_sip_calls.h b/plat/rockchip/rk3368/include/plat_sip_calls.h
new file mode 100644
index 0000000..a778f49
--- /dev/null
+++ b/plat/rockchip/rk3368/include/plat_sip_calls.h
@@ -0,0 +1,32 @@
+/*
+ * 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PLAT_SIP_CALLS_H__
+#define __PLAT_SIP_CALLS_H__
+
+#define RK_PLAT_SIP_NUM_CALLS	0
+
+#endif /* __PLAT_SIP_CALLS_H__ */
diff --git a/plat/rockchip/rk3368/plat_sip_calls.c b/plat/rockchip/rk3368/plat_sip_calls.c
new file mode 100644
index 0000000..3d2f39a
--- /dev/null
+++ b/plat/rockchip/rk3368/plat_sip_calls.c
@@ -0,0 +1,47 @@
+/*
+ * 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 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 <debug.h>
+#include <mmio.h>
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+#include <runtime_svc.h>
+
+uint64_t rockchip_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) {
+	default:
+		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
diff --git a/plat/rockchip/rk3368/platform.mk b/plat/rockchip/rk3368/platform.mk
index 50eda32..b90b792 100644
--- a/plat/rockchip/rk3368/platform.mk
+++ b/plat/rockchip/rk3368/platform.mk
@@ -69,6 +69,8 @@
 				${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/pmu/pmu.c		\
 				${RK_PLAT_SOC}/drivers/soc/soc.c		\
 				${RK_PLAT_SOC}/drivers/ddr/ddr_rk3368.c		\
diff --git a/plat/rockchip/rk3399/include/plat_sip_calls.h b/plat/rockchip/rk3399/include/plat_sip_calls.h
new file mode 100644
index 0000000..a778f49
--- /dev/null
+++ b/plat/rockchip/rk3399/include/plat_sip_calls.h
@@ -0,0 +1,32 @@
+/*
+ * 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PLAT_SIP_CALLS_H__
+#define __PLAT_SIP_CALLS_H__
+
+#define RK_PLAT_SIP_NUM_CALLS	0
+
+#endif /* __PLAT_SIP_CALLS_H__ */
diff --git a/plat/rockchip/rk3399/plat_sip_calls.c b/plat/rockchip/rk3399/plat_sip_calls.c
new file mode 100644
index 0000000..3d2f39a
--- /dev/null
+++ b/plat/rockchip/rk3399/plat_sip_calls.c
@@ -0,0 +1,47 @@
+/*
+ * 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 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 <debug.h>
+#include <mmio.h>
+#include <plat_sip_calls.h>
+#include <rockchip_sip_svc.h>
+#include <runtime_svc.h>
+
+uint64_t rockchip_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) {
+	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 b0ce56f..9b5848e 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -70,6 +70,8 @@
                                 ${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/soc/soc.c
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
index f89cdce..1ba301d 100644
--- a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
@@ -28,12 +28,8 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <arch_helpers.h>
-#include <cci.h>
 #include <debug.h>
-#include <gicv2.h>
 #include <mmio.h>
-#include <plat_arm.h>
 #include <platform.h>
 #include <xlat_tables.h>
 #include "../zynqmp_private.h"
@@ -187,11 +183,9 @@
 
 	tmp = id;
 	tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK |
-	       ZYNQMP_CSU_IDCODE_FAMILY_MASK |
-	       ZYNQMP_CSU_IDCODE_REVISION_MASK;
+	       ZYNQMP_CSU_IDCODE_FAMILY_MASK;
 	maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT |
-		 ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT |
-		 ZYNQMP_CSU_IDCODE_REVISION << ZYNQMP_CSU_IDCODE_REVISION_SHIFT;
+		 ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT;
 	if (tmp != maskid) {
 		ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid);
 		return "UNKN";
@@ -275,13 +269,13 @@
 	return zynqmp_pmufw_present;
 }
 
-/*
- * A single boot loader stack is expected to work on both the Foundation ZYNQMP
- * models and the two flavours of the Base ZYNQMP models (AEMv8 & Cortex). The
- * SYS_ID register provides a mechanism for detecting the differences between
- * these platforms. This information is stored in a per-BL array to allow the
- * code to take the correct path.Per BL platform configuration.
- */
+unsigned int zynqmp_get_bootmode(void)
+{
+	uint32_t r = mmio_read_32(CRL_APB_BOOT_MODE_USER);
+
+	return r & CRL_APB_BOOT_MODE_MASK;
+}
+
 void zynqmp_config_setup(void)
 {
 	zynqmp_discover_pmufw();
diff --git a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
index 9c9d18d..ffed591 100644
--- a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
+++ b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
@@ -96,7 +96,7 @@
 			       void *plat_params_from_bl2)
 {
 	/* Initialize the console to provide early debug support */
-	console_init(ZYNQMP_UART0_BASE, zynqmp_get_uart_clk(),
+	console_init(ZYNQMP_UART_BASE, zynqmp_get_uart_clk(),
 		     ZYNQMP_UART_BAUDRATE);
 
 	/* Initialize the platform config for future decision making */
@@ -113,25 +113,25 @@
 	 * present.
 	 */
 
-	/* Populate entry point information for BL32 and BL33 */
+	/* Populate common information for BL32 and BL33 */
 	SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
 	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
-	bl32_image_ep_info.pc = BL32_BASE;
-	bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry();
-
-	NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
-
 	SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
-
-	/*
-	 * Tell BL31 where the non-trusted software image
-	 * is located and the entry state information
-	 */
-	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
-	bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
-					  DISABLE_ALL_EXCEPTIONS);
 	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
 
+	if (zynqmp_get_bootmode() == ZYNQMP_BOOTMODE_JTAG) {
+		/* use build time defaults in JTAG boot mode */
+		bl32_image_ep_info.pc = BL32_BASE;
+		bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry();
+		bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+		bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+						  DISABLE_ALL_EXCEPTIONS);
+	} else {
+		/* use parameters from FSBL */
+		fsbl_atf_handover(&bl32_image_ep_info, &bl33_image_ep_info);
+	}
+
+	NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
 	NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
 }
 
@@ -147,18 +147,20 @@
 }
 
 /*
- * Perform the very early platform specific architectural setup here. At the
- * moment this is only intializes the MMU in a quick and dirty way.
+ * Perform the very early platform specific architectural setup here.
  */
 void bl31_plat_arch_setup(void)
 {
 	plat_arm_interconnect_init();
 	plat_arm_interconnect_enter_coherency();
 
-	arm_configure_mmu_el3(BL31_RO_BASE,
+	arm_setup_page_tables(BL31_RO_BASE,
 			      BL31_COHERENT_RAM_LIMIT - BL31_RO_BASE,
 			      BL31_RO_BASE,
 			      BL31_RO_LIMIT,
+			      0,
+			      0,
 			      BL31_COHERENT_RAM_BASE,
 			      BL31_COHERENT_RAM_LIMIT);
+	enable_mmu_el3(0);
 }
diff --git a/plat/xilinx/zynqmp/include/platform_def.h b/plat/xilinx/zynqmp/include/platform_def.h
index 947a0f3..76a52de 100644
--- a/plat/xilinx/zynqmp/include/platform_def.h
+++ b/plat/xilinx/zynqmp/include/platform_def.h
@@ -50,64 +50,62 @@
 /*******************************************************************************
  * BL31 specific defines.
  ******************************************************************************/
-
-#define ZYNQMP_BL31_SIZE	0x1b000
 /*
  * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if
  * present). BL31_BASE is calculated using the current BL31 debug size plus a
  * little space for growth.
  */
-#if ZYNQMP_ATF_LOCATION_ID == ZYNQMP_IN_TRUSTED_SRAM
-# define BL31_BASE			(ZYNQMP_TRUSTED_SRAM_LIMIT - \
-					 ZYNQMP_BL31_SIZE)
-# define BL31_PROGBITS_LIMIT		(ZYNQMP_TRUSTED_SRAM_LIMIT - 0x6000)
-# define BL31_LIMIT			ZYNQMP_TRUSTED_SRAM_LIMIT
-#elif ZYNQMP_ATF_LOCATION_ID == ZYNQMP_IN_TRUSTED_DRAM
-# define BL31_BASE			(ZYNQMP_TRUSTED_DRAM_LIMIT - \
-					 ZYNQMP_BL31_SIZE)
-# define BL31_PROGBITS_LIMIT		(ZYNQMP_TRUSTED_DRAM_LIMIT - 0x6000)
-# define BL31_LIMIT			(ZYNQMP_TRUSTED_DRAM_BASE + \
-					ZYNQMP_TRUSTED_DRAM_SIZE)
+#ifndef ZYNQMP_ATF_MEM_BASE
+# define BL31_BASE			0xfffe5000
+# define BL31_PROGBITS_LIMIT		0xffffa000
+# define BL31_LIMIT			0xffffffff
 #else
-# error "Unsupported ZYNQMP_ATF_LOCATION_ID value"
+# define BL31_BASE			(ZYNQMP_ATF_MEM_BASE)
+# define BL31_LIMIT			(ZYNQMP_ATF_MEM_BASE + ZYNQMP_ATF_MEM_SIZE - 1)
+# ifdef ZYNQMP_ATF_MEM_PROGBITS_SIZE
+#  define BL31_PROGBITS_LIMIT		(ZYNQMP_ATF_MEM_BASE + ZYNQMP_ATF_MEM_PROGBITS_SIZE - 1)
+# endif
 #endif
 
 /*******************************************************************************
  * BL32 specific defines.
  ******************************************************************************/
-/*
- * On ZYNQMP, the TSP can execute either from Trusted SRAM or Trusted DRAM.
- */
-#if ZYNQMP_TSP_RAM_LOCATION_ID == ZYNQMP_IN_TRUSTED_SRAM
-# define TSP_SEC_MEM_BASE		ZYNQMP_TRUSTED_SRAM_BASE
-# define TSP_SEC_MEM_SIZE		ZYNQMP_TRUSTED_SRAM_SIZE
-# define TSP_PROGBITS_LIMIT		(ZYNQMP_TRUSTED_SRAM_LIMIT - \
-					 ZYNQMP_BL31_SIZE)
-# define BL32_BASE			ZYNQMP_TRUSTED_SRAM_BASE
-# define BL32_LIMIT			(ZYNQMP_TRUSTED_SRAM_LIMIT - \
-					 ZYNQMP_BL31_SIZE)
-#elif ZYNQMP_TSP_RAM_LOCATION_ID == ZYNQMP_IN_TRUSTED_DRAM
-# define TSP_SEC_MEM_BASE		ZYNQMP_TRUSTED_DRAM_BASE
-# define TSP_SEC_MEM_SIZE		(ZYNQMP_TRUSTED_DRAM_LIMIT - \
-					 ZYNQMP_BL31_SIZE)
-# define BL32_BASE			ZYNQMP_TRUSTED_DRAM_BASE
-# define BL32_LIMIT			(ZYNQMP_TRUSTED_DRAM_LIMIT - \
-					 ZYNQMP_BL31_SIZE)
+#ifndef ZYNQMP_BL32_MEM_BASE
+# define BL32_BASE			0x60000000
+# define BL32_LIMIT			0x7fffffff
 #else
-# error "Unsupported ZYNQMP_TSP_RAM_LOCATION_ID value"
+# define BL32_BASE			(ZYNQMP_BL32_MEM_BASE)
+# define BL32_LIMIT			(ZYNQMP_BL32_MEM_BASE + ZYNQMP_BL32_MEM_SIZE - 1)
 #endif
 
-/*
- * ID of the secure physical generic timer interrupt used by the TSP.
- */
+/*******************************************************************************
+ * BL33 specific defines.
+ ******************************************************************************/
+#ifndef PRELOADED_BL33_BASE
+# define PLAT_ARM_NS_IMAGE_OFFSET	0x8000000
+#else
+# define PLAT_ARM_NS_IMAGE_OFFSET	PRELOADED_BL33_BASE
+#endif
+
+/*******************************************************************************
+ * TSP  specific defines.
+ ******************************************************************************/
+#define TSP_SEC_MEM_BASE		BL32_BASE
+#define TSP_SEC_MEM_SIZE		(BL32_LIMIT - BL32_BASE + 1)
+
+/* ID of the secure physical generic timer interrupt used by the TSP */
 #define TSP_IRQ_SEC_PHY_TIMER		ARM_IRQ_SEC_PHY_TIMER
 
 /*******************************************************************************
  * Platform specific page table and MMU setup constants
  ******************************************************************************/
 #define ADDR_SPACE_SIZE			(1ull << 32)
-#define MAX_XLAT_TABLES			5
-#define MAX_MMAP_REGIONS		7
+#define MAX_MMAP_REGIONS		6
+#if IMAGE_BL32
+# define MAX_XLAT_TABLES		5
+#else
+# define MAX_XLAT_TABLES		4
+#endif
 
 #define CACHE_WRITEBACK_SHIFT   6
 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c
index d693a2d..56eb742 100644
--- a/plat/xilinx/zynqmp/plat_psci.c
+++ b/plat/xilinx/zynqmp/plat_psci.c
@@ -104,7 +104,7 @@
 	proc = pm_get_proc(cpu_id);
 
 	/* Send request to PMU to wake up selected APU CPU core */
-	pm_req_wakeup(proc->node_id, 1, zynqmp_sec_entry, REQ_ACK_NO);
+	pm_req_wakeup(proc->node_id, 1, zynqmp_sec_entry, REQ_ACK_BLOCKING);
 
 	return PSCI_E_SUCCESS;
 }
diff --git a/plat/xilinx/zynqmp/plat_startup.c b/plat/xilinx/zynqmp/plat_startup.c
new file mode 100644
index 0000000..c2c9bfb
--- /dev/null
+++ b/plat/xilinx/zynqmp/plat_startup.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 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 <mmio.h>
+#include "zynqmp_def.h"
+
+/*
+ * ATFHandoffParams
+ * Parameter		bitfield	encoding
+ * -----------------------------------------------------------------------------
+ * Exec State		0		0 -> Aarch64, 1-> Aarch32
+ * endianness		1		0 -> LE, 1 -> BE
+ * secure (TZ)		2		0 -> Non secure, 1 -> secure
+ * EL			3:4		00 -> EL0, 01 -> EL1, 10 -> EL2, 11 -> EL3
+ * CPU#			5:6		00 -> A53_0, 01 -> A53_1, 10 -> A53_2, 11 -> A53_3
+ */
+
+#define FSBL_FLAGS_ESTATE_SHIFT		0
+#define FSBL_FLAGS_ESTATE_MASK		(1 << FSBL_FLAGS_ESTATE_SHIFT)
+#define FSBL_FLAGS_ESTATE_A64		0
+#define FSBL_FLAGS_ESTATE_A32		1
+
+#define FSBL_FLAGS_ENDIAN_SHIFT		1
+#define FSBL_FLAGS_ENDIAN_MASK		(1 << FSBL_FLAGS_ENDIAN_SHIFT)
+#define FSBL_FLAGS_ENDIAN_LE		0
+#define FSBL_FLAGS_ENDIAN_BE		1
+
+#define FSBL_FLAGS_TZ_SHIFT		2
+#define FSBL_FLAGS_TZ_MASK		(1 << FSBL_FLAGS_TZ_SHIFT)
+#define FSBL_FLAGS_NON_SECURE		0
+#define FSBL_FLAGS_SECURE		1
+
+#define FSBL_FLAGS_EL_SHIFT		3
+#define FSBL_FLAGS_EL_MASK		(3 << FSBL_FLAGS_EL_SHIFT)
+#define FSBL_FLAGS_EL0			0
+#define FSBL_FLAGS_EL1			1
+#define FSBL_FLAGS_EL2			2
+#define FSBL_FLAGS_EL3			3
+
+#define FSBL_FLAGS_CPU_SHIFT		5
+#define FSBL_FLAGS_CPU_MASK		(3 << FSBL_FLAGS_CPU_SHIFT)
+#define FSBL_FLAGS_A53_0		0
+#define FSBL_FLAGS_A53_1		1
+#define FSBL_FLAGS_A53_2		2
+#define FSBL_FLAGS_A53_3		3
+
+#define FSBL_MAX_PARTITIONS		8
+
+/* Structure corresponding to each partition entry */
+struct xfsbl_partition {
+	uint64_t entry_point;
+	uint64_t flags;
+};
+
+/* Structure for handoff parameters to ARM Trusted Firmware (ATF) */
+struct xfsbl_atf_handoff_params {
+	uint8_t magic[4];
+	uint32_t num_entries;
+	struct xfsbl_partition partition[FSBL_MAX_PARTITIONS];
+};
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target CPU for @partition.
+ *
+ * Return: FSBL_FLAGS_A53_0, FSBL_FLAGS_A53_1, FSBL_FLAGS_A53_2 or FSBL_FLAGS_A53_3
+ */
+static int get_fsbl_cpu(const struct xfsbl_partition *partition)
+{
+	uint64_t flags = partition->flags & FSBL_FLAGS_CPU_MASK;
+
+	return flags >> FSBL_FLAGS_CPU_SHIFT;
+}
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target exception level for @partition.
+ *
+ * Return: FSBL_FLAGS_EL0, FSBL_FLAGS_EL1, FSBL_FLAGS_EL2 or FSBL_FLAGS_EL3
+ */
+static int get_fsbl_el(const struct xfsbl_partition *partition)
+{
+	uint64_t flags = partition->flags & FSBL_FLAGS_EL_MASK;
+
+	return flags >> FSBL_FLAGS_EL_SHIFT;
+}
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target security state for @partition.
+ *
+ * Return: FSBL_FLAGS_NON_SECURE or FSBL_FLAGS_SECURE
+ */
+static int get_fsbl_ss(const struct xfsbl_partition *partition)
+{
+	uint64_t flags = partition->flags & FSBL_FLAGS_TZ_MASK;
+
+	return flags >> FSBL_FLAGS_TZ_SHIFT;
+}
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target endianness for @partition.
+ *
+ * Return: SPSR_E_LITTLE or SPSR_E_BIG
+ */
+static int get_fsbl_endian(const struct xfsbl_partition *partition)
+{
+	uint64_t flags = partition->flags & FSBL_FLAGS_ENDIAN_MASK;
+
+	flags >>= FSBL_FLAGS_ENDIAN_SHIFT;
+
+	if (flags == FSBL_FLAGS_ENDIAN_BE)
+		return SPSR_E_BIG;
+	else
+		return SPSR_E_LITTLE;
+}
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target execution state for @partition.
+ *
+ * Return: FSBL_FLAGS_ESTATE_A32 or FSBL_FLAGS_ESTATE_A64
+ */
+static int get_fsbl_estate(const struct xfsbl_partition *partition)
+{
+	uint64_t flags = partition->flags & FSBL_FLAGS_ESTATE_MASK;
+
+	return flags >> FSBL_FLAGS_ESTATE_SHIFT;
+}
+
+/**
+ * Populates the bl32 and bl33 image info structures
+ * @bl32:	BL32 image info structure
+ * @bl33:	BL33 image info structure
+ *
+ * Process the handoff paramters from the FSBL and populate the BL32 and BL33
+ * image info structures accordingly.
+ */
+void fsbl_atf_handover(entry_point_info_t *bl32, entry_point_info_t *bl33)
+{
+	uint64_t atf_handoff_addr;
+	const struct xfsbl_atf_handoff_params *ATFHandoffParams;
+
+	atf_handoff_addr = mmio_read_32(PMU_GLOBAL_GEN_STORAGE6);
+	assert((atf_handoff_addr < BL31_BASE) ||
+	       (atf_handoff_addr > (uint64_t)&__BL31_END__));
+	if (!atf_handoff_addr) {
+		ERROR("BL31: No ATF handoff structure passed\n");
+		panic();
+	}
+
+	ATFHandoffParams = (struct xfsbl_atf_handoff_params *)atf_handoff_addr;
+	if ((ATFHandoffParams->magic[0] != 'X') ||
+	    (ATFHandoffParams->magic[1] != 'L') ||
+	    (ATFHandoffParams->magic[2] != 'N') ||
+	    (ATFHandoffParams->magic[3] != 'X')) {
+		ERROR("BL31: invalid ATF handoff structure at %lx\n",
+		      atf_handoff_addr);
+		panic();
+	}
+
+	VERBOSE("BL31: ATF handoff params at:0x%lx, entries:%u\n",
+		atf_handoff_addr, ATFHandoffParams->num_entries);
+	if (ATFHandoffParams->num_entries > FSBL_MAX_PARTITIONS) {
+		ERROR("BL31: ATF handoff params: too many partitions (%u/%u)\n",
+		      ATFHandoffParams->num_entries, FSBL_MAX_PARTITIONS);
+		panic();
+	}
+
+	/*
+	 * we loop over all passed entries but only populate two image structs
+	 * (bl32, bl33). I.e. the last applicable images in the handoff
+	 * structure will be used for the hand off
+	 */
+	for (size_t i = 0; i < ATFHandoffParams->num_entries; i++) {
+		entry_point_info_t *image;
+		int target_estate, target_secure;
+		int target_cpu, target_endianness, target_el;
+
+		VERBOSE("BL31: %zd: entry:0x%lx, flags:0x%lx\n", i,
+			ATFHandoffParams->partition[i].entry_point,
+			ATFHandoffParams->partition[i].flags);
+
+		target_cpu = get_fsbl_cpu(&ATFHandoffParams->partition[i]);
+		if (target_cpu != FSBL_FLAGS_A53_0) {
+			WARN("BL31: invalid target CPU (%i)\n", target_cpu);
+			continue;
+		}
+
+		target_el = get_fsbl_el(&ATFHandoffParams->partition[i]);
+		if ((target_el == FSBL_FLAGS_EL3) ||
+		    (target_el == FSBL_FLAGS_EL0)) {
+			WARN("BL31: invalid exception level (%i)\n", target_el);
+			continue;
+		}
+
+		target_secure = get_fsbl_ss(&ATFHandoffParams->partition[i]);
+		if (target_secure == FSBL_FLAGS_SECURE &&
+		    target_el == FSBL_FLAGS_EL2) {
+			WARN("BL31: invalid security state (%i) for exception level (%i)\n",
+			     target_secure, target_el);
+			continue;
+		}
+
+		target_estate = get_fsbl_estate(&ATFHandoffParams->partition[i]);
+		target_endianness = get_fsbl_endian(&ATFHandoffParams->partition[i]);
+
+		if (target_secure == FSBL_FLAGS_SECURE) {
+			image = bl32;
+
+			if (target_estate == FSBL_FLAGS_ESTATE_A32)
+				bl32->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
+							 target_endianness,
+							 DISABLE_ALL_EXCEPTIONS);
+			else
+				bl32->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+						     DISABLE_ALL_EXCEPTIONS);
+		} else {
+			image = bl33;
+
+			if (target_estate == FSBL_FLAGS_ESTATE_A32) {
+				if (target_el == FSBL_FLAGS_EL2)
+					target_el = MODE32_hyp;
+				else
+					target_el = MODE32_sys;
+
+				bl33->spsr = SPSR_MODE32(target_el, SPSR_T_ARM,
+							 target_endianness,
+							 DISABLE_ALL_EXCEPTIONS);
+			} else {
+				if (target_el == FSBL_FLAGS_EL2)
+					target_el = MODE_EL2;
+				else
+					target_el = MODE_EL1;
+
+				bl33->spsr = SPSR_64(target_el, MODE_SP_ELX,
+						     DISABLE_ALL_EXCEPTIONS);
+			}
+		}
+
+		VERBOSE("Setting up %s entry point to:%lx, el:%x\n",
+			target_secure == FSBL_FLAGS_SECURE ? "BL32" : "BL33",
+			ATFHandoffParams->partition[i].entry_point,
+			target_el);
+		image->pc = ATFHandoffParams->partition[i].entry_point;
+
+		if (target_endianness == SPSR_E_BIG)
+			EP_SET_EE(image->h.attr, EP_EE_BIG);
+		else
+			EP_SET_EE(image->h.attr, EP_EE_LITTLE);
+	}
+}
diff --git a/plat/xilinx/zynqmp/plat_topology.c b/plat/xilinx/zynqmp/plat_topology.c
index 34e7b53..e1263e0 100644
--- a/plat/xilinx/zynqmp/plat_topology.c
+++ b/plat/xilinx/zynqmp/plat_topology.c
@@ -28,9 +28,6 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <platform_def.h>
-#include <psci.h>
-
 static const unsigned char plat_power_domain_tree_desc[] = {1, 4};
 
 const unsigned char *plat_get_power_domain_tree_desc(void)
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
index febff29..ad87cd9 100644
--- a/plat/xilinx/zynqmp/platform.mk
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -31,29 +31,30 @@
 PSCI_EXTENDED_STATE_ID := 1
 A53_DISABLE_NON_TEMPORAL_HINT := 0
 
-ZYNQMP_ATF_LOCATION	?=	tsram
-ifeq (${ZYNQMP_ATF_LOCATION}, tsram)
-  ZYNQMP_ATF_LOCATION_ID := ZYNQMP_IN_TRUSTED_SRAM
-else ifeq (${ZYNQMP_ATF_LOCATION}, tdram)
-  ZYNQMP_ATF_LOCATION_ID := ZYNQMP_IN_TRUSTED_DRAM
-else
-  $(error "Unsupported ZYNQMP_ATF_LOCATION value")
+ifdef ZYNQMP_ATF_MEM_BASE
+    $(eval $(call add_define,ZYNQMP_ATF_MEM_BASE))
+
+    ifndef ZYNQMP_ATF_MEM_SIZE
+        $(error "ZYNQMP_ATF_BASE defined without ZYNQMP_ATF_SIZE")
+    endif
+    $(eval $(call add_define,ZYNQMP_ATF_MEM_SIZE))
+
+    ifdef ZYNQMP_ATF_MEM_PROGBITS_SIZE
+        $(eval $(call add_define,ZYNQMP_ATF_MEM_PROGBITS_SIZE))
+    endif
 endif
 
-# On ZYNQMP, the TSP can execute either from Trusted SRAM or Trusted DRAM.
-# Trusted SRAM is the default.
-ZYNQMP_TSP_RAM_LOCATION	?=	tsram
-ifeq (${ZYNQMP_TSP_RAM_LOCATION}, tsram)
-  ZYNQMP_TSP_RAM_LOCATION_ID := ZYNQMP_IN_TRUSTED_SRAM
-else ifeq (${ZYNQMP_TSP_RAM_LOCATION}, tdram)
-  ZYNQMP_TSP_RAM_LOCATION_ID := ZYNQMP_IN_TRUSTED_DRAM
-else
-  $(error "Unsupported ZYNQMP_TSP_RAM_LOCATION value")
+ifdef ZYNQMP_BL32_MEM_BASE
+    $(eval $(call add_define,ZYNQMP_BL32_MEM_BASE))
+
+    ifndef ZYNQMP_BL32_MEM_SIZE
+        $(error "ZYNQMP_BL32_BASE defined without ZYNQMP_BL32_SIZE")
+    endif
+    $(eval $(call add_define,ZYNQMP_BL32_MEM_SIZE))
 endif
 
-# Process flags
-$(eval $(call add_define,ZYNQMP_ATF_LOCATION_ID))
-$(eval $(call add_define,ZYNQMP_TSP_RAM_LOCATION_ID))
+ZYNQMP_CONSOLE	?=	cadence
+$(eval $(call add_define_val,ZYNQMP_CONSOLE,ZYNQMP_CONSOLE_ID_${ZYNQMP_CONSOLE}))
 
 PLAT_INCLUDES		:=	-Iinclude/plat/arm/common/			\
 				-Iinclude/plat/arm/common/aarch64/		\
@@ -84,6 +85,7 @@
 				plat/xilinx/zynqmp/bl31_zynqmp_setup.c		\
 				plat/xilinx/zynqmp/plat_psci.c			\
 				plat/xilinx/zynqmp/plat_zynqmp.c		\
+				plat/xilinx/zynqmp/plat_startup.c		\
 				plat/xilinx/zynqmp/plat_topology.c		\
 				plat/xilinx/zynqmp/sip_svc_setup.c		\
 				plat/xilinx/zynqmp/pm_service/pm_svc_main.c	\
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
index 2f2e2ed..eac7801 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -36,6 +36,7 @@
 #include <arch_helpers.h>
 #include <platform.h>
 #include "pm_client.h"
+#include "pm_ipi.h"
 #include "pm_common.h"
 #include "pm_api_sys.h"
 
@@ -390,21 +391,34 @@
 					unsigned int wake,
 					unsigned int enable)
 {
-	return PM_RET_ERROR_NOTSUPPORTED;
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	PM_PACK_PAYLOAD5(payload, PM_REGISTER_NOTIFIER,
+			 nid, event, wake, enable);
+
+	return pm_ipi_send(primary_proc, payload);
 }
 
 /**
- * pm_get_op_characteristic() - PM call to get a particular operating
- *				characteristic of a node
- * @nid	Node ID
- * @type	Operating characterstic type to be returned
+ * pm_get_op_characteristic() - PM call to request operating characteristics
+ *				of a node
+ * @nid		Node id of the slave
+ * @type	Type of the operating characteristic
+ *		(power, temperature and latency)
+ * @result	Returns the operating characteristic for the requested node,
+ *		specified by the type
  *
  * @return	Returns status, either success or error+reason
  */
 enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid,
-					    enum pm_opchar_type type)
+					    enum pm_opchar_type type,
+					    uint32_t *result)
 {
-	return PM_RET_ERROR_NOTSUPPORTED;
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD3(payload, PM_GET_OP_CHARACTERISTIC, nid, type);
+	return pm_ipi_send_sync(primary_proc, payload, result);
 }
 
 /* Direct-Control API functions */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
index f0365cd..22bdb47 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
@@ -91,7 +91,8 @@
 					unsigned int wake,
 					unsigned int enable);
 enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid,
-					    enum pm_opchar_type type);
+					    enum pm_opchar_type type,
+					    uint32_t *result);
 enum pm_ret_status pm_acknowledge_cb(enum pm_node_id nid,
 				     enum pm_ret_status status,
 				     unsigned int oppoint);
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.c b/plat/xilinx/zynqmp/pm_service/pm_client.c
index eb986bc..cf0d5f0 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-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-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:
@@ -33,9 +33,11 @@
  * for getting information about and changing state of the APU.
  */
 
+#include <bakery_lock.h>
 #include <gicv2.h>
 #include <bl_common.h>
 #include <mmio.h>
+#include <utils.h>
 #include "pm_api_sys.h"
 #include "pm_client.h"
 #include "pm_ipi.h"
@@ -47,6 +49,7 @@
 #define OCM_BANK_3	(OCM_BANK_2 + 0x10000)
 
 #define UNDEFINED_CPUID		(~0)
+DEFINE_BAKERY_LOCK(pm_client_secure_lock);
 
 /* Declaration of linker defined symbol */
 extern unsigned long __BL31_END__;
@@ -162,8 +165,12 @@
  */
 void pm_client_suspend(const struct pm_proc *proc)
 {
+	bakery_lock_get(&pm_client_secure_lock);
+
 	/* Set powerdown request */
 	mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask);
+
+	bakery_lock_release(&pm_client_secure_lock);
 }
 
 
@@ -177,9 +184,14 @@
 {
 	/* Enable interrupts at processor level (for current cpu) */
 	gicv2_cpuif_enable();
+
+	bakery_lock_get(&pm_client_secure_lock);
+
 	/* Clear powerdown request */
 	mmio_write_32(APU_PWRCTL,
 		 mmio_read_32(APU_PWRCTL) & ~primary_proc->pwrdn_mask);
+
+	bakery_lock_release(&pm_client_secure_lock);
 }
 
 /**
@@ -195,8 +207,12 @@
 	if (cpuid == UNDEFINED_CPUID)
 		return;
 
+	bakery_lock_get(&pm_client_secure_lock);
+
 	/* clear powerdown bit for affected cpu */
 	uint32_t val = mmio_read_32(APU_PWRCTL);
 	val &= ~(proc->pwrdn_mask);
 	mmio_write_32(APU_PWRCTL, val);
+
+	bakery_lock_release(&pm_client_secure_lock);
 }
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.h b/plat/xilinx/zynqmp/pm_service/pm_client.h
index b9f196d..9483b0d 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_client.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_client.h
@@ -40,11 +40,6 @@
 #include "pm_common.h"
 
 /* Functions to be implemented by each PU */
-enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
-			       uint32_t payload[PAYLOAD_ARG_CNT]);
-enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
-				    uint32_t payload[PAYLOAD_ARG_CNT],
-				    uint32_t *val);
 void pm_client_suspend(const struct pm_proc *proc);
 void pm_client_abort_suspend(void);
 void pm_client_wakeup(const struct pm_proc *proc);
diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h
index 08f4aab..adeec64 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_defs.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h
@@ -142,6 +142,7 @@
 	NODE_RPLL,
 	NODE_IOPLL,
 	NODE_DDR,
+	NODE_IPI_APU,
 };
 
 enum pm_request_ack {
@@ -171,8 +172,8 @@
 
 enum pm_opchar_type {
 	PM_OPCHAR_TYPE_POWER = 1,
-	PM_OPCHAR_TYPE_ENERGY,
 	PM_OPCHAR_TYPE_TEMP,
+	PM_OPCHAR_TYPE_LATENCY,
 };
 
 /**
diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.c b/plat/xilinx/zynqmp/pm_service/pm_ipi.c
index ef2b4fe..c3e7ccb 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_ipi.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_ipi.c
@@ -66,8 +66,7 @@
 #define IPI_APU_ISR		(IPI_BASEADDR + 0X00000010)
 #define IPI_APU_IER		(IPI_BASEADDR + 0X00000018)
 #define IPI_APU_IDR		(IPI_BASEADDR + 0X0000001C)
-#define IPI_APU_ISR_PMU_0_MASK		0X00010000
-#define IPI_APU_IER_PMU_0_MASK		0X00010000
+#define IPI_APU_IXR_PMU_0_MASK		(1 << 16)
 
 #define IPI_TRIG_OFFSET		0
 #define IPI_OBS_OFFSET		4
@@ -75,14 +74,14 @@
 /* Power Management IPI interrupt number */
 #define PM_INT_NUM		0
 #define IPI_PMU_PM_INT_BASE	(IPI_PMU_0_TRIG + (PM_INT_NUM * 0x1000))
-#define IPI_PMU_PM_INT_MASK	(IPI_APU_ISR_PMU_0_MASK << PM_INT_NUM)
+#define IPI_PMU_PM_INT_MASK	(IPI_APU_IXR_PMU_0_MASK << PM_INT_NUM)
 #if (PM_INT_NUM < 0 || PM_INT_NUM > 3)
 	#error PM_INT_NUM value out of range
 #endif
 
 #define IPI_APU_MASK		1U
 
-static bakery_lock_t pm_secure_lock;
+DEFINE_BAKERY_LOCK(pm_secure_lock);
 
 const struct pm_ipi apu_ipi = {
 	.mask = IPI_APU_MASK,
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
index 6744065..e3c25c3 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
@@ -191,8 +191,12 @@
 		SMC_RET1(handle, (uint64_t)ret);
 
 	case PM_GET_OP_CHARACTERISTIC:
-		ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1]);
-		SMC_RET1(handle, (uint64_t)ret);
+	{
+		uint32_t result;
+
+		ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1], &result);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result << 32));
+	}
 
 	case PM_REGISTER_NOTIFIER:
 		ret = pm_register_notifier(pm_arg[0], pm_arg[1], pm_arg[2],
diff --git a/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c b/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
index 291ccba..ae66fa4 100644
--- a/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
+++ b/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -32,9 +32,7 @@
 #include <console.h>
 #include <debug.h>
 #include <platform_tsp.h>
-#include <xlat_tables.h>
 #include <plat_arm.h>
-#include "../zynqmp_def.h"
 #include "../zynqmp_private.h"
 
 /*
@@ -70,7 +68,7 @@
 	 * Initialize a different console than already in use to display
 	 * messages from TSP
 	 */
-	console_init(ZYNQMP_UART0_BASE, zynqmp_get_uart_clk(),
+	console_init(ZYNQMP_UART_BASE, zynqmp_get_uart_clk(),
 		     ZYNQMP_UART_BAUDRATE);
 
 	/* Initialize the platform config for future decision making */
@@ -92,13 +90,16 @@
  ******************************************************************************/
 void tsp_plat_arch_setup(void)
 {
-	arm_configure_mmu_el1(BL32_RO_BASE,
+	arm_setup_page_tables(BL32_RO_BASE,
 			      (BL32_END - BL32_RO_BASE),
 			      BL32_RO_BASE,
-			      BL32_RO_LIMIT
+			      BL32_RO_LIMIT,
+			      0,
+			      0
 #if USE_COHERENT_MEM
 			      , BL32_COHERENT_RAM_BASE,
 			      BL32_COHERENT_RAM_LIMIT
 #endif
 			      );
+	enable_mmu_el1(0);
 }
diff --git a/plat/xilinx/zynqmp/zynqmp_def.h b/plat/xilinx/zynqmp/zynqmp_def.h
index 32190e4..4bb332e 100644
--- a/plat/xilinx/zynqmp/zynqmp_def.h
+++ b/plat/xilinx/zynqmp/zynqmp_def.h
@@ -33,6 +33,13 @@
 
 #include <common_def.h>
 
+#define ZYNQMP_CONSOLE_ID_cadence	1
+#define ZYNQMP_CONSOLE_ID_cadence0	1
+#define ZYNQMP_CONSOLE_ID_cadence1	2
+#define ZYNQMP_CONSOLE_ID_dcc		3
+
+#define ZYNQMP_CONSOLE_IS(con)	(ZYNQMP_CONSOLE_ID_ ## con == ZYNQMP_CONSOLE)
+
 /* Firmware Image Package */
 #define ZYNQMP_PRIMARY_CPU		0
 
@@ -43,24 +50,11 @@
 /*******************************************************************************
  * ZYNQMP memory map related constants
  ******************************************************************************/
-
-#define ZYNQMP_TRUSTED_SRAM_BASE	0xFFFC0000
-#define ZYNQMP_TRUSTED_SRAM_SIZE	0x00040000
-#define ZYNQMP_TRUSTED_SRAM_LIMIT	(ZYNQMP_TRUSTED_SRAM_BASE + \
-					 ZYNQMP_TRUSTED_SRAM_SIZE)
-
-
-/* Location of trusted dram on the base zynqmp */
-#define ZYNQMP_TRUSTED_DRAM_BASE	0x30000000 /* Can't overlap TZROM area */
-#define ZYNQMP_TRUSTED_DRAM_SIZE	0x10000000
-#define ZYNQMP_TRUSTED_DRAM_LIMIT	(ZYNQMP_TRUSTED_DRAM_BASE + \
-					 ZYNQMP_TRUSTED_DRAM_SIZE)
-
 /* Aggregate of all devices in the first GB */
 #define DEVICE0_BASE		0xFF000000
 #define DEVICE0_SIZE		0x00E00000
 #define DEVICE1_BASE		0xF9000000
-#define DEVICE1_SIZE		0x01000000
+#define DEVICE1_SIZE		0x00800000
 
 /* For cpu reset APU space here too 0xFE5F1000 CRF_APB*/
 #define CRF_APB_BASE		0xFD1A0000
@@ -76,6 +70,7 @@
 #define CRL_APB_BASE			0xFF5E0000
 #define CRL_APB_RPLL_CTRL		(CRL_APB_BASE + 0x30)
 #define CRL_APB_TIMESTAMP_REF_CTRL	(CRL_APB_BASE + 0x128)
+#define CRL_APB_BOOT_MODE_USER		(CRL_APB_BASE + 0x200)
 #define CRL_APB_RESET_CTRL		(CRL_APB_BASE + 0x218)
 
 #define CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT	(1 << 24)
@@ -84,6 +79,9 @@
 
 #define CRL_APB_RESET_CTRL_SOFT_RESET	(1 << 4)
 
+#define CRL_APB_BOOT_MODE_MASK		(0xf << 0)
+#define ZYNQMP_BOOTMODE_JTAG		0
+
 /* system counter registers and bitfields */
 #define IOU_SCNTRS_BASE			0xFF260000
 #define IOU_SCNTRS_CONTROL		(IOU_SCNTRS_BASE + 0)
@@ -107,6 +105,7 @@
 /* PMU registers and bitfields */
 #define PMU_GLOBAL_BASE			0xFFD80000
 #define PMU_GLOBAL_CNTRL		(PMU_GLOBAL_BASE + 0)
+#define PMU_GLOBAL_GEN_STORAGE6		(PMU_GLOBAL_BASE + 0x48)
 #define PMU_GLOBAL_REQ_PWRUP_STATUS	(PMU_GLOBAL_BASE + 0x110)
 #define PMU_GLOBAL_REQ_PWRUP_EN		(PMU_GLOBAL_BASE + 0x118)
 #define PMU_GLOBAL_REQ_PWRUP_DIS	(PMU_GLOBAL_BASE + 0x11c)
@@ -114,16 +113,6 @@
 
 #define PMU_GLOBAL_CNTRL_FW_IS_PRESENT	(1 << 4)
 
-#define DRAM1_BASE		0x00000000ull
-#define DRAM1_SIZE		0x10000000ull
-#define DRAM1_END		(DRAM1_BASE + DRAM1_SIZE - 1)
-
-#define DRAM_BASE		DRAM1_BASE
-#define DRAM_SIZE		DRAM1_SIZE
-
-/* Load address of BL33 in the ZYNQMP port */
-#define PLAT_ARM_NS_IMAGE_OFFSET	(DRAM1_BASE + 0x8000000) /* DRAM + 128MB */
-
 /*******************************************************************************
  * CCI-400 related constants
  ******************************************************************************/
@@ -159,7 +148,15 @@
 #define ZYNQMP_UART0_BASE		0xFF000000
 #define ZYNQMP_UART1_BASE		0xFF001000
 
-#define PLAT_ARM_CRASH_UART_BASE	ZYNQMP_UART0_BASE
+#if ZYNQMP_CONSOLE_IS(cadence)
+# define ZYNQMP_UART_BASE	ZYNQMP_UART0_BASE
+#elif ZYNQMP_CONSOLE_IS(cadence1)
+# define ZYNQMP_UART_BASE	ZYNQMP_UART1_BASE
+#else
+# error "invalid ZYNQMP_CONSOLE"
+#endif
+
+#define PLAT_ARM_CRASH_UART_BASE	ZYNQMP_UART_BASE
 /* impossible to call C routine how it is done now - hardcode any value */
 #define	PLAT_ARM_CRASH_UART_CLK_IN_HZ	100000000 /* FIXME */
 
diff --git a/plat/xilinx/zynqmp/zynqmp_private.h b/plat/xilinx/zynqmp/zynqmp_private.h
index 1f5be39..ddef37b 100644
--- a/plat/xilinx/zynqmp/zynqmp_private.h
+++ b/plat/xilinx/zynqmp/zynqmp_private.h
@@ -38,5 +38,10 @@
 /* ZynqMP specific functions */
 unsigned int zynqmp_get_uart_clk(void);
 int zynqmp_is_pmu_up(void);
+unsigned int zynqmp_get_bootmode(void);
+
+/* For FSBL handover */
+void fsbl_atf_handover(entry_point_info_t *bl32_image_ep_info,
+		       entry_point_info_t *bl33_image_ep_info);
 
 #endif /* __ZYNQMP_PRIVATE_H__ */
diff --git a/services/std_svc/psci/psci_common.c b/services/std_svc/psci/psci_common.c
index 8a2b81c..5090037 100644
--- a/services/std_svc/psci/psci_common.c
+++ b/services/std_svc/psci/psci_common.c
@@ -711,6 +711,16 @@
 	psci_acquire_pwr_domain_locks(end_pwrlvl,
 				      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);
+#endif
+
 	psci_get_target_local_pwr_states(end_pwrlvl, &state_info);
 
 	/*
@@ -736,6 +746,16 @@
 	 */
 	psci_set_pwr_domains_to_run(end_pwrlvl);
 
+#if ENABLE_PSCI_STAT
+	/*
+	 * Update PSCI stats.
+	 * Caches are off when writing stats data on the power down path.
+	 * 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);
+#endif
+
 	/*
 	 * This loop releases the lock corresponding to each power level
 	 * in the reverse order to which they were acquired.
diff --git a/services/std_svc/psci/psci_main.c b/services/std_svc/psci/psci_main.c
index 68ad5f6..86f45ca 100644
--- a/services/std_svc/psci/psci_main.c
+++ b/services/std_svc/psci/psci_main.c
@@ -110,11 +110,32 @@
 		 */
 		cpu_pd_state = state_info.pwr_domain_state[PSCI_CPU_PWR_LVL];
 		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);
+#endif
+
 		psci_plat_pm_ops->cpu_standby(cpu_pd_state);
 
 		/* Upon exit from standby, set the state back to RUN. */
 		psci_set_cpu_local_state(PSCI_LOCAL_STATE_RUN);
 
+#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);
+
+		/* Update PSCI stats */
+		psci_stats_update_pwr_up(PSCI_CPU_PWR_LVL, &state_info,
+			PMF_NO_CACHE_MAINT);
+#endif
+
 		return PSCI_E_SUCCESS;
 	}
 
@@ -368,6 +389,14 @@
 		case PSCI_FEATURES:
 			SMC_RET1(handle, psci_features(x1));
 
+#if ENABLE_PSCI_STAT
+		case PSCI_STAT_RESIDENCY_AARCH32:
+			SMC_RET1(handle, psci_stat_residency(x1, x2));
+
+		case PSCI_STAT_COUNT_AARCH32:
+			SMC_RET1(handle, psci_stat_count(x1, x2));
+#endif
+
 		default:
 			break;
 		}
@@ -393,6 +422,14 @@
 		case PSCI_SYSTEM_SUSPEND_AARCH64:
 			SMC_RET1(handle, psci_system_suspend(x1, x2));
 
+#if ENABLE_PSCI_STAT
+		case PSCI_STAT_RESIDENCY_AARCH64:
+			SMC_RET1(handle, psci_stat_residency(x1, x2));
+
+		case PSCI_STAT_COUNT_AARCH64:
+			SMC_RET1(handle, psci_stat_count(x1, x2));
+#endif
+
 		default:
 			break;
 		}
diff --git a/services/std_svc/psci/psci_off.c b/services/std_svc/psci/psci_off.c
index 686666d..36dab49 100644
--- a/services/std_svc/psci/psci_off.c
+++ b/services/std_svc/psci/psci_off.c
@@ -100,6 +100,11 @@
 	 */
 	psci_do_state_coordination(end_pwrlvl, &state_info);
 
+#if ENABLE_PSCI_STAT
+	/* Update the last cpu for each level till end_pwrlvl */
+	psci_stats_update_pwr_down(end_pwrlvl, &state_info);
+#endif
+
 	/*
 	 * Arch. management. Perform the necessary steps to flush all
 	 * cpu caches.
@@ -112,6 +117,16 @@
 	 */
 	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);
+#endif
+
 exit:
 	/*
 	 * Release the locks corresponding to each power level in the
diff --git a/services/std_svc/psci/psci_private.h b/services/std_svc/psci/psci_private.h
index 8a671b3..ffb0732 100644
--- a/services/std_svc/psci/psci_private.h
+++ b/services/std_svc/psci/psci_private.h
@@ -35,6 +35,7 @@
 #include <bakery_lock.h>
 #include <bl_common.h>
 #include <cpu_data.h>
+#include <pmf.h>
 #include <psci.h>
 #include <spinlock.h>
 
@@ -67,7 +68,9 @@
 			define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) |	\
 			define_psci_cap(PSCI_MIG_AARCH64) |		\
 			define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64) |	\
-			define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64))
+			define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64) |	\
+			define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64) |	\
+			define_psci_cap(PSCI_STAT_COUNT_AARCH64))
 
 /*
  * Helper macros to get/set the fields of PSCI per-cpu data.
@@ -102,6 +105,15 @@
 #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
@@ -228,4 +240,15 @@
 void __dead2 psci_system_off(void);
 void __dead2 psci_system_reset(void);
 
+/* Private exported functions from psci_stat.c */
+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);
+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,
+			unsigned int power_state);
+
 #endif /* __PSCI_PRIVATE_H__ */
diff --git a/services/std_svc/psci/psci_setup.c b/services/std_svc/psci/psci_setup.c
index cd1bb09..975b257 100644
--- a/services/std_svc/psci/psci_setup.c
+++ b/services/std_svc/psci/psci_setup.c
@@ -252,5 +252,10 @@
 	if (psci_plat_pm_ops->system_reset)
 		psci_caps |=  define_psci_cap(PSCI_SYSTEM_RESET);
 
+#if ENABLE_PSCI_STAT
+	psci_caps |=  define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);
+	psci_caps |=  define_psci_cap(PSCI_STAT_COUNT_AARCH64);
+#endif
+
 	return 0;
 }
diff --git a/services/std_svc/psci/psci_stat.c b/services/std_svc/psci/psci_stat.c
new file mode 100644
index 0000000..155bbb0
--- /dev/null
+++ b/services/std_svc/psci/psci_stat.c
@@ -0,0 +1,309 @@
+/*
+ * 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 <assert.h>
+#include <debug.h>
+#include <platform.h>
+#include <platform_def.h>
+#include "psci_private.h"
+
+#ifndef PLAT_MAX_PWR_LVL_STATES
+#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;
+	u_register_t count;
+} psci_stat_t;
+
+/*
+ * Following is used to keep track of the last cpu
+ * that goes to power down in non cpu power domains.
+ */
+static int last_cpu_in_non_cpu_pd[PSCI_NUM_NON_CPU_PWR_DOMAINS] = {-1};
+
+/*
+ * Following are used to store PSCI STAT values for
+ * CPU and non CPU power domains.
+ */
+static psci_stat_t psci_cpu_stat[PLATFORM_CORE_COUNT]
+				[PLAT_MAX_PWR_LVL_STATES];
+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
+ * `get_pwr_lvl_state_idx` pm hook, then that will be used to return the index.
+ */
+static int get_stat_idx(plat_local_state_t local_state, int pwr_lvl)
+{
+	int idx;
+
+	if (psci_plat_pm_ops->get_pwr_lvl_state_idx == NULL) {
+		assert(PLAT_MAX_PWR_LVL_STATES == 2);
+		if (is_local_state_retn(local_state))
+			return 0;
+
+		assert(is_local_state_off(local_state));
+		return 1;
+	}
+
+	idx = psci_plat_pm_ops->get_pwr_lvl_state_idx(local_state, pwr_lvl);
+	assert((idx >= 0) && (idx < PLAT_MAX_PWR_LVL_STATES));
+	return idx;
+}
+
+/*******************************************************************************
+ * This function is passed the target local power states for each power
+ * domain (state_info) between the current CPU domain and its ancestors until
+ * the target power level (end_pwrlvl).
+ *
+ * Then, for each level (apart from the CPU level) until the 'end_pwrlvl', it
+ * updates the `last_cpu_in_non_cpu_pd[]` with last power down cpu id.
+ *
+ * This function will only be invoked with data cache enabled and while
+ * powering down a core.
+ ******************************************************************************/
+void psci_stats_update_pwr_down(unsigned int end_pwrlvl,
+			const psci_power_state_t *state_info)
+{
+	int lvl, parent_idx, cpu_idx = plat_my_core_pos();
+
+	assert(end_pwrlvl <= PLAT_MAX_PWR_LVL);
+	assert(state_info);
+
+	parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
+
+	for (lvl = PSCI_CPU_PWR_LVL + 1; lvl <= end_pwrlvl; lvl++) {
+
+		/* Break early if the target power state is RUN */
+		if (is_local_state_run(state_info->pwr_domain_state[lvl]))
+			break;
+
+		/*
+		 * The power domain is entering a low power state, so this is
+		 * the last CPU for this power domain
+		 */
+		last_cpu_in_non_cpu_pd[parent_idx] = cpu_idx;
+
+		parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
+	}
+
+}
+
+/*******************************************************************************
+ * This function updates the PSCI STATS(residency time and count) for CPU
+ * and NON-CPU power domains.
+ * 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)
+{
+	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);
+
+	/* Update CPU stats. */
+	psci_cpu_stat[cpu_idx][stat_idx].residency += residency;
+	psci_cpu_stat[cpu_idx][stat_idx].count++;
+
+	/*
+	 * Check what power domains above CPU were off
+	 * prior to this CPU powering on.
+	 */
+	parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node;
+	for (lvl = PSCI_CPU_PWR_LVL + 1; lvl <= end_pwrlvl; lvl++) {
+		local_state = state_info->pwr_domain_state[lvl];
+		if (is_local_state_run(local_state)) {
+			/* Break early */
+			break;
+		}
+
+		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);
+
+		/* Initialize back to reset value */
+		last_cpu_in_non_cpu_pd[parent_idx] = -1;
+
+		/* 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++;
+
+		parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
+	}
+
+}
+
+/*******************************************************************************
+ * This function returns the appropriate count and residency time of the
+ * local state for the highest power level expressed in the `power_state`
+ * for the node represented by `target_cpu`.
+ ******************************************************************************/
+int psci_get_stat(u_register_t target_cpu, unsigned int power_state,
+			 psci_stat_t *psci_stat)
+{
+	int rc, pwrlvl, lvl, parent_idx, stat_idx, target_idx;
+	psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} };
+	plat_local_state_t local_state;
+
+	/* Validate the target_cpu parameter and determine the cpu index */
+	target_idx = plat_core_pos_by_mpidr(target_cpu);
+	if (target_idx == -1)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Validate the power_state parameter */
+	if (!psci_plat_pm_ops->translate_power_state_by_mpidr)
+		rc = psci_validate_power_state(power_state, &state_info);
+	else
+		rc = psci_plat_pm_ops->translate_power_state_by_mpidr(
+				target_cpu, power_state, &state_info);
+
+	if (rc != PSCI_E_SUCCESS)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Find the highest power level */
+	pwrlvl = psci_find_target_suspend_lvl(&state_info);
+	if (pwrlvl == PSCI_INVALID_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Get the index into the stats array */
+	local_state = state_info.pwr_domain_state[pwrlvl];
+	stat_idx = get_stat_idx(local_state, pwrlvl);
+
+	if (pwrlvl > PSCI_CPU_PWR_LVL) {
+		/* Get the power domain index */
+		parent_idx = psci_cpu_pd_nodes[target_idx].parent_node;
+		for (lvl = PSCI_CPU_PWR_LVL + 1; lvl < pwrlvl; lvl++)
+			parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node;
+
+		/* Get the non cpu power domain stats */
+		*psci_stat = psci_non_cpu_stat[parent_idx][stat_idx];
+	} else {
+		/* Get the cpu power domain stats */
+		*psci_stat = psci_cpu_stat[target_idx][stat_idx];
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+/* This is the top level function for PSCI_STAT_RESIDENCY SMC. */
+u_register_t psci_stat_residency(u_register_t target_cpu,
+		unsigned int power_state)
+{
+	psci_stat_t psci_stat;
+
+	int rc = psci_get_stat(target_cpu, power_state, &psci_stat);
+	if (rc == PSCI_E_SUCCESS)
+		return psci_stat.residency;
+	else
+		return 0;
+}
+
+/* This is the top level function for PSCI_STAT_COUNT SMC. */
+u_register_t psci_stat_count(u_register_t target_cpu,
+	unsigned int power_state)
+{
+	psci_stat_t psci_stat;
+
+	int rc = psci_get_stat(target_cpu, power_state, &psci_stat);
+	if (rc == PSCI_E_SUCCESS)
+		return psci_stat.count;
+	else
+		return 0;
+}
diff --git a/services/std_svc/psci/psci_suspend.c b/services/std_svc/psci/psci_suspend.c
index 8c6ab6b..e6c8cd9 100644
--- a/services/std_svc/psci/psci_suspend.c
+++ b/services/std_svc/psci/psci_suspend.c
@@ -168,6 +168,11 @@
 	 */
 	psci_do_state_coordination(end_pwrlvl, state_info);
 
+#if ENABLE_PSCI_STAT
+	/* Update the last cpu for each level till end_pwrlvl */
+	psci_stats_update_pwr_down(end_pwrlvl, state_info);
+#endif
+
 	if (is_power_down_state)
 		psci_suspend_to_pwrdown_start(end_pwrlvl, ep, state_info);
 
@@ -179,6 +184,16 @@
 	 */
 	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);
+#endif
+
 exit:
 	/*
 	 * Release the locks corresponding to each power level in the
diff --git a/tools/cert_create/src/main.c b/tools/cert_create/src/main.c
index c87d988..c58f41d 100644
--- a/tools/cert_create/src/main.c
+++ b/tools/cert_create/src/main.c
@@ -428,9 +428,11 @@
 			 */
 			switch (ext->type) {
 			case EXT_TYPE_NVCOUNTER:
-				nvctr = atoi(ext->arg);
-				CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
+				if (ext->arg) {
+					nvctr = atoi(ext->arg);
+					CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
 						EXT_CRIT, nvctr));
+				}
 				break;
 			case EXT_TYPE_HASH:
 				if (ext->arg == NULL) {