Merge pull request #972 from achingupta/ag/freebsd-dt-change

Device tree changes to boot FreeBSD on FVPs
diff --git a/Makefile b/Makefile
index c5c281a..aec10c9 100644
--- a/Makefile
+++ b/Makefile
@@ -336,11 +336,6 @@
 # Process platform overrideable behaviour
 ################################################################################
 
-# Check if -pedantic option should be used
-ifeq (${DISABLE_PEDANTIC},0)
-        TF_CFLAGS	+= 	-pedantic
-endif
-
 # Using the ARM Trusted Firmware BL2 implies that a BL33 image also needs to be
 # supplied for the FIP and Certificate generation tools. This flag can be
 # overridden by the platform.
diff --git a/bl1/bl1_fwu.c b/bl1/bl1_fwu.c
index ace364d..205ea92 100644
--- a/bl1/bl1_fwu.c
+++ b/bl1/bl1_fwu.c
@@ -40,6 +40,8 @@
 			unsigned int flags);
 static int bl1_fwu_sec_image_done(void **handle,
 			unsigned int flags);
+static int bl1_fwu_image_reset(unsigned int image_id,
+			unsigned int flags);
 __dead2 static void bl1_fwu_done(void *client_cookie, void *reserved);
 
 /*
@@ -47,6 +49,9 @@
  */
 static unsigned int sec_exec_image_id = INVALID_IMAGE_ID;
 
+/* Authentication status of each image. */
+extern unsigned int auth_img_flags[];
+
 void cm_set_next_context(void *cpu_context);
 
 /*******************************************************************************
@@ -78,6 +83,9 @@
 	case FWU_SMC_SEC_IMAGE_DONE:
 		SMC_RET1(handle, bl1_fwu_sec_image_done(&handle, flags));
 
+	case FWU_SMC_IMAGE_RESET:
+		SMC_RET1(handle, bl1_fwu_image_reset(x1, flags));
+
 	case FWU_SMC_UPDATE_DONE:
 		bl1_fwu_done((void *)x1, NULL);
 		/* We should never return from bl1_fwu_done() */
@@ -91,6 +99,124 @@
 }
 
 /*******************************************************************************
+ * Utility functions to keep track of the images that are loaded at any time.
+ ******************************************************************************/
+
+#ifdef PLAT_FWU_MAX_SIMULTANEOUS_IMAGES
+#define FWU_MAX_SIMULTANEOUS_IMAGES	PLAT_FWU_MAX_SIMULTANEOUS_IMAGES
+#else
+#define FWU_MAX_SIMULTANEOUS_IMAGES	10
+#endif
+
+static int bl1_fwu_loaded_ids[FWU_MAX_SIMULTANEOUS_IMAGES] = {
+	[0 ... FWU_MAX_SIMULTANEOUS_IMAGES-1] = INVALID_IMAGE_ID
+};
+
+/*
+ * Adds an image_id to the bl1_fwu_loaded_ids array.
+ * Returns 0 on success, 1 on error.
+ */
+static int bl1_fwu_add_loaded_id(int image_id)
+{
+	int i;
+
+	/* Check if the ID is already in the list */
+	for (i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) {
+		if (bl1_fwu_loaded_ids[i] == image_id)
+			return 0;
+	}
+
+	/* Find an empty slot */
+	for (i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) {
+		if (bl1_fwu_loaded_ids[i] == INVALID_IMAGE_ID) {
+			bl1_fwu_loaded_ids[i] = image_id;
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+/*
+ * Removes an image_id from the bl1_fwu_loaded_ids array.
+ * Returns 0 on success, 1 on error.
+ */
+static int bl1_fwu_remove_loaded_id(int image_id)
+{
+	int i;
+
+	/* Find the ID */
+	for (i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) {
+		if (bl1_fwu_loaded_ids[i] == image_id) {
+			bl1_fwu_loaded_ids[i] = INVALID_IMAGE_ID;
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+/*******************************************************************************
+ * This function checks if the specified image overlaps another image already
+ * loaded. It returns 0 if there is no overlap, a negative error code otherwise.
+ ******************************************************************************/
+static int bl1_fwu_image_check_overlaps(int image_id)
+{
+	const image_desc_t *image_desc, *checked_image_desc;
+	const image_info_t *info, *checked_info;
+
+	uintptr_t image_base, image_end;
+	uintptr_t checked_image_base, checked_image_end;
+
+	checked_image_desc = bl1_plat_get_image_desc(image_id);
+	checked_info = &checked_image_desc->image_info;
+
+	/* Image being checked mustn't be empty. */
+	assert(checked_info->image_size != 0);
+
+	checked_image_base = checked_info->image_base;
+	checked_image_end = checked_image_base + checked_info->image_size - 1;
+	/* No need to check for overlaps, it's done in bl1_fwu_image_copy(). */
+
+	for (int i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) {
+
+		/* Don't check image against itself. */
+		if (bl1_fwu_loaded_ids[i] == image_id)
+			continue;
+
+		image_desc = bl1_plat_get_image_desc(bl1_fwu_loaded_ids[i]);
+
+		/* Only check images that are loaded or being loaded. */
+		assert (image_desc->state != IMAGE_STATE_RESET);
+
+		info = &image_desc->image_info;
+
+		/* There cannot be overlaps with an empty image. */
+		if (info->image_size == 0)
+			continue;
+
+		image_base = info->image_base;
+		image_end = image_base + info->image_size - 1;
+		/*
+		 * Overflows cannot happen. It is checked in
+		 * bl1_fwu_image_copy() when the image goes from RESET to
+		 * COPYING or COPIED.
+		 */
+		assert (image_end > image_base);
+
+		/* Check if there are overlaps. */
+		if (!(image_end < checked_image_base ||
+		    checked_image_end < image_base)) {
+			VERBOSE("Image with ID %d overlaps existing image with ID %d",
+				checked_image_desc->image_id, image_desc->image_id);
+			return -EPERM;
+		}
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
  * This function is responsible for copying secure images in AP Secure RAM.
  ******************************************************************************/
 static int bl1_fwu_image_copy(unsigned int image_id,
@@ -189,6 +315,13 @@
 		/* Save the given image size. */
 		image_desc->image_info.image_size = image_size;
 
+		/* Make sure the image doesn't overlap other images. */
+		if (bl1_fwu_image_check_overlaps(image_id)) {
+			image_desc->image_info.image_size = 0;
+			WARN("BL1-FWU: This image overlaps another one\n");
+			return -EPERM;
+		}
+
 		/*
 		 * copied_size must be explicitly initialized here because the
 		 * FWU code doesn't necessarily do it when it resets the state
@@ -213,6 +346,11 @@
 		return -ENOMEM;
 	}
 
+	if (bl1_fwu_add_loaded_id(image_id)) {
+		WARN("BL1-FWU: Too many images loaded at the same time.\n");
+		return -ENOMEM;
+	}
+
 	/* Everything looks sane. Go ahead and copy the block of data. */
 	dest_addr = image_desc->image_info.image_base + image_desc->copied_size;
 	memcpy((void *) dest_addr, (const void *) image_src, block_size);
@@ -290,6 +428,11 @@
 			return -ENOMEM;
 		}
 
+		if (bl1_fwu_add_loaded_id(image_id)) {
+			WARN("BL1-FWU: Too many images loaded at the same time.\n");
+			return -ENOMEM;
+		}
+
 		base_addr = image_src;
 		total_size = image_size;
 
@@ -319,6 +462,13 @@
 			/* Indicate that image can be copied again*/
 			image_desc->state = IMAGE_STATE_RESET;
 		}
+
+		/*
+		 * Even if this fails it's ok because the ID isn't in the array.
+		 * The image cannot be in RESET state here, it is checked at the
+		 * beginning of the function.
+		 */
+		bl1_fwu_remove_loaded_id(image_id);
 		return -EAUTH;
 	}
 
@@ -475,6 +625,13 @@
 	assert(EP_GET_EXE(image_desc->ep_info.h.attr) == EXECUTABLE);
 	assert(image_desc->state == IMAGE_STATE_EXECUTED);
 
+#if ENABLE_ASSERTIONS
+	int rc = bl1_fwu_remove_loaded_id(sec_exec_image_id);
+	assert(rc == 0);
+#else
+	bl1_fwu_remove_loaded_id(sec_exec_image_id);
+#endif
+
 	/* Update the flags. */
 	image_desc->state = IMAGE_STATE_RESET;
 	sec_exec_image_id = INVALID_IMAGE_ID;
@@ -517,3 +674,56 @@
 	bl1_plat_fwu_done(client_cookie, reserved);
 	assert(0);
 }
+
+/*******************************************************************************
+ * This function resets an image to IMAGE_STATE_RESET. It fails if the image is
+ * being executed.
+ ******************************************************************************/
+static int bl1_fwu_image_reset(unsigned int image_id, unsigned int flags)
+{
+	image_desc_t *image_desc = bl1_plat_get_image_desc(image_id);
+
+	if ((!image_desc) || (GET_SECURITY_STATE(flags) == SECURE)) {
+		WARN("BL1-FWU: Reset not allowed due to invalid args\n");
+		return -EPERM;
+	}
+
+	switch (image_desc->state) {
+
+	case IMAGE_STATE_RESET:
+		/* Nothing to do. */
+		break;
+
+	case IMAGE_STATE_INTERRUPTED:
+	case IMAGE_STATE_AUTHENTICATED:
+	case IMAGE_STATE_COPIED:
+	case IMAGE_STATE_COPYING:
+
+		if (bl1_fwu_remove_loaded_id(image_id)) {
+			WARN("BL1-FWU: Image reset couldn't find the image ID\n");
+			return -EPERM;
+		}
+
+		/* Clear the memory.*/
+		zero_normalmem((void *)image_desc->image_info.image_base,
+				image_desc->copied_size);
+		flush_dcache_range(image_desc->image_info.image_base,
+				image_desc->copied_size);
+
+		/* Reset status variables */
+		image_desc->copied_size = 0;
+		image_desc->image_info.image_size = 0;
+		image_desc->state = IMAGE_STATE_RESET;
+
+		/* Clear authentication state */
+		auth_img_flags[image_id] = 0;
+
+		break;
+
+	case IMAGE_STATE_EXECUTED:
+	default:
+		assert(0);
+	}
+
+	return 0;
+}
diff --git a/contributing.md b/contributing.md
index 9a253ca..65d2ca8 100644
--- a/contributing.md
+++ b/contributing.md
@@ -44,8 +44,22 @@
 *   Where appropriate, please update the documentation.
     *   Consider whether the [User Guide], [Porting Guide], [Firmware Design] or
         other in-source documentation needs updating.
-    *   If this is your first contribution, you may add your name or your
-        company name to the [Acknowledgements] file.
+    *   Ensure that each changed file has the correct copyright and license
+        information. Files that entirely consist of contributions to this
+        project should have the copyright notice and BSD-3-Clause SPDX license
+        identifier as shown in [license.md](./license.md). Files that contain
+        changes to imported Third Party IP should contain a notice as follows,
+        with the original copyright and license text retained:
+        ```
+        Portions copyright (c) [XXXX-]YYYY, ARM Limited and Contributors. All rights reserved.
+        ```
+        where XXXX is the year of first contribution (if different to YYYY) and
+        YYYY is the year of most recent contribution.
+    *   If not done previously, you may add your name or your company name to
+        the [Acknowledgements] file.
+    *   If you are submitting new files that you intend to be the technical
+        sub-maintainer for (for example, a new platform port), then also update
+        the [Maintainers] file.
     *   For topics with multiple commits, you should make all documentation
         changes (and nothing else) in the last commit of the series. Otherwise,
         include the documentation changes within the single commit.
@@ -66,27 +80,28 @@
 *   Push your local changes to your fork of the repository.
 *   Submit a [pull request] to the [arm-trusted-firmware] `integration` branch.
     *   The changes in the [pull request] will then undergo further review and
-        testing. Any review comments will be made as comments on the [pull
-        request]. This may require you to do some rework.
-*   When the changes are accepted, ARM will integrate them.
-    *   Typically, ARM will merge the [pull request] into the `integration`
-        branch within the GitHub UI, creating a merge commit.
+        testing by the [Maintainers]. Any review comments will be made as
+        comments on the [pull request]. This may require you to do some rework.
+*   When the changes are accepted, the [Maintainers] will integrate them.
+    *   Typically, the [Maintainers] will merge the [pull request] into the
+        `integration` branch within the GitHub UI, creating a merge commit.
     *   Please avoid creating merge commits in the [pull request] itself.
-    *   If the [pull request] is not based on a recent commit, ARM may rebase
-        it onto the `master` branch first, or ask you to do this.
-    *   If the [pull request] cannot be automatically merged, ARM will ask you
-        to rebase it onto the `master` branch.
-    *   After final integration testing, ARM will push your merge commit to the
-        `master` branch. If a problem is found at this stage, the merge commit
-        will be removed from the `integration` branch and ARM will ask you to
-        create a new pull request to resolve the problem.
+    *   If the [pull request] is not based on a recent commit, the [Maintainers]
+        may rebase it onto the `master` branch first, or ask you to do this.
+    *   If the [pull request] cannot be automatically merged, the [Maintainers]
+        will ask you to rebase it onto the `master` branch.
+    *   After final integration testing, the [Maintainers] will push your merge
+        commit to the `master` branch. If a problem is found during integration,
+        the merge commit will be removed from the `integration` branch and the
+        [Maintainers] will ask you to create a new pull request to resolve the
+        problem.
     *   Please do not delete your topic branch until it is safely merged into
         the `master` branch.
 
 
 - - - - - - - - - - - - - - - - - - - - - - - - - -
 
-_Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved._
+_Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved._
 
 
 [User Guide]:                           ./docs/user-guide.md
@@ -95,6 +110,7 @@
 [Firmware Design]:                      ./docs/firmware-design.md
 [Acknowledgements]:                     ./acknowledgements.md "Contributor acknowledgements"
 [DCO]:                                  ./dco.txt
+[Maintainers]:                          ./maintainers.md
 
 [GitHub account]:               https://github.com/signup/free
 [Fork]:                         https://help.github.com/articles/fork-a-repo
diff --git a/docs/firmware-design.md b/docs/firmware-design.md
index def802c..358292a 100644
--- a/docs/firmware-design.md
+++ b/docs/firmware-design.md
@@ -1744,8 +1744,8 @@
     ------------------
 
 The ToC header and entry formats are described in the header file
-`include/firmware_image_package.h`. This file is used by both the tool and the
-ARM Trusted firmware.
+`include/tools_share/firmware_image_package.h`. This file is used by both the
+tool and the ARM Trusted firmware.
 
 The ToC header has the following fields:
 
@@ -1760,8 +1760,9 @@
 
     `uuid`: All files are referred to by a pre-defined Universally Unique
         IDentifier [UUID] . The UUIDs are defined in
-        `include/firmware_image_package`. The platform translates the requested
-        image name into the corresponding UUID when accessing the package.
+        `include/tools_share/firmware_image_package.h`. The platform translates
+        the requested image name into the corresponding UUID when accessing the
+        package.
     `offset_address`: The offset address at which the corresponding payload data
         can be found. The offset is calculated from the ToC base address.
     `size`: The size of the corresponding payload data in bytes.
diff --git a/docs/firmware-update.md b/docs/firmware-update.md
index 21872fd..e3eec26 100644
--- a/docs/firmware-update.md
+++ b/docs/firmware-update.md
@@ -117,6 +117,7 @@
 *   RESET:         This is the initial state of every image at the start of FWU.
                    Authentication failure also leads to this state. A secure
                    image may yield to this state if it has completed execution.
+                   It can also be reached by using `FWU_SMC_IMAGE_RESET`.
 
 *   COPYING:       This is the state of a secure image while BL1 is copying it
                    in blocks from non-secure to secure memory.
@@ -211,6 +212,7 @@
         if (source block is in secure memory) return -ENOMEM
         if (source block is not mapped into BL1) return -ENOMEM
         if (image_size > free secure memory) return -ENOMEM
+        if (image overlaps another image) return -EPERM
 
 This SMC copies the secure image indicated by `image_id` from non-secure memory
 to secure memory for later authentication. The image may be copied in a single
@@ -355,9 +357,28 @@
 a `void *`. The SMC does not return.
 
 
+### FWU_SMC_IMAGE_RESET
+
+    Arguments:
+        uint32_t     function ID : 0x16
+        unsigned int image_id
+
+    Return:
+        int : 0 (Success)
+            : -EPERM
+
+    Pre-conditions:
+        if (secure world caller) return -EPERM
+        if (image in EXECUTED) return -EPERM
+
+This SMC sets the state of an image to RESET and zeroes the memory used by it.
+
+This is only allowed if the image is not being executed.
+
+
 - - - - - - - - - - - - - - - - - - - - - - - - - -
 
-_Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved._
+_Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved._
 
 
 [Porting Guide]:        ./porting-guide.md
diff --git a/docs/plat/hikey960.md b/docs/plat/hikey960.md
new file mode 100644
index 0000000..786a54b
--- /dev/null
+++ b/docs/plat/hikey960.md
@@ -0,0 +1,134 @@
+
+Description
+====================
+  HiKey960 is one of 96boards. Hisilicon Hi3660 processor is installed on HiKey960.
+
+  More information are listed in [link](http://www.96boards.org/documentation/ConsumerEdition/HiKey960/README.md).
+
+
+How to build
+====================
+
+1. Code Locations
+-----------------
+
+   * ARM Trusted Firmware:
+   [link](https://github.com/ARM-software/arm-trusted-firmware)
+
+   * edk2:
+   [link](https://github.com/96boards-hikey/edk2/tree/testing/hikey960_v2.5)
+
+   * OpenPlatformPkg:
+   [link](https://github.com/96boards-hikey/OpenPlatformPkg/tree/testing/hikey960_v1.3.4)
+
+   * l-loader:
+   [link](https://github.com/96boards-hikey/l-loader/tree/testing/hikey960_v1.2)
+
+   * uefi-tools:
+   [link](https://github.com/96boards-hikey/uefi-tools/tree/hikey960_v1)
+
+
+2. Build Procedure
+------------------
+
+   * Fetch all the above 5 repositories into local host.
+     Make all the repositories in the same ${BUILD_PATH}.
+
+   * Create the symbol link to OpenPlatformPkg in edk2.
+     <br>`$cd ${BUILD_PATH}/edk2`</br>
+     <br>`$ln -sf ../OpenPlatformPkg`</br>
+
+   * Prepare AARCH64 toolchain.
+
+   * If your hikey960 hardware is v1, update _uefi-tools/platform.config_ first. _(optional)_
+     <br>__Uncomment the below sentence. Otherwise, UEFI can't output messages on serial
+     console on hikey960 v1.__</br>
+     <br>`BUILDFLAGS=-DSERIAL_BASE=0xFDF05000`</br>
+     <br>If your hikey960 hardware is v2 or newer, nothing to do.</br>
+
+   * Build it as debug mode. Create script file for build.
+     <br>`BUILD_OPTION=DEBUG`</br>
+     <br>`export AARCH64_TOOLCHAIN=GCC48`</br>
+     <br>`export UEFI_TOOLS_DIR=${BUILD_PATH}/uefi-tools`<br>
+     <br>`export EDK2_DIR=${BUILD_PATH}/edk2`</br>
+     <br>`EDK2_OUTPUT_DIR=${EDK2_DIR}/Build/HiKey960/${BUILD_OPTION}_${AARCH64_TOOLCHAIN}`</br>
+     <br>`cd ${EDK2_DIR}`</br>
+     <br>`# Build UEFI & ARM Trust Firmware`</br>
+     <br>`${UEFI_TOOLS_DIR}/uefi-build.sh -b ${BUILD_OPTION} -a ../arm-trusted-firmware hikey960`</br>
+     <br>`# Generate l-loader.bin`</br>
+     <br>`cd ${BUILD_PATH}/l-loader`</br>
+     <br>`ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin`</br>
+     <br>`ln -sf ${EDK2_OUTPUT_DIR}/FV/fip.bin`</br>
+     <br>`ln -sf ${EDK2_OUTPUT_DIR}/FV/BL33_AP_UEFI.fd`</br>
+     <br>`python gen_loader.py -o l-loader.bin --img_bl1=bl1.bin --img_ns_bl1u=BL33_AP_UEFI.fd`</br>
+
+   * Generate partition table.
+     <br>_Make sure that you're using the sgdisk in the l-loader directory._</br>
+     <br>`$PTABLE=aosp-32g SECTOR_SIZE=4096 SGDISK=./sgdisk bash -x generate_ptable.sh`</br>
+
+
+3. Setup Console
+----------------
+
+   * Install ser2net. Use telnet as the console since UEFI will output window
+     that fails to display in minicom.
+     <br>`$sudo apt-get install ser2net`</br>
+
+   * Configure ser2net.
+     <br>`$sudo vi /etc/ser2net.conf`</br>
+     <br>Append one line for serial-over-USB in below.</br>
+     <br>_#ser2net.conf_</br>
+     <br>`2004:telnet:0:/dev/ttyUSB0:115200 8DATABITS NONE 1STOPBIT banner`</br>
+
+   * Open the console.
+     <br>`$telnet localhost 2004`</br>
+     <br>And you could open the console remotely, too.</br>
+
+
+4. Boot UEFI in recovery mode
+-----------------------------
+
+   * Fetch that are used in recovery mode. The code location is in below.
+     [link](https://github.com/96boards-hikey/tools-images-hikey960)
+
+   * Generate l-loader.bin.
+     <br>`$cd tools-images-hikey960`</br>
+     <br>`$ln -sf ${BUILD_PATH}/l-loader/l-loader.bin`</br>
+
+   * Prepare config file.
+     <br>_$vi config_</br>
+     <br>_# The content of config file_</br>
+     <br>`./sec_user_xloader.img 0x00020000`</br>
+     <br>`./sec_uce_boot.img 0x6A908000`</br>
+     <br>`./l-loader.bin 0x1AC00000`</br>
+
+   * Remove the modemmanager package. This package may causes hikey_idt tool failure.
+     <br>`$sudo apt-get purge modemmanager`</br>
+
+   * Run the command to download l-loader.bin into HiKey960.
+     <br>`$sudo ./hikey_idt -c config -p /dev/ttyUSB1`</br>
+
+   * UEFI running in recovery mode.
+     <br>When prompt '.' is displayed on console, press hotkey 'f' in keyboard. Then Android fastboot app is running.</br>
+     <br>The timeout of prompt '.' is 10 seconds.</br>
+
+   * Update images.
+     <br>`$sudo fastboot flash ptable prm_ptable.img`</br>
+     <br>`$sudo fastboot flash xloader sec_xloader.img`</br>
+     <br>`$sudo fastboot flash fastboot l-loader.bin`</br>
+     <br>`$sudo fastboot flash fip fip.bin`</br>
+     <br>`$sudo fastboot flash boot boot.img`</br>
+     <br>`$sudo fastboot flash cache cache.img`</br>
+     <br>`$sudo fastboot flash system system.img`</br>
+     <br>`$sudo fastboot flash userdata userdata.img`</br>
+
+   * Notice: UEFI could also boot kernel in recovery mode, but BL31 isn't loaded in
+     recovery mode.
+
+
+5. Boot UEFI in normal mode
+-----------------------------
+
+   * Make sure "Boot Mode" switch is OFF for normal boot mode. Then power on HiKey960.
+
+   * Reference [link](https://github.com/96boards-hikey/tools-images-hikey960/blob/master/build-from-source/README-ATF-UEFI-build-from-source.md)
diff --git a/docs/porting-guide.md b/docs/porting-guide.md
index 4d7a5ea..c7b9e89 100644
--- a/docs/porting-guide.md
+++ b/docs/porting-guide.md
@@ -354,6 +354,13 @@
     NS_BL2U image identifier, used by BL1 to fetch an image descriptor
     corresponding to NS_BL2U.
 
+For the the Firmware update capability of TRUSTED BOARD BOOT, the following
+macros may also be defined:
+
+*   **#define : PLAT_FWU_MAX_SIMULTANEOUS_IMAGES**
+
+    Total number of images that can be loaded simultaneously. If the platform
+    doesn't specify any value, it defaults to 10.
 
 If a SCP_BL2 image is supported by the platform, the following constants must
 also be defined:
diff --git a/docs/user-guide.md b/docs/user-guide.md
index 5165000..0065ac0 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -300,9 +300,6 @@
 *   `DEBUG`: Chooses between a debug and release build. It can take either 0
     (release) or 1 (debug) as values. 0 is the default.
 
-*   `DISABLE_PEDANTIC`: When set to 1 it will disable the -pedantic option in
-    the GCC command line. Default is 0.
-
 *   `EL3_PAYLOAD_BASE`: This option enables booting an EL3 payload instead of
     the normal boot flow. It must specify the entry point address of the EL3
     payload. Please refer to the "Booting an EL3 payload" section for more
@@ -625,6 +622,10 @@
     SCP_BL2U to the FIP and FWU_FIP respectively, and enables them to be loaded
     during boot. Default is 1.
 
+*   `CSS_USE_SCMI_DRIVER`: Boolean flag which selects SCMI driver instead of
+    SCPI driver for communicating with the SCP during power management operations.
+    If this option is set to 1, then SCMI driver will be used. Default is 0.
+
 #### ARM FVP platform specific build options
 
 *   `FVP_CLUSTER_COUNT`    : Configures the cluster count to be used to
@@ -641,6 +642,7 @@
                                 if `FVP_CLUSTER_COUNT` > 2.
 
 *   `FVP_USE_GIC_DRIVER`   : Selects the GIC driver to be built. Options:
+    -    `FVP_GIC600`      : The GIC600 implementation of GICv3 is selected
     -    `FVP_GICV2`       : The GICv2 only driver is selected
     -    `FVP_GICV3`       : The GICv3 only driver is selected (default option)
     -    `FVP_GICV3_LEGACY`: The Legacy GICv3 driver is selected (deprecated)
diff --git a/drivers/arm/gic/v3/gic600.c b/drivers/arm/gic/v3/gic600.c
new file mode 100644
index 0000000..4ea31ab
--- /dev/null
+++ b/drivers/arm/gic/v3/gic600.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Driver for GIC600-specific features. This driver only overrides APIs that are
+ * different to those generic ones in GICv3 driver.
+ *
+ * GIC600 supports independently power-gating redistributor interface.
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <gicv3.h>
+
+#include "gicv3_private.h"
+
+/* GIC600-specific register offsets */
+#define GICR_PWRR		0x24
+
+/* GICR_PWRR fields */
+#define PWRR_RDPD_SHIFT		0
+#define PWRR_RDGPD_SHIFT	2
+#define PWRR_RDGPO_SHIFT	3
+
+#define PWRR_RDGPD		(1 << PWRR_RDGPD_SHIFT)
+#define PWRR_RDGPO		(1 << PWRR_RDGPO_SHIFT)
+
+/* Values to write to GICR_PWRR register to power redistributor */
+#define PWRR_ON			(0 << PWRR_RDPD_SHIFT)
+#define PWRR_OFF		(1 << PWRR_RDPD_SHIFT)
+
+/* Generic GICv3 resources */
+extern const gicv3_driver_data_t *gicv3_driver_data;
+
+/* GIC600-specific accessor functions */
+static void gicr_write_pwrr(uintptr_t base, unsigned int val)
+{
+       mmio_write_32(base + GICR_PWRR, val);
+}
+
+static uint32_t gicr_read_pwrr(uintptr_t base)
+{
+       return mmio_read_32(base + GICR_PWRR);
+}
+
+static int gicr_group_powering_down(uint32_t pwrr)
+{
+	/*
+	 * Whether the redistributor group power down operation is in transit:
+	 * i.e. it's intending to, but not finished yet.
+	 */
+	return ((pwrr & PWRR_RDGPD) && !(pwrr & PWRR_RDGPO));
+}
+
+static void gic600_pwr_on(uintptr_t base)
+{
+	/* Power on redistributor */
+	gicr_write_pwrr(base, PWRR_ON);
+
+	/* Wait until the power on state is reflected */
+	while (gicr_read_pwrr(base) & PWRR_RDGPO)
+		;
+}
+
+static void gic600_pwr_off(uintptr_t base)
+{
+	/* Power off redistributor */
+	gicr_write_pwrr(base, PWRR_OFF);
+
+	/*
+	 * If this is the last man, turning this redistributor frame off will
+	 * result in the group itself being powered off. In that case, wait as
+	 * long as it's in transition, or has aborted the transition altogether
+	 * for any reason.
+	 */
+	if (gicr_read_pwrr(base) & PWRR_RDGPD) {
+		while (gicr_group_powering_down(gicr_read_pwrr(base)))
+			;
+	}
+}
+
+/*
+ * Power off GIC600 redistributor
+ */
+void gicv3_rdistif_off(unsigned int proc_num)
+{
+	uintptr_t gicr_base;
+
+	assert(gicv3_driver_data);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+	assert(gicr_base);
+
+	/* Attempt to power redistributor off */
+	gic600_pwr_off(gicr_base);
+}
+
+/*
+ * Power on GIC600 redistributor
+ */
+void gicv3_rdistif_on(unsigned int proc_num)
+{
+	uintptr_t gicr_base;
+
+	assert(gicv3_driver_data);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+	assert(gicr_base);
+
+	/* Power redistributor on */
+	gic600_pwr_on(gicr_base);
+}
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index 566c446..b68d998 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -8,12 +8,10 @@
 #include <arch_helpers.h>
 #include <assert.h>
 #include <debug.h>
-#include <gic_common.h>
 #include <gicv3.h>
-#include "../common/gic_common_private.h"
 #include "gicv3_private.h"
 
-static const gicv3_driver_data_t *driver_data;
+const gicv3_driver_data_t *gicv3_driver_data;
 static unsigned int gicv2_compat;
 
 /*
@@ -90,18 +88,20 @@
 					   plat_driver_data->gicr_base,
 					   plat_driver_data->mpidr_to_core_pos);
 
-	driver_data = plat_driver_data;
+	gicv3_driver_data = plat_driver_data;
 
 	/*
 	 * The GIC driver data is initialized by the primary CPU with caches
 	 * enabled. When the secondary CPU boots up, it initializes the
 	 * GICC/GICR interface with the caches disabled. Hence flush the
-	 * driver_data to ensure coherency. This is not required if the
+	 * driver data to ensure coherency. This is not required if the
 	 * platform has HW_ASSISTED_COHERENCY enabled.
 	 */
 #if !HW_ASSISTED_COHERENCY
-	flush_dcache_range((uintptr_t) &driver_data, sizeof(driver_data));
-	flush_dcache_range((uintptr_t) driver_data, sizeof(*driver_data));
+	flush_dcache_range((uintptr_t) &gicv3_driver_data,
+			sizeof(gicv3_driver_data));
+	flush_dcache_range((uintptr_t) gicv3_driver_data,
+			sizeof(*gicv3_driver_data));
 #endif
 
 	INFO("GICv3 %s legacy support detected."
@@ -117,10 +117,10 @@
 {
 	unsigned int bitmap = 0;
 
-	assert(driver_data);
-	assert(driver_data->gicd_base);
-	assert(driver_data->g1s_interrupt_array ||
-	       driver_data->g0_interrupt_array);
+	assert(gicv3_driver_data);
+	assert(gicv3_driver_data->gicd_base);
+	assert(gicv3_driver_data->g1s_interrupt_array ||
+	       gicv3_driver_data->g0_interrupt_array);
 
 	assert(IS_IN_EL3());
 
@@ -129,39 +129,39 @@
 	 * the ARE_S bit. The Distributor might generate a system error
 	 * otherwise.
 	 */
-	gicd_clr_ctlr(driver_data->gicd_base,
+	gicd_clr_ctlr(gicv3_driver_data->gicd_base,
 		      CTLR_ENABLE_G0_BIT |
 		      CTLR_ENABLE_G1S_BIT |
 		      CTLR_ENABLE_G1NS_BIT,
 		      RWP_TRUE);
 
 	/* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */
-	gicd_set_ctlr(driver_data->gicd_base,
+	gicd_set_ctlr(gicv3_driver_data->gicd_base,
 			CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE);
 
 	/* Set the default attribute of all SPIs */
-	gicv3_spis_configure_defaults(driver_data->gicd_base);
+	gicv3_spis_configure_defaults(gicv3_driver_data->gicd_base);
 
 	/* Configure the G1S SPIs */
-	if (driver_data->g1s_interrupt_array) {
-		gicv3_secure_spis_configure(driver_data->gicd_base,
-					driver_data->g1s_interrupt_num,
-					driver_data->g1s_interrupt_array,
+	if (gicv3_driver_data->g1s_interrupt_array) {
+		gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
+					gicv3_driver_data->g1s_interrupt_num,
+					gicv3_driver_data->g1s_interrupt_array,
 					INTR_GROUP1S);
 		bitmap |= CTLR_ENABLE_G1S_BIT;
 	}
 
 	/* Configure the G0 SPIs */
-	if (driver_data->g0_interrupt_array) {
-		gicv3_secure_spis_configure(driver_data->gicd_base,
-					driver_data->g0_interrupt_num,
-					driver_data->g0_interrupt_array,
+	if (gicv3_driver_data->g0_interrupt_array) {
+		gicv3_secure_spis_configure(gicv3_driver_data->gicd_base,
+					gicv3_driver_data->g0_interrupt_num,
+					gicv3_driver_data->g0_interrupt_array,
 					INTR_GROUP0);
 		bitmap |= CTLR_ENABLE_G0_BIT;
 	}
 
 	/* Enable the secure SPIs now that they have been configured */
-	gicd_set_ctlr(driver_data->gicd_base, bitmap, RWP_TRUE);
+	gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE);
 }
 
 /*******************************************************************************
@@ -173,37 +173,37 @@
 {
 	uintptr_t gicr_base;
 
-	assert(driver_data);
-	assert(proc_num < driver_data->rdistif_num);
-	assert(driver_data->rdistif_base_addrs);
-	assert(driver_data->gicd_base);
-	assert(gicd_read_ctlr(driver_data->gicd_base) & CTLR_ARE_S_BIT);
-	assert(driver_data->g1s_interrupt_array ||
-	       driver_data->g0_interrupt_array);
+	assert(gicv3_driver_data);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
+	assert(gicv3_driver_data->gicd_base);
+	assert(gicd_read_ctlr(gicv3_driver_data->gicd_base) & CTLR_ARE_S_BIT);
+	assert(gicv3_driver_data->g1s_interrupt_array ||
+	       gicv3_driver_data->g0_interrupt_array);
 
 	assert(IS_IN_EL3());
 
 	/* Power on redistributor */
 	gicv3_rdistif_on(proc_num);
 
-	gicr_base = driver_data->rdistif_base_addrs[proc_num];
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
 
 	/* Set the default attribute of all SGIs and PPIs */
 	gicv3_ppi_sgi_configure_defaults(gicr_base);
 
 	/* Configure the G1S SGIs/PPIs */
-	if (driver_data->g1s_interrupt_array) {
+	if (gicv3_driver_data->g1s_interrupt_array) {
 		gicv3_secure_ppi_sgi_configure(gicr_base,
-					driver_data->g1s_interrupt_num,
-					driver_data->g1s_interrupt_array,
+					gicv3_driver_data->g1s_interrupt_num,
+					gicv3_driver_data->g1s_interrupt_array,
 					INTR_GROUP1S);
 	}
 
 	/* Configure the G0 SGIs/PPIs */
-	if (driver_data->g0_interrupt_array) {
+	if (gicv3_driver_data->g0_interrupt_array) {
 		gicv3_secure_ppi_sgi_configure(gicr_base,
-					driver_data->g0_interrupt_num,
-					driver_data->g0_interrupt_array,
+					gicv3_driver_data->g0_interrupt_num,
+					gicv3_driver_data->g0_interrupt_array,
 					INTR_GROUP0);
 	}
 }
@@ -231,13 +231,13 @@
 	unsigned int scr_el3;
 	unsigned int icc_sre_el3;
 
-	assert(driver_data);
-	assert(proc_num < driver_data->rdistif_num);
-	assert(driver_data->rdistif_base_addrs);
+	assert(gicv3_driver_data);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
 	assert(IS_IN_EL3());
 
 	/* Mark the connected core as awake */
-	gicr_base = driver_data->rdistif_base_addrs[proc_num];
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
 	gicv3_rdistif_mark_core_awake(gicr_base);
 
 	/* Disable the legacy interrupt bypass */
@@ -291,9 +291,9 @@
 {
 	uintptr_t gicr_base;
 
-	assert(driver_data);
-	assert(proc_num < driver_data->rdistif_num);
-	assert(driver_data->rdistif_base_addrs);
+	assert(gicv3_driver_data);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
+	assert(gicv3_driver_data->rdistif_base_addrs);
 
 	assert(IS_IN_EL3());
 
@@ -314,7 +314,7 @@
 	isb();
 
 	/* Mark the connected core as asleep */
-	gicr_base = driver_data->rdistif_base_addrs[proc_num];
+	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
 	gicv3_rdistif_mark_core_asleep(gicr_base);
 }
 
@@ -371,25 +371,25 @@
 	uintptr_t gicr_base;
 
 	assert(IS_IN_EL3());
-	assert(driver_data);
+	assert(gicv3_driver_data);
 
 	/* Ensure the parameters are valid */
 	assert(id < PENDING_G1S_INTID || id >= MIN_LPI_ID);
-	assert(proc_num < driver_data->rdistif_num);
+	assert(proc_num < gicv3_driver_data->rdistif_num);
 
 	/* All LPI interrupts are Group 1 non secure */
 	if (id >= MIN_LPI_ID)
 		return INTR_GROUP1NS;
 
 	if (id < MIN_SPI_ID) {
-		assert(driver_data->rdistif_base_addrs);
-		gicr_base = driver_data->rdistif_base_addrs[proc_num];
+		assert(gicv3_driver_data->rdistif_base_addrs);
+		gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
 		igroup = gicr_get_igroupr0(gicr_base, id);
 		grpmodr = gicr_get_igrpmodr0(gicr_base, id);
 	} else {
-		assert(driver_data->gicd_base);
-		igroup = gicd_get_igroupr(driver_data->gicd_base, id);
-		grpmodr = gicd_get_igrpmodr(driver_data->gicd_base, id);
+		assert(gicv3_driver_data->gicd_base);
+		igroup = gicd_get_igroupr(gicv3_driver_data->gicd_base, id);
+		grpmodr = gicd_get_igrpmodr(gicv3_driver_data->gicd_base, id);
 	}
 
 	/*
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
index 473fdb1..f95cfab 100644
--- a/drivers/arm/gic/v3/gicv3_private.h
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,9 +7,11 @@
 #ifndef __GICV3_PRIVATE_H__
 #define __GICV3_PRIVATE_H__
 
+#include <gic_common.h>
 #include <gicv3.h>
 #include <mmio.h>
 #include <stdint.h>
+#include "../common/gic_common_private.h"
 
 /*******************************************************************************
  * GICv3 private macro definitions
diff --git a/drivers/auth/mbedtls/mbedtls_common.c b/drivers/auth/mbedtls/mbedtls_common.c
index 336e44b..e9aa409 100644
--- a/drivers/auth/mbedtls/mbedtls_common.c
+++ b/drivers/auth/mbedtls/mbedtls_common.c
@@ -9,6 +9,7 @@
 /* mbed TLS headers */
 #include <mbedtls/memory_buffer_alloc.h>
 #include <mbedtls/platform.h>
+#include <mbedtls_config.h>
 
 /*
  * mbed TLS heap
@@ -16,7 +17,7 @@
 #if (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA)
 #define MBEDTLS_HEAP_SIZE		(14*1024)
 #elif (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA)
-#define MBEDTLS_HEAP_SIZE		(6*1024)
+#define MBEDTLS_HEAP_SIZE		(7*1024)
 #endif
 static unsigned char heap[MBEDTLS_HEAP_SIZE];
 
@@ -31,8 +32,10 @@
 		/* Initialize the mbed TLS heap */
 		mbedtls_memory_buffer_alloc_init(heap, MBEDTLS_HEAP_SIZE);
 
+#ifdef MBEDTLS_PLATFORM_SNPRINTF_ALT
 		/* Use reduced version of snprintf to save space. */
 		mbedtls_platform_set_snprintf(tf_snprintf);
+#endif
 
 		ready = 1;
 	}
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.c b/drivers/auth/mbedtls/mbedtls_crypto.c
index 2c15148..b157a32 100644
--- a/drivers/auth/mbedtls/mbedtls_crypto.c
+++ b/drivers/auth/mbedtls/mbedtls_crypto.c
@@ -60,7 +60,7 @@
 	mbedtls_asn1_buf signature;
 	mbedtls_md_type_t md_alg;
 	mbedtls_pk_type_t pk_alg;
-	mbedtls_pk_context pk;
+	mbedtls_pk_context pk = {0};
 	int rc;
 	void *sig_opts = NULL;
 	const mbedtls_md_info_t *md_info;
@@ -76,7 +76,7 @@
 	}
 
 	/* Get the actual signature algorithm (MD + PK) */
-	rc = mbedtls_oid_get_sig_alg(&sig_oid, &md_alg, &pk_alg);
+	rc = mbedtls_x509_get_sig_alg(&sig_oid, &sig_params, &md_alg, &pk_alg, &sig_opts);
 	if (rc != 0) {
 		return CRYPTO_ERR_SIGNATURE;
 	}
@@ -87,7 +87,8 @@
 	end = (unsigned char *)(p + pk_len);
 	rc = mbedtls_pk_parse_subpubkey(&p, end, &pk);
 	if (rc != 0) {
-		return CRYPTO_ERR_SIGNATURE;
+		rc = CRYPTO_ERR_SIGNATURE;
+		goto end2;
 	}
 
 	/* Get the signature (bitstring) */
@@ -97,7 +98,7 @@
 	rc = mbedtls_asn1_get_bitstring_null(&p, end, &signature.len);
 	if (rc != 0) {
 		rc = CRYPTO_ERR_SIGNATURE;
-		goto end;
+		goto end1;
 	}
 	signature.p = p;
 
@@ -105,13 +106,13 @@
 	md_info = mbedtls_md_info_from_type(md_alg);
 	if (md_info == NULL) {
 		rc = CRYPTO_ERR_SIGNATURE;
-		goto end;
+		goto end1;
 	}
 	p = (unsigned char *)data_ptr;
 	rc = mbedtls_md(md_info, p, data_len, hash);
 	if (rc != 0) {
 		rc = CRYPTO_ERR_SIGNATURE;
-		goto end;
+		goto end1;
 	}
 
 	/* Verify the signature */
@@ -120,14 +121,16 @@
 			signature.p, signature.len);
 	if (rc != 0) {
 		rc = CRYPTO_ERR_SIGNATURE;
-		goto end;
+		goto end1;
 	}
 
 	/* Signature verification success */
 	rc = CRYPTO_SUCCESS;
 
-end:
+end1:
 	mbedtls_pk_free(&pk);
+end2:
+	mbedtls_free(sig_opts);
 	return rc;
 }
 
diff --git a/include/bl1/bl1.h b/include/bl1/bl1.h
index 8f4f992..1544523 100644
--- a/include/bl1/bl1.h
+++ b/include/bl1/bl1.h
@@ -39,11 +39,12 @@
 #define FWU_SMC_IMAGE_RESUME		0x13
 #define FWU_SMC_SEC_IMAGE_DONE		0x14
 #define FWU_SMC_UPDATE_DONE		0x15
+#define FWU_SMC_IMAGE_RESET		0x16
 
 /*
  * Number of FWU calls (above) implemented
  */
-#define FWU_NUM_SMC_CALLS		6
+#define FWU_NUM_SMC_CALLS		7
 
 #if TRUSTED_BOARD_BOOT
 # define BL1_NUM_SMC_CALLS		(FWU_NUM_SMC_CALLS + 4)
@@ -56,7 +57,7 @@
  * calls from the SMC function ID
  */
 #define FWU_SMC_FID_START		FWU_SMC_IMAGE_COPY
-#define FWU_SMC_FID_END			FWU_SMC_UPDATE_DONE
+#define FWU_SMC_FID_END			FWU_SMC_IMAGE_RESET
 #define is_fwu_fid(_fid) \
     ((_fid >= FWU_SMC_FID_START) && (_fid <= FWU_SMC_FID_END))
 
diff --git a/include/drivers/auth/mbedtls/mbedtls_config.h b/include/drivers/auth/mbedtls/mbedtls_config.h
index 22e7574..0a05886 100644
--- a/include/drivers/auth/mbedtls/mbedtls_config.h
+++ b/include/drivers/auth/mbedtls/mbedtls_config.h
@@ -22,12 +22,15 @@
 /* Prevent mbed TLS from using snprintf so that it can use tf_snprintf. */
 #define MBEDTLS_PLATFORM_SNPRINTF_ALT
 
+#if !ERROR_DEPRECATED
 #define MBEDTLS_PKCS1_V15
+#endif
 #define MBEDTLS_PKCS1_V21
 
 #define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
 #define MBEDTLS_X509_CHECK_KEY_USAGE
 #define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE
+#define MBEDTLS_X509_RSASSA_PSS_SUPPORT
 
 #define MBEDTLS_ASN1_PARSE_C
 #define MBEDTLS_ASN1_WRITE_C
diff --git a/include/lib/cpus/aarch64/cortex_a55.h b/include/lib/cpus/aarch64/cortex_a55.h
new file mode 100644
index 0000000..293f2b2
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a55.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CORTEX_A55_H__
+#define __CORTEX_A55_H__
+
+/* Cortex-A55 MIDR for revision 0 */
+#define CORTEX_A55_MIDR		0x410fd050
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A55_CPUPWRCTLR_EL1		S3_0_C15_C2_7
+#define CORTEX_A55_CPUECTLR_EL1		S3_0_C15_C1_4
+
+/* Definitions of register field mask in CORTEX_A55_CPUPWRCTLR_EL1 */
+#define CORTEX_A55_CORE_PWRDN_EN_MASK	0x1
+
+#endif /* __CORTEX_A55_H__ */
diff --git a/include/lib/cpus/aarch64/cortex_a75.h b/include/lib/cpus/aarch64/cortex_a75.h
new file mode 100644
index 0000000..1ffe20b
--- /dev/null
+++ b/include/lib/cpus/aarch64/cortex_a75.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CORTEX_A75_H__
+#define __CORTEX_A75_H__
+
+/* Cortex-A75 MIDR */
+#define CORTEX_A75_MIDR		0x410fd0a0
+
+/*******************************************************************************
+ * CPU Extended Control register specific definitions.
+ ******************************************************************************/
+#define CORTEX_A75_CPUPWRCTLR_EL1	S3_0_C15_C2_7
+#define CORTEX_A75_CPUECTLR_EL1		S3_0_C15_C1_4
+
+/* Definitions of register field mask in CORTEX_A75_CPUPWRCTLR_EL1 */
+#define CORTEX_A75_CORE_PWRDN_EN_MASK	0x1
+
+#endif /* __CORTEX_A75_H__ */
diff --git a/include/lib/stdlib/machine/endian.h b/include/lib/stdlib/machine/endian.h
new file mode 100644
index 0000000..57e33b1
--- /dev/null
+++ b/include/lib/stdlib/machine/endian.h
@@ -0,0 +1,168 @@
+/*-
+ * Copyright (c) 2001 David E. O'Brien
+ *
+ * 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.
+ * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ *	@(#)endian.h	8.1 (Berkeley) 6/10/93
+ * $NetBSD: endian.h,v 1.7 1999/08/21 05:53:51 simonb Exp $
+ * $FreeBSD$
+ */
+/*
+ * Portions copyright (c) 2017, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef _MACHINE_ENDIAN_H_
+#define	_MACHINE_ENDIAN_H_
+
+#include <sys/_types.h>
+
+/*
+ * Definitions for byte order, according to byte significance from low
+ * address to high.
+ */
+#define	_LITTLE_ENDIAN  1234    /* LSB first: i386, vax */
+#define	_BIG_ENDIAN     4321    /* MSB first: 68000, ibm, net */
+#define	_PDP_ENDIAN     3412    /* LSB first in word, MSW first in long */
+
+#define	_BYTE_ORDER	_LITTLE_ENDIAN
+
+#if __BSD_VISIBLE
+#define	LITTLE_ENDIAN   _LITTLE_ENDIAN
+#define	BIG_ENDIAN      _BIG_ENDIAN
+#define	PDP_ENDIAN      _PDP_ENDIAN
+#define	BYTE_ORDER      _BYTE_ORDER
+#endif
+
+#define	_QUAD_HIGHWORD  1
+#define	_QUAD_LOWWORD 0
+#define	__ntohl(x)        (__bswap32(x))
+#define	__ntohs(x)        (__bswap16(x))
+#define	__htonl(x)        (__bswap32(x))
+#define	__htons(x)        (__bswap16(x))
+
+#ifdef AARCH32
+static __inline __uint64_t
+__bswap64(__uint64_t _x)
+{
+
+	return ((_x >> 56) | ((_x >> 40) & 0xff00) | ((_x >> 24) & 0xff0000) |
+	    ((_x >> 8) & 0xff000000) | ((_x << 8) & ((__uint64_t)0xff << 32)) |
+	    ((_x << 24) & ((__uint64_t)0xff << 40)) |
+	    ((_x << 40) & ((__uint64_t)0xff << 48)) | ((_x << 56)));
+}
+
+static __inline __uint32_t
+__bswap32_var(__uint32_t v)
+{
+	__uint32_t t1;
+
+	__asm __volatile("eor %1, %0, %0, ror #16\n"
+			"bic %1, %1, #0x00ff0000\n"
+			"mov %0, %0, ror #8\n"
+			"eor %0, %0, %1, lsr #8\n"
+			 : "+r" (v), "=r" (t1));
+
+	return (v);
+}
+
+static __inline __uint16_t
+__bswap16_var(__uint16_t v)
+{
+	__uint32_t ret = v & 0xffff;
+
+	__asm __volatile(
+	    "mov    %0, %0, ror #8\n"
+	    "orr    %0, %0, %0, lsr #16\n"
+	    "bic    %0, %0, %0, lsl #16"
+	    : "+r" (ret));
+
+	return ((__uint16_t)ret);
+}
+#elif defined AARCH64
+static __inline __uint64_t
+__bswap64(__uint64_t x)
+{
+	__uint64_t ret;
+
+	__asm __volatile("rev %0, %1\n"
+			 : "=&r" (ret), "+r" (x));
+	
+	return (ret);
+}
+
+static __inline __uint32_t
+__bswap32_var(__uint32_t v)
+{
+	__uint32_t ret;
+
+	__asm __volatile("rev32 %x0, %x1\n"
+			 : "=&r" (ret), "+r" (v));
+	
+	return (ret);
+}
+
+static __inline __uint16_t
+__bswap16_var(__uint16_t v)
+{
+	__uint32_t ret;
+
+	__asm __volatile("rev16 %w0, %w1\n"
+			 : "=&r" (ret), "+r" (v));
+
+	return ((__uint16_t)ret);
+}		
+#else
+#error "Only AArch32 or AArch64 supported"
+#endif /* AARCH32 */
+
+#ifdef __OPTIMIZE__
+
+#define	__bswap32_constant(x)	\
+    ((((x) & 0xff000000U) >> 24) |	\
+     (((x) & 0x00ff0000U) >>  8) |	\
+     (((x) & 0x0000ff00U) <<  8) |	\
+     (((x) & 0x000000ffU) << 24))
+
+#define	__bswap16_constant(x)	\
+    ((((x) & 0xff00) >> 8) |		\
+     (((x) & 0x00ff) << 8))
+
+#define	__bswap16(x)	\
+    ((__uint16_t)(__builtin_constant_p(x) ?	\
+     __bswap16_constant(x) :			\
+     __bswap16_var(x)))
+
+#define	__bswap32(x)	\
+    ((__uint32_t)(__builtin_constant_p(x) ? 	\
+     __bswap32_constant(x) :			\
+     __bswap32_var(x)))
+
+#else
+#define	__bswap16(x)	__bswap16_var(x)
+#define	__bswap32(x)	__bswap32_var(x)
+
+#endif /* __OPTIMIZE__ */
+#endif /* !_MACHINE_ENDIAN_H_ */
diff --git a/include/lib/stdlib/sys/endian.h b/include/lib/stdlib/sys/endian.h
new file mode 100644
index 0000000..d50110c
--- /dev/null
+++ b/include/lib/stdlib/sys/endian.h
@@ -0,0 +1,205 @@
+/*-
+ * Copyright (c) 2002 Thomas Moestl <tmm@FreeBSD.org>
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_ENDIAN_H_
+#define _SYS_ENDIAN_H_
+
+#include <sys/cdefs.h>
+#include <sys/_types.h>
+#include <machine/endian.h>
+
+#ifndef _UINT8_T_DECLARED
+typedef	__uint8_t	uint8_t;
+#define	_UINT8_T_DECLARED
+#endif
+ 
+#ifndef _UINT16_T_DECLARED
+typedef	__uint16_t	uint16_t;
+#define	_UINT16_T_DECLARED
+#endif
+ 
+#ifndef _UINT32_T_DECLARED
+typedef	__uint32_t	uint32_t;
+#define	_UINT32_T_DECLARED
+#endif
+ 
+#ifndef _UINT64_T_DECLARED
+typedef	__uint64_t	uint64_t;
+#define	_UINT64_T_DECLARED
+#endif
+ 
+/*
+ * General byte order swapping functions.
+ */
+#define	bswap16(x)	__bswap16(x)
+#define	bswap32(x)	__bswap32(x)
+#define	bswap64(x)	__bswap64(x)
+
+/*
+ * Host to big endian, host to little endian, big endian to host, and little
+ * endian to host byte order functions as detailed in byteorder(9).
+ */
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#define	htobe16(x)	bswap16((x))
+#define	htobe32(x)	bswap32((x))
+#define	htobe64(x)	bswap64((x))
+#define	htole16(x)	((uint16_t)(x))
+#define	htole32(x)	((uint32_t)(x))
+#define	htole64(x)	((uint64_t)(x))
+
+#define	be16toh(x)	bswap16((x))
+#define	be32toh(x)	bswap32((x))
+#define	be64toh(x)	bswap64((x))
+#define	le16toh(x)	((uint16_t)(x))
+#define	le32toh(x)	((uint32_t)(x))
+#define	le64toh(x)	((uint64_t)(x))
+#else /* _BYTE_ORDER != _LITTLE_ENDIAN */
+#define	htobe16(x)	((uint16_t)(x))
+#define	htobe32(x)	((uint32_t)(x))
+#define	htobe64(x)	((uint64_t)(x))
+#define	htole16(x)	bswap16((x))
+#define	htole32(x)	bswap32((x))
+#define	htole64(x)	bswap64((x))
+
+#define	be16toh(x)	((uint16_t)(x))
+#define	be32toh(x)	((uint32_t)(x))
+#define	be64toh(x)	((uint64_t)(x))
+#define	le16toh(x)	bswap16((x))
+#define	le32toh(x)	bswap32((x))
+#define	le64toh(x)	bswap64((x))
+#endif /* _BYTE_ORDER == _LITTLE_ENDIAN */
+
+/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */
+
+static __inline uint16_t
+be16dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return ((p[0] << 8) | p[1]);
+}
+
+static __inline uint32_t
+be32dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+static __inline uint64_t
+be64dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4));
+}
+
+static __inline uint16_t
+le16dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return ((p[1] << 8) | p[0]);
+}
+
+static __inline uint32_t
+le32dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
+}
+
+static __inline uint64_t
+le64dec(const void *pp)
+{
+	uint8_t const *p = (uint8_t const *)pp;
+
+	return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
+}
+
+static __inline void
+be16enc(void *pp, uint16_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	p[0] = (u >> 8) & 0xff;
+	p[1] = u & 0xff;
+}
+
+static __inline void
+be32enc(void *pp, uint32_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	p[0] = (u >> 24) & 0xff;
+	p[1] = (u >> 16) & 0xff;
+	p[2] = (u >> 8) & 0xff;
+	p[3] = u & 0xff;
+}
+
+static __inline void
+be64enc(void *pp, uint64_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	be32enc(p, (uint32_t)(u >> 32));
+	be32enc(p + 4, (uint32_t)(u & 0xffffffffU));
+}
+
+static __inline void
+le16enc(void *pp, uint16_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	p[0] = u & 0xff;
+	p[1] = (u >> 8) & 0xff;
+}
+
+static __inline void
+le32enc(void *pp, uint32_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	p[0] = u & 0xff;
+	p[1] = (u >> 8) & 0xff;
+	p[2] = (u >> 16) & 0xff;
+	p[3] = (u >> 24) & 0xff;
+}
+
+static __inline void
+le64enc(void *pp, uint64_t u)
+{
+	uint8_t *p = (uint8_t *)pp;
+
+	le32enc(p, (uint32_t)(u & 0xffffffffU));
+	le32enc(p + 4, (uint32_t)(u >> 32));
+}
+
+#endif	/* _SYS_ENDIAN_H_ */
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index 7967173..62c0ce7 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -46,7 +46,7 @@
  * arm_lock_xxx() macros
  */
 #define ARM_INSTANTIATE_LOCK	DEFINE_BAKERY_LOCK(arm_lock);
-
+#define ARM_LOCK_GET_INSTANCE	(&arm_lock)
 /*
  * These are wrapper macros to the Coherent Memory Bakery Lock API.
  */
@@ -60,6 +60,7 @@
  * Empty macros for all other BL stages other than BL31 and BL32
  */
 #define ARM_INSTANTIATE_LOCK
+#define ARM_LOCK_GET_INSTANCE	0
 #define arm_lock_init()
 #define arm_lock_get()
 #define arm_lock_release()
diff --git a/include/plat/arm/css/common/css_def.h b/include/plat/arm/css/common/css_def.h
index 6f9d640..0b74ced 100644
--- a/include/plat/arm/css/common/css_def.h
+++ b/include/plat/arm/css/common/css_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -48,6 +48,17 @@
 					CSS_IRQ_SEC_SYS_TIMER
 
 /*
+ * The lower Non-secure MHU channel is being used for SCMI for ARM Trusted
+ * Firmware.
+ * TODO: Move SCMI to Secure channel once the migration to SCMI in SCP is
+ * complete.
+ */
+#define MHU_CPU_INTR_L_SET_OFFSET	0x108
+#define MHU_CPU_INTR_H_SET_OFFSET	0x128
+#define CSS_SCMI_PAYLOAD_BASE		(NSRAM_BASE + 0x500)
+#define CSS_SCMI_MHU_DB_REG_OFF		MHU_CPU_INTR_L_SET_OFFSET
+
+/*
  * SCP <=> AP boot configuration
  *
  * The SCP/AP boot configuration is a 32-bit word located at a known offset from
@@ -63,6 +74,11 @@
 						CSS_DEVICE_SIZE,	\
 						MT_DEVICE | MT_RW | MT_SECURE)
 
+#define CSS_MAP_NSRAM			MAP_REGION_FLAT(		\
+						NSRAM_BASE,	\
+						NSRAM_SIZE,	\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
 /* Platform ID address */
 #define SSC_VERSION_OFFSET			0x040
 
diff --git a/lib/cpus/aarch64/cortex_a55.S b/lib/cpus/aarch64/cortex_a55.S
new file mode 100644
index 0000000..f103159
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a55.S
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cortex_a55.h>
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl_common.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+	/* ---------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ---------------------------------------------
+	 */
+func cortex_a55_core_pwr_dwn
+	/* ---------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_A55_CPUPWRCTLR_EL1
+	orr	x0, x0, #CORTEX_A55_CORE_PWRDN_EN_MASK
+	msr	CORTEX_A55_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc cortex_a55_core_pwr_dwn
+
+	/* ---------------------------------------------
+	 * This function provides cortex_a55 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a55_regs, "aS"
+cortex_a55_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func cortex_a55_cpu_reg_dump
+	adr	x6, cortex_a55_regs
+	mrs	x8, CORTEX_A55_CPUECTLR_EL1
+	ret
+endfunc cortex_a55_cpu_reg_dump
+
+declare_cpu_ops cortex_a55, CORTEX_A55_MIDR, \
+	CPU_NO_RESET_FUNC, \
+	cortex_a55_core_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a75.S b/lib/cpus/aarch64/cortex_a75.S
new file mode 100644
index 0000000..1f4500c
--- /dev/null
+++ b/lib/cpus/aarch64/cortex_a75.S
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <bl_common.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+#include <cortex_a75.h>
+
+	/* ---------------------------------------------
+	 * HW will do the cache maintenance while powering down
+	 * ---------------------------------------------
+	 */
+func cortex_a75_core_pwr_dwn
+	/* ---------------------------------------------
+	 * Enable CPU power down bit in power control register
+	 * ---------------------------------------------
+	 */
+	mrs	x0, CORTEX_A75_CPUPWRCTLR_EL1
+	orr	x0, x0, #CORTEX_A75_CORE_PWRDN_EN_MASK
+	msr	CORTEX_A75_CPUPWRCTLR_EL1, x0
+	isb
+	ret
+endfunc cortex_a75_core_pwr_dwn
+
+	/* ---------------------------------------------
+	 * This function provides cortex_a75 specific
+	 * register information for crash reporting.
+	 * It needs to return with x6 pointing to
+	 * a list of register names in ascii and
+	 * x8 - x15 having values of registers to be
+	 * reported.
+	 * ---------------------------------------------
+	 */
+.section .rodata.cortex_a75_regs, "aS"
+cortex_a75_regs:  /* The ascii list of register names to be reported */
+	.asciz	"cpuectlr_el1", ""
+
+func cortex_a75_cpu_reg_dump
+	adr	x6, cortex_a75_regs
+	mrs	x8, CORTEX_A75_CPUECTLR_EL1
+	ret
+endfunc cortex_a75_cpu_reg_dump
+
+declare_cpu_ops cortex_a75, CORTEX_A75_MIDR, \
+	CPU_NO_RESET_FUNC, \
+	cortex_a75_core_pwr_dwn
diff --git a/maintainers.md b/maintainers.md
new file mode 100644
index 0000000..c8fc19d
--- /dev/null
+++ b/maintainers.md
@@ -0,0 +1,84 @@
+ARM Trusted Firmware Maintainers
+================================
+
+ARM Trusted Firmware is an ARM maintained project. All contributions are
+ultimately merged by the maintainers listed below. Technical ownership of some
+parts of the codebase is delegated to the sub-maintainers listed below. An
+acknowledgement from these sub-maintainers may be required before the
+maintainers merge a contribution.
+
+
+## Maintainers
+
+Dan Handley (dan.handley@arm.com, [danh-arm](https://github.com/danh-arm))
+
+David Cunado (david.cunado@arm.com, [davidcunado-arm](https://github.com/davidcunado-arm))
+
+
+## OPTEE and QEMU platform sub-maintainer
+
+Jens Wiklander (jens.wiklander@linaro.org, [jenswi-linaro](https://github.com/jenswi-linaro))
+
+Files:
+*   docs/spd/optee-dispatcher.md
+*   docs/plat/qemu.md
+*   services/spd/opteed/*
+*   plat/qemu/*
+
+
+## TLK/Trusty SPDs and NVidia platforms sub-maintainer
+
+Varun Wadekar (vwadekar@nvidia.com, [vwadekar](https://github.com/vwadekar))
+
+Files:
+*   docs/spd/tlk-dispatcher.md
+*   docs/spd/trusty-dispatcher.md
+*   include/bl32/payloads/tlk.h
+*   include/lib/cpus/aarch64/denver.h
+*   lib/cpus/aarch64/denver.S
+*   services/spd/tlkd/*
+*   services/spd/trusty/*
+*   plat/nvidia/*
+
+
+## eMMC/UFS drivers and HiSilicon platform sub-maintainer
+
+Haojian Zhuang (haojian.zhuang@linaro.org, [hzhuang1](https://github.com/hzhuang1))
+
+Files:
+*   docs/plat/hikey.md
+*   docs/plat/hikey960.md
+*   drivers/emmc/*
+*   drivers/partition/*
+*   drivers/synopsys/emmc/*
+*   drivers/synopsys/ufs/*
+*   drivers/ufs/*
+*   include/drivers/dw_ufs.h
+*   include/drivers/emmc.h
+*   include/drivers/ufs.h
+*   include/drivers/synopsys/dw_mmc.h
+*   plat/hisilicon/*
+
+
+## MediaTek platform sub-maintainer
+
+Yidi Lin (林以廸 yidi.lin@mediatek.com, [mtk09422](https://github.com/mtk09422))
+
+Files:
+*   plat/mediatek/*
+
+
+## RockChip platform sub-maintainer
+Tony Xie (tony.xie@rock-chips.com, [TonyXie06](https://github.com/TonyXie06)
+or [rkchrome](https://github.com/rkchrome))
+
+Files:
+*   plat/rockchip/*
+
+
+## Xilinx platform sub-maintainer
+Sören Brinkmann (soren.brinkmann@xilinx.com, [sorenb-xlnx](https://github.com/sorenb-xlnx))
+
+Files:
+*   docs/plat/xilinx-zynqmp.md
+*   plat/xilinx/*
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index a31e59c..2c8f82a 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -54,9 +54,6 @@
 # Build platform
 DEFAULT_PLAT			:= fvp
 
-# By default, use the -pedantic option in the gcc command line
-DISABLE_PEDANTIC		:= 0
-
 # Flag to enable Performance Measurement Framework
 ENABLE_PMF			:= 0
 
diff --git a/plat/arm/board/common/board_css_common.c b/plat/arm/board/common/board_css_common.c
index 1758a23..42f754e 100644
--- a/plat/arm/board/common/board_css_common.c
+++ b/plat/arm/board/common/board_css_common.c
@@ -49,6 +49,15 @@
 	ARM_MAP_SHARED_RAM,
 	V2M_MAP_IOFPGA,
 	CSS_MAP_DEVICE,
+#if CSS_USE_SCMI_DRIVER
+	/*
+	 * The SCMI payload area is currently in the Non Secure SRAM. This is
+	 * a potential security risk but this will be resolved once SCP
+	 * completely replaces SCPI with SCMI as the only communication
+	 * protocol.
+	 */
+	CSS_MAP_NSRAM,
+#endif
 	SOC_CSS_MAP_DEVICE,
 	{0}
 };
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 6a759c5..d6e8ced 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -31,13 +31,18 @@
 
 $(eval $(call add_define,FVP_INTERCONNECT_DRIVER))
 
-# Choose the GIC sources depending upon the how the FVP will be invoked
-ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
-FVP_GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c	\
+FVP_GICV3_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
 				drivers/arm/gic/v3/gicv3_main.c		\
 				drivers/arm/gic/v3/gicv3_helpers.c	\
 				plat/common/plat_gicv3.c		\
 				plat/arm/common/arm_gicv3.c
+
+# Choose the GIC sources depending upon the how the FVP will be invoked
+ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3)
+FVP_GIC_SOURCES		:=	${FVP_GICV3_SOURCES}
+else ifeq (${FVP_USE_GIC_DRIVER},FVP_GIC600)
+FVP_GIC_SOURCES		:=	${FVP_GICV3_SOURCES}			\
+				drivers/arm/gic/v3/gic600.c
 else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV2)
 FVP_GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c	\
 				drivers/arm/gic/v2/gicv2_main.c		\
@@ -82,9 +87,11 @@
 ifeq (${ARCH}, aarch64)
 FVP_CPU_LIBS		+=	lib/cpus/aarch64/cortex_a35.S			\
 				lib/cpus/aarch64/cortex_a53.S			\
+				lib/cpus/aarch64/cortex_a55.S			\
 				lib/cpus/aarch64/cortex_a57.S			\
 				lib/cpus/aarch64/cortex_a72.S			\
-				lib/cpus/aarch64/cortex_a73.S
+				lib/cpus/aarch64/cortex_a73.S			\
+				lib/cpus/aarch64/cortex_a75.S
 else
 FVP_CPU_LIBS		+=	lib/cpus/aarch32/cortex_a32.S
 endif
diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h
index 8f03826..68c38ee 100644
--- a/plat/arm/board/juno/include/platform_def.h
+++ b/plat/arm/board/juno/include/platform_def.h
@@ -74,8 +74,13 @@
 #endif
 
 #ifdef IMAGE_BL31
-# define PLAT_ARM_MMAP_ENTRIES		5
-# define MAX_XLAT_TABLES		2
+# if CSS_USE_SCMI_DRIVER
+#  define PLAT_ARM_MMAP_ENTRIES		6
+#  define MAX_XLAT_TABLES		3
+# else
+#  define PLAT_ARM_MMAP_ENTRIES		5
+#  define MAX_XLAT_TABLES		2
+# endif
 #endif
 
 #ifdef IMAGE_BL32
diff --git a/plat/arm/board/juno/juno_topology.c b/plat/arm/board/juno/juno_topology.c
index d2e0c77..b9412b1 100644
--- a/plat/arm/board/juno/juno_topology.c
+++ b/plat/arm/board/juno/juno_topology.c
@@ -51,3 +51,10 @@
 	return (((mpidr) & 0x100) ? JUNO_CLUSTER1_CORE_COUNT :\
 				JUNO_CLUSTER0_CORE_COUNT);
 }
+
+/*
+ * The array mapping platform core position (implemented by plat_my_core_pos())
+ * to the SCMI power domain ID implemented by SCP.
+ */
+const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[PLATFORM_CORE_COUNT] = {
+			2, 3, 4, 5, 0, 1 };
diff --git a/plat/arm/css/common/css_common.mk b/plat/arm/css/common/css_common.mk
index a3d4513..c2ae921 100644
--- a/plat/arm/css/common/css_common.mk
+++ b/plat/arm/css/common/css_common.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -8,6 +8,9 @@
 # By default, SCP images are needed by CSS platforms.
 CSS_LOAD_SCP_IMAGES	?=	1
 
+# By default, SCMI driver is disabled for CSS platforms
+CSS_USE_SCMI_DRIVER	?=	0
+
 PLAT_INCLUDES		+=	-Iinclude/plat/arm/css/common			\
 				-Iinclude/plat/arm/css/common/aarch64
 
@@ -25,10 +28,18 @@
 				plat/arm/css/drivers/scpi/css_scpi.c
 
 BL31_SOURCES		+=	plat/arm/css/common/css_pm.c			\
-				plat/arm/css/common/css_topology.c		\
-				plat/arm/css/drivers/scp/css_pm_scpi.c		\
+				plat/arm/css/common/css_topology.c
+
+ifeq (${CSS_USE_SCMI_DRIVER},0)
+BL31_SOURCES		+=	plat/arm/css/drivers/scp/css_pm_scpi.c		\
 				plat/arm/css/drivers/scpi/css_mhu.c		\
 				plat/arm/css/drivers/scpi/css_scpi.c
+else
+BL31_SOURCES		+=	plat/arm/css/drivers/scp/css_pm_scmi.c		\
+				plat/arm/css/drivers/scmi/scmi_common.c		\
+				plat/arm/css/drivers/scmi/scmi_pwr_dmn_proto.c	\
+				plat/arm/css/drivers/scmi/scmi_sys_pwr_proto.c
+endif
 
 ifneq (${RESET_TO_BL31},0)
   $(error "Using BL31 as the reset vector is not supported on CSS platforms. \
@@ -56,3 +67,8 @@
 # Process CSS_DETECT_PRE_1_7_0_SCP flag
 $(eval $(call assert_boolean,CSS_DETECT_PRE_1_7_0_SCP))
 $(eval $(call add_define,CSS_DETECT_PRE_1_7_0_SCP))
+
+# Process CSS_USE_SCMI_DRIVER flag
+$(eval $(call assert_boolean,CSS_USE_SCMI_DRIVER))
+$(eval $(call add_define,CSS_USE_SCMI_DRIVER))
+
diff --git a/plat/arm/css/drivers/scmi/scmi.h b/plat/arm/css/drivers/scmi/scmi.h
new file mode 100644
index 0000000..850402a
--- /dev/null
+++ b/plat/arm/css/drivers/scmi/scmi.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CSS_SCMI_H__
+#define __CSS_SCMI_H__
+
+#include <bakery_lock.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* Supported SCMI Protocol Versions */
+#define SCMI_PWR_DMN_PROTO_VER			MAKE_SCMI_VERSION(1, 0)
+#define SCMI_SYS_PWR_PROTO_VER			MAKE_SCMI_VERSION(1, 0)
+
+#define GET_SCMI_MAJOR_VER(ver)			(((ver) >> 16) & 0xffff)
+#define GET_SCMI_MINOR_VER(ver)			((ver) & 0xffff)
+
+#define MAKE_SCMI_VERSION(maj, min)	\
+			((((maj) & 0xffff) << 16) | ((min) & 0xffff))
+
+/* Macro to check if the driver is compatible with the SCMI version reported */
+#define is_scmi_version_compatible(drv, scmi)				\
+	((GET_SCMI_MAJOR_VER(drv) == GET_SCMI_MAJOR_VER(scmi)) &&	\
+	(GET_SCMI_MINOR_VER(drv) <= GET_SCMI_MINOR_VER(scmi)))
+
+/* SCMI Protocol identifiers */
+#define SCMI_PWR_DMN_PROTO_ID			0x11
+#define SCMI_SYS_PWR_PROTO_ID			0x12
+
+/* Mandatory messages IDs for all SCMI protocols */
+#define SCMI_PROTO_VERSION_MSG			0x0
+#define SCMI_PROTO_ATTR_MSG			0x1
+#define SCMI_PROTO_MSG_ATTR_MSG			0x2
+
+/* SCMI power domain management protocol message IDs */
+#define SCMI_PWR_STATE_SET_MSG			0x4
+#define SCMI_PWR_STATE_GET_MSG			0x5
+
+/* SCMI system power management protocol message IDs */
+#define SCMI_SYS_PWR_STATE_SET_MSG		0x3
+#define SCMI_SYS_PWR_STATE_GET_MSG		0x4
+
+/* Helper macros for system power management protocol commands */
+
+/*
+ * Macros to describe the bit-fields of the `attribute` of system power domain
+ * protocol PROTOCOL_MSG_ATTRIBUTE message.
+ */
+#define SYS_PWR_ATTR_WARM_RESET_SHIFT		31
+#define SCMI_SYS_PWR_WARM_RESET_SUPPORTED	(1U << SYS_PWR_ATTR_WARM_RESET_SHIFT)
+
+#define SYS_PWR_ATTR_SUSPEND_SHIFT		30
+#define SCMI_SYS_PWR_SUSPEND_SUPPORTED		(1 << SYS_PWR_ATTR_SUSPEND_SHIFT)
+
+/*
+ * Macros to describe the bit-fields of the `flags` parameter of system power
+ * domain protocol SYSTEM_POWER_STATE_SET message.
+ */
+#define SYS_PWR_SET_GRACEFUL_REQ_SHIFT		0
+#define SCMI_SYS_PWR_GRACEFUL_REQ		(1 << SYS_PWR_SET_GRACEFUL_REQ_SHIFT)
+#define SCMI_SYS_PWR_FORCEFUL_REQ		(0 << SYS_PWR_SET_GRACEFUL_REQ_SHIFT)
+
+/*
+ * Macros to describe the `system_state` parameter of system power
+ * domain protocol SYSTEM_POWER_STATE_SET message.
+ */
+#define SCMI_SYS_PWR_SHUTDOWN			0x0
+#define SCMI_SYS_PWR_COLD_RESET			0x1
+#define SCMI_SYS_PWR_WARM_RESET			0x2
+#define SCMI_SYS_PWR_POWER_UP			0x3
+#define SCMI_SYS_PWR_SUSPEND			0x4
+
+/* SCMI Error code definitions */
+#define SCMI_E_QUEUED			1
+#define SCMI_E_SUCCESS			0
+#define SCMI_E_NOT_SUPPORTED		-1
+#define SCMI_E_INVALID_PARAM		-2
+#define SCMI_E_DENIED			-3
+#define SCMI_E_NOT_FOUND		-4
+#define SCMI_E_OUT_OF_RANGE		-5
+#define SCMI_E_BUSY			-6
+
+/*
+ * SCMI driver platform information. The details of the doorbell mechanism
+ * can be found in the SCMI specification.
+ */
+typedef struct scmi_channel_plat_info {
+	/* SCMI mailbox memory */
+	uintptr_t scmi_mbx_mem;
+	/* The door bell register address */
+	uintptr_t db_reg_addr;
+	/* The bit mask that need to be preserved when ringing doorbell */
+	uint32_t db_preserve_mask;
+	/* The bit mask that need to be set to ring doorbell */
+	uint32_t db_modify_mask;
+} scmi_channel_plat_info_t;
+
+/*
+ * Structure to represent an SCMI channel.
+ */
+typedef struct scmi_channel {
+	scmi_channel_plat_info_t *info;
+	 /* The lock for channel access */
+	bakery_lock_t *lock;
+	/* Indicate whether the channel is initialized */
+	int is_initialized;
+} scmi_channel_t;
+
+/* External Common API */
+void *scmi_init(scmi_channel_t *ch);
+int scmi_proto_msg_attr(void *p, uint32_t proto_id, uint32_t command_id,
+						uint32_t *attr);
+int scmi_proto_version(void *p, uint32_t proto_id, uint32_t *version);
+
+/*
+ * Power domain protocol commands. Refer to the SCMI specification for more
+ * details on these commands.
+ */
+int scmi_pwr_state_set(void *p, uint32_t domain_id, uint32_t scmi_pwr_state);
+int scmi_pwr_state_get(void *p, uint32_t domain_id, uint32_t *scmi_pwr_state);
+
+/*
+ * System power management protocol commands. Refer SCMI specification for more
+ * details on these commands.
+ */
+int scmi_sys_pwr_state_set(void *p, uint32_t flags, uint32_t system_state);
+int scmi_sys_pwr_state_get(void *p, uint32_t *system_state);
+
+#endif	/* __CSS_SCMI_H__ */
diff --git a/plat/arm/css/drivers/scmi/scmi_common.c b/plat/arm/css/drivers/scmi/scmi_common.c
new file mode 100644
index 0000000..d0051c7
--- /dev/null
+++ b/plat/arm/css/drivers/scmi/scmi_common.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include "scmi.h"
+#include "scmi_private.h"
+
+/*
+ * Private helper function to get exclusive access to SCMI channel.
+ */
+void scmi_get_channel(scmi_channel_t *ch)
+{
+	assert(ch->lock);
+	bakery_lock_get(ch->lock);
+
+	/* Make sure any previous command has finished */
+	assert(SCMI_IS_CHANNEL_FREE(
+			((mailbox_mem_t *)(ch->info->scmi_mbx_mem))->status));
+}
+
+/*
+ * Private helper function to transfer ownership of channel from AP to SCP.
+ */
+void scmi_send_sync_command(scmi_channel_t *ch)
+{
+	mailbox_mem_t *mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+
+	SCMI_MARK_CHANNEL_BUSY(mbx_mem->status);
+
+	/*
+	 * Ensure that any write to the SCMI payload area is seen by SCP before
+	 * we write to the doorbell register. If these 2 writes were reordered
+	 * by the CPU then SCP would read stale payload data
+	 */
+	dmbst();
+
+	SCMI_RING_DOORBELL(ch->info->db_reg_addr, ch->info->db_modify_mask,
+					ch->info->db_preserve_mask);
+
+	/*
+	 * Ensure that the write to the doorbell register is ordered prior to
+	 * checking whether the channel is free.
+	 */
+	dmbsy();
+
+	/* Wait for channel to be free */
+	while (!SCMI_IS_CHANNEL_FREE(mbx_mem->status))
+		;
+
+	/*
+	 * Ensure that any read to the SCMI payload area is done after reading
+	 * mailbox status. If these 2 reads were reordered then the CPU would
+	 * read invalid payload data
+	 */
+	dmbld();
+}
+
+/*
+ * Private helper function to release exclusive access to SCMI channel.
+ */
+void scmi_put_channel(scmi_channel_t *ch)
+{
+	/* Make sure any previous command has finished */
+	assert(SCMI_IS_CHANNEL_FREE(
+			((mailbox_mem_t *)(ch->info->scmi_mbx_mem))->status));
+
+	assert(ch->lock);
+	bakery_lock_release(ch->lock);
+}
+
+/*
+ * API to query the SCMI protocol version.
+ */
+int scmi_proto_version(void *p, uint32_t proto_id, uint32_t *version)
+{
+	mailbox_mem_t *mbx_mem;
+	int token = 0, ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(proto_id, SCMI_PROTO_VERSION_MSG,
+							token);
+	mbx_mem->len = SCMI_PROTO_VERSION_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *version);
+	assert(mbx_mem->len == SCMI_PROTO_VERSION_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
+
+/*
+ * API to query the protocol message attributes for a SCMI protocol.
+ */
+int scmi_proto_msg_attr(void *p, uint32_t proto_id,
+		uint32_t command_id, uint32_t *attr)
+{
+	mailbox_mem_t *mbx_mem;
+	int token = 0, ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(proto_id,
+				SCMI_PROTO_MSG_ATTR_MSG, token);
+	mbx_mem->len = SCMI_PROTO_MSG_ATTR_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+	SCMI_PAYLOAD_ARG1(mbx_mem->payload, command_id);
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *attr);
+	assert(mbx_mem->len == SCMI_PROTO_MSG_ATTR_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
+
+/*
+ * SCMI Driver initialization API. Returns initialized channel on success
+ * or NULL on error. The return type is an opaque void pointer.
+ */
+void *scmi_init(scmi_channel_t *ch)
+{
+	uint32_t version;
+	int ret;
+
+	assert(ch && ch->info);
+	assert(ch->info->db_reg_addr);
+	assert(ch->info->db_modify_mask);
+	assert(ch->info->db_preserve_mask);
+
+	assert(ch->lock);
+
+	bakery_lock_init(ch->lock);
+
+	ch->is_initialized = 1;
+
+	ret = scmi_proto_version(ch, SCMI_PWR_DMN_PROTO_ID, &version);
+	if (ret != SCMI_E_SUCCESS) {
+		WARN("SCMI power domain protocol version message failed");
+		goto error;
+	}
+
+	if (!is_scmi_version_compatible(SCMI_PWR_DMN_PROTO_VER, version)) {
+		WARN("SCMI power domain protocol version 0x%x incompatible with driver version 0x%x",
+			version, SCMI_PWR_DMN_PROTO_VER);
+		goto error;
+	}
+
+	VERBOSE("SCMI power domain protocol version 0x%x detected\n", version);
+
+	ret = scmi_proto_version(ch, SCMI_SYS_PWR_PROTO_ID, &version);
+	if ((ret != SCMI_E_SUCCESS)) {
+		WARN("SCMI system power protocol version message failed");
+		goto error;
+	}
+
+	if (!is_scmi_version_compatible(SCMI_SYS_PWR_PROTO_VER, version)) {
+		WARN("SCMI system power management protocol version 0x%x incompatible with driver version 0x%x",
+			version, SCMI_SYS_PWR_PROTO_VER);
+		goto error;
+	}
+
+	VERBOSE("SCMI system power management protocol version 0x%x detected\n",
+						version);
+
+	INFO("SCMI driver initialized\n");
+
+	return (void *)ch;
+
+error:
+	ch->is_initialized = 0;
+	return NULL;
+}
diff --git a/plat/arm/css/drivers/scmi/scmi_private.h b/plat/arm/css/drivers/scmi/scmi_private.h
new file mode 100644
index 0000000..20e1e9b
--- /dev/null
+++ b/plat/arm/css/drivers/scmi/scmi_private.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CSS_SCMI_PRIVATE_H__
+#define __CSS_SCMI_PRIVATE_H__
+
+/*
+ * SCMI power domain management protocol message and response lengths. It is
+ * calculated as sum of length in bytes of the message header (4) and payload
+ * area (the number of bytes of parameters or return values in the payload).
+ */
+#define SCMI_PROTO_VERSION_MSG_LEN		4
+#define SCMI_PROTO_VERSION_RESP_LEN		12
+
+#define SCMI_PROTO_MSG_ATTR_MSG_LEN		8
+#define SCMI_PROTO_MSG_ATTR_RESP_LEN		12
+
+#define SCMI_PWR_STATE_SET_MSG_LEN		16
+#define SCMI_PWR_STATE_SET_RESP_LEN		8
+
+#define SCMI_PWR_STATE_GET_MSG_LEN		8
+#define SCMI_PWR_STATE_GET_RESP_LEN		12
+
+#define SCMI_SYS_PWR_STATE_SET_MSG_LEN		12
+#define SCMI_SYS_PWR_STATE_SET_RESP_LEN		8
+
+#define SCMI_SYS_PWR_STATE_GET_MSG_LEN		4
+#define SCMI_SYS_PWR_STATE_GET_RESP_LEN		12
+
+/* SCMI message header format bit field */
+#define SCMI_MSG_ID_SHIFT		0
+#define SCMI_MSG_ID_WIDTH		8
+#define SCMI_MSG_ID_MASK		((1 << SCMI_MSG_ID_WIDTH) - 1)
+
+#define SCMI_MSG_TYPE_SHIFT		8
+#define SCMI_MSG_TYPE_WIDTH		2
+#define SCMI_MSG_TYPE_MASK		((1 << SCMI_MSG_TYPE_WIDTH) - 1)
+
+#define SCMI_MSG_PROTO_ID_SHIFT		10
+#define SCMI_MSG_PROTO_ID_WIDTH		8
+#define SCMI_MSG_PROTO_ID_MASK		((1 << SCMI_MSG_PROTO_ID_WIDTH) - 1)
+
+#define SCMI_MSG_TOKEN_SHIFT		18
+#define SCMI_MSG_TOKEN_WIDTH		10
+#define SCMI_MSG_TOKEN_MASK		((1 << SCMI_MSG_TOKEN_WIDTH) - 1)
+
+
+/* SCMI mailbox flags */
+#define SCMI_FLAG_RESP_POLL	0
+#define SCMI_FLAG_RESP_INT	1
+
+/* SCMI power domain protocol `POWER_STATE_SET` message flags */
+#define SCMI_PWR_STATE_SET_FLAG_SYNC	0
+#define SCMI_PWR_STATE_SET_FLAG_ASYNC	1
+
+/*
+ * Helper macro to create an SCMI message header given protocol, message id
+ * and token.
+ */
+#define SCMI_MSG_CREATE(protocol, msg_id, token)				\
+	((((protocol) & SCMI_MSG_PROTO_ID_MASK) << SCMI_MSG_PROTO_ID_SHIFT) |	\
+	(((msg_id) & SCMI_MSG_ID_MASK) << SCMI_MSG_ID_SHIFT) |			\
+	(((token) & SCMI_MSG_TOKEN_MASK) << SCMI_MSG_TOKEN_SHIFT))
+
+/* Helper macro to get the token from a SCMI message header */
+#define SCMI_MSG_GET_TOKEN(msg)				\
+	(((msg) >> SCMI_MSG_TOKEN_SHIFT) & SCMI_MSG_TOKEN_MASK)
+
+/* SCMI Channel Status bit fields */
+#define SCMI_CH_STATUS_RES0_MASK	0xFFFFFFFE
+#define SCMI_CH_STATUS_FREE_SHIFT	0
+#define SCMI_CH_STATUS_FREE_WIDTH	1
+#define SCMI_CH_STATUS_FREE_MASK	((1 << SCMI_CH_STATUS_FREE_WIDTH) - 1)
+
+/* Helper macros to check and write the channel status */
+#define SCMI_IS_CHANNEL_FREE(status)					\
+	(!!(((status) >> SCMI_CH_STATUS_FREE_SHIFT) & SCMI_CH_STATUS_FREE_MASK))
+
+#define SCMI_MARK_CHANNEL_BUSY(status)	do {				\
+		assert(SCMI_IS_CHANNEL_FREE(status));			\
+		(status) &= ~(SCMI_CH_STATUS_FREE_MASK <<		\
+				SCMI_CH_STATUS_FREE_SHIFT);		\
+	} while (0)
+
+/* Helper macros to copy arguments to the mailbox payload */
+#define SCMI_PAYLOAD_ARG1(payld_arr, arg1)				\
+		mmio_write_32((uintptr_t)&payld_arr[0], arg1)
+
+#define SCMI_PAYLOAD_ARG2(payld_arr, arg1, arg2)	do {		\
+		SCMI_PAYLOAD_ARG1(payld_arr, arg1);			\
+		mmio_write_32((uintptr_t)&payld_arr[1], arg2);		\
+	} while (0)
+
+#define SCMI_PAYLOAD_ARG3(payld_arr, arg1, arg2, arg3)	do {		\
+		SCMI_PAYLOAD_ARG2(payld_arr, arg1, arg2);		\
+		mmio_write_32((uintptr_t)&payld_arr[2], arg3);		\
+	} while (0)
+
+/* Helper macros to read return values from the mailbox payload */
+#define SCMI_PAYLOAD_RET_VAL1(payld_arr, val1)				\
+		(val1) = mmio_read_32((uintptr_t)&payld_arr[0])
+
+#define SCMI_PAYLOAD_RET_VAL2(payld_arr, val1, val2)	do {		\
+		SCMI_PAYLOAD_RET_VAL1(payld_arr, val1);			\
+		(val2) = mmio_read_32((uintptr_t)&payld_arr[1]);	\
+	} while (0)
+
+#define SCMI_PAYLOAD_RET_VAL3(payld_arr, val1, val2, val3)	do {	\
+		SCMI_PAYLOAD_RET_VAL2(payld_arr, val1, val2);		\
+		(val3) = mmio_read_32((uintptr_t)&payld_arr[2]);	\
+	} while (0)
+
+/* Helper macro to ring doorbell */
+#define SCMI_RING_DOORBELL(addr, modify_mask, preserve_mask)	do {	\
+		uint32_t db = mmio_read_32(addr) & (preserve_mask);	\
+		mmio_write_32(addr, db | (modify_mask));		\
+	} while (0)
+
+/*
+ * Private data structure for representing the mailbox memory layout. Refer
+ * the SCMI specification for more details.
+ */
+typedef struct mailbox_mem {
+	uint32_t res_a; /* Reserved */
+	volatile uint32_t status;
+	uint64_t res_b; /* Reserved */
+	uint32_t flags;
+	volatile uint32_t len;
+	uint32_t msg_header;
+	uint32_t payload[];
+} mailbox_mem_t;
+
+
+/* Private APIs for use within SCMI driver */
+void scmi_get_channel(scmi_channel_t *ch);
+void scmi_send_sync_command(scmi_channel_t *ch);
+void scmi_put_channel(scmi_channel_t *ch);
+
+static inline void validate_scmi_channel(scmi_channel_t *ch)
+{
+	assert(ch && ch->is_initialized);
+	assert(ch->info && ch->info->scmi_mbx_mem);
+}
+
+#endif	/* __CSS_SCMI_PRIVATE_H__ */
diff --git a/plat/arm/css/drivers/scmi/scmi_pwr_dmn_proto.c b/plat/arm/css/drivers/scmi/scmi_pwr_dmn_proto.c
new file mode 100644
index 0000000..90c5d6b
--- /dev/null
+++ b/plat/arm/css/drivers/scmi/scmi_pwr_dmn_proto.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include "scmi.h"
+#include "scmi_private.h"
+
+/*
+ * API to set the SCMI power domain power state.
+ */
+int scmi_pwr_state_set(void *p, uint32_t domain_id,
+					uint32_t scmi_pwr_state)
+{
+	mailbox_mem_t *mbx_mem;
+	int token = 0, ret;
+
+	/*
+	 * Only asynchronous mode of `set power state` command is allowed on
+	 * application processors.
+	 */
+	uint32_t pwr_state_set_msg_flag = SCMI_PWR_STATE_SET_FLAG_ASYNC;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_PWR_DMN_PROTO_ID,
+			SCMI_PWR_STATE_SET_MSG, token);
+	mbx_mem->len = SCMI_PWR_STATE_SET_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+	SCMI_PAYLOAD_ARG3(mbx_mem->payload, pwr_state_set_msg_flag,
+						domain_id, scmi_pwr_state);
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
+	assert(mbx_mem->len == SCMI_PWR_STATE_SET_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
+
+/*
+ * API to get the SCMI power domain power state.
+ */
+int scmi_pwr_state_get(void *p, uint32_t domain_id,
+					uint32_t *scmi_pwr_state)
+{
+	mailbox_mem_t *mbx_mem;
+	int token = 0, ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_PWR_DMN_PROTO_ID,
+			SCMI_PWR_STATE_GET_MSG, token);
+	mbx_mem->len = SCMI_PWR_STATE_GET_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+	SCMI_PAYLOAD_ARG1(mbx_mem->payload, domain_id);
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *scmi_pwr_state);
+	assert(mbx_mem->len == SCMI_PWR_STATE_GET_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
diff --git a/plat/arm/css/drivers/scmi/scmi_sys_pwr_proto.c b/plat/arm/css/drivers/scmi/scmi_sys_pwr_proto.c
new file mode 100644
index 0000000..f6da394
--- /dev/null
+++ b/plat/arm/css/drivers/scmi/scmi_sys_pwr_proto.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include "scmi.h"
+#include "scmi_private.h"
+
+/*
+ * API to set the SCMI system power state
+ */
+int scmi_sys_pwr_state_set(void *p, uint32_t flags, uint32_t system_state)
+{
+	mailbox_mem_t *mbx_mem;
+	int token = 0, ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_PWR_PROTO_ID,
+			SCMI_SYS_PWR_STATE_SET_MSG, token);
+	mbx_mem->len = SCMI_SYS_PWR_STATE_SET_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+	SCMI_PAYLOAD_ARG2(mbx_mem->payload, flags, system_state);
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
+	assert(mbx_mem->len == SCMI_SYS_PWR_STATE_SET_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
+
+/*
+ * API to get the SCMI system power state
+ */
+int scmi_sys_pwr_state_get(void *p, uint32_t *system_state)
+{
+	mailbox_mem_t *mbx_mem;
+	int token = 0, ret;
+	scmi_channel_t *ch = (scmi_channel_t *)p;
+
+	validate_scmi_channel(ch);
+
+	scmi_get_channel(ch);
+
+	mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+	mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_PWR_PROTO_ID,
+			SCMI_SYS_PWR_STATE_GET_MSG, token);
+	mbx_mem->len = SCMI_SYS_PWR_STATE_GET_MSG_LEN;
+	mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+
+	scmi_send_sync_command(ch);
+
+	/* Get the return values */
+	SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *system_state);
+	assert(mbx_mem->len == SCMI_SYS_PWR_STATE_GET_RESP_LEN);
+	assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+	scmi_put_channel(ch);
+
+	return ret;
+}
diff --git a/plat/arm/css/drivers/scp/css_pm_scmi.c b/plat/arm/css/drivers/scp/css_pm_scmi.c
new file mode 100644
index 0000000..b4c0a7d
--- /dev/null
+++ b/plat/arm/css/drivers/scp/css_pm_scmi.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <css_def.h>
+#include <css_pm.h>
+#include <debug.h>
+#include <plat_arm.h>
+#include <platform.h>
+#include <string.h>
+#include "../scmi/scmi.h"
+#include "css_scp.h"
+
+/*
+ * This file implements the SCP helper functions using SCMI protocol.
+ */
+
+/*
+ * SCMI power state parameter bit field encoding for ARM CSS platforms.
+ *
+ * 31  20 19       16 15      12 11       8 7        4 3         0
+ * +-------------------------------------------------------------+
+ * | SBZ | Max level |  Level 3 |  Level 2 |  Level 1 |  Level 0 |
+ * |     |           |   state  |   state  |   state  |   state  |
+ * +-------------------------------------------------------------+
+ *
+ * `Max level` encodes the highest level that has a valid power state
+ * encoded in the power state.
+ */
+#define SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT	16
+#define SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH	4
+#define SCMI_PWR_STATE_MAX_PWR_LVL_MASK		\
+				((1 << SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH) - 1)
+#define SCMI_SET_PWR_STATE_MAX_PWR_LVL(pwr_state, max_lvl)		\
+		(pwr_state) |= ((max_lvl) & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)	\
+				<< SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT
+#define SCMI_GET_PWR_STATE_MAX_PWR_LVL(pwr_state)		\
+		(((pwr_state) >> SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT)	\
+				& SCMI_PWR_STATE_MAX_PWR_LVL_MASK)
+
+#define SCMI_PWR_STATE_LVL_WIDTH		4
+#define SCMI_PWR_STATE_LVL_MASK			\
+				((1 << SCMI_PWR_STATE_LVL_WIDTH) - 1)
+#define SCMI_SET_PWR_STATE_LVL(pwr_state, lvl, lvl_state)		\
+		(pwr_state) |= ((lvl_state) & SCMI_PWR_STATE_LVL_MASK)	\
+				<< (SCMI_PWR_STATE_LVL_WIDTH * (lvl))
+#define SCMI_GET_PWR_STATE_LVL(pwr_state, lvl)		\
+		(((pwr_state) >> (SCMI_PWR_STATE_LVL_WIDTH * (lvl))) &	\
+				SCMI_PWR_STATE_LVL_MASK)
+
+/*
+ * The SCMI power state enumeration for a power domain level
+ */
+typedef enum {
+	scmi_power_state_off = 0,
+	scmi_power_state_on = 1,
+	scmi_power_state_sleep = 2,
+} scmi_power_state_t;
+
+/*
+ * This mapping array has to be exported by the platform. Each element at
+ * a given index maps that core to an SCMI power domain.
+ */
+extern uint32_t plat_css_core_pos_to_scmi_dmn_id_map[];
+
+/*
+ * The global handle for invoking the SCMI driver APIs after the driver
+ * has been initialized.
+ */
+void *scmi_handle;
+
+/* The SCMI channel global object */
+static scmi_channel_t scmi_channel;
+
+ARM_INSTANTIATE_LOCK
+
+/*
+ * Helper function to suspend a CPU power domain and its parent power domains
+ * if applicable.
+ */
+void css_scp_suspend(const psci_power_state_t *target_state)
+{
+	int lvl, ret;
+	uint32_t scmi_pwr_state = 0;
+
+	/* At least power domain level 0 should be specified to be suspended */
+	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+						ARM_LOCAL_STATE_OFF);
+
+	/* Check if power down at system power domain level is requested */
+	if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) {
+		/* Issue SCMI command for SYSTEM_SUSPEND */
+		ret = scmi_sys_pwr_state_set(scmi_handle,
+				SCMI_SYS_PWR_FORCEFUL_REQ,
+				SCMI_SYS_PWR_SUSPEND);
+		if (ret != SCMI_E_SUCCESS) {
+			ERROR("SCMI system power domain suspend return 0x%x unexpected\n",
+					ret);
+			panic();
+		}
+		return;
+	}
+
+	/*
+	 * If we reach here, then assert that power down at system power domain
+	 * level is running.
+	 */
+	assert(target_state->pwr_domain_state[CSS_SYSTEM_PWR_DMN_LVL] ==
+							ARM_LOCAL_STATE_RUN);
+
+	/* For level 0, specify `scmi_power_state_sleep` as the power state */
+	SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, ARM_PWR_LVL0,
+						scmi_power_state_sleep);
+
+	for (lvl = ARM_PWR_LVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+		if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN)
+			break;
+
+		assert(target_state->pwr_domain_state[lvl] ==
+							ARM_LOCAL_STATE_OFF);
+		/*
+		 * Specify `scmi_power_state_off` as power state for higher
+		 * levels.
+		 */
+		SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+						scmi_power_state_off);
+	}
+
+	SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
+
+	ret = scmi_pwr_state_set(scmi_handle,
+		plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()],
+		scmi_pwr_state);
+
+	if (ret != SCMI_E_SUCCESS) {
+		ERROR("SCMI set power state command return 0x%x unexpected\n",
+				ret);
+		panic();
+	}
+}
+
+/*
+ * Helper function to turn off a CPU power domain and its parent power domains
+ * if applicable.
+ */
+void css_scp_off(const psci_power_state_t *target_state)
+{
+	int lvl = 0, ret;
+	uint32_t scmi_pwr_state = 0;
+
+	/* At-least the CPU level should be specified to be OFF */
+	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+							ARM_LOCAL_STATE_OFF);
+
+	/* PSCI CPU OFF cannot be used to turn OFF system power domain */
+	assert(target_state->pwr_domain_state[CSS_SYSTEM_PWR_DMN_LVL] ==
+							ARM_LOCAL_STATE_RUN);
+
+	for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+		if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN)
+			break;
+
+		assert(target_state->pwr_domain_state[lvl] ==
+							ARM_LOCAL_STATE_OFF);
+		SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+				scmi_power_state_off);
+	}
+
+	SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
+
+	ret = scmi_pwr_state_set(scmi_handle,
+		plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()],
+		scmi_pwr_state);
+
+	if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) {
+		ERROR("SCMI set power state command return 0x%x unexpected\n",
+				ret);
+		panic();
+	}
+}
+
+/*
+ * Helper function to turn ON a CPU power domain and its parent power domains
+ * if applicable.
+ */
+void css_scp_on(u_register_t mpidr)
+{
+	int lvl = 0, ret;
+	uint32_t scmi_pwr_state = 0;
+
+	for (; lvl <= PLAT_MAX_PWR_LVL; lvl++)
+		SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+				scmi_power_state_on);
+
+	SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
+
+	ret = scmi_pwr_state_set(scmi_handle,
+		plat_css_core_pos_to_scmi_dmn_id_map[plat_core_pos_by_mpidr(mpidr)],
+		scmi_pwr_state);
+
+	if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) {
+		ERROR("SCMI set power state command return 0x%x unexpected\n",
+				ret);
+		panic();
+	}
+}
+
+/*
+ * Helper function to get the power state of a power domain node as reported
+ * by the SCP.
+ */
+int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
+{
+	int ret, cpu_idx;
+	uint32_t scmi_pwr_state = 0, lvl_state;
+
+	/* We don't support get power state at the system power domain level */
+	if ((power_level > PLAT_MAX_PWR_LVL) ||
+			(power_level == CSS_SYSTEM_PWR_DMN_LVL)) {
+		WARN("Invalid power level %u specified for SCMI get power state\n",
+				power_level);
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	cpu_idx = plat_core_pos_by_mpidr(mpidr);
+	assert(cpu_idx > -1);
+
+	ret = scmi_pwr_state_get(scmi_handle,
+		plat_css_core_pos_to_scmi_dmn_id_map[cpu_idx],
+		&scmi_pwr_state);
+
+	if (ret != SCMI_E_SUCCESS) {
+		WARN("SCMI get power state command return 0x%x unexpected\n",
+				ret);
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	/*
+	 * Find the maximum power level described in the get power state
+	 * command. If it is less than the requested power level, then assume
+	 * the requested power level is ON.
+	 */
+	if (SCMI_GET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state) < power_level)
+		return HW_ON;
+
+	lvl_state = SCMI_GET_PWR_STATE_LVL(scmi_pwr_state, power_level);
+	if (lvl_state == scmi_power_state_on)
+		return HW_ON;
+
+	assert((lvl_state == scmi_power_state_off) ||
+				(lvl_state == scmi_power_state_sleep));
+	return HW_OFF;
+}
+
+/*
+ * Helper function to shutdown the system via SCMI.
+ */
+void __dead2 css_scp_sys_shutdown(void)
+{
+	int ret;
+
+	/*
+	 * Disable GIC CPU interface to prevent pending interrupt from waking
+	 * up the AP from WFI.
+	 */
+	plat_arm_gic_cpuif_disable();
+
+	/*
+	 * Issue SCMI command for SYSTEM_SHUTDOWN. First issue a graceful
+	 * request and if that fails force the request.
+	 */
+	ret = scmi_sys_pwr_state_set(scmi_handle,
+			SCMI_SYS_PWR_FORCEFUL_REQ,
+			SCMI_SYS_PWR_SHUTDOWN);
+	if (ret != SCMI_E_SUCCESS) {
+		ERROR("SCMI system power domain shutdown return 0x%x unexpected\n",
+				ret);
+		panic();
+	}
+
+	wfi();
+	ERROR("CSS System Shutdown: operation not handled.\n");
+	panic();
+}
+
+/*
+ * Helper function to reset the system via SCMI.
+ */
+void __dead2 css_scp_sys_reboot(void)
+{
+	int ret;
+
+	/*
+	 * Disable GIC CPU interface to prevent pending interrupt from waking
+	 * up the AP from WFI.
+	 */
+	plat_arm_gic_cpuif_disable();
+
+	/*
+	 * Issue SCMI command for SYSTEM_REBOOT. First issue a graceful
+	 * request and if that fails force the request.
+	 */
+	ret = scmi_sys_pwr_state_set(scmi_handle,
+			SCMI_SYS_PWR_FORCEFUL_REQ,
+			SCMI_SYS_PWR_COLD_RESET);
+	if (ret != SCMI_E_SUCCESS) {
+		ERROR("SCMI system power domain reset return 0x%x unexpected\n",
+				ret);
+		panic();
+	}
+
+	wfi();
+	ERROR("CSS System Reset: operation not handled.\n");
+	panic();
+}
+
+scmi_channel_plat_info_t plat_css_scmi_plat_info = {
+		.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE,
+		.db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF,
+		.db_preserve_mask = 0xfffffffd,
+		.db_modify_mask = 0x2,
+};
+
+void plat_arm_pwrc_setup(void)
+{
+	scmi_channel.info = &plat_css_scmi_plat_info;
+	scmi_channel.lock = ARM_LOCK_GET_INSTANCE;
+	scmi_handle = scmi_init(&scmi_channel);
+	if (scmi_handle == NULL) {
+		ERROR("SCMI Initialization failed\n");
+		panic();
+	}
+}
+
+/******************************************************************************
+ * This function overrides the default definition for ARM platforms. Initialize
+ * the SCMI driver, query capability via SCMI and modify the PSCI capability
+ * based on that.
+ *****************************************************************************/
+const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops)
+{
+	uint32_t msg_attr;
+	int ret;
+
+	assert(scmi_handle);
+
+	/* Check that power domain POWER_STATE_SET message is supported */
+	ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID,
+				SCMI_PWR_STATE_SET_MSG, &msg_attr);
+	if (ret != SCMI_E_SUCCESS) {
+		ERROR("Set power state command is not supported by SCMI\n");
+		panic();
+	}
+
+	/*
+	 * Don't support PSCI NODE_HW_STATE call if SCMI doesn't support
+	 * POWER_STATE_GET message.
+	 */
+	ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID,
+				SCMI_PWR_STATE_GET_MSG, &msg_attr);
+	if (ret != SCMI_E_SUCCESS)
+		ops->get_node_hw_state = NULL;
+
+	/* Check if the SCMI SYSTEM_POWER_STATE_SET message is supported */
+	ret = scmi_proto_msg_attr(scmi_handle, SCMI_SYS_PWR_PROTO_ID,
+				SCMI_SYS_PWR_STATE_SET_MSG, &msg_attr);
+	if (ret != SCMI_E_SUCCESS) {
+		/* System power management operations are not supported */
+		ops->system_off = NULL;
+		ops->system_reset = NULL;
+		ops->get_sys_suspend_power_state = NULL;
+	} else if (!(msg_attr & SCMI_SYS_PWR_SUSPEND_SUPPORTED)) {
+		/*
+		 * System power management protocol is available, but it does
+		 * not support SYSTEM SUSPEND.
+		 */
+		ops->get_sys_suspend_power_state = NULL;
+	}
+
+	return ops;
+}
diff --git a/plat/hisilicon/hikey/hikey_bl31_setup.c b/plat/hisilicon/hikey/hikey_bl31_setup.c
index 9a1114a..82bd97e 100644
--- a/plat/hisilicon/hikey/hikey_bl31_setup.c
+++ b/plat/hisilicon/hikey/hikey_bl31_setup.c
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <arch_helpers.h>
 #include <arm_gic.h>
 #include <assert.h>
 #include <bl_common.h>
@@ -88,6 +89,7 @@
 
 	/* Initialize CCI driver */
 	cci_init(CCI400_BASE, cci_map, ARRAY_SIZE(cci_map));
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
 
 	/*
 	 * Copy BL3-2 and BL3-3 entry point information.
diff --git a/plat/hisilicon/hikey/hikey_pm.c b/plat/hisilicon/hikey/hikey_pm.c
index 9b4ef5b..c796e8a 100644
--- a/plat/hisilicon/hikey/hikey_pm.c
+++ b/plat/hisilicon/hikey/hikey_pm.c
@@ -15,21 +15,19 @@
 #include <hisi_sram_map.h>
 #include <mmio.h>
 #include <psci.h>
+#include <sp804_delay_timer.h>
 
 #include "hikey_def.h"
 
-#define HIKEY_CLUSTER_STATE_ON		0
-#define HIKEY_CLUSTER_STATE_OFF		1
+#define CORE_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define CLUSTER_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define SYSTEM_PWR_STATE(state) \
+	((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
 
 static uintptr_t hikey_sec_entrypoint;
-/* There're two clusters in HiKey. */
-static int hikey_cluster_state[] = {HIKEY_CLUSTER_STATE_OFF,
-				    HIKEY_CLUSTER_STATE_OFF};
 
-/*******************************************************************************
- * Handler called when a power domain is about to be turned on. The
- * level and mpidr determine the affinity instance.
- ******************************************************************************/
 static int hikey_pwr_domain_on(u_register_t mpidr)
 {
 	int cpu, cluster;
@@ -54,14 +52,14 @@
 	mpidr = read_mpidr();
 	cluster = MPIDR_AFFLVL1_VAL(mpidr);
 	cpu = MPIDR_AFFLVL0_VAL(mpidr);
-	if (hikey_cluster_state[cluster] == HIKEY_CLUSTER_STATE_OFF) {
-		/*
-		 * Enable CCI coherency for this cluster.
-		 * No need for locks as no other cpu is active at the moment.
-		 */
+
+
+	/*
+	 * Enable CCI coherency for this cluster.
+	 * No need for locks as no other cpu is active at the moment.
+	 */
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
 		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
-		hikey_cluster_state[cluster] = HIKEY_CLUSTER_STATE_ON;
-	}
 
 	/* Zero the jump address in the mailbox for this cpu */
 	hisi_pwrc_set_core_bx_addr(cpu, cluster, 0);
@@ -72,35 +70,133 @@
 	gicv2_cpuif_enable();
 }
 
-/*******************************************************************************
- * Handler called when a power domain is about to be turned off. The
- * target_state encodes the power state that each level should transition to.
- ******************************************************************************/
 void hikey_pwr_domain_off(const psci_power_state_t *target_state)
 {
 	unsigned long mpidr;
 	int cpu, cluster;
 
-	gicv2_cpuif_disable();
-
 	mpidr = read_mpidr();
 	cluster = MPIDR_AFFLVL1_VAL(mpidr);
 	cpu = MPIDR_AFFLVL0_VAL(mpidr);
-	if (target_state->pwr_domain_state[MPIDR_AFFLVL1] ==
-	    PLAT_MAX_OFF_STATE) {
+
+	gicv2_cpuif_disable();
+	hisi_ipc_cpu_off(cpu, cluster);
+
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
 		hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE);
 		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
 		hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE);
 
 		hisi_ipc_cluster_off(cpu, cluster);
-		hikey_cluster_state[cluster] = HIKEY_CLUSTER_STATE_OFF;
 	}
-	hisi_ipc_cpu_off(cpu, cluster);
+}
+
+static void hikey_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int cpu = mpidr & MPIDR_CPU_MASK;
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+
+		/* Program the jump address for the target cpu */
+		hisi_pwrc_set_core_bx_addr(cpu, cluster, hikey_sec_entrypoint);
+
+		gicv2_cpuif_disable();
+
+		if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+			hisi_ipc_cpu_suspend(cpu, cluster);
+	}
+
+	/* Perform the common cluster specific operations */
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE);
+		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+		hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE);
+
+		if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+			hisi_pwrc_set_cluster_wfi(1);
+			hisi_pwrc_set_cluster_wfi(0);
+			hisi_ipc_psci_system_off();
+		} else
+			hisi_ipc_cluster_suspend(cpu, cluster);
+	}
+}
+
+static void hikey_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr;
+	unsigned int cluster, cpu;
+
+	/* Nothing to be done on waking up from retention from CPU level */
+	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	/* Get the mpidr for this cpu */
+	mpidr = read_mpidr_el1();
+	cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFF1_SHIFT;
+	cpu = mpidr & MPIDR_CPU_MASK;
+
+	/* Enable CCI coherency for cluster */
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+
+	hisi_pwrc_set_core_bx_addr(cpu, cluster, 0);
+
+	if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		gicv2_distif_init();
+		gicv2_pcpu_distif_init();
+		gicv2_cpuif_enable();
+	} else {
+		gicv2_pcpu_distif_init();
+		gicv2_cpuif_enable();
+	}
+}
+
+static void hikey_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	int i;
+
+	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
 }
 
-/*******************************************************************************
- * Handler to reboot the system.
- ******************************************************************************/
+static void __dead2 hikey_system_off(void)
+{
+	NOTICE("%s: off system\n", __func__);
+
+	/* Pull down GPIO_0_0 to trigger PMIC shutdown */
+	mmio_write_32(0xF8001810, 0x2); /* Pinmux */
+	mmio_write_8(0xF8011400, 1);	/* Pin direction */
+	mmio_write_8(0xF8011004, 0);	/* Pin output value */
+
+	/* Wait for 2s to power off system by PMIC */
+	sp804_timer_init(SP804_TIMER0_BASE, 10, 192);
+	mdelay(2000);
+
+	/*
+	 * PMIC shutdown depends on two conditions: GPIO_0_0 (PWR_HOLD) low,
+	 * and VBUS_DET < 3.6V. For HiKey, VBUS_DET is connected to VDD_4V2
+	 * through Jumper 1-2. So, to complete shutdown, user needs to manually
+	 * remove Jumper 1-2.
+	 */
+	NOTICE("+------------------------------------------+\n");
+	NOTICE("| IMPORTANT: Remove Jumper 1-2 to shutdown |\n");
+	NOTICE("| DANGER:    SoC is still burning. DANGER! |\n");
+	NOTICE("| Board will be reboot to avoid overheat   |\n");
+	NOTICE("+------------------------------------------+\n");
+
+	/* Send the system reset request */
+	mmio_write_32(AO_SC_SYS_STAT0, 0x48698284);
+
+	wfi();
+	panic();
+}
+
 static void __dead2 hikey_system_reset(void)
 {
 	/* Send the system reset request */
@@ -112,9 +208,6 @@
 	panic();
 }
 
-/*******************************************************************************
- * Handler called to check the validity of the power state parameter.
- ******************************************************************************/
 int hikey_validate_power_state(unsigned int power_state,
 			       psci_power_state_t *req_state)
 {
@@ -153,9 +246,6 @@
 	return PSCI_E_SUCCESS;
 }
 
-/*******************************************************************************
- * Handler called to check the validity of the non secure entrypoint.
- ******************************************************************************/
 static int hikey_validate_ns_entrypoint(uintptr_t entrypoint)
 {
 	/*
@@ -168,26 +258,20 @@
 	return PSCI_E_INVALID_ADDRESS;
 }
 
-/*******************************************************************************
- * Export the platform handlers to enable psci to invoke them
- ******************************************************************************/
 static const plat_psci_ops_t hikey_psci_ops = {
 	.cpu_standby			= NULL,
 	.pwr_domain_on			= hikey_pwr_domain_on,
 	.pwr_domain_on_finish		= hikey_pwr_domain_on_finish,
 	.pwr_domain_off			= hikey_pwr_domain_off,
-	.pwr_domain_suspend		= NULL,
-	.pwr_domain_suspend_finish	= NULL,
-	.system_off			= NULL,
+	.pwr_domain_suspend		= hikey_pwr_domain_suspend,
+	.pwr_domain_suspend_finish	= hikey_pwr_domain_suspend_finish,
+	.system_off			= hikey_system_off,
 	.system_reset			= hikey_system_reset,
 	.validate_power_state		= hikey_validate_power_state,
 	.validate_ns_entrypoint		= hikey_validate_ns_entrypoint,
-	.get_sys_suspend_power_state	= NULL,
+	.get_sys_suspend_power_state	= hikey_get_sys_suspend_power_state,
 };
 
-/*******************************************************************************
- * Export the platform specific power ops and initialize Power Controller
- ******************************************************************************/
 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
 			const plat_psci_ops_t **psci_ops)
 {
@@ -197,6 +281,5 @@
 	 * Initialize PSCI ops struct
 	 */
 	*psci_ops = &hikey_psci_ops;
-
 	return 0;
 }
diff --git a/plat/hisilicon/hikey/hikey_topology.c b/plat/hisilicon/hikey/hikey_topology.c
index 37ea20a..95948b8 100644
--- a/plat/hisilicon/hikey/hikey_topology.c
+++ b/plat/hisilicon/hikey/hikey_topology.c
@@ -18,8 +18,10 @@
 	1,
 	/* Number of clusters */
 	PLATFORM_CLUSTER_COUNT,
-	/* Number of CPU cores */
-	PLATFORM_CORE_COUNT
+	/* Number of children for the first cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+	/* Number of children for the second cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
 };
 
 /*******************************************************************************
diff --git a/plat/hisilicon/hikey/hisi_sip_svc.c b/plat/hisilicon/hikey/hisi_sip_svc.c
new file mode 100644
index 0000000..15953af
--- /dev/null
+++ b/plat/hisilicon/hikey/hisi_sip_svc.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <hisi_sip_svc.h>
+#include <debug.h>
+#include <pmf.h>
+#include <runtime_svc.h>
+#include <stdint.h>
+#include <uuid.h>
+
+
+/* Hisi SiP Service UUID */
+DEFINE_SVC_UUID(hisi_sip_svc_uid,
+		0xe599df74, 0x7682, 0x40aa, 0x9f, 0xf8,
+		0xc0, 0x85, 0x52, 0xbc, 0x39, 0x3f);
+
+static int hisi_sip_setup(void)
+{
+	if (pmf_setup() != 0)
+		return 1;
+	return 0;
+}
+
+/*
+ * This function handles Hisi defined SiP Calls
+ */
+static uintptr_t hisi_sip_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 call_count = 0;
+
+	/*
+	 * Dispatch PMF calls to PMF SMC handler and return its return
+	 * value
+	 */
+	if (is_pmf_fid(smc_fid)) {
+		return pmf_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
+				handle, flags);
+	}
+
+	switch (smc_fid) {
+	case HISI_SIP_SVC_CALL_COUNT:
+		/* PMF calls */
+		call_count += PMF_NUM_SMC_CALLS;
+
+		/* State switch call */
+		call_count += 1;
+
+		SMC_RET1(handle, call_count);
+
+	case HISI_SIP_SVC_UID:
+		/* Return UID to the caller */
+		SMC_UUID_RET(handle, hisi_sip_svc_uid);
+
+	case HISI_SIP_SVC_VERSION:
+		/* Return the version of current implementation */
+		SMC_RET2(handle, HISI_SIP_SVC_VERSION_MAJOR, HISI_SIP_SVC_VERSION_MINOR);
+
+	default:
+		WARN("Unimplemented HISI SiP Service Call: 0x%x \n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+
+}
+
+
+/* Define a runtime service descriptor for fast SMC calls */
+DECLARE_RT_SVC(
+	hisi_sip_svc,
+	OEN_SIP_START,
+	OEN_SIP_END,
+	SMC_TYPE_FAST,
+	hisi_sip_setup,
+	hisi_sip_handler
+);
diff --git a/plat/hisilicon/hikey/include/hisi_sip_svc.h b/plat/hisilicon/hikey/include/hisi_sip_svc.h
new file mode 100644
index 0000000..662b6cc
--- /dev/null
+++ b/plat/hisilicon/hikey/include/hisi_sip_svc.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HISI_SIP_SVC_H__
+#define __HISI_SIP_SVC_H__
+
+/* SMC function IDs for SiP Service queries */
+
+#define HISI_SIP_SVC_CALL_COUNT		0x8200ff00
+#define HISI_SIP_SVC_UID			0x8200ff01
+/*					0x8200ff02 is reserved */
+#define HISI_SIP_SVC_VERSION			0x8200ff03
+
+/* HISI SiP Service Calls version numbers */
+#define HISI_SIP_SVC_VERSION_MAJOR		0x0
+#define HISI_SIP_SVC_VERSION_MINOR		0x1
+
+#endif /* __ARM_SIP_SVC_H__ */
diff --git a/plat/hisilicon/hikey/platform.mk b/plat/hisilicon/hikey/platform.mk
index ec4bb5c..85dc40d 100644
--- a/plat/hisilicon/hikey/platform.mk
+++ b/plat/hisilicon/hikey/platform.mk
@@ -65,6 +65,8 @@
 				plat/common/plat_gicv2.c
 
 BL31_SOURCES		+=	drivers/arm/cci/cci.c			\
+				drivers/arm/sp804/sp804_delay_timer.c	\
+				drivers/delay_timer/delay_timer.c	\
 				lib/cpus/aarch64/cortex_a53.S		\
 				plat/common/aarch64/plat_psci_common.c	\
 				plat/hisilicon/hikey/aarch64/hikey_helpers.S \
@@ -75,3 +77,8 @@
 				plat/hisilicon/hikey/hisi_pwrc.c	\
 				plat/hisilicon/hikey/hisi_pwrc_sram.S	\
 				${HIKEY_GIC_SOURCES}
+ifeq (${ENABLE_PMF}, 1)
+BL31_SOURCES		+=	plat/hisilicon/hikey/hisi_sip_svc.c			\
+				lib/pmf/pmf_smc.c
+endif
+
diff --git a/plat/hisilicon/hikey960/aarch64/hikey960_common.c b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
new file mode 100644
index 0000000..d7894b3
--- /dev/null
+++ b/plat/hisilicon/hikey960/aarch64/hikey960_common.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <debug.h>
+#include <mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <xlat_tables.h>
+
+#include "../hikey960_def.h"
+#include "../hikey960_private.h"
+
+#define MAP_DDR		MAP_REGION_FLAT(DDR_BASE,			\
+					DDR_SIZE,			\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_DEVICE	MAP_REGION_FLAT(DEVICE_BASE,			\
+					DEVICE_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_BL1_RW	MAP_REGION_FLAT(BL1_RW_BASE,			\
+					BL1_RW_LIMIT - BL1_RW_BASE,	\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_UFS_DATA	MAP_REGION_FLAT(HIKEY960_UFS_DATA_BASE,		\
+					HIKEY960_UFS_DATA_SIZE,		\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_UFS_DESC	MAP_REGION_FLAT(HIKEY960_UFS_DESC_BASE,		\
+					HIKEY960_UFS_DESC_SIZE,		\
+					MT_MEMORY | MT_RW | MT_NS)
+
+/*
+ * 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
+ * hikey960_init_mmu_elx() will give the available subset of that,
+ */
+#if IMAGE_BL1
+static const mmap_region_t hikey960_mmap[] = {
+	MAP_UFS_DATA,
+	MAP_BL1_RW,
+	MAP_UFS_DESC,
+	MAP_DEVICE,
+	{0}
+};
+#endif
+
+#if IMAGE_BL2
+static const mmap_region_t hikey960_mmap[] = {
+	MAP_DDR,
+	MAP_DEVICE,
+	{0}
+};
+#endif
+
+#if IMAGE_BL31
+static const mmap_region_t hikey960_mmap[] = {
+	MAP_DEVICE,
+	{0}
+};
+#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
+ */
+#define HIKEY960_CONFIGURE_MMU_EL(_el)					\
+	void hikey960_init_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(hikey960_mmap);					\
+	       init_xlat_tables();					\
+									\
+	       enable_mmu_el##_el(0);					\
+	}
+
+/* Define EL1 and EL3 variants of the function initialising the MMU */
+HIKEY960_CONFIGURE_MMU_EL(1)
+HIKEY960_CONFIGURE_MMU_EL(3)
+
+unsigned long plat_get_ns_image_entrypoint(void)
+{
+	return NS_BL1U_BASE;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return 1920000;
+}
diff --git a/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S b/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S
new file mode 100644
index 0000000..2e24416
--- /dev/null
+++ b/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <cortex_a53.h>
+#include <cortex_a73.h>
+#include "../hikey960_def.h"
+
+	.globl	plat_my_core_pos
+	.globl	platform_mem_init
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_report_exception
+	.globl	plat_reset_handler
+	.globl	set_retention_ticks
+	.globl	clr_retention_ticks
+	.globl	clr_ex
+	.globl	nop
+
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 * void platform_mem_init(void);
+	 *
+	 * We don't need to carry out any memory initialization
+	 * on HIKEY. The Secure RAM is accessible straight away.
+	 * -----------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0, x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, CRASH_CONSOLE_BASE
+	mov_imm	x1, PL011_UART_CLK_IN_HZ
+	mov_imm	x2, PL011_BAUDRATE
+	b	console_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, CRASH_CONSOLE_BASE
+	b	console_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * void plat_report_exception(unsigned int type)
+	 * Function to report an unhandled exception
+	 * with platform-specific means.
+	 * On HIKEY platform, it updates the LEDs
+	 * to indicate where we are
+	 * ---------------------------------------------
+	 */
+func plat_report_exception
+	mov	x8, x30
+
+	/* Turn on LED according to x0 (0 -- f) */
+	ldr	x2, =0xf7020000
+	and	x1, x0, #1
+	str	w1, [x2, #4]
+	and	x1, x0, #2
+	str	w1, [x2, #8]
+	and	x1, x0, #4
+	str	w1, [x2, #16]
+	and	x1, x0, #8
+	str	w1, [x2, #32]
+
+	mrs	x2, currentel
+	and	x2, x2, #0x0c
+	/* Check EL1 */
+	cmp	x2, #0x04
+	beq	plat_report_el1
+
+	adr	x4, plat_err_str
+	bl	asm_print_str
+
+	adr	x4, esr_el3_str
+	bl	asm_print_str
+
+	mrs	x4, esr_el3
+	bl	asm_print_hex
+
+	adr	x4, elr_el3_str
+	bl	asm_print_str
+
+	mrs	x4, elr_el3
+	bl	asm_print_hex
+	b	plat_report_end
+
+plat_report_el1:
+	adr	x4, plat_err_str
+	bl	asm_print_str
+
+	adr	x4, esr_el1_str
+	bl	asm_print_str
+
+	mrs	x4, esr_el1
+	bl	asm_print_hex
+
+	adr	x4, elr_el1_str
+	bl	asm_print_str
+
+	mrs	x4, elr_el1
+	bl	asm_print_hex
+plat_report_end:
+	mov	x30, x8
+	ret
+endfunc plat_report_exception
+
+	/* -----------------------------------------------------
+	 * void plat_reset_handler(void);
+	 * -----------------------------------------------------
+	 */
+func plat_reset_handler
+	ret
+endfunc plat_reset_handler
+
+	/* -----------------------------------------------------
+	 * void set_retention_ticks(unsigned int val);
+	 * Clobber list : x0
+	 * -----------------------------------------------------
+	 */
+func set_retention_ticks
+	mrs	x0, CPUECTLR_EL1
+	bic	x0, x0, #CPUECTLR_CPU_RET_CTRL_MASK
+	orr	x0, x0, #RETENTION_ENTRY_TICKS_8
+	msr	CPUECTLR_EL1, x0
+	isb
+	dsb	sy
+	ret
+endfunc set_retention_ticks
+
+	/* -----------------------------------------------------
+	 * void clr_retention_ticks(unsigned int val);
+	 * Clobber list : x0
+	 * -----------------------------------------------------
+	 */
+func clr_retention_ticks
+	mrs	x0, CPUECTLR_EL1
+	bic	x0, x0, #CPUECTLR_CPU_RET_CTRL_MASK
+	msr	CPUECTLR_EL1, x0
+	isb
+	dsb	sy
+	ret
+endfunc clr_retention_ticks
+
+	/* -----------------------------------------------------
+	 * void clrex(void);
+	 * -----------------------------------------------------
+	 */
+func clr_ex
+	clrex
+	ret
+endfunc clr_ex
+
+	/* -----------------------------------------------------
+	 * void nop(void);
+	 * -----------------------------------------------------
+	 */
+func nop
+	nop
+	ret
+endfunc nop
+
+.section .rodata.rev_err_str, "aS"
+plat_err_str:
+	.asciz "\nPlatform exception reporting:"
+esr_el3_str:
+	.asciz "\nESR_EL3: "
+elr_el3_str:
+	.asciz "\nELR_EL3: "
+esr_el1_str:
+	.asciz "\nESR_EL1: "
+elr_el1_str:
+	.asciz "\nELR_EL1: "
diff --git a/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c b/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c
new file mode 100644
index 0000000..8ce1e4f
--- /dev/null
+++ b/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <hi3660.h>
+#include <mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <hisi_ipc.h>
+#include <debug.h>
+
+#include "../../hikey960_private.h"
+
+#define IPC_MBX_SOURCE_REG(m)		(IPC_BASE + ((m) << 6))
+#define IPC_MBX_DSET_REG(m)		(IPC_BASE + ((m) << 6) + 0x04)
+#define IPC_MBX_DCLEAR_REG(m)		(IPC_BASE + ((m) << 6) + 0x08)
+#define IPC_MBX_DSTATUS_REG(m)		(IPC_BASE + ((m) << 6) + 0x0C)
+#define IPC_MBX_MODE_REG(m)		(IPC_BASE + ((m) << 6) + 0x10)
+#define IPC_MBX_IMASK_REG(m)		(IPC_BASE + ((m) << 6) + 0x14)
+#define IPC_MBX_ICLR_REG(m)		(IPC_BASE + ((m) << 6) + 0x18)
+#define IPC_MBX_SEND_REG(m)		(IPC_BASE + ((m) << 6) + 0x1C)
+#define IPC_MBX_DATA_REG(m, d)		(IPC_BASE + ((m) << 6) + 0x20 + \
+					 ((d) * 4))
+#define IPC_CPU_IMST_REG(m)		(IPC_BASE + ((m) << 3))
+#define IPC_LOCK_REG			(IPC_BASE + 0xA00)
+#define IPC_ACK_BIT_SHIFT		(1 << 7)
+#define IPC_UNLOCK_VALUE		(0x1ACCE551)
+
+/*********************************************************
+ *bit[31:24]:0~AP
+ *bit[23:16]:0x1~A15, 0x2~A7
+ *bit[15:8]:0~ON, 1~OFF
+ *bit[7:0]:0x3 cpu power mode
+ *********************************************************/
+#define IPC_CMD_TYPE(src_obj, cluster_obj, is_off, mode) \
+	((src_obj << 24) | (((cluster_obj) + 1) << 16) | (is_off << 8) | (mode))
+
+/*********************************************************
+ *bit[15:8]:0~no idle, 1~idle
+ *bit[7:0]:cpux
+ *********************************************************/
+
+#define IPC_CMD_PARA(is_idle, cpu) \
+	((is_idle << 8) | (cpu))
+
+#define IPC_STATE_IDLE			0x10
+
+enum src_id {
+	SRC_IDLE = 0,
+	SRC_A15 = 1 << 0,
+	SRC_A7 = 1 << 1,
+	SRC_IOM3 = 1 << 2,
+	SRC_LPM3 = 1 << 3
+};
+
+/*lpm3's mailboxs are 13~17*/
+enum lpm3_mbox_id {
+	LPM3_MBX0 = 13,
+	LPM3_MBX1,
+	LPM3_MBX2,
+	LPM3_MBX3,
+	LPM3_MBX4,
+};
+
+static void cpu_relax(void)
+{
+	volatile int i;
+
+	for (i = 0; i < 10; i++)
+		nop();
+}
+
+static inline void
+hisi_ipc_clear_ack(enum src_id source, enum lpm3_mbox_id mbox)
+{
+	unsigned int int_status = 0;
+
+	do {
+		int_status = mmio_read_32(IPC_MBX_MODE_REG(mbox));
+		int_status &= 0xF0;
+		cpu_relax();
+	} while (int_status != IPC_ACK_BIT_SHIFT);
+
+	mmio_write_32(IPC_MBX_ICLR_REG(mbox), source);
+}
+
+static void
+hisi_ipc_send_cmd_with_ack(enum src_id source, enum lpm3_mbox_id mbox,
+			   unsigned int cmdtype, unsigned int cmdpara)
+{
+	unsigned int regval;
+	unsigned int mask;
+	unsigned int state;
+
+	mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
+	/* wait for idle and occupy */
+	do {
+		state = mmio_read_32(IPC_MBX_MODE_REG(mbox));
+		if (state == IPC_STATE_IDLE) {
+			mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
+			regval = mmio_read_32(IPC_MBX_SOURCE_REG(mbox));
+			if (regval == source)
+				break;
+		}
+		cpu_relax();
+
+	} while (1);
+
+	/* auto answer */
+	mmio_write_32(IPC_MBX_MODE_REG(mbox), 0x1);
+
+	mask = (~((int)source | SRC_LPM3) & 0x3F);
+	/* mask the other cpus */
+	mmio_write_32(IPC_MBX_IMASK_REG(mbox), mask);
+	/* set data */
+	mmio_write_32(IPC_MBX_DATA_REG(mbox, 0), cmdtype);
+	mmio_write_32(IPC_MBX_DATA_REG(mbox, 1), cmdpara);
+	/* send cmd */
+	mmio_write_32(IPC_MBX_SEND_REG(mbox), source);
+	/* wait ack and clear */
+	hisi_ipc_clear_ack(source, mbox);
+
+	/* release mailbox */
+	mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source);
+}
+
+void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster,
+			enum pm_mode mode)
+{
+	unsigned int cmdtype = 0;
+	unsigned int cmdpara = 0;
+	enum src_id source = SRC_IDLE;
+	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
+
+	cmdtype = IPC_CMD_TYPE(0, cluster, mode, 0x3);
+	cmdpara = IPC_CMD_PARA(0, core);
+	source = cluster ? SRC_A7 : SRC_A15;
+	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
+}
+
+void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster,
+			 unsigned int affinity_level)
+{
+	unsigned int cmdtype = 0;
+	unsigned int cmdpara = 0;
+	enum src_id source = SRC_IDLE;
+	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
+
+	if (affinity_level == 0x3)
+		cmdtype = IPC_CMD_TYPE(0, -1, 0x1, 0x3 + affinity_level);
+	else
+		cmdtype = IPC_CMD_TYPE(0, cluster, 0x1, 0x3 + affinity_level);
+
+	cmdpara = IPC_CMD_PARA(1, core);
+	source = cluster ? SRC_A7 : SRC_A15;
+	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
+}
+
+void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster)
+{
+	unsigned int cmdtype = 0;
+	unsigned int cmdpara = 0;
+	enum src_id source = SRC_IDLE;
+	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
+
+	cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x1, 0x0);
+	cmdpara = IPC_CMD_PARA(0, 0);
+	source = cluster ? SRC_A7 : SRC_A15;
+	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
+}
+
+void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster,
+				unsigned int cmd_id)
+{
+	unsigned int cmdtype = 0;
+	unsigned int cmdpara = 0;
+	enum src_id source = SRC_IDLE;
+	enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core);
+
+	cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x0, 0x0);
+	cmdpara = cmd_id;
+	source = cluster ? SRC_A7 : SRC_A15;
+	hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara);
+}
+
+int hisi_ipc_init(void)
+{
+	int ret = 0;
+	enum lpm3_mbox_id  i = LPM3_MBX0;
+
+	mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE);
+	for (i = LPM3_MBX0; i <= LPM3_MBX4; i++) {
+		mmio_write_32(IPC_MBX_MODE_REG(i), 1);
+		mmio_write_32(IPC_MBX_IMASK_REG(i),
+			      ((int)SRC_IOM3 | (int)SRC_A15 | (int)SRC_A7));
+		mmio_write_32(IPC_MBX_ICLR_REG(i), SRC_A7);
+	}
+
+	return ret;
+}
diff --git a/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c
new file mode 100644
index 0000000..f82144a
--- /dev/null
+++ b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <../hikey960_def.h>
+#include <hisi_ipc.h>
+#include "hisi_pwrc.h"
+
+
+/* resource lock api */
+#define RES0_LOCK_BASE		(SOC_PCTRL_RESOURCE0_LOCK_ADDR(PCTRL_BASE))
+#define RES1_LOCK_BASE		(SOC_PCTRL_RESOURCE1_LOCK_ADDR(PCTRL_BASE))
+#define RES2_LOCK_BASE		(SOC_PCTRL_RESOURCE2_LOCK_ADDR(PCTRL_BASE))
+
+#define LOCK_BIT			(0x1 << 28)
+#define LOCK_ID_MASK			(0x7 << 29)
+#define CPUIDLE_LOCK_ID(core)		(0x6 - (core))
+#define LOCK_UNLOCK_OFFSET		0x4
+#define LOCK_STAT_OFFSET		0x8
+
+#define CLUSTER0_CPUS_ONLINE_MASK	(0xF << 16)
+#define	CLUSTER1_CPUS_ONLINE_MASK	(0xF << 20)
+
+/* cpu hotplug flag api */
+#define SCTRL_BASE			(SOC_ACPU_SCTRL_BASE_ADDR)
+#define REG_SCBAKDATA3_OFFSET		(SOC_SCTRL_SCBAKDATA3_ADDR(SCTRL_BASE))
+#define REG_SCBAKDATA8_OFFSET		(SOC_SCTRL_SCBAKDATA8_ADDR(SCTRL_BASE))
+#define REG_SCBAKDATA9_OFFSET		(SOC_SCTRL_SCBAKDATA9_ADDR(SCTRL_BASE))
+
+#define CPUIDLE_FLAG_REG(cluster) \
+			((cluster == 0) ? REG_SCBAKDATA8_OFFSET : \
+			 REG_SCBAKDATA9_OFFSET)
+#define CLUSTER_IDLE_BIT				BIT(8)
+#define CLUSTER_IDLE_MASK		(CLUSTER_IDLE_BIT | 0x0F)
+
+#define AP_SUSPEND_FLAG			(1 << 16)
+
+#define CLUSTER_PWDN_IDLE		(0<<28)
+#define CLUSTER_PWDN_HOTPLUG		(1<<28)
+#define CLUSTER_PWDN_SR			(2<<28)
+
+#define CLUSTER0_PDC_OFFSET			0x260
+#define CLUSTER1_PDC_OFFSET			0x300
+
+#define PDC_EN_OFFSET				0x0
+#define PDC_COREPWRINTEN_OFFSET		0x4
+#define PDC_COREPWRINTSTAT_OFFSET	0x8
+#define PDC_COREGICMASK_OFFSET		0xc
+#define PDC_COREPOWERUP_OFFSET		0x10
+#define PDC_COREPOWERDN_OFFSET		0x14
+#define PDC_COREPOWERSTAT_OFFSET	0x18
+
+#define PDC_COREPWRSTAT_MASK   (0XFFFF)
+
+enum pdc_gic_mask {
+	PDC_MASK_GIC_WAKE_IRQ,
+	PDC_UNMASK_GIC_WAKE_IRQ
+};
+
+enum pdc_finish_int_mask {
+	PDC_DISABLE_FINISH_INT,
+	PDC_ENABLE_FINISH_INT
+};
+
+static void hisi_resource_lock(unsigned int lockid, unsigned int offset)
+{
+	unsigned int lock_id = (lockid << 29);
+	unsigned int lock_val =  lock_id | LOCK_BIT;
+	unsigned int lock_state;
+
+	do {
+		mmio_write_32(offset, lock_val);
+		lock_state = mmio_read_32(LOCK_STAT_OFFSET + (uintptr_t)offset);
+	} while ((lock_state & LOCK_ID_MASK) != lock_id);
+}
+
+static void hisi_resource_unlock(unsigned int lockid, unsigned int offset)
+{
+	unsigned int lock_val = (lockid << 29) | LOCK_BIT;
+
+	mmio_write_32((LOCK_UNLOCK_OFFSET + (uintptr_t)offset), lock_val);
+}
+
+
+static void hisi_cpuhotplug_lock(unsigned int cluster, unsigned int core)
+{
+	unsigned int lock_id;
+
+	lock_id = (cluster << 2) + core;
+
+	hisi_resource_lock(lock_id, RES2_LOCK_BASE);
+}
+
+static void hisi_cpuhotplug_unlock(unsigned int cluster, unsigned int core)
+{
+	unsigned int lock_id;
+
+	lock_id = (cluster << 2) + core;
+
+	hisi_resource_unlock(lock_id, RES2_LOCK_BASE);
+}
+
+/* get the resource lock */
+void hisi_cpuidle_lock(unsigned int cluster, unsigned int core)
+{
+	unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE);
+
+	hisi_resource_lock(CPUIDLE_LOCK_ID(core), offset);
+}
+
+/* release the resource lock */
+void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core)
+{
+	unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE);
+
+	hisi_resource_unlock(CPUIDLE_LOCK_ID(core), offset);
+}
+
+unsigned int hisi_get_cpuidle_flag(unsigned int cluster)
+{
+	unsigned int val;
+
+	val = mmio_read_32(CPUIDLE_FLAG_REG(cluster));
+	val &= 0xF;
+
+	return val;
+}
+
+void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core)
+{
+	mmio_setbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
+}
+
+void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core)
+{
+	mmio_clrbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core));
+
+}
+
+int hisi_test_ap_suspend_flag(unsigned int cluster)
+{
+	unsigned int val;
+
+	val = mmio_read_32(CPUIDLE_FLAG_REG(cluster));
+	val &= AP_SUSPEND_FLAG;
+	return !!val;
+}
+
+void hisi_set_cluster_pwdn_flag(unsigned int cluster,
+				unsigned int core, unsigned int value)
+{
+	unsigned int val;
+
+	hisi_cpuhotplug_lock(cluster, core);
+
+	val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
+	val = (value << (cluster << 1)) | (val & 0xFFFFFFF);
+	mmio_write_32(REG_SCBAKDATA3_OFFSET, val);
+
+	hisi_cpuhotplug_unlock(cluster, core);
+}
+
+unsigned int hisi_get_cpu_boot_flag(unsigned int cluster, unsigned int core)
+{
+	unsigned int val;
+
+	hisi_cpuhotplug_lock(cluster, core);
+	val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
+	val = val >> (16 + (cluster << 2));
+	val &= 0xF;
+	hisi_cpuhotplug_unlock(cluster, core);
+
+	return val;
+}
+
+unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core)
+{
+	unsigned int val;
+
+	hisi_cpuhotplug_lock(cluster, core);
+	val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
+	val = val >> (16 + (cluster << 2));
+	val &= 0xF;
+	hisi_cpuhotplug_unlock(cluster, core);
+
+	if (val)
+		return 0;
+	else
+		return 1;
+}
+
+void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core)
+{
+	unsigned int flag = BIT((cluster<<2) + core + 16);
+
+	hisi_cpuhotplug_lock(cluster, core);
+
+	mmio_setbits_32(REG_SCBAKDATA3_OFFSET, flag);
+
+	hisi_cpuhotplug_unlock(cluster, core);
+}
+
+void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core)
+{
+	unsigned int flag = BIT((cluster<<2) + core + 16);
+
+	hisi_cpuhotplug_lock(cluster, core);
+
+	mmio_clrbits_32(REG_SCBAKDATA3_OFFSET, flag);
+
+	hisi_cpuhotplug_unlock(cluster, core);
+}
+
+int cluster_is_powered_on(unsigned int cluster)
+{
+	unsigned int val = mmio_read_32(REG_SCBAKDATA3_OFFSET);
+	int ret;
+
+	if (cluster == 0)
+		ret = val & CLUSTER0_CPUS_ONLINE_MASK;
+	else
+		ret = val & CLUSTER1_CPUS_ONLINE_MASK;
+
+	return !!ret;
+}
+
+static void *hisi_get_pdc_addr(unsigned int cluster)
+{
+	void *pdc_base_addr;
+	uintptr_t addr;
+
+	if (cluster == 0)
+		addr = SOC_CRGPERIPH_A53_PDCEN_ADDR(CRG_BASE);
+	else
+		addr = SOC_CRGPERIPH_MAIA_PDCEN_ADDR(CRG_BASE);
+	pdc_base_addr = (void *)addr;
+
+	return pdc_base_addr;
+}
+
+static unsigned int hisi_get_pdc_stat(unsigned int cluster)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+	unsigned int val;
+
+	val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPOWERSTAT_OFFSET);
+
+	return val;
+}
+
+int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core)
+{
+	unsigned int mask = 0xf << (core * 4);
+	unsigned int pdc_stat = hisi_get_pdc_stat(cluster);
+	unsigned int boot_flag = hisi_get_cpu_boot_flag(cluster, core);
+	unsigned int cpuidle_flag = hisi_get_cpuidle_flag(cluster);
+
+	mask = (PDC_COREPWRSTAT_MASK & (~mask));
+	pdc_stat &= mask;
+
+	if ((boot_flag ^ cpuidle_flag) || pdc_stat)
+		return 0;
+	else
+		return 1;
+}
+
+void hisi_disable_pdc(unsigned int cluster)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	mmio_write_32((uintptr_t)pdc_base_addr, 0x0);
+}
+
+void hisi_enable_pdc(unsigned int cluster)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	mmio_write_32((uintptr_t)pdc_base_addr, 0x1);
+}
+
+static inline void hisi_pdc_set_intmask(void *pdc_base_addr,
+					unsigned int core,
+					enum pdc_finish_int_mask intmask)
+{
+	unsigned int val;
+
+	val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET);
+	if (intmask == PDC_ENABLE_FINISH_INT)
+		val |= BIT(core);
+	else
+		val &= ~BIT(core);
+
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, val);
+}
+
+static inline void hisi_pdc_set_gicmask(void *pdc_base_addr,
+					unsigned int core,
+					enum pdc_gic_mask gicmask)
+{
+	unsigned int val;
+
+	val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET);
+	if (gicmask == PDC_MASK_GIC_WAKE_IRQ)
+		val |= BIT(core);
+	else
+		val &= ~BIT(core);
+
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET, val);
+}
+
+void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster)
+{
+	int i;
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	for (i = 0; i < 4; i++)
+		hisi_pdc_set_gicmask(pdc_base_addr, i, PDC_MASK_GIC_WAKE_IRQ);
+}
+
+static void hisi_pdc_powerup_core(unsigned int cluster, unsigned int core,
+				  enum pdc_gic_mask gicmask,
+				  enum pdc_finish_int_mask intmask)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERUP_OFFSET,
+		      BIT(core));
+}
+
+static void hisi_pdc_powerdn_core(unsigned int cluster, unsigned int core,
+				  enum pdc_gic_mask gicmask,
+				  enum pdc_finish_int_mask intmask)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
+		      BIT(core));
+}
+
+void hisi_powerup_core(unsigned int cluster, unsigned int core)
+{
+	hisi_pdc_powerup_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
+			      PDC_DISABLE_FINISH_INT);
+}
+
+void hisi_powerdn_core(unsigned int cluster, unsigned int core)
+{
+	hisi_pdc_powerdn_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ,
+			      PDC_DISABLE_FINISH_INT);
+}
+
+void hisi_powerup_cluster(unsigned int cluster, unsigned int core)
+{
+	hisi_ipc_pm_on_off(core, cluster, PM_ON);
+}
+
+void hisi_powerdn_cluster(unsigned int cluster, unsigned int core)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_HOTPLUG);
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
+		      (0x10001 << core));
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
+		      BIT(core));
+}
+
+void hisi_enter_core_idle(unsigned int cluster, unsigned int core)
+{
+	hisi_pdc_powerdn_core(cluster, core, PDC_UNMASK_GIC_WAKE_IRQ,
+			      PDC_DISABLE_FINISH_INT);
+}
+
+void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core)
+{
+	void *pdc_base_addr = hisi_get_pdc_addr(cluster);
+
+	hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_IDLE);
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET,
+		      (0x10001 << core));
+	mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET,
+		      BIT(core));
+}
+
+void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core)
+{
+	hisi_ipc_pm_suspend(core, cluster, 0x3);
+}
diff --git a/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h
new file mode 100644
index 0000000..a4d887f
--- /dev/null
+++ b/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HISI_PWRC_H__
+#define __HISI_PWRC_H__
+
+#include <hi3660.h>
+#include <hi3660_crg.h>
+
+#define PCTRL_BASE					(PCTRL_REG_BASE)
+#define CRG_BASE					(CRG_REG_BASE)
+
+#define SOC_CRGPERIPH_A53_PDCEN_ADDR(base)		((base) + (0x260))
+#define SOC_CRGPERIPH_MAIA_PDCEN_ADDR(base)		((base) + (0x300))
+
+#define SOC_PCTRL_RESOURCE0_LOCK_ADDR(base)		((base) + (0x400))
+#define SOC_PCTRL_RESOURCE0_UNLOCK_ADDR(base)		((base) + (0x404))
+#define SOC_PCTRL_RESOURCE0_LOCK_ST_ADDR(base)		((base) + (0x408))
+#define SOC_PCTRL_RESOURCE1_LOCK_ADDR(base)		((base) + (0x40C))
+#define SOC_PCTRL_RESOURCE1_UNLOCK_ADDR(base)		((base) + (0x410))
+#define SOC_PCTRL_RESOURCE1_LOCK_ST_ADDR(base)		((base) + (0x414))
+#define SOC_PCTRL_RESOURCE2_LOCK_ADDR(base)		((base) + (0x418))
+
+#define SOC_SCTRL_SCBAKDATA3_ADDR(base)			((base) + (0x418))
+#define SOC_SCTRL_SCBAKDATA8_ADDR(base)			((base) + (0x42C))
+#define SOC_SCTRL_SCBAKDATA9_ADDR(base)			((base) + (0x430))
+
+#define SOC_ACPU_SCTRL_BASE_ADDR			(0xFFF0A000)
+
+void hisi_cpuidle_lock(unsigned int cluster, unsigned int core);
+void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core);
+void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core);
+void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core);
+void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core);
+void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core);
+int cluster_is_powered_on(unsigned int cluster);
+void hisi_enter_core_idle(unsigned int cluster, unsigned int core);
+void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core);
+int hisi_test_ap_suspend_flag(unsigned int cluster);
+void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core);
+
+
+/* pdc api */
+void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster);
+int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core);
+void hisi_disable_pdc(unsigned int cluster);
+void hisi_enable_pdc(unsigned int cluster);
+void hisi_powerup_core(unsigned int cluster, unsigned int core);
+void hisi_powerdn_core(unsigned int cluster, unsigned int core);
+void hisi_powerup_cluster(unsigned int cluster, unsigned int core);
+void hisi_powerdn_cluster(unsigned int cluster, unsigned int core);
+unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core);
+
+#endif /* __HISI_PWRC_H__ */
diff --git a/plat/hisilicon/hikey960/hi3660_mailbox.c b/plat/hisilicon/hikey960/hi3660_mailbox.c
new file mode 100644
index 0000000..aa12932
--- /dev/null
+++ b/plat/hisilicon/hikey960/hi3660_mailbox.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <hi3660_mailbox.h>
+#include <mailbox.h>
+#include <mmio.h>
+#include <string.h>
+
+typedef struct hi3660_chan {
+	unsigned char	src;
+	unsigned char	dst;
+	unsigned char	used;
+} hi3660_chan_t;
+
+static hi3660_chan_t chan_map[MBX_MAX_CHANNELS];
+
+static void hi3660_mbox_check_state(int chan, unsigned int state)
+{
+	unsigned int data;
+
+	data = mmio_read_32(MBX_MODE(chan));
+	assert((data & (MBX_MODE_AUTO_ANSWER | MBX_MODE_AUTO_LINK)) == 0);
+
+	data &= MBX_MODE_STATE_STATUS_MASK;
+	assert(data == state);
+	(void)state;
+}
+
+static int hi3660_mbox_send(int chan, void *message, int len)
+{
+	int i;
+	unsigned int *buf;
+	unsigned int data;
+
+	assert((chan >= 0) && (chan < MBX_MAX_CHANNELS) &&
+	       (message != NULL) && (len <= MBX_MAX_DATA_LEN));
+	assert((chan_map[chan].used != 0) &&
+	       (chan_map[chan].src != 0) &&
+	       (chan_map[chan].dst != 0));
+
+	buf = (unsigned int *)message;
+	len = ((len + 3) >> 2);		/* convert to word count */
+	for (i = 0; i < len; i++)
+		mmio_write_32(MBX_DATA0(chan) + (i << 2), *(buf + i));
+	/* send out */
+	mmio_write_32(MBX_SEND(chan), chan_map[chan].src);
+
+	do {
+		data = mmio_read_32(MBX_ICLR(chan));
+	} while ((data & chan_map[chan].src) == 0);
+	/* ack */
+	mmio_write_32(MBX_ICLR(chan), chan_map[chan].src);
+	return 0;
+}
+
+static int hi3660_mbox_recv(int chan, void *message, int *len)
+{
+	unsigned int *buf, data;
+	int i;
+
+	assert((chan >= 0) && (chan < MBX_MAX_CHANNELS) &&
+	       (message != NULL) && (len != NULL));
+	assert((chan_map[chan].used != 0) &&
+	       (chan_map[chan].src != 0) &&
+	       (chan_map[chan].dst != 0));
+	/* wait IPC event */
+	do {
+		data = mmio_read_32(MBX_MODE(chan));
+	} while ((data & MBX_MODE_STATE_STATUS_MASK) != MBX_MODE_STATE_DEST);
+	/* wait to clear interrupt */
+	do {
+		data = mmio_read_32(MBX_ICLR(chan));
+	} while (data == 0);
+	do {
+		mmio_write_32(MBX_ICLR(chan), chan_map[chan].dst);
+		data = mmio_read_32(MBX_ICLR(chan));
+	} while (data);
+
+	/* read data from IPC */
+	buf = (unsigned int *)message;
+	for (i = 0; i < MBX_MAX_DATA_LEN; i += 4)
+		*(buf + (i >> 2)) = mmio_read_32(MBX_DATA0(chan) + i);
+	*len = MBX_MAX_DATA_LEN;
+	/* ack */
+	mmio_write_32(MBX_SEND(chan), chan_map[chan].dst);
+	return 0;
+}
+
+static int hi3660_mbox_request(int chan, int direction)
+{
+	unsigned int data;
+	unsigned int src, dst;
+
+	assert((chan >= 0) && (chan < MBX_MAX_CHANNELS));
+
+	if (direction == MAILBOX_DIR_TX) {
+		src = CPU_A53;
+		dst = CPU_LPM3;
+	} else if (direction == MAILBOX_DIR_RX) {
+		src = CPU_LPM3;
+		dst = CPU_A53;
+	} else
+		assert(0);
+	mmio_write_32(MBX_SOURCE(chan), src);
+	data = mmio_read_32(MBX_SOURCE(chan));
+	assert(data == src);
+
+	/* mask all interrupts */
+	mmio_write_32(MBX_IMASK(chan), CPU_MASK);
+	/* unmask interrupt */
+	mmio_write_32(MBX_IMASK(chan), ~(src | dst));
+
+	/* set destination */
+	mmio_write_32(MBX_DCLEAR(chan), (~dst) & CPU_MASK);
+	mmio_write_32(MBX_DSET(chan), dst);
+	data = mmio_read_32(MBX_DSTATUS(chan));
+	assert((data & dst) != 0);
+
+	/* clear auto link & auto answer */
+	data = mmio_read_32(MBX_MODE(chan));
+	data &= ~(MBX_MODE_AUTO_ANSWER | MBX_MODE_AUTO_LINK);
+	mmio_write_32(MBX_MODE(chan), data);
+
+	hi3660_mbox_check_state(chan, MBX_MODE_STATE_SOURCE);
+	chan_map[chan].used = 1;
+	chan_map[chan].src = src;
+	chan_map[chan].dst = dst;
+	return 0;
+}
+
+static void hi3660_mbox_free(int chan)
+{
+	assert((chan >= 0) && (chan < MBX_MAX_CHANNELS));
+}
+
+static mbox_ops_t hi3660_mbox_ops = {
+	.send		= hi3660_mbox_send,
+	.recv		= hi3660_mbox_recv,
+	.request	= hi3660_mbox_request,
+	.free		= hi3660_mbox_free,
+};
+
+int hi3660_mbox_init(mbox_params_t *params)
+{
+	int result;
+	unsigned int data;
+
+	assert(params != NULL);
+	result = mbox_init(&hi3660_mbox_ops, params);
+	assert(result == 0);
+	memset(&chan_map, 0, sizeof(chan_map));
+
+	/* unlock mailbox */
+	data = mmio_read_32(IPC_LOCK);
+	while (data == MBX_IPC_LOCKED) {
+		mmio_write_32(IPC_LOCK, MBX_IPC_UNLOCK_MAGIC);
+		data = mmio_read_32(IPC_LOCK);
+	}
+	(void)result;
+	return 0;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_bl1_setup.c b/plat/hisilicon/hikey960/hikey960_bl1_setup.c
new file mode 100644
index 0000000..f9666df
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl1_setup.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <console.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <dw_ufs.h>
+#include <errno.h>
+#include <gicv2.h>
+#include <hi3660.h>
+#include <mmio.h>
+#include <generic_delay_timer.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <string.h>
+#include <tbbr/tbbr_img_desc.h>
+#include <ufs.h>
+
+#include "../../bl1/bl1_private.h"
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+enum {
+	BOOT_MODE_RECOVERY = 0,
+	BOOT_MODE_NORMAL,
+	BOOT_MODE_MASK = 1,
+};
+
+/*
+ * Declarations of linker defined symbols which will help us find the layout
+ * of trusted RAM
+ */
+extern unsigned long __COHERENT_RAM_START__;
+extern unsigned long __COHERENT_RAM_END__;
+
+/*
+ * The next 2 constants identify the extents of the coherent memory region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to
+ * page-aligned addresses.
+ */
+#define BL1_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
+#define BL1_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
+
+/* Data structure which holds the extents of the trusted RAM for BL1 */
+static meminfo_t bl1_tzram_layout;
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+const unsigned int g0_interrupt_array[] = {
+	IRQ_SEC_PHY_TIMER,
+	IRQ_SEC_SGI_0
+};
+
+const gicv2_driver_data_t hikey960_gic_data = {
+	.gicd_base = GICD_REG_BASE,
+	.gicc_base = GICC_REG_BASE,
+	.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
+	.g0_interrupt_array = g0_interrupt_array,
+};
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+	return &bl1_tzram_layout;
+}
+
+/*
+ * Perform any BL1 specific platform actions.
+ */
+void bl1_early_platform_setup(void)
+{
+	const size_t bl1_size = BL1_RAM_LIMIT - BL1_RAM_BASE;
+	unsigned int id, uart_base;
+
+	generic_delay_timer_init();
+	hikey960_read_boardid(&id);
+	if (id == 5300)
+		uart_base = PL011_UART5_BASE;
+	else
+		uart_base = PL011_UART6_BASE;
+	/* Initialize the console to provide early debug support */
+	console_init(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE);
+
+	/* Allow BL1 to see the whole Trusted RAM */
+	bl1_tzram_layout.total_base = BL1_RW_BASE;
+	bl1_tzram_layout.total_size = BL1_RW_SIZE;
+
+	/* Calculate how much RAM BL1 is using and how much remains free */
+	bl1_tzram_layout.free_base = BL1_RW_BASE;
+	bl1_tzram_layout.free_size = BL1_RW_SIZE;
+	reserve_mem(&bl1_tzram_layout.free_base,
+		    &bl1_tzram_layout.free_size,
+		    BL1_RAM_BASE,
+		    bl1_size);
+
+	INFO("BL1: 0x%lx - 0x%lx [size = %lu]\n", BL1_RAM_BASE, BL1_RAM_LIMIT,
+	     bl1_size);
+}
+
+/*
+ * Perform the very early platform specific architecture setup here. At the
+ * moment this only does basic initialization. Later architectural setup
+ * (bl1_arch_setup()) does not do anything platform specific.
+ */
+void bl1_plat_arch_setup(void)
+{
+	hikey960_init_mmu_el3(bl1_tzram_layout.total_base,
+			      bl1_tzram_layout.total_size,
+			      BL1_RO_BASE,
+			      BL1_RO_LIMIT,
+			      BL1_COHERENT_RAM_BASE,
+			      BL1_COHERENT_RAM_LIMIT);
+}
+
+static void hikey960_clk_init(void)
+{
+	/* change ldi0 sel to ppll2 */
+	mmio_write_32(0xfff350b4, 0xf0002000);
+	/* ldi0 20' */
+	mmio_write_32(0xfff350bc, 0xfc004c00);
+}
+
+static void hikey960_pmu_init(void)
+{
+	/* clear np_xo_abb_dig_START bit in PMIC_CLK_TOP_CTRL7 register */
+	mmio_clrbits_32(PMU_SSI0_CLK_TOP_CTRL7_REG, NP_XO_ABB_DIG);
+}
+
+static void hikey960_enable_ppll3(void)
+{
+	/* enable ppll3 */
+	mmio_write_32(PMC_PPLL3_CTRL0_REG, 0x4904305);
+	mmio_write_32(PMC_PPLL3_CTRL1_REG, 0x2300000);
+	mmio_write_32(PMC_PPLL3_CTRL1_REG, 0x6300000);
+}
+
+static void bus_idle_clear(unsigned int value)
+{
+	unsigned int pmc_value, value1, value2;
+	int timeout = 100;
+
+	pmc_value = value << 16;
+	pmc_value &= ~value;
+	mmio_write_32(PMC_NOC_POWER_IDLEREQ_REG, pmc_value);
+
+	for (;;) {
+		value1 = (unsigned int)mmio_read_32(PMC_NOC_POWER_IDLEACK_REG);
+		value2 = (unsigned int)mmio_read_32(PMC_NOC_POWER_IDLE_REG);
+		if (((value1 & value) == 0) && ((value2 & value) == 0))
+			break;
+		udelay(1);
+		timeout--;
+		if (timeout <= 0) {
+			WARN("%s timeout\n", __func__);
+			break;
+		}
+	}
+}
+
+static void set_vivobus_power_up(void)
+{
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00020002);
+	mmio_write_32(CRG_PEREN0_REG, 0x00001000);
+}
+
+static void set_dss_power_up(void)
+{
+	/* set edc0 133MHz = 1600MHz / 12 */
+	mmio_write_32(CRG_CLKDIV5_REG, 0x003f000b);
+	/* set ldi0 ppl0 */
+	mmio_write_32(CRG_CLKDIV3_REG, 0xf0001000);
+	/* set ldi0 133MHz, 1600MHz / 12 */
+	mmio_write_32(CRG_CLKDIV5_REG, 0xfc002c00);
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00000020);
+	udelay(100);
+	/* DISP CRG */
+	mmio_write_32(CRG_PERRSTDIS4_REG, 0x00000010);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x01400140);
+	mmio_write_32(CRG_PEREN0_REG, 0x00002000);
+	mmio_write_32(CRG_PEREN3_REG, 0x0003b000);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS3_REG, 0x0003b000);
+	mmio_write_32(CRG_PERDIS0_REG, 0x00002000);
+	mmio_write_32(CRG_CLKDIV18_REG, 0x01400000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x00000040);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS4_REG, 0x00000006);
+	mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000c00);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x01400140);
+	mmio_write_32(CRG_PEREN0_REG, 0x00002000);
+	mmio_write_32(CRG_PEREN3_REG, 0x0003b000);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_DSS);
+	/* set edc0 400MHz for 2K 1600MHz / 4 */
+	mmio_write_32(CRG_CLKDIV5_REG, 0x003f0003);
+	/* set ldi 266MHz, 1600MHz / 6 */
+	mmio_write_32(CRG_CLKDIV5_REG, 0xfc001400);
+}
+
+static void set_vcodec_power_up(void)
+{
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00040004);
+	mmio_write_32(CRG_PEREN0_REG, 0x00000060);
+	mmio_write_32(CRG_PEREN2_REG, 0x10000000);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS0_REG, 0x00000018);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VCODEC);
+}
+
+static void set_vdec_power_up(void)
+{
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00000004);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x80008000);
+	mmio_write_32(CRG_PEREN2_REG, 0x20080000);
+	mmio_write_32(CRG_PEREN3_REG, 0x00000800);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS3_REG, 0x00000800);
+	mmio_write_32(CRG_PERDIS2_REG, 0x20080000);
+	mmio_write_32(CRG_CLKDIV18_REG, 0x80000000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x00000004);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000200);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x80008000);
+	mmio_write_32(CRG_PEREN2_REG, 0x20080000);
+	mmio_write_32(CRG_PEREN3_REG, 0x00000800);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VDEC);
+}
+
+static void set_venc_power_up(void)
+{
+	/* set venc ppll3 */
+	mmio_write_32(CRG_CLKDIV8_REG, 0x18001000);
+	/* set venc 258MHz, 1290MHz / 5 */
+	mmio_write_32(CRG_CLKDIV8_REG, 0x07c00100);
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00000002);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV19_REG, 0x00010001);
+	mmio_write_32(CRG_PEREN2_REG, 0x40000100);
+	mmio_write_32(CRG_PEREN3_REG, 0x00000400);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS3_REG, 0x00000400);
+	mmio_write_32(CRG_PERDIS2_REG, 0x40000100);
+	mmio_write_32(CRG_CLKDIV19_REG, 0x00010000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x00000002);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV19_REG, 0x00010001);
+	mmio_write_32(CRG_PEREN2_REG, 0x40000100);
+	mmio_write_32(CRG_PEREN3_REG, 0x00000400);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VENC);
+	/* set venc 645MHz, 1290MHz / 2 */
+	mmio_write_32(CRG_CLKDIV8_REG, 0x07c00040);
+}
+
+static void set_isp_power_up(void)
+{
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00000001);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x70007000);
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00100010);
+	mmio_write_32(CRG_PEREN5_REG, 0x01000010);
+	mmio_write_32(CRG_PEREN3_REG, 0x0bf00000);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS5_REG, 0x01000010);
+	mmio_write_32(CRG_PERDIS3_REG, 0x0bf00000);
+	mmio_write_32(CRG_CLKDIV18_REG, 0x70000000);
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00100000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x00000001);
+	/* unreset */
+	mmio_write_32(CRG_ISP_SEC_RSTDIS_REG, 0x0000002f);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV18_REG, 0x70007000);
+	mmio_write_32(CRG_CLKDIV20_REG, 0x00100010);
+	mmio_write_32(CRG_PEREN5_REG, 0x01000010);
+	mmio_write_32(CRG_PEREN3_REG, 0x0bf00000);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_ISP);
+	/* csi clk enable */
+	mmio_write_32(CRG_PEREN3_REG, 0x00700000);
+}
+
+static void set_ivp_power_up(void)
+{
+	/* set ivp ppll0 */
+	mmio_write_32(CRG_CLKDIV0_REG, 0xc0000000);
+	/* set ivp 267MHz, 1600MHz / 6 */
+	mmio_write_32(CRG_CLKDIV0_REG, 0x3c001400);
+	/* mtcmos on */
+	mmio_write_32(CRG_PERPWREN_REG, 0x00200000);
+	udelay(100);
+	/* IVP CRG unreset */
+	mmio_write_32(CRG_IVP_SEC_RSTDIS_REG, 0x00000001);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV20_REG, 0x02000200);
+	mmio_write_32(CRG_PEREN4_REG, 0x000000a8);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(CRG_PERDIS4_REG, 0x000000a8);
+	mmio_write_32(CRG_CLKDIV20_REG, 0x02000000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(CRG_ISODIS_REG, 0x01000000);
+	/* unreset */
+	mmio_write_32(CRG_IVP_SEC_RSTDIS_REG, 0x00000002);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV20_REG, 0x02000200);
+	mmio_write_32(CRG_PEREN4_REG, 0x000000a8);
+	/* bus idle clear */
+	bus_idle_clear(PMC_NOC_POWER_IDLEREQ_IVP);
+	/* set ivp 533MHz, 1600MHz / 3 */
+	mmio_write_32(CRG_CLKDIV0_REG, 0x3c000800);
+}
+
+static void set_audio_power_up(void)
+{
+	unsigned int ret;
+	int timeout = 100;
+	/* mtcmos on */
+	mmio_write_32(SCTRL_SCPWREN_REG, 0x00000001);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV19_REG, 0x80108010);
+	mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010001);
+	mmio_write_32(SCTRL_SCPEREN0_REG, 0x0c000000);
+	mmio_write_32(CRG_PEREN0_REG, 0x04000000);
+	mmio_write_32(CRG_PEREN5_REG, 0x00000080);
+	mmio_write_32(SCTRL_SCPEREN1_REG, 0x0000000f);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(SCTRL_SCPERDIS1_REG, 0x0000000f);
+	mmio_write_32(SCTRL_SCPERDIS0_REG, 0x0c000000);
+	mmio_write_32(CRG_PERDIS5_REG, 0x00000080);
+	mmio_write_32(CRG_PERDIS0_REG, 0x04000000);
+	mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010000);
+	mmio_write_32(CRG_CLKDIV19_REG, 0x80100000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(SCTRL_SCISODIS_REG, 0x00000001);
+	udelay(1);
+	/* unreset */
+	mmio_write_32(SCTRL_PERRSTDIS1_SEC_REG, 0x00000001);
+	mmio_write_32(SCTRL_SCPERRSTDIS0_REG, 0x00000780);
+	/* clk enable */
+	mmio_write_32(CRG_CLKDIV19_REG, 0x80108010);
+	mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010001);
+	mmio_write_32(SCTRL_SCPEREN0_REG, 0x0c000000);
+	mmio_write_32(CRG_PEREN0_REG, 0x04000000);
+	mmio_write_32(CRG_PEREN5_REG, 0x00000080);
+	mmio_write_32(SCTRL_SCPEREN1_REG, 0x0000000f);
+	/* bus idle clear */
+	mmio_write_32(SCTRL_SCPERCTRL7_REG, 0x00040000);
+	for (;;) {
+		ret = mmio_read_32(SCTRL_SCPERSTAT6_REG);
+		if (((ret & (1 << 5)) == 0) && ((ret & (1 << 8)) == 0))
+			break;
+		udelay(1);
+		timeout--;
+		if (timeout <= 0) {
+			WARN("%s timeout\n", __func__);
+			break;
+		}
+	}
+	mmio_write_32(ASP_CFG_MMBUF_CTRL_REG, 0x00ff0000);
+}
+
+static void set_pcie_power_up(void)
+{
+	/* mtcmos on */
+	mmio_write_32(SCTRL_SCPWREN_REG, 0x00000010);
+	udelay(100);
+	/* clk enable */
+	mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000800);
+	mmio_write_32(SCTRL_SCPEREN2_REG, 0x00104000);
+	mmio_write_32(CRG_PEREN7_REG, 0x000003a0);
+	udelay(1);
+	/* clk disable */
+	mmio_write_32(SCTRL_SCPERDIS2_REG, 0x00104000);
+	mmio_write_32(CRG_PERDIS7_REG, 0x000003a0);
+	mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000000);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(SCTRL_SCISODIS_REG, 0x00000030);
+	/* unreset */
+	mmio_write_32(CRG_PERRSTDIS3_REG, 0x8c000000);
+	/* clk enable */
+	mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000800);
+	mmio_write_32(SCTRL_SCPEREN2_REG, 0x00104000);
+	mmio_write_32(CRG_PEREN7_REG, 0x000003a0);
+}
+
+static void ispfunc_enable(void)
+{
+	/* enable ispfunc. Otherwise powerup isp_srt causes exception. */
+	mmio_write_32(0xfff35000, 0x00000008);
+	mmio_write_32(0xfff35460, 0xc004ffff);
+	mmio_write_32(0xfff35030, 0x02000000);
+	mdelay(10);
+}
+
+static void isps_control_clock(int flag)
+{
+	unsigned int ret;
+
+	/* flag: 0 -- disable clock, 1 -- enable clock */
+	if (flag) {
+		ret = mmio_read_32(0xe8420364);
+		ret |= 1;
+		mmio_write_32(0xe8420364, ret);
+	} else {
+		ret = mmio_read_32(0xe8420364);
+		ret &= ~1;
+		mmio_write_32(0xe8420364, ret);
+	}
+}
+
+static void set_isp_srt_power_up(void)
+{
+	unsigned int ret;
+
+	ispfunc_enable();
+	/* reset */
+	mmio_write_32(0xe8420374, 0x00000001);
+	mmio_write_32(0xe8420350, 0x00000000);
+	mmio_write_32(0xe8420358, 0x00000000);
+	/* mtcmos on */
+	mmio_write_32(0xfff35150, 0x00400000);
+	udelay(100);
+	/* clk enable */
+	isps_control_clock(1);
+	udelay(1);
+	isps_control_clock(0);
+	udelay(1);
+	/* iso disable */
+	mmio_write_32(0xfff35148, 0x08000000);
+	/* unreset */
+	ret = mmio_read_32(0xe8420374);
+	ret &= ~0x1;
+	mmio_write_32(0xe8420374, ret);
+	/* clk enable */
+	isps_control_clock(1);
+	/* enable clock gating for accessing csi registers */
+	mmio_write_32(0xe8420010, ~0);
+}
+
+static void hikey960_regulator_enable(void)
+{
+	set_vivobus_power_up();
+	hikey960_enable_ppll3();
+	set_dss_power_up();
+	set_vcodec_power_up();
+	set_vdec_power_up();
+	set_venc_power_up();
+	set_isp_power_up();
+	set_ivp_power_up();
+	set_audio_power_up();
+	set_pcie_power_up();
+	set_isp_srt_power_up();
+}
+
+static void hikey960_ufs_reset(void)
+{
+	unsigned int data, mask;
+
+	mmio_write_32(CRG_PERDIS7_REG, 1 << 14);
+	mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN);
+	do {
+		data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG);
+	} while (data & BIT_SYSCTRL_REF_CLOCK_EN);
+	/* use abb clk */
+	mmio_clrbits_32(UFS_SYS_UFS_SYSCTRL_REG, BIT_UFS_REFCLK_SRC_SE1);
+	mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_REFCLK_ISO_EN);
+	mmio_write_32(PCTRL_PERI_CTRL3_REG, (1 << 0) | (1 << 16));
+	mdelay(1);
+	mmio_write_32(CRG_PEREN7_REG, 1 << 14);
+	mmio_setbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN);
+
+	mmio_write_32(CRG_PERRSTEN3_REG, PERI_UFS_BIT);
+	do {
+		data = mmio_read_32(CRG_PERRSTSTAT3_REG);
+	} while ((data & PERI_UFS_BIT) == 0);
+	mmio_setbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_MTCMOS_EN);
+	mdelay(1);
+	mmio_setbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_PWR_READY);
+	mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+		      MASK_UFS_DEVICE_RESET);
+	/* clear SC_DIV_UFS_PERIBUS */
+	mask = SC_DIV_UFS_PERIBUS << 16;
+	mmio_write_32(CRG_CLKDIV17_REG, mask);
+	/* set SC_DIV_UFSPHY_CFG(3) */
+	mask = SC_DIV_UFSPHY_CFG_MASK << 16;
+	data = SC_DIV_UFSPHY_CFG(3);
+	mmio_write_32(CRG_CLKDIV16_REG, mask | data);
+	data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG);
+	data &= ~MASK_SYSCTRL_CFG_CLOCK_FREQ;
+	data |= 0x39;
+	mmio_write_32(UFS_SYS_PHY_CLK_CTRL_REG, data);
+	mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, MASK_SYSCTRL_REF_CLOCK_SEL);
+	mmio_setbits_32(UFS_SYS_CLOCK_GATE_BYPASS_REG,
+			MASK_UFS_CLK_GATE_BYPASS);
+	mmio_setbits_32(UFS_SYS_UFS_SYSCTRL_REG, MASK_UFS_SYSCTRL_BYPASS);
+
+	mmio_setbits_32(UFS_SYS_PSW_CLK_CTRL_REG, BIT_SYSCTRL_PSW_CLK_EN);
+	mmio_clrbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_ISO_CTRL);
+	mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_PHY_ISO_CTRL);
+	mmio_clrbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_LP_ISOL_EN);
+	mmio_write_32(CRG_PERRSTDIS3_REG, PERI_ARST_UFS_BIT);
+	mmio_setbits_32(UFS_SYS_RESET_CTRL_EN_REG, BIT_SYSCTRL_LP_RESET_N);
+	mdelay(1);
+	mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+		      MASK_UFS_DEVICE_RESET | BIT_UFS_DEVICE_RESET);
+	mdelay(20);
+	mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG,
+		      0x03300330);
+
+	mmio_write_32(CRG_PERRSTDIS3_REG, PERI_UFS_BIT);
+	do {
+		data = mmio_read_32(CRG_PERRSTSTAT3_REG);
+	} while (data & PERI_UFS_BIT);
+}
+
+static void hikey960_ufs_init(void)
+{
+	dw_ufs_params_t ufs_params;
+
+	memset(&ufs_params, 0, sizeof(ufs_params));
+	ufs_params.reg_base = UFS_REG_BASE;
+	ufs_params.desc_base = HIKEY960_UFS_DESC_BASE;
+	ufs_params.desc_size = HIKEY960_UFS_DESC_SIZE;
+
+	if ((ufs_params.flags & UFS_FLAGS_SKIPINIT) == 0)
+		hikey960_ufs_reset();
+	dw_ufs_init(&ufs_params);
+}
+
+static void hikey960_tzc_init(void)
+{
+	mmio_write_32(TZC_EN0_REG, 0x7fbff066);
+	mmio_write_32(TZC_EN1_REG, 0xfffff5fc);
+	mmio_write_32(TZC_EN2_REG, 0x0007005c);
+	mmio_write_32(TZC_EN3_REG, 0x37030700);
+	mmio_write_32(TZC_EN4_REG, 0xf63fefae);
+	mmio_write_32(TZC_EN5_REG, 0x000410fd);
+	mmio_write_32(TZC_EN6_REG, 0x0063ff68);
+	mmio_write_32(TZC_EN7_REG, 0x030000f3);
+	mmio_write_32(TZC_EN8_REG, 0x00000007);
+}
+
+static void hikey960_peri_init(void)
+{
+	/* unreset */
+	mmio_setbits_32(CRG_PERRSTDIS4_REG, 1);
+}
+
+static void hikey960_pinmux_init(void)
+{
+	unsigned int id;
+
+	hikey960_read_boardid(&id);
+	if (id == 5301) {
+		/* hikey960 hardware v2 */
+		/* GPIO150: LED */
+		mmio_write_32(IOMG_FIX_006_REG, 0);
+		/* GPIO151: LED */
+		mmio_write_32(IOMG_FIX_007_REG, 0);
+		/* GPIO189: LED */
+		mmio_write_32(IOMG_AO_011_REG, 0);
+		/* GPIO190: LED */
+		mmio_write_32(IOMG_AO_012_REG, 0);
+		/* GPIO46 */
+		mmio_write_32(IOMG_044_REG, 0);
+		/* GPIO202 */
+		mmio_write_32(IOMG_AO_023_REG, 0);
+		/* GPIO206 */
+		mmio_write_32(IOMG_AO_026_REG, 0);
+		/* GPIO219 - PD pullup */
+		mmio_write_32(IOMG_AO_039_REG, 0);
+		mmio_write_32(IOCG_AO_043_REG, 1 << 0);
+	}
+	/* GPIO005 - PMU SSI, 10mA */
+	mmio_write_32(IOCG_006_REG, 2 << 4);
+}
+
+/*
+ * Function which will perform any remaining platform-specific setup that can
+ * occur after the MMU and data cache have been enabled.
+ */
+void bl1_platform_setup(void)
+{
+	hikey960_clk_init();
+	hikey960_pmu_init();
+	hikey960_regulator_enable();
+	hikey960_tzc_init();
+	hikey960_peri_init();
+	hikey960_ufs_init();
+	hikey960_pinmux_init();
+	hikey960_io_setup();
+}
+
+/*
+ * The following function checks if Firmware update is needed,
+ * by checking if TOC in FIP image is valid or not.
+ */
+unsigned int bl1_plat_get_next_image_id(void)
+{
+	unsigned int mode, ret;
+
+	mode = mmio_read_32(SCTRL_BAK_DATA0_REG);
+	switch (mode & BOOT_MODE_MASK) {
+	case BOOT_MODE_RECOVERY:
+		ret = NS_BL1U_IMAGE_ID;
+		break;
+	case BOOT_MODE_NORMAL:
+		ret = BL2_IMAGE_ID;
+		break;
+	default:
+		WARN("Invalid boot mode is found:%d\n", mode);
+		panic();
+	}
+	return ret;
+}
+
+image_desc_t *bl1_plat_get_image_desc(unsigned int image_id)
+{
+	unsigned int index = 0;
+
+	while (bl1_tbbr_image_descs[index].image_id != INVALID_IMAGE_ID) {
+		if (bl1_tbbr_image_descs[index].image_id == image_id)
+			return &bl1_tbbr_image_descs[index];
+		index++;
+	}
+
+	return NULL;
+}
+
+void bl1_plat_set_ep_info(unsigned int image_id,
+		entry_point_info_t *ep_info)
+{
+	unsigned int data = 0;
+	uintptr_t tmp = HIKEY960_NS_TMP_OFFSET;
+
+	if (image_id == BL2_IMAGE_ID)
+		return;
+	/* Copy NS BL1U from 0x1AC1_8000 to 0x1AC9_8000 */
+	memcpy((void *)tmp, (void *)HIKEY960_NS_IMAGE_OFFSET,
+		NS_BL1U_SIZE);
+	memcpy((void *)NS_BL1U_BASE, (void *)tmp, NS_BL1U_SIZE);
+	inv_dcache_range(NS_BL1U_BASE, NS_BL1U_SIZE);
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	gicv2_driver_init(&hikey960_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+	/* CNTFRQ is read-only in EL1 */
+	write_cntfrq_el0(plat_get_syscnt_freq2());
+	data = read_cpacr_el1();
+	do {
+		data |= 3 << 20;
+		write_cpacr_el1(data);
+		data = read_cpacr_el1();
+	} while ((data & (3 << 20)) != (3 << 20));
+	INFO("cpacr_el1:0x%x\n", data);
+
+	ep_info->args.arg0 = 0xffff & read_mpidr();
+	ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+				DISABLE_ALL_EXCEPTIONS);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_bl2_setup.c b/plat/hisilicon/hikey960/hikey960_bl2_setup.c
new file mode 100644
index 0000000..e225793
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl2_setup.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <console.h>
+#include <debug.h>
+#include <errno.h>
+#include <generic_delay_timer.h>
+#include <hi3660.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <string.h>
+#include <ufs.h>
+
+#include "hikey960_def.h"
+#include "hikey960_private.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__)
+
+/*
+ * The next 2 constants identify the extents of the coherent memory region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to
+ * page-aligned addresses.
+ */
+#define BL2_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
+#define BL2_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
+
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+typedef struct bl2_to_bl31_params_mem {
+	bl31_params_t		bl31_params;
+	image_info_t		bl31_image_info;
+	image_info_t		bl32_image_info;
+	image_info_t		bl33_image_info;
+	entry_point_info_t	bl33_ep_info;
+	entry_point_info_t	bl32_ep_info;
+	entry_point_info_t	bl31_ep_info;
+} bl2_to_bl31_params_mem_t;
+
+static bl2_to_bl31_params_mem_t bl31_params_mem;
+
+meminfo_t *bl2_plat_sec_mem_layout(void)
+{
+	return &bl2_tzram_layout;
+}
+
+bl31_params_t *bl2_plat_get_bl31_params(void)
+{
+	bl31_params_t *bl2_to_bl31_params = NULL;
+
+	/*
+	 * Initialise the memory for all the arguments that needs to
+	 * be passed to BL3-1
+	 */
+	memset(&bl31_params_mem, 0, sizeof(bl2_to_bl31_params_mem_t));
+
+	/* Assign memory for TF related information */
+	bl2_to_bl31_params = &bl31_params_mem.bl31_params;
+	SET_PARAM_HEAD(bl2_to_bl31_params, PARAM_BL31, VERSION_1, 0);
+
+	/* Fill BL3-1 related information */
+	bl2_to_bl31_params->bl31_image_info = &bl31_params_mem.bl31_image_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info, PARAM_IMAGE_BINARY,
+		VERSION_1, 0);
+
+	/* Fill BL3-2 related information if it exists */
+#if BL32_BASE
+	bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_ep_info, PARAM_EP,
+		VERSION_1, 0);
+	bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info, PARAM_IMAGE_BINARY,
+		VERSION_1, 0);
+#endif
+
+	/* Fill BL3-3 related information */
+	bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl33_ep_info,
+		PARAM_EP, VERSION_1, 0);
+
+	/* BL3-3 expects to receive the primary CPU MPID (through x0) */
+	bl2_to_bl31_params->bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
+
+	bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info;
+	SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info, PARAM_IMAGE_BINARY,
+		VERSION_1, 0);
+
+	return bl2_to_bl31_params;
+}
+
+/*******************************************************************************
+ * Populate the extents of memory available for loading SCP_BL2 (if used),
+ * i.e. anywhere in trusted RAM as long as it doesn't overwrite BL2.
+ ******************************************************************************/
+void bl2_plat_get_scp_bl2_meminfo(meminfo_t *scp_bl2_meminfo)
+{
+	ufs_params_t ufs_params;
+
+	memset(&ufs_params, 0, sizeof(ufs_params_t));
+	ufs_params.reg_base = UFS_REG_BASE;
+	ufs_params.desc_base = HIKEY960_UFS_DESC_BASE;
+	ufs_params.desc_size = HIKEY960_UFS_DESC_SIZE;
+	ufs_params.flags = UFS_FLAGS_SKIPINIT;
+	ufs_init(NULL, &ufs_params);
+
+	hikey960_io_setup();
+
+	*scp_bl2_meminfo = bl2_tzram_layout;
+}
+
+extern int load_lpm3(void);
+
+int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
+{
+	int i;
+	int *buf;
+
+	assert(scp_bl2_image_info->image_size < SCP_MEM_SIZE);
+
+	INFO("BL2: Initiating SCP_BL2 transfer to SCP\n");
+
+	INFO("BL2: SCP_BL2: 0x%lx@0x%x\n",
+	     scp_bl2_image_info->image_base,
+	     scp_bl2_image_info->image_size);
+
+	buf = (int *)scp_bl2_image_info->image_base;
+
+	INFO("BL2: SCP_BL2 HEAD:\n");
+	for (i = 0; i < 64; i += 4)
+		INFO("BL2: SCP_BL2 0x%x 0x%x 0x%x 0x%x\n",
+			buf[i], buf[i+1], buf[i+2], buf[i+3]);
+
+	buf = (int *)(scp_bl2_image_info->image_base +
+		      scp_bl2_image_info->image_size - 256);
+
+	INFO("BL2: SCP_BL2 TAIL:\n");
+	for (i = 0; i < 64; i += 4)
+		INFO("BL2: SCP_BL2 0x%x 0x%x 0x%x 0x%x\n",
+			buf[i], buf[i+1], buf[i+2], buf[i+3]);
+
+	memcpy((void *)SCP_MEM_BASE,
+	       (void *)scp_bl2_image_info->image_base,
+	       scp_bl2_image_info->image_size);
+
+	INFO("BL2: SCP_BL2 transferred to SCP\n");
+
+	load_lpm3();
+	(void)buf;
+
+	return 0;
+}
+
+struct entry_point_info *bl2_plat_get_bl31_ep_info(void)
+{
+	return &bl31_params_mem.bl31_ep_info;
+}
+
+void bl2_plat_set_bl31_ep_info(image_info_t *image,
+			       entry_point_info_t *bl31_ep_info)
+{
+	SET_SECURITY_STATE(bl31_ep_info->h.attr, SECURE);
+	bl31_ep_info->spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+				       DISABLE_ALL_EXCEPTIONS);
+}
+
+void bl2_plat_set_bl33_ep_info(image_info_t *image,
+			       entry_point_info_t *bl33_ep_info)
+{
+	unsigned long el_status;
+	unsigned int mode;
+
+	/* Figure out what mode we enter the non-secure world in */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	if (el_status)
+		mode = MODE_EL2;
+	else
+		mode = MODE_EL1;
+
+	/*
+	 * TODO: Consider the possibility of specifying the SPSR in
+	 * the FIP ToC and allowing the platform to have a say as
+	 * well.
+	 */
+	bl33_ep_info->spsr = SPSR_64(mode, MODE_SP_ELX,
+				       DISABLE_ALL_EXCEPTIONS);
+	SET_SECURITY_STATE(bl33_ep_info->h.attr, NON_SECURE);
+}
+
+void bl2_plat_flush_bl31_params(void)
+{
+	flush_dcache_range((unsigned long)&bl31_params_mem,
+			   sizeof(bl2_to_bl31_params_mem_t));
+}
+
+void bl2_plat_get_bl33_meminfo(meminfo_t *bl33_meminfo)
+{
+	bl33_meminfo->total_base = DDR_BASE;
+	bl33_meminfo->total_size = DDR_SIZE;
+	bl33_meminfo->free_base = DDR_BASE;
+	bl33_meminfo->free_size = DDR_SIZE;
+}
+
+void bl2_early_platform_setup(meminfo_t *mem_layout)
+{
+	unsigned int id, uart_base;
+
+	generic_delay_timer_init();
+	hikey960_read_boardid(&id);
+	if (id == 5300)
+		uart_base = PL011_UART5_BASE;
+	else
+		uart_base = PL011_UART6_BASE;
+
+	/* Initialize the console to provide early debug support */
+	console_init(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE);
+
+	/* Setup the BL2 memory layout */
+	bl2_tzram_layout = *mem_layout;
+}
+
+void bl2_plat_arch_setup(void)
+{
+	hikey960_init_mmu_el1(bl2_tzram_layout.total_base,
+			      bl2_tzram_layout.total_size,
+			      BL2_RO_BASE,
+			      BL2_RO_LIMIT,
+			      BL2_COHERENT_RAM_BASE,
+			      BL2_COHERENT_RAM_LIMIT);
+}
+
+void bl2_platform_setup(void)
+{
+	/* disable WDT0 */
+	if (mmio_read_32(WDT0_REG_BASE + WDT_LOCK_OFFSET) == WDT_LOCKED) {
+		mmio_write_32(WDT0_REG_BASE + WDT_LOCK_OFFSET, WDT_UNLOCK);
+		mmio_write_32(WDT0_REG_BASE + WDT_CONTROL_OFFSET, 0);
+		mmio_write_32(WDT0_REG_BASE + WDT_LOCK_OFFSET, 0);
+	}
+}
diff --git a/plat/hisilicon/hikey960/hikey960_bl31_setup.c b/plat/hisilicon/hikey960/hikey960_bl31_setup.c
new file mode 100644
index 0000000..41c591b
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_bl31_setup.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <arm_gic.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <cci.h>
+#include <console.h>
+#include <debug.h>
+#include <errno.h>
+#include <generic_delay_timer.h>
+#include <gicv2.h>
+#include <hi3660.h>
+#include <hisi_ipc.h>
+#include <platform_def.h>
+
+#include "hikey960_def.h"
+#include "hikey960_private.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 BL31_RO_BASE	(unsigned long)(&__RO_START__)
+#define BL31_RO_LIMIT	(unsigned long)(&__RO_END__)
+
+/*
+ * The next 2 constants identify the extents of the coherent memory region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to
+ * page-aligned addresses.
+ */
+#define BL31_COHERENT_RAM_BASE	(unsigned long)(&__COHERENT_RAM_START__)
+#define BL31_COHERENT_RAM_LIMIT	(unsigned long)(&__COHERENT_RAM_END__)
+
+static entry_point_info_t bl32_ep_info;
+static entry_point_info_t bl33_ep_info;
+
+/******************************************************************************
+ * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
+ * interrupts.
+ *****************************************************************************/
+const unsigned int g0_interrupt_array[] = {
+	IRQ_SEC_PHY_TIMER,
+	IRQ_SEC_SGI_0
+};
+
+const gicv2_driver_data_t hikey960_gic_data = {
+	.gicd_base = GICD_REG_BASE,
+	.gicc_base = GICC_REG_BASE,
+	.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
+	.g0_interrupt_array = g0_interrupt_array,
+};
+
+static const int cci_map[] = {
+	CCI400_SL_IFACE3_CLUSTER_IX,
+	CCI400_SL_IFACE4_CLUSTER_IX
+};
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info;
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc)
+		return next_image_info;
+	return NULL;
+}
+
+void bl31_early_platform_setup(bl31_params_t *from_bl2,
+		void *plat_params_from_bl2)
+{
+	unsigned int id, uart_base;
+
+	generic_delay_timer_init();
+	hikey960_read_boardid(&id);
+	if (id == 5300)
+		uart_base = PL011_UART5_BASE;
+	else
+		uart_base = PL011_UART6_BASE;
+
+	/* Initialize the console to provide early debug support */
+	console_init(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE);
+
+	/* Initialize CCI driver */
+	cci_init(CCI400_REG_BASE, cci_map, ARRAY_SIZE(cci_map));
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+	/*
+	 * Copy BL3-2 and BL3-3 entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	bl32_ep_info = *from_bl2->bl32_ep_info;
+	bl33_ep_info = *from_bl2->bl33_ep_info;
+}
+
+void bl31_plat_arch_setup(void)
+{
+	hikey960_init_mmu_el3(BL31_BASE,
+			BL31_LIMIT - BL31_BASE,
+			BL31_RO_BASE,
+			BL31_RO_LIMIT,
+			BL31_COHERENT_RAM_BASE,
+			BL31_COHERENT_RAM_LIMIT);
+}
+
+void bl31_platform_setup(void)
+{
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	gicv2_driver_init(&hikey960_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+
+	hisi_ipc_init();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+}
diff --git a/plat/hisilicon/hikey960/hikey960_boardid.c b/plat/hisilicon/hikey960/hikey960_boardid.c
new file mode 100644
index 0000000..ac3e0385
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_boardid.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <hi3660.h>
+#include <mmio.h>
+
+#include "hikey960_private.h"
+
+#define ADC_ADCIN0				0
+#define ADC_ADCIN1				1
+#define ADC_ADCIN2				2
+
+#define HKADC_DATA_GRADE0			0
+#define HKADC_DATA_GRADE1			100
+#define HKADC_DATA_GRADE2			300
+#define HKADC_DATA_GRADE3			500
+#define HKADC_DATA_GRADE4			700
+#define HKADC_DATA_GRADE5			900
+#define HKADC_DATA_GRADE6			1100
+#define HKADC_DATA_GRADE7			1300
+#define HKADC_DATA_GRADE8			1500
+#define HKADC_DATA_GRADE9			1700
+#define HKADC_DATA_GRADE10			1800
+
+#define BOARDID_VALUE0				0
+#define BOARDID_VALUE1				1
+#define BOARDID_VALUE2				2
+#define BOARDID_VALUE3				3
+#define BOARDID_VALUE4				4
+#define BOARDID_VALUE5				5
+#define BOARDID_VALUE6				6
+#define BOARDID_VALUE7				7
+#define BOARDID_VALUE8				8
+#define BOARDID_VALUE9				9
+#define BOARDID_UNKNOWN				0xF
+
+#define BOARDID3_BASE				5
+
+
+static void init_adc(void)
+{
+	/* reset hkadc */
+	mmio_write_32(CRG_PERRSTEN2_REG, PERRSTEN2_HKADCSSI);
+	/* wait a few clock cycles */
+	udelay(2);
+	mmio_write_32(CRG_PERRSTDIS2_REG, PERRSTEN2_HKADCSSI);
+	udelay(2);
+	/* enable hkadc clock */
+	mmio_write_32(CRG_PERDIS2_REG, PEREN2_HKADCSSI);
+	udelay(2);
+	mmio_write_32(CRG_PEREN2_REG, PEREN2_HKADCSSI);
+	udelay(2);
+}
+
+static int get_adc(unsigned int channel, unsigned int *value)
+{
+	unsigned int	data, value1, value0;
+
+	if (channel > HKADC_CHANNEL_MAX) {
+		WARN("invalid channel:%d\n", channel);
+		return -EFAULT;
+	}
+	/* configure the read/write operation for external HKADC */
+	mmio_write_32(HKADC_WR01_DATA_REG, HKADC_WR01_VALUE | channel);
+	mmio_write_32(HKADC_WR23_DATA_REG, HKADC_WR23_VALUE);
+	mmio_write_32(HKADC_WR45_DATA_REG, HKADC_WR45_VALUE);
+	/* configure the number of accessing registers */
+	mmio_write_32(HKADC_WR_NUM_REG, HKADC_WR_NUM_VALUE);
+	/* configure delay of accessing registers */
+	mmio_write_32(HKADC_DELAY01_REG, HKADC_CHANNEL0_DELAY01_VALUE);
+	mmio_write_32(HKADC_DELAY23_REG, HKADC_DELAY23_VALUE);
+
+	/* start HKADC */
+	mmio_write_32(HKADC_DSP_START_REG, 1);
+	do {
+		data = mmio_read_32(HKADC_DSP_START_REG);
+	} while (data & 1);
+
+	/* convert AD result */
+	value1 = mmio_read_32(HKADC_DSP_RD2_DATA_REG) & 0xffff;
+	value0 = mmio_read_32(HKADC_DSP_RD3_DATA_REG) & 0xffff;
+
+	data = ((value1 << 4) & HKADC_VALUE_HIGH) |
+	       ((value0 >> 4) & HKADC_VALUE_LOW);
+	*value = data;
+	return 0;
+}
+
+static int get_value(unsigned int channel, unsigned int *value)
+{
+	int ret;
+
+	ret = get_adc(channel, value);
+	if (ret)
+		return ret;
+
+	/* convert ADC value to micro-volt */
+	ret = ((*value & HKADC_VALID_VALUE) * HKADC_VREF_1V8) / HKADC_ACCURACY;
+	*value = ret;
+	return 0;
+}
+
+static int adcin_data_remap(unsigned int adcin_value)
+{
+	int	ret;
+
+	if (adcin_value < HKADC_DATA_GRADE0)
+		ret = BOARDID_UNKNOWN;
+	else if (adcin_value < HKADC_DATA_GRADE1)
+		ret = BOARDID_VALUE0;
+	else if (adcin_value < HKADC_DATA_GRADE2)
+		ret = BOARDID_VALUE1;
+	else if (adcin_value < HKADC_DATA_GRADE3)
+		ret = BOARDID_VALUE2;
+	else if (adcin_value < HKADC_DATA_GRADE4)
+		ret = BOARDID_VALUE3;
+	else if (adcin_value < HKADC_DATA_GRADE5)
+		ret = BOARDID_VALUE4;
+	else if (adcin_value < HKADC_DATA_GRADE6)
+		ret = BOARDID_VALUE5;
+	else if (adcin_value < HKADC_DATA_GRADE7)
+		ret = BOARDID_VALUE6;
+	else if (adcin_value < HKADC_DATA_GRADE8)
+		ret = BOARDID_VALUE7;
+	else if (adcin_value < HKADC_DATA_GRADE9)
+		ret = BOARDID_VALUE8;
+	else if (adcin_value < HKADC_DATA_GRADE10)
+		ret = BOARDID_VALUE9;
+	else
+		ret = BOARDID_UNKNOWN;
+	return ret;
+}
+
+int hikey960_read_boardid(unsigned int *id)
+{
+	unsigned int	adcin0, adcin1, adcin2;
+	unsigned int	adcin0_remap, adcin1_remap, adcin2_remap;
+
+	assert(id != NULL);
+
+	init_adc();
+
+	/* read ADC channel0 data */
+	get_value(ADC_ADCIN0, &adcin0);
+	adcin0_remap = adcin_data_remap(adcin0);
+	INFO("[BDID]adcin0:%d adcin0_remap:%d\n", adcin0, adcin0_remap);
+	if (adcin0_remap == BOARDID_UNKNOWN)
+		return -EINVAL;
+	/* read ADC channel1 data */
+	get_value(ADC_ADCIN1, &adcin1);
+	adcin1_remap = adcin_data_remap(adcin1);
+	INFO("[BDID]adcin1:%d adcin1_remap:%d\n", adcin1, adcin1_remap);
+	if (adcin1_remap == BOARDID_UNKNOWN)
+		return -EINVAL;
+	/* read ADC channel2 data */
+	get_value(ADC_ADCIN2, &adcin2);
+	adcin2_remap = adcin_data_remap(adcin2);
+	INFO("[BDID]adcin2:%d adcin2_remap:%d\n", adcin2, adcin2_remap);
+	if (adcin2_remap == BOARDID_UNKNOWN)
+		return -EINVAL;
+	*id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) +
+		(adcin1_remap * 10) + adcin0_remap;
+	INFO("[BDID]boardid: %d\n", *id);
+	return 0;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_def.h b/plat/hisilicon/hikey960/hikey960_def.h
new file mode 100644
index 0000000..e713e2e
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_def.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HIKEY960_DEF_H__
+#define __HIKEY960_DEF_H__
+
+#include <common_def.h>
+#include <tbbr_img_def.h>
+
+#define DDR_BASE			0x0
+#define DDR_SIZE			0xC0000000
+
+#define DEVICE_BASE			0xE0000000
+#define DEVICE_SIZE			0x20000000
+
+/*
+ * PL011 related constants
+ */
+#define PL011_UART5_BASE		0xFDF05000
+#define PL011_UART6_BASE		0xFFF32000
+#define PL011_BAUDRATE			115200
+#define PL011_UART_CLK_IN_HZ		19200000
+
+#define UFS_BASE			0
+/* FIP partition */
+#define HIKEY960_FIP_BASE		(UFS_BASE + 0x1400000)
+#define HIKEY960_FIP_MAX_SIZE		(12 << 20)
+
+#define HIKEY960_UFS_DESC_BASE		0x20000000
+#define HIKEY960_UFS_DESC_SIZE		0x00200000	/* 2MB */
+#define HIKEY960_UFS_DATA_BASE		0x10000000
+#define HIKEY960_UFS_DATA_SIZE		0x0A000000	/* 160MB */
+
+#endif /* __HIKEY960_DEF_H__ */
diff --git a/plat/hisilicon/hikey960/hikey960_io_storage.c b/plat/hisilicon/hikey960/hikey960_io_storage.c
new file mode 100644
index 0000000..de54e88
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_io_storage.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <firmware_image_package.h>
+#include <io_block.h>
+#include <io_driver.h>
+#include <io_fip.h>
+#include <io_memmap.h>
+#include <io_storage.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <semihosting.h>	/* For FOPEN_MODE_... */
+#include <string.h>
+#include <ufs.h>
+
+struct plat_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	int (*check)(const uintptr_t spec);
+};
+
+static const io_dev_connector_t *ufs_dev_con, *fip_dev_con;
+static uintptr_t ufs_dev_handle, fip_dev_handle;
+
+static int check_ufs(const uintptr_t spec);
+static int check_fip(const uintptr_t spec);
+size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size);
+size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size);
+
+static const io_block_spec_t ufs_fip_spec = {
+	.offset		= HIKEY960_FIP_BASE,
+	.length		= HIKEY960_FIP_MAX_SIZE,
+};
+
+static const io_block_spec_t ufs_data_spec = {
+	.offset		= 0,
+	.length		= 256 << 20,
+};
+
+static const io_block_dev_spec_t ufs_dev_spec = {
+	/* It's used as temp buffer in block driver. */
+	.buffer		= {
+		.offset	= HIKEY960_UFS_DATA_BASE,
+		.length	= HIKEY960_UFS_DATA_SIZE,
+	},
+	.ops		= {
+		.read	= ufs_read_lun3_blks,
+		.write	= ufs_write_lun3_blks,
+	},
+	.block_size	= UFS_BLOCK_SIZE,
+};
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t scp_bl2_uuid_spec = {
+	.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+		&ufs_dev_handle,
+		(uintptr_t)&ufs_fip_spec,
+		check_ufs
+	},
+	[BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl2_uuid_spec,
+		check_fip
+	},
+	[SCP_BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_bl2_uuid_spec,
+		check_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		check_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl33_uuid_spec,
+		check_fip
+	},
+	[BL2U_IMAGE_ID] = {
+		&ufs_dev_handle,
+		(uintptr_t)&ufs_data_spec,
+		check_ufs
+	}
+};
+
+static int check_ufs(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_handle;
+
+	result = io_dev_init(ufs_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(ufs_dev_handle, spec, &local_handle);
+		if (result == 0)
+			io_close(local_handle);
+	}
+	return result;
+}
+
+static int check_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if a Firmware Image Package is available */
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using FIP\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+void hikey960_io_setup(void)
+{
+	int result;
+
+	result = register_io_dev_block(&ufs_dev_con);
+	assert(result == 0);
+
+	result = register_io_dev_fip(&fip_dev_con);
+	assert(result == 0);
+
+	result = io_dev_open(ufs_dev_con, (uintptr_t)&ufs_dev_spec,
+			     &ufs_dev_handle);
+	assert(result == 0);
+
+	result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle);
+	assert(result == 0);
+
+	/* Ignore improbable errors in release builds */
+	(void)result;
+}
+
+/* Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	assert(result == 0);
+
+	*image_spec = policy->image_spec;
+	*dev_handle = *(policy->dev_handle);
+
+	return result;
+}
+
+size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size)
+{
+	return ufs_read_blocks(3, lba, buf, size);
+}
+
+size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size)
+{
+	return ufs_write_blocks(3, lba, buf, size);
+}
diff --git a/plat/hisilicon/hikey960/hikey960_mcu_load.c b/plat/hisilicon/hikey960/hikey960_mcu_load.c
new file mode 100644
index 0000000..7bf9a3d
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_mcu_load.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <hi3660.h>
+#include <mmio.h>
+#include <string.h>
+
+#define ADDR_CONVERT(addr)		((addr) < 0x40000 ?	\
+					 (addr) + 0xFFF30000 :	\
+					 (addr) + 0x40000000)
+
+static void fw_data_init(void)
+{
+	unsigned long data_head_addr;
+	unsigned int *data_addr;
+
+	data_head_addr = mmio_read_32((uintptr_t) HISI_DATA_HEAD_BASE) + 0x14;
+	data_addr = (unsigned int *) ADDR_CONVERT(data_head_addr);
+
+	memcpy((void *)HISI_DATA0_BASE,
+	       (const void *)(unsigned long)ADDR_CONVERT(data_addr[0]),
+	       HISI_DATA0_SIZE);
+	memcpy((void *)HISI_DATA1_BASE,
+	       (const void *)(unsigned long)ADDR_CONVERT(data_addr[1]),
+	       HISI_DATA1_SIZE);
+}
+
+int load_lpm3(void)
+{
+	INFO("start fw loading\n");
+
+	fw_data_init();
+
+	flush_dcache_range((uintptr_t)HISI_RESERVED_MEM_BASE,
+			   HISI_RESERVED_MEM_SIZE);
+
+	sev();
+	sev();
+
+	INFO("fw load success\n");
+
+	return 0;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_pm.c b/plat/hisilicon/hikey960/hikey960_pm.c
new file mode 100644
index 0000000..257299e
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_pm.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <cci.h>
+#include <console.h>
+#include <debug.h>
+#include <gicv2.h>
+#include <hi3660.h>
+#include <hi3660_crg.h>
+#include <mmio.h>
+#include <psci.h>
+#include "drivers/pwrc/hisi_pwrc.h"
+
+#include "hikey960_def.h"
+#include "hikey960_private.h"
+
+#define CORE_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define CLUSTER_PWR_STATE(state) \
+	((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define SYSTEM_PWR_STATE(state) \
+	((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+
+#define DMAC_GLB_REG_SEC	0x694
+#define AXI_CONF_BASE		0x820
+
+static uintptr_t hikey960_sec_entrypoint;
+
+static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state)
+{
+	unsigned long scr;
+	unsigned int val = 0;
+
+	assert(cpu_state == PLAT_MAX_RET_STATE);
+
+	scr = read_scr_el3();
+
+	/* Enable Physical IRQ and FIQ to wake the CPU*/
+	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
+
+	set_retention_ticks(val);
+	wfi();
+	clr_retention_ticks(val);
+
+	/*
+	 * Restore SCR to the original value, synchronisazion of
+	 * scr_el3 is done by eret while el3_exit to save some
+	 * execution cycles.
+	 */
+	write_scr_el3(scr);
+}
+
+static int hikey960_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int core = mpidr & MPIDR_CPU_MASK;
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+	int cluster_stat = cluster_is_powered_on(cluster);
+
+	hisi_set_cpu_boot_flag(cluster, core);
+
+	mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
+		      hikey960_sec_entrypoint >> 2);
+
+	if (cluster_stat)
+		hisi_powerup_core(cluster, core);
+	else
+		hisi_powerup_cluster(cluster, core);
+
+	return PSCI_E_SUCCESS;
+}
+
+static void
+hikey960_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
+		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+void hikey960_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+	unsigned int core = mpidr & MPIDR_CPU_MASK;
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	clr_ex();
+	isb();
+	dsbsy();
+
+	gicv2_cpuif_disable();
+
+	hisi_clear_cpu_boot_flag(cluster, core);
+	hisi_powerdn_core(cluster, core);
+
+	/* check if any core is powered up */
+	if (hisi_test_pwrdn_allcores(cluster, core)) {
+
+		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+
+		isb();
+		dsbsy();
+
+		hisi_powerdn_cluster(cluster, core);
+	}
+}
+
+static void __dead2 hikey960_system_reset(void)
+{
+	mmio_write_32(SCTRL_SCPEREN1_REG,
+		      SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS);
+	mmio_write_32(SCTRL_SCSYSSTAT_REG, 0xdeadbeef);
+	panic();
+}
+
+int hikey960_validate_power_state(unsigned int power_state,
+			       psci_power_state_t *req_state)
+{
+	int pstate = psci_get_pstate_type(power_state);
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int i;
+
+	assert(req_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	/* Sanity check the requested state */
+	if (pstate == PSTATE_TYPE_STANDBY) {
+		/*
+		 * It's possible to enter standby only on power level 0
+		 * Ignore any other power level.
+		 */
+		if (pwr_lvl != MPIDR_AFFLVL0)
+			return PSCI_E_INVALID_PARAMS;
+
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] =
+					PLAT_MAX_RET_STATE;
+	} else {
+		for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++)
+			req_state->pwr_domain_state[i] =
+					PLAT_MAX_OFF_STATE;
+	}
+
+	/*
+	 * We expect the 'state id' to be zero.
+	 */
+	if (psci_get_pstate_id(power_state))
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+static int hikey960_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+	/*
+	 * Check if the non secure entrypoint lies within the non
+	 * secure DRAM.
+	 */
+	if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE)))
+		return PSCI_E_SUCCESS;
+
+	return PSCI_E_INVALID_ADDRESS;
+}
+
+static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int core = mpidr & MPIDR_CPU_MASK;
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		clr_ex();
+		isb();
+		dsbsy();
+
+		gicv2_cpuif_disable();
+
+		hisi_cpuidle_lock(cluster, core);
+		hisi_set_cpuidle_flag(cluster, core);
+		hisi_cpuidle_unlock(cluster, core);
+
+		mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core),
+		      hikey960_sec_entrypoint >> 2);
+
+		hisi_enter_core_idle(cluster, core);
+	}
+
+	/* Perform the common cluster specific operations */
+	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) {
+		hisi_cpuidle_lock(cluster, core);
+		hisi_disable_pdc(cluster);
+
+		/* check if any core is powered up */
+		if (hisi_test_pwrdn_allcores(cluster, core)) {
+
+			cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+
+			isb();
+			dsbsy();
+
+			/* mask the pdc wakeup irq, then
+			 * enable pdc to power down the core
+			 */
+			hisi_pdc_mask_cluster_wakeirq(cluster);
+			hisi_enable_pdc(cluster);
+
+			hisi_cpuidle_unlock(cluster, core);
+
+			/* check the SR flag bit to determine
+			 * CLUSTER_IDLE_IPC or AP_SR_IPC to send
+			 */
+			if (hisi_test_ap_suspend_flag(cluster))
+				hisi_enter_ap_suspend(cluster, core);
+			else
+				hisi_enter_cluster_idle(cluster, core);
+		} else {
+			/* enable pdc */
+			hisi_enable_pdc(cluster);
+			hisi_cpuidle_unlock(cluster, core);
+		}
+	}
+}
+
+static void hikey960_sr_dma_reinit(void)
+{
+	unsigned int ctr = 0;
+
+	mmio_write_32(DMAC_BASE + DMAC_GLB_REG_SEC, 0x3);
+
+	/* 1~15 channel is set non_secure */
+	for (ctr = 1; ctr <= 15; ctr++)
+		mmio_write_32(DMAC_BASE + AXI_CONF_BASE + ctr * (0x40),
+			      (1 << 6) | (1 << 18));
+}
+
+static void
+hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+	unsigned int cluster =
+		(mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS;
+
+	/* Nothing to be done on waking up from retention from CPU level */
+	if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE)
+		return;
+
+	if (hisi_test_ap_suspend_flag(cluster)) {
+		hikey960_sr_dma_reinit();
+		gicv2_cpuif_enable();
+		console_init(PL011_UART6_BASE, PL011_UART_CLK_IN_HZ,
+			     PL011_BAUDRATE);
+	}
+
+	hikey960_pwr_domain_on_finish(target_state);
+}
+
+static void hikey960_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	int i;
+
+	for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+}
+
+static const plat_psci_ops_t hikey960_psci_ops = {
+	.cpu_standby			= hikey960_pwr_domain_standby,
+	.pwr_domain_on			= hikey960_pwr_domain_on,
+	.pwr_domain_on_finish		= hikey960_pwr_domain_on_finish,
+	.pwr_domain_off			= hikey960_pwr_domain_off,
+	.pwr_domain_suspend		= hikey960_pwr_domain_suspend,
+	.pwr_domain_suspend_finish	= hikey960_pwr_domain_suspend_finish,
+	.system_off			= NULL,
+	.system_reset			= hikey960_system_reset,
+	.validate_power_state		= hikey960_validate_power_state,
+	.validate_ns_entrypoint		= hikey960_validate_ns_entrypoint,
+	.get_sys_suspend_power_state	= hikey960_get_sys_suspend_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	hikey960_sec_entrypoint = sec_entrypoint;
+
+	INFO("%s: sec_entrypoint=0x%lx\n", __func__,
+	     (unsigned long)hikey960_sec_entrypoint);
+
+	/*
+	 * Initialize PSCI ops struct
+	 */
+	*psci_ops = &hikey960_psci_ops;
+	return 0;
+}
diff --git a/plat/hisilicon/hikey960/hikey960_private.h b/plat/hisilicon/hikey960/hikey960_private.h
new file mode 100644
index 0000000..8f2a842
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_private.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HIKEY960_PRIVATE_H__
+#define __HIKEY960_PRIVATE_H__
+
+#include <bl_common.h>
+
+/*
+ * Function and variable prototypes
+ */
+void hikey960_init_mmu_el1(unsigned long total_base,
+			unsigned long total_size,
+			unsigned long ro_start,
+			unsigned long ro_limit,
+			unsigned long coh_start,
+			unsigned long coh_limit);
+void hikey960_init_mmu_el3(unsigned long total_base,
+			unsigned long total_size,
+			unsigned long ro_start,
+			unsigned long ro_limit,
+			unsigned long coh_start,
+			unsigned long coh_limit);
+void hikey960_io_setup(void);
+int hikey960_read_boardid(unsigned int *id);
+void set_retention_ticks(unsigned int val);
+void clr_retention_ticks(unsigned int val);
+void clr_ex(void);
+void nop(void);
+
+#endif /* __HIKEY960_PRIVATE_H__ */
diff --git a/plat/hisilicon/hikey960/hikey960_topology.c b/plat/hisilicon/hikey960/hikey960_topology.c
new file mode 100644
index 0000000..3363724
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_topology.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <platform_def.h>
+#include <psci.h>
+
+/*
+ * The HiKey power domain tree descriptor. The cluster power domains
+ * are arranged so that when the PSCI generic code creates the power
+ * domain tree, the indices of the CPU power domain nodes it allocates
+ * match the linear indices returned by plat_core_pos_by_mpidr().
+ */
+const unsigned char hikey960_power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	1,
+	/* Number of clusters */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+	/* Number of children for the second cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+};
+
+/*******************************************************************************
+ * This function returns the HiKey topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return hikey960_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK))
+		return -1;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT)
+		return -1;
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= PLATFORM_CORE_COUNT_PER_CLUSTER)
+		return -1;
+
+	return (cpu_id + (cluster_id * 4));
+}
diff --git a/plat/hisilicon/hikey960/include/hi3660.h b/plat/hisilicon/hikey960/include/hi3660.h
new file mode 100644
index 0000000..83d1b36
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660.h
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __HI3660_H__
+#define __HI3660_H__
+
+#include <hi3660_crg.h>
+#include <hi3660_hkadc.h>
+#include <hi3660_mem_map.h>
+
+#define ASP_CFG_REG_BASE		0xE804E000
+
+#define ASP_CFG_MMBUF_CTRL_REG		(ASP_CFG_REG_BASE + 0x148)
+
+#define LP_RAM_BASE			0xFFF50000
+
+#define SCTRL_REG_BASE			0xFFF0A000
+
+#define SCTRL_CONTROL_REG		(SCTRL_REG_BASE + 0x000)
+#define SCTRL_CONTROL_SYS_MODE(x)	(((x) & 0xf) << 3)
+#define SCTRL_CONTROL_SYS_MODE_NORMAL	((1 << 2) << 3)
+#define SCTRL_CONTROL_SYS_MODE_SLOW	((1 << 1) << 3)
+#define SCTRL_CONTROL_SYS_MODE_MASK	(0xf << 3)
+#define SCTRL_CONTROL_MODE_CTRL_NORMAL	(1 << 2)
+#define SCTRL_CONTROL_MODE_CTRL_SLOW	(1 << 1)
+#define SCTRL_CONTROL_MODE_CTRL_MASK	0x7
+
+#define SCTRL_SCSYSSTAT_REG		(SCTRL_REG_BASE + 0x004)
+
+#define SCTRL_DEEPSLEEPED_REG		(SCTRL_REG_BASE + 0x008)
+#define SCTRL_EFUSE_USB_MASK		(1 << 30)
+#define SCTRL_EFUSE_USB_PLL		(1 << 30)
+#define SCTRL_EFUSE_USB_ABB		(0 << 30)
+#define SCTRL_EFUSE_UFS_MASK		(3 << 6)
+#define SCTRL_EFUSE_UFS_PLL		(1 << 6)
+#define SCTRL_EFUSE_UFS_ABB		(0 << 6)
+
+#define SCTRL_SCISOEN_REG		(SCTRL_REG_BASE + 0x040)
+#define SCTRL_SCISODIS_REG		(SCTRL_REG_BASE + 0x044)
+#define SCISO_MMBUFISO			(1 << 3)
+
+#define SCTRL_SCPWREN_REG		(SCTRL_REG_BASE + 0x060)
+#define SCPWREN_MMBUFPWREN		(1 << 3)
+
+#define SCTRL_PLL_CTRL0_REG		(SCTRL_REG_BASE + 0x100)
+#define SCTRL_PLL0_POSTDIV2(x)		(((x) & 0x7) << 23)
+#define SCTRL_PLL0_POSTDIV1(x)		(((x) & 0x7) << 20)
+#define SCTRL_PLL0_FBDIV(x)		(((x) & 0xfff) << 8)
+#define SCTRL_PLL0_REFDIV(x)		(((x) & 0x3f) << 2)
+#define SCTRL_PLL0_EN			(1 << 0)
+
+#define SCTRL_PLL_CTRL1_REG		(SCTRL_REG_BASE + 0x104)
+#define SCTRL_PLL0_CLK_NO_GATE		(1 << 26)
+#define SCTRL_PLL0_CFG_VLD		(1 << 25)
+#define SCTRL_PLL0_FRACDIV(x)		((x) & 0xFFFFFF)
+
+#define SCTRL_PLL_STAT_REG		(SCTRL_REG_BASE + 0x10C)
+#define SCTRL_PLL0_STAT			(1 << 0)
+
+#define SCTRL_SCPEREN0_REG		(SCTRL_REG_BASE + 0x160)
+#define SCTRL_SCPERDIS0_REG		(SCTRL_REG_BASE + 0x164)
+#define SCTRL_SCPERSTAT0_REG		(SCTRL_REG_BASE + 0x168)
+
+#define SCTRL_SCPEREN1_REG		(SCTRL_REG_BASE + 0x170)
+#define SCTRL_SCPERDIS1_REG		(SCTRL_REG_BASE + 0x174)
+#define SCTRL_SCPEREN1_REG		(SCTRL_REG_BASE + 0x170)
+#define SCTRL_SCPERDIS1_REG		(SCTRL_REG_BASE + 0x174)
+#define SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS	(1 << 31)
+#define SCPEREN_GT_PCLK_MMBUFCFG	(1 << 25)
+#define SCPEREN_GT_PCLK_MMBUF		(1 << 23)
+#define SCPEREN_GT_ACLK_MMBUF		(1 << 22)
+#define SCPEREN_GT_CLK_NOC_AOBUS2MMBUF	(1 << 6)
+
+#define SCTRL_SCPEREN2_REG		(SCTRL_REG_BASE + 0x190)
+#define SCTRL_SCPERDIS2_REG		(SCTRL_REG_BASE + 0x194)
+#define SCTRL_SCPERSTAT2_REG		(SCTRL_REG_BASE + 0x198)
+#define SCTRL_SCPERRSTEN0_REG		(SCTRL_REG_BASE + 0x200)
+#define SCTRL_SCPERRSTDIS0_REG		(SCTRL_REG_BASE + 0x204)
+#define SCTRL_SCPERRSTSTAT0_REG		(SCTRL_REG_BASE + 0x208)
+#define SCTRL_SCPERRSTEN1_REG		(SCTRL_REG_BASE + 0x20C)
+#define SCTRL_SCPERRSTDIS1_REG		(SCTRL_REG_BASE + 0x210)
+#define SCTRL_SCPERRSTSTAT1_REG		(SCTRL_REG_BASE + 0x214)
+#define IP_RST_MMBUFCFG			(1 << 12)
+#define IP_RST_MMBUF			(1 << 11)
+
+#define SCTRL_SCPERRSTEN2_REG		(SCTRL_REG_BASE + 0x218)
+#define SCTRL_SCPERRSTDIS2_REG		(SCTRL_REG_BASE + 0x21C)
+#define SCTRL_SCPERRSTSTAT2_REG		(SCTRL_REG_BASE + 0x220)
+
+#define SCTRL_SCCLKDIV2_REG		(SCTRL_REG_BASE + 0x258)
+#define SEL_CLK_MMBUF_MASK		(0x3 << 8)
+#define SEL_CLK_MMBUF_PLL0		(0x3 << 8)
+#define SCCLKDIV2_GT_PCLK_MMBUF		(1 << 7)
+
+#define SCTRL_SCCLKDIV4_REG		(SCTRL_REG_BASE + 0x260)
+#define GT_MMBUF_SYS			(1 << 13)
+#define GT_MMBUF_FLL			(1 << 12)
+#define GT_PLL_CLK_MMBUF		(1 << 11)
+
+#define SCTRL_SCCLKDIV6_REG		(SCTRL_REG_BASE + 0x268)
+
+#define SCTRL_SCPERCTRL7_REG		(SCTRL_REG_BASE + 0x31C)
+#define SCTRL_SCPERSTAT6_REG		(SCTRL_REG_BASE + 0x378)
+
+#define SCTRL_SCINNERSTAT_REG		(SCTRL_REG_BASE + 0x3A0)
+#define EMMC_UFS_SEL			(1 << 15)
+
+#define SCTRL_BAK_DATA0_REG		(SCTRL_REG_BASE + 0x40C)
+#define SCTRL_BAK_DATA4_REG		(SCTRL_REG_BASE + 0x41C)
+
+#define SCTRL_LPMCU_CLKEN_REG		(SCTRL_REG_BASE + 0x480)
+#define SCTRL_LPMCU_CLKDIS_REG		(SCTRL_REG_BASE + 0x484)
+#define SCTRL_LPMCU_RSTEN_REG		(SCTRL_REG_BASE + 0x500)
+#define SCTRL_LPMCU_RSTDIS_REG		(SCTRL_REG_BASE + 0x504)
+#define DDRC_SOFT_BIT			(1 << 6)
+#define DDRC_CLK_BIT			(1 << 5)
+
+#define SCTRL_SCPEREN0_SEC_REG		(SCTRL_REG_BASE + 0x900)
+#define SCTRL_SCPERDIS0_SEC_REG		(SCTRL_REG_BASE + 0x904)
+#define MMBUF_SEC_CTRL_MASK		(0xfff << 20)
+#define MMBUF_SEC_CTRL(x)		(((x) & 0xfff) << 20)
+
+#define SCTRL_PERRSTEN1_SEC_REG		(SCTRL_REG_BASE + 0xA50)
+#define SCTRL_PERRSTDIS1_SEC_REG	(SCTRL_REG_BASE + 0xA54)
+#define SCTRL_PERRSTSTAT1_SEC_REG	(SCTRL_REG_BASE + 0xA58)
+#define RST_ASP_SUBSYS_BIT		(1 << 0)
+
+#define SCTRL_PERRSTEN2_SEC_REG		(SCTRL_REG_BASE + 0xB50)
+#define SCTRL_PERRSTDIS2_SEC_REG	(SCTRL_REG_BASE + 0xB54)
+#define SCTRL_PERRSTSTAT2_SEC_REG	(SCTRL_REG_BASE + 0xB58)
+
+#define SCTRL_HISEECLKDIV_REG		(SCTRL_REG_BASE + 0xC28)
+#define SC_SEL_HISEE_PLL_MASK		(1 << 4)
+#define SC_SEL_HISEE_PLL0		(1 << 4)
+#define SC_SEL_HISEE_PLL2		(0 << 4)
+#define SC_DIV_HISEE_PLL_MASK		(7 << 16)
+#define SC_DIV_HISEE_PLL(x)		((x) & 0x7)
+
+#define SCTRL_SCSOCID0_REG		(SCTRL_REG_BASE + 0xE00)
+
+#define PMC_REG_BASE			0xFFF31000
+#define PMC_PPLL1_CTRL0_REG		(PMC_REG_BASE + 0x038)
+#define PMC_PPLL1_CTRL1_REG		(PMC_REG_BASE + 0x03C)
+#define PMC_PPLL2_CTRL0_REG		(PMC_REG_BASE + 0x040)
+#define PMC_PPLL2_CTRL1_REG		(PMC_REG_BASE + 0x044)
+#define PMC_PPLL3_CTRL0_REG		(PMC_REG_BASE + 0x048)
+#define PMC_PPLL3_CTRL1_REG		(PMC_REG_BASE + 0x04C)
+#define PPLLx_LOCK			(1 << 26)
+#define PPLLx_WITHOUT_CLK_GATE		(1 << 26)
+#define PPLLx_CFG_VLD			(1 << 25)
+#define PPLLx_INT_MOD			(1 << 24)
+#define PPLLx_POSTDIV2_MASK		(0x7 << 23)
+#define PPLLx_POSTDIV2(x)		(((x) & 0x7) << 23)
+#define PPLLx_POSTDIV1_MASK		(0x7 << 20)
+#define PPLLx_POSTDIV1(x)		(((x) & 0x7) << 20)
+#define PPLLx_FRACDIV_MASK		(0x00FFFFFF)
+#define PPLLx_FRACDIV(x)		((x) & 0x00FFFFFF)
+#define PPLLx_FBDIV_MASK		(0xfff << 8)
+#define PPLLx_FBDIV(x)			(((x) & 0xfff) << 8)
+#define PPLLx_REFDIV_MASK		(0x3f << 2)
+#define PPLLx_REFDIV(x)			(((x) & 0x3f) << 2)
+#define PPLLx_BP			(1 << 1)
+#define PPLLx_EN			(1 << 0)
+
+#define PMC_DDRLP_CTRL_REG		(PMC_REG_BASE + 0x30C)
+#define DDRC_CSYSREQ_CFG(x)		((x) & 0xF)
+
+#define PMC_NOC_POWER_IDLEREQ_REG	(PMC_REG_BASE + 0x380)
+#define PMC_NOC_POWER_IDLEREQ_IVP	(1 << 14)
+#define PMC_NOC_POWER_IDLEREQ_DSS	(1 << 13)
+#define PMC_NOC_POWER_IDLEREQ_VENC	(1 << 11)
+#define PMC_NOC_POWER_IDLEREQ_VDEC	(1 << 10)
+#define PMC_NOC_POWER_IDLEREQ_ISP	(1 << 5)
+#define PMC_NOC_POWER_IDLEREQ_VCODEC	(1 << 4)
+#define DDRPHY_BYPASS_MODE		(1 << 0)
+
+#define PMC_NOC_POWER_IDLEACK_REG	(PMC_REG_BASE + 0x384)
+#define PMC_NOC_POWER_IDLE_REG		(PMC_REG_BASE + 0x388)
+
+#define PMU_SSI0_REG_BASE		0xFFF34000
+
+#define PMU_SSI0_LDO8_CTRL0_REG		(PMU_SSI0_REG_BASE + (0x68 << 2))
+#define LDO8_CTRL0_EN_1_8V		0x02
+
+#define PMU_SSI0_CLK_TOP_CTRL7_REG	(PMU_SSI0_REG_BASE + (0x10C << 2))
+#define NP_XO_ABB_DIG			(1 << 1)
+
+#define LP_CONFIG_REG_BASE		0xFFF3F000
+
+#define DMAC_BASE			0xFDF30000
+
+#define CCI400_REG_BASE			0xE8100000
+#define CCI400_SL_IFACE3_CLUSTER_IX	0
+#define CCI400_SL_IFACE4_CLUSTER_IX	1
+
+#define GICD_REG_BASE			0xE82B1000
+#define GICC_REG_BASE			0xE82B2000
+/*
+ * GIC400 interrupt handling related constants
+ */
+#define IRQ_SEC_PHY_TIMER		29
+#define IRQ_SEC_SGI_0			8
+#define IRQ_SEC_SGI_1			9
+#define IRQ_SEC_SGI_2			10
+#define IRQ_SEC_SGI_3			11
+#define IRQ_SEC_SGI_4			12
+#define IRQ_SEC_SGI_5			13
+#define IRQ_SEC_SGI_6			14
+#define IRQ_SEC_SGI_7			15
+#define IRQ_SEC_SGI_8			16
+
+#define IPC_REG_BASE			0xE896A000
+#define IPC_BASE			(IPC_REG_BASE)
+
+#define IOMG_REG_BASE			0xE896C000
+
+/* GPIO46: HUB 3.3V enable. active low */
+#define IOMG_044_REG			(IOMG_REG_BASE + 0x0B0)
+#define IOMG_UART5_RX_REG		(IOMG_REG_BASE + 0x0BC)
+#define IOMG_UART5_TX_REG		(IOMG_REG_BASE + 0x0C0)
+
+#define IOCG_REG_BASE			0xE896C800
+
+/* GPIO005: PMIC SSI. (2 << 4) */
+#define IOCG_006_REG			(IOCG_REG_BASE + 0x018)
+
+#define TIMER9_REG_BASE			0xE8A00000
+
+#define WDT0_REG_BASE			0xE8A06000
+#define WDT1_REG_BASE			0xE8A07000
+#define WDT_CONTROL_OFFSET		0x008
+#define WDT_LOCK_OFFSET			0xC00
+
+#define WDT_UNLOCK			0x1ACCE551
+#define WDT_LOCKED			1
+
+#define PCTRL_REG_BASE			0xE8A09000
+#define PCTRL_PERI_CTRL3_REG		(PCTRL_REG_BASE + 0x010)
+#define PCTRL_PERI_CTRL24_REG		(PCTRL_REG_BASE + 0x064)
+
+#define TZC_REG_BASE			0xE8A21000
+#define TZC_STAT0_REG			(TZC_REG_BASE + 0x800)
+#define TZC_EN0_REG			(TZC_REG_BASE + 0x804)
+#define TZC_DIS0_REG			(TZC_REG_BASE + 0x808)
+#define TZC_STAT1_REG			(TZC_REG_BASE + 0x80C)
+#define TZC_EN1_REG			(TZC_REG_BASE + 0x810)
+#define TZC_DIS1_REG			(TZC_REG_BASE + 0x814)
+#define TZC_STAT2_REG			(TZC_REG_BASE + 0x818)
+#define TZC_EN2_REG			(TZC_REG_BASE + 0x81C)
+#define TZC_DIS2_REG			(TZC_REG_BASE + 0x820)
+#define TZC_STAT3_REG			(TZC_REG_BASE + 0x824)
+#define TZC_EN3_REG			(TZC_REG_BASE + 0x828)
+#define TZC_DIS3_REG			(TZC_REG_BASE + 0x82C)
+#define TZC_STAT4_REG			(TZC_REG_BASE + 0x830)
+#define TZC_EN4_REG			(TZC_REG_BASE + 0x834)
+#define TZC_DIS4_REG			(TZC_REG_BASE + 0x838)
+#define TZC_STAT5_REG			(TZC_REG_BASE + 0x83C)
+#define TZC_EN5_REG			(TZC_REG_BASE + 0x840)
+#define TZC_DIS5_REG			(TZC_REG_BASE + 0x844)
+#define TZC_STAT6_REG			(TZC_REG_BASE + 0x848)
+#define TZC_EN6_REG			(TZC_REG_BASE + 0x84C)
+#define TZC_DIS6_REG			(TZC_REG_BASE + 0x850)
+#define TZC_STAT7_REG			(TZC_REG_BASE + 0x854)
+#define TZC_EN7_REG			(TZC_REG_BASE + 0x858)
+#define TZC_DIS7_REG			(TZC_REG_BASE + 0x85C)
+#define TZC_STAT8_REG			(TZC_REG_BASE + 0x860)
+#define TZC_EN8_REG			(TZC_REG_BASE + 0x864)
+#define TZC_DIS8_REG			(TZC_REG_BASE + 0x868)
+
+#define MMBUF_BASE			0xEA800000
+
+#define ACPU_DMCPACK0_BASE		0xEA900000
+
+#define ACPU_DMCPACK1_BASE		0xEA920000
+
+#define ACPU_DMCPACK2_BASE		0xEA940000
+
+#define ACPU_DMCPACK3_BASE		0xEA960000
+
+#define UART5_REG_BASE			0xFDF05000
+
+#define USB3OTG_REG_BASE		0xFF100000
+
+#define UFS_REG_BASE			0xFF3B0000
+
+#define UFS_SYS_REG_BASE		0xFF3B1000
+
+#define UFS_SYS_PSW_POWER_CTRL_REG	(UFS_SYS_REG_BASE + 0x004)
+#define UFS_SYS_PHY_ISO_EN_REG		(UFS_SYS_REG_BASE + 0x008)
+#define UFS_SYS_HC_LP_CTRL_REG		(UFS_SYS_REG_BASE + 0x00C)
+#define UFS_SYS_PHY_CLK_CTRL_REG	(UFS_SYS_REG_BASE + 0x010)
+#define UFS_SYS_PSW_CLK_CTRL_REG	(UFS_SYS_REG_BASE + 0x014)
+#define UFS_SYS_CLOCK_GATE_BYPASS_REG	(UFS_SYS_REG_BASE + 0x018)
+#define UFS_SYS_RESET_CTRL_EN_REG	(UFS_SYS_REG_BASE + 0x01C)
+#define UFS_SYS_MONITOR_HH_REG		(UFS_SYS_REG_BASE + 0x03C)
+#define UFS_SYS_UFS_SYSCTRL_REG		(UFS_SYS_REG_BASE + 0x05C)
+#define UFS_SYS_UFS_DEVICE_RESET_CTRL_REG	(UFS_SYS_REG_BASE + 0x060)
+#define UFS_SYS_UFS_APB_ADDR_MASK_REG	(UFS_SYS_REG_BASE + 0x064)
+
+#define BIT_UFS_PSW_ISO_CTRL			(1 << 16)
+#define BIT_UFS_PSW_MTCMOS_EN			(1 << 0)
+#define BIT_UFS_REFCLK_ISO_EN			(1 << 16)
+#define BIT_UFS_PHY_ISO_CTRL			(1 << 0)
+#define BIT_SYSCTRL_LP_ISOL_EN			(1 << 16)
+#define BIT_SYSCTRL_PWR_READY			(1 << 8)
+#define BIT_SYSCTRL_REF_CLOCK_EN		(1 << 24)
+#define MASK_SYSCTRL_REF_CLOCK_SEL		(3 << 8)
+#define MASK_SYSCTRL_CFG_CLOCK_FREQ		(0xFF)
+#define BIT_SYSCTRL_PSW_CLK_EN			(1 << 4)
+#define MASK_UFS_CLK_GATE_BYPASS		(0x3F)
+#define BIT_SYSCTRL_LP_RESET_N			(1 << 0)
+#define BIT_UFS_REFCLK_SRC_SE1			(1 << 0)
+#define MASK_UFS_SYSCTRL_BYPASS			(0x3F << 16)
+#define MASK_UFS_DEVICE_RESET			(1 << 16)
+#define BIT_UFS_DEVICE_RESET			(1 << 0)
+
+#define IOMG_FIX_REG_BASE		0xFF3B6000
+
+/* GPIO150: LED */
+#define IOMG_FIX_006_REG		(IOMG_FIX_REG_BASE + 0x018)
+/* GPIO151: LED */
+#define IOMG_FIX_007_REG		(IOMG_FIX_REG_BASE + 0x01C)
+
+#define IOMG_AO_REG_BASE		0xFFF11000
+
+/* GPIO189: LED */
+#define IOMG_AO_011_REG			(IOMG_AO_REG_BASE + 0x02C)
+/* GPIO190: LED */
+#define IOMG_AO_012_REG			(IOMG_AO_REG_BASE + 0x030)
+/* GPIO202: type C enable. active low */
+#define IOMG_AO_023_REG			(IOMG_AO_REG_BASE + 0x05C)
+/* GPIO206: USB switch. active low */
+#define IOMG_AO_026_REG			(IOMG_AO_REG_BASE + 0x068)
+/* GPIO219: PD interrupt. pull up */
+#define IOMG_AO_039_REG			(IOMG_AO_REG_BASE + 0x09C)
+
+#define IOCG_AO_REG_BASE		0xFFF1187C
+/* GPIO219: PD interrupt. pull up */
+#define IOCG_AO_043_REG			(IOCG_AO_REG_BASE + 0x030)
+
+#endif  /* __HI3660_H__ */
diff --git a/plat/hisilicon/hikey960/include/hi3660_crg.h b/plat/hisilicon/hikey960/include/hi3660_crg.h
new file mode 100644
index 0000000..db1df9e
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_crg.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __HI3660_CRG_H__
+#define __HI3660_CRG_H__
+
+#define CRG_REG_BASE			0xFFF35000
+
+#define CRG_PEREN0_REG			(CRG_REG_BASE + 0x000)
+#define CRG_PERDIS0_REG			(CRG_REG_BASE + 0x004)
+#define CRG_PERSTAT0_REG		(CRG_REG_BASE + 0x008)
+#define PEREN0_GT_CLK_AOMM		(1 << 31)
+
+#define CRG_PEREN1_REG			(CRG_REG_BASE + 0x010)
+#define CRG_PERDIS1_REG			(CRG_REG_BASE + 0x014)
+#define CRG_PERSTAT1_REG		(CRG_REG_BASE + 0x018)
+#define CRG_PEREN2_REG			(CRG_REG_BASE + 0x020)
+#define CRG_PERDIS2_REG			(CRG_REG_BASE + 0x024)
+#define CRG_PERSTAT2_REG		(CRG_REG_BASE + 0x028)
+#define PEREN2_HKADCSSI			(1 << 24)
+
+#define CRG_PEREN3_REG			(CRG_REG_BASE + 0x030)
+#define CRG_PERDIS3_REG			(CRG_REG_BASE + 0x034)
+
+#define CRG_PEREN4_REG			(CRG_REG_BASE + 0x040)
+#define CRG_PERDIS4_REG			(CRG_REG_BASE + 0x044)
+#define CRG_PERCLKEN4_REG		(CRG_REG_BASE + 0x048)
+#define CRG_PERSTAT4_REG		(CRG_REG_BASE + 0x04C)
+#define GT_ACLK_USB3OTG			(1 << 1)
+#define GT_CLK_USB3OTG_REF		(1 << 0)
+
+#define CRG_PEREN5_REG			(CRG_REG_BASE + 0x050)
+#define CRG_PERDIS5_REG			(CRG_REG_BASE + 0x054)
+#define CRG_PERSTAT5_REG		(CRG_REG_BASE + 0x058)
+#define CRG_PERRSTEN0_REG		(CRG_REG_BASE + 0x060)
+#define CRG_PERRSTDIS0_REG		(CRG_REG_BASE + 0x064)
+#define CRG_PERRSTSTAT0_REG		(CRG_REG_BASE + 0x068)
+#define CRG_PERRSTEN1_REG		(CRG_REG_BASE + 0x06C)
+#define CRG_PERRSTDIS1_REG		(CRG_REG_BASE + 0x070)
+#define CRG_PERRSTSTAT1_REG		(CRG_REG_BASE + 0x074)
+#define CRG_PERRSTEN2_REG		(CRG_REG_BASE + 0x078)
+#define CRG_PERRSTDIS2_REG		(CRG_REG_BASE + 0x07C)
+#define CRG_PERRSTSTAT2_REG		(CRG_REG_BASE + 0x080)
+#define PERRSTEN2_HKADCSSI		(1 << 24)
+
+#define CRG_PERRSTEN3_REG		(CRG_REG_BASE + 0x084)
+#define CRG_PERRSTDIS3_REG		(CRG_REG_BASE + 0x088)
+#define CRG_PERRSTSTAT3_REG		(CRG_REG_BASE + 0x08C)
+#define CRG_PERRSTEN4_REG		(CRG_REG_BASE + 0x090)
+#define CRG_PERRSTDIS4_REG		(CRG_REG_BASE + 0x094)
+#define CRG_PERRSTSTAT4_REG		(CRG_REG_BASE + 0x098)
+#define IP_RST_USB3OTG_MUX		(1 << 8)
+#define IP_RST_USB3OTG_AHBIF		(1 << 7)
+#define IP_RST_USB3OTG_32K		(1 << 6)
+#define IP_RST_USB3OTG			(1 << 5)
+#define IP_RST_USB3OTGPHY_POR		(1 << 3)
+
+#define CRG_PERRSTEN5_REG		(CRG_REG_BASE + 0x09C)
+#define CRG_PERRSTDIS5_REG		(CRG_REG_BASE + 0x0A0)
+#define CRG_PERRSTSTAT5_REG		(CRG_REG_BASE + 0x0A4)
+
+/* bit fields in CRG_PERI */
+#define PERI_PCLK_PCTRL_BIT		(1 << 31)
+#define PERI_TIMER12_BIT		(1 << 25)
+#define PERI_TIMER11_BIT		(1 << 24)
+#define PERI_TIMER10_BIT		(1 << 23)
+#define PERI_TIMER9_BIT			(1 << 22)
+#define PERI_UART5_BIT			(1 << 15)
+#define PERI_UFS_BIT			(1 << 12)
+#define PERI_ARST_UFS_BIT		(1 << 7)
+#define PERI_PPLL2_EN_CPU		(1 << 3)
+#define PERI_PWM_BIT			(1 << 0)
+#define PERI_DDRC_BIT			(1 << 0)
+#define PERI_DDRC_D_BIT			(1 << 4)
+#define PERI_DDRC_C_BIT			(1 << 3)
+#define PERI_DDRC_B_BIT			(1 << 2)
+#define PERI_DDRC_A_BIT			(1 << 1)
+#define PERI_DDRC_DMUX_BIT		(1 << 0)
+
+#define CRG_CLKDIV0_REG			(CRG_REG_BASE + 0x0A0)
+#define SC_DIV_LPMCU_MASK		((0x1F << 5) << 16)
+#define SC_DIV_LPMCU(x)			(((x) & 0x1F) << 5)
+
+#define CRG_CLKDIV1_REG			(CRG_REG_BASE + 0x0B0)
+#define SEL_LPMCU_PLL_MASK		((1 << 1) << 16)
+#define SEL_SYSBUS_MASK			((1 << 0) << 16)
+#define SEL_LPMCU_PLL1			(1 << 1)
+#define SEL_LPMCU_PLL0			(0 << 1)
+#define SEL_SYSBUS_PLL0			(1 << 0)
+#define SEL_SYSBUS_PLL1			(0 << 0)
+
+#define CRG_CLKDIV3_REG			(CRG_REG_BASE + 0x0B4)
+#define CRG_CLKDIV5_REG			(CRG_REG_BASE + 0x0BC)
+#define CRG_CLKDIV8_REG			(CRG_REG_BASE + 0x0C8)
+
+#define CRG_CLKDIV12_REG		(CRG_REG_BASE + 0x0D8)
+#define SC_DIV_A53HPM_MASK		(0x7 << 13)
+#define SC_DIV_A53HPM(x)		(((x) & 0x7) << 13)
+
+#define CRG_CLKDIV16_REG		(CRG_REG_BASE + 0x0E8)
+#define DDRC_CLK_SW_REQ_CFG_MASK	(0x3 << 12)
+#define DDRC_CLK_SW_REQ_CFG(x)		(((x) & 0x3) << 12)
+#define SC_DIV_UFSPHY_CFG_MASK		(0x3 << 9)
+#define SC_DIV_UFSPHY_CFG(x)		(((x) & 0x3) << 9)
+#define DDRCPLL_SW			(1 << 8)
+
+#define CRG_CLKDIV17_REG		(CRG_REG_BASE + 0x0EC)
+#define SC_DIV_UFS_PERIBUS		(1 << 14)
+
+#define CRG_CLKDIV18_REG		(CRG_REG_BASE + 0x0F0)
+#define CRG_CLKDIV19_REG		(CRG_REG_BASE + 0x0F4)
+#define CRG_CLKDIV20_REG		(CRG_REG_BASE + 0x0F8)
+#define CLKDIV20_GT_CLK_AOMM		(1 << 3)
+
+#define CRG_CLKDIV22_REG		(CRG_REG_BASE + 0x100)
+#define SEL_PLL_320M_MASK		(1 << 16)
+#define SEL_PLL2_320M			(1 << 0)
+#define SEL_PLL0_320M			(0 << 0)
+
+#define CRG_CLKDIV23_REG		(CRG_REG_BASE + 0x104)
+#define PERI_DDRC_SW_BIT		(1 << 13)
+#define DIV_CLK_DDRSYS_MASK		(0x3 << 10)
+#define DIV_CLK_DDRSYS(x)		(((x) & 0x3) << 10)
+#define GET_DIV_CLK_DDRSYS(x)		(((x) & DIV_CLK_DDRSYS_MASK) >> 10)
+#define DIV_CLK_DDRCFG_MASK		(0x6 << 5)
+#define DIV_CLK_DDRCFG(x)		(((x) & 0x6) << 5)
+#define GET_DIV_CLK_DDRCFG(x)		(((x) & DIV_CLK_DDRCFG_MASK) >> 5)
+#define DIV_CLK_DDRC_MASK		0x1F
+#define DIV_CLK_DDRC(x)			((x) & DIV_CLK_DDRC_MASK)
+#define GET_DIV_CLK_DDRC(x)		((x) & DIV_CLK_DDRC_MASK)
+
+#define CRG_CLKDIV25_REG		(CRG_REG_BASE + 0x10C)
+#define DIV_SYSBUS_PLL_MASK		(0xF << 16)
+#define DIV_SYSBUS_PLL(x)		((x) & 0xF)
+
+#define CRG_PERI_CTRL2_REG		(CRG_REG_BASE + 0x128)
+#define PERI_TIME_STAMP_CLK_MASK	(0x7 << 28)
+#define PERI_TIME_STAMP_CLK_DIV(x)	(((x) & 0x7) << 22)
+
+#define CRG_ISODIS_REG			(CRG_REG_BASE + 0x148)
+#define CRG_PERPWREN_REG		(CRG_REG_BASE + 0x150)
+
+#define CRG_PEREN7_REG			(CRG_REG_BASE + 0x420)
+#define CRG_PERDIS7_REG			(CRG_REG_BASE + 0x424)
+#define CRG_PERSTAT7_REG		(CRG_REG_BASE + 0x428)
+#define GT_CLK_UFSPHY_CFG		(1 << 14)
+
+#define CRG_PEREN8_REG			(CRG_REG_BASE + 0x430)
+#define CRG_PERDIS8_REG			(CRG_REG_BASE + 0x434)
+#define CRG_PERSTAT8_REG		(CRG_REG_BASE + 0x438)
+#define PERI_DMC_D_BIT			(1 << 22)
+#define PERI_DMC_C_BIT			(1 << 21)
+#define PERI_DMC_B_BIT			(1 << 20)
+#define PERI_DMC_A_BIT			(1 << 19)
+#define PERI_DMC_BIT			(1 << 18)
+
+#define CRG_PEREN11_REG			(CRG_REG_BASE + 0x460)
+#define PPLL1_GATE_CPU			(1 << 18)
+
+#define CRG_PERSTAT11_REG		(CRG_REG_BASE + 0x46C)
+#define PPLL3_EN_STAT			(1 << 21)
+#define PPLL2_EN_STAT			(1 << 20)
+#define PPLL1_EN_STAT			(1 << 19)
+
+#define CRG_IVP_SEC_RSTDIS_REG		(CRG_REG_BASE + 0xC04)
+#define CRG_ISP_SEC_RSTDIS_REG		(CRG_REG_BASE + 0xC84)
+
+#define CRG_RVBAR(c, n)			(0xE00 + (0x10 * c) + (0x4 * n))
+#define CRG_GENERAL_SEC_RSTEN_REG	(CRG_REG_BASE + 0xE20)
+#define CRG_GENERAL_SEC_RSTDIS_REG	(CRG_REG_BASE + 0xE24)
+#define IP_RST_GPIO0_SEC		(1 << 2)
+
+#define CRG_GENERAL_SEC_CLKDIV0_REG	(CRG_REG_BASE + 0xE90)
+#define SC_DIV_AO_HISE_MASK		3
+#define SC_DIV_AO_HISE(x)		((x) & 0x3)
+
+#endif	/* __HI3660_CRG_H__ */
diff --git a/plat/hisilicon/hikey960/include/hi3660_hkadc.h b/plat/hisilicon/hikey960/include/hi3660_hkadc.h
new file mode 100644
index 0000000..6e67114
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_hkadc.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __HI3660_HKADC_H__
+#define __HI3660_HKADC_H__
+
+#define HKADC_SSI_REG_BASE			0xE82B8000
+
+#define HKADC_DSP_START_REG			(HKADC_SSI_REG_BASE + 0x000)
+#define HKADC_WR_NUM_REG			(HKADC_SSI_REG_BASE + 0x008)
+#define HKADC_DSP_START_CLR_REG			(HKADC_SSI_REG_BASE + 0x01C)
+#define HKADC_WR01_DATA_REG			(HKADC_SSI_REG_BASE + 0x020)
+
+#define WR1_WRITE_MODE				(1 << 31)
+#define WR1_READ_MODE				(0 << 31)
+#define WR1_ADDR(x)				(((x) & 0x7F) << 24)
+#define WR1_DATA(x)				(((x) & 0xFF) << 16)
+#define WR0_WRITE_MODE				(1 << 15)
+#define WR0_READ_MODE				(0 << 15)
+#define WR0_ADDR(x)				(((x) & 0x7F) << 8)
+#define WR0_DATA(x)				((x) & 0xFF)
+
+#define HKADC_WR23_DATA_REG			(HKADC_SSI_REG_BASE + 0x024)
+#define HKADC_WR45_DATA_REG			(HKADC_SSI_REG_BASE + 0x028)
+#define HKADC_DELAY01_REG			(HKADC_SSI_REG_BASE + 0x030)
+#define HKADC_DELAY23_REG			(HKADC_SSI_REG_BASE + 0x034)
+#define HKADC_DELAY45_REG			(HKADC_SSI_REG_BASE + 0x038)
+#define HKADC_DSP_RD2_DATA_REG			(HKADC_SSI_REG_BASE + 0x048)
+#define HKADC_DSP_RD3_DATA_REG			(HKADC_SSI_REG_BASE + 0x04C)
+
+/* HKADC Internal Registers */
+#define HKADC_CTRL_ADDR				0x00
+#define HKADC_START_ADDR			0x01
+#define HKADC_DATA1_ADDR			0x03   /* high 8 bits */
+#define HKADC_DATA0_ADDR			0x04   /* low 8 bits */
+#define HKADC_MODE_CFG				0x0A
+
+#define HKADC_VALUE_HIGH			0x0FF0
+#define HKADC_VALUE_LOW				0x000F
+#define HKADC_VALID_VALUE			0x0FFF
+
+#define HKADC_CHANNEL_MAX			15
+#define HKADC_VREF_1V8				1800
+#define HKADC_ACCURACY				0x0FFF
+
+#define HKADC_WR01_VALUE			((HKADC_START_ADDR << 24) | \
+						 (0x1 << 16))
+#define HKADC_WR23_VALUE			((0x1 << 31) |		\
+						 (HKADC_DATA0_ADDR << 24) | \
+						 (1 << 15) |		\
+						 (HKADC_DATA1_ADDR << 8))
+#define HKADC_WR45_VALUE			(0x80)
+#define HKADC_CHANNEL0_DELAY01_VALUE		((0x0700 << 16) | 0xFFFF)
+#define HKADC_DELAY01_VALUE			((0x0700 << 16) | 0x0200)
+#define HKADC_DELAY23_VALUE			((0x00C8 << 16) | 0x00C8)
+#define START_DELAY_TIMEOUT			2000
+#define HKADC_WR_NUM_VALUE			4
+
+#endif /* __HI3660_HKADC_H__ */
diff --git a/plat/hisilicon/hikey960/include/hi3660_mem_map.h b/plat/hisilicon/hikey960/include/hi3660_mem_map.h
new file mode 100644
index 0000000..db3efaf
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hi3660_mem_map.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HI3660_MEM_MAP__
+#define __HI3660_MEM_MAP__
+
+#define HISI_DATA_HEAD_BASE		(0x89C44400)
+
+#define HISI_RESERVED_MEM_BASE		(0x89C80000)
+#define HISI_RESERVED_MEM_SIZE		(0x00040000)
+
+#define HISI_DATA0_BASE			(0x89C96180)
+#define HISI_DATA0_SIZE			(0x000003A0)
+#define HISI_DATA1_BASE			(0x89C93480)
+#define HISI_DATA1_SIZE			(0x00002D00)
+
+#endif /* __HI3660_MEM_MAP__ */
diff --git a/plat/hisilicon/hikey960/include/hisi_ipc.h b/plat/hisilicon/hikey960/include/hisi_ipc.h
new file mode 100644
index 0000000..9dda1a5
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/hisi_ipc.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __HISI_IPC_H__
+#define __HISI_IPC_H__
+
+enum pm_mode {
+	PM_ON = 0,
+	PM_OFF,
+};
+
+void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster,
+			enum pm_mode mode);
+void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster,
+			 unsigned int affinity_level);
+void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster);
+void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster,
+				unsigned int cmd_id);
+int hisi_ipc_init(void);
+
+#endif /* __HISI_IPC_H__ */
diff --git a/plat/hisilicon/hikey960/include/plat_macros.S b/plat/hisilicon/hikey960/include/plat_macros.S
new file mode 100644
index 0000000..9f1befd
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/plat_macros.S
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_MACROS_S__
+#define __PLAT_MACROS_S__
+
+#include <cci.h>
+#include <hi3660.h>
+#include <gic_v2.h>
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n"    \
+                " Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+/* ---------------------------------------------
+ * The below macro prints out relevant GIC
+ * registers whenever an unhandled exception is
+ * taken in BL31.
+ * ---------------------------------------------
+ */
+.macro plat_crash_print_regs
+	mov_imm	x16, GICD_REG_BASE
+	mov_imm	x17, GICC_REG_BASE
+
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	/* Store to the crash buf and print to cosole */
+	bl	str_in_crash_buf_print
+
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+2:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	1f
+	bl	asm_print_hex
+	adr	x4, spacer
+	bl	asm_print_str
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+	adr	x4, newline
+	bl	asm_print_str
+	b	2b
+1:
+	adr	x6, cci_iface_regs
+	/* Store in x7 the base address of the first interface */
+	mov_imm	x7, (CCI400_REG_BASE + SLAVE_IFACE_OFFSET(	\
+	                CCI400_SL_IFACE3_CLUSTER_IX))
+	ldr	w8, [x7, #SNOOP_CTRL_REG]
+	/* Store in x7 the base address of the second interface */
+	mov_imm	x7, (CCI400_REG_BASE + SLAVE_IFACE_OFFSET(	\
+	                CCI400_SL_IFACE4_CLUSTER_IX))
+	ldr	w9, [x7, #SNOOP_CTRL_REG]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+.endm
+
+#endif /* __PLAT_MACROS_S__ */
diff --git a/plat/hisilicon/hikey960/include/platform_def.h b/plat/hisilicon/hikey960/include/platform_def.h
new file mode 100644
index 0000000..369117b
--- /dev/null
+++ b/plat/hisilicon/hikey960/include/platform_def.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLATFORM_DEF_H__
+#define __PLATFORM_DEF_H__
+
+#include <arch.h>
+#include "../hikey960_def.h"
+
+
+/*
+ * Generic platform constants
+ */
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE		0x800
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLATFORM_CACHE_LINE_SIZE	64
+#define PLATFORM_CLUSTER_COUNT		2
+#define PLATFORM_CORE_COUNT_PER_CLUSTER	4
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER_COUNT * \
+					 PLATFORM_CORE_COUNT_PER_CLUSTER)
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CORE_COUNT + \
+					 PLATFORM_CLUSTER_COUNT + 1)
+
+#define PLAT_MAX_RET_STATE		1
+#define PLAT_MAX_OFF_STATE		2
+
+#define MAX_IO_DEVICES			3
+#define MAX_IO_HANDLES			4
+/* UFS RPMB and UFS User Data */
+#define MAX_IO_BLOCK_DEVICES		2
+
+
+/*
+ * Platform memory map related constants
+ */
+
+/*
+ * BL1 specific defines.
+ */
+#define BL1_RO_BASE			(0x1AC00000)
+#define BL1_RO_LIMIT			(BL1_RO_BASE + 0x10000)
+#define BL1_RW_BASE			(BL1_RO_LIMIT)		/* 1AC1_0000 */
+#define BL1_RW_SIZE			(0x00188000)
+#define BL1_RW_LIMIT			(0x1B000000)
+
+/*
+ * BL2 specific defines.
+ */
+#define BL2_BASE			(BL1_RW_BASE + 0x8000)	/* 1AC1_8000 */
+#define BL2_LIMIT			(BL2_BASE + 0x40000)	/* 1AC5_8000 */
+
+/*
+ * BL31 specific defines.
+ */
+#define BL31_BASE			(BL2_LIMIT)		/* 1AC5_8000 */
+#define BL31_LIMIT			(BL31_BASE + 0x40000)	/* 1AC9_8000 */
+
+#define NS_BL1U_BASE			(BL31_LIMIT)		/* 1AC9_8000 */
+#define NS_BL1U_SIZE			(0x00100000)
+#define NS_BL1U_LIMIT			(NS_BL1U_BASE + NS_BL1U_SIZE)
+
+#define HIKEY960_NS_IMAGE_OFFSET	(0x1AC18000)	/* offset in l-loader */
+#define HIKEY960_NS_TMP_OFFSET		(0x1AE00000)
+
+#define SCP_BL2_BASE			BL31_BASE
+
+#define SCP_MEM_BASE			(0x89C80000)
+#define SCP_MEM_SIZE			(0x00040000)
+
+/*
+ * Platform specific page table and MMU setup constants
+ */
+#define ADDR_SPACE_SIZE			(1ull << 32)
+
+#if IMAGE_BL1 || IMAGE_BL2 || IMAGE_BL31
+#define MAX_XLAT_TABLES			3
+#endif
+
+#define MAX_MMAP_REGIONS		16
+
+/*
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ */
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/hisilicon/hikey960/platform.mk b/plat/hisilicon/hikey960/platform.mk
new file mode 100644
index 0000000..145eee0
--- /dev/null
+++ b/plat/hisilicon/hikey960/platform.mk
@@ -0,0 +1,65 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+CRASH_CONSOLE_BASE		:=	PL011_UART6_BASE
+COLD_BOOT_SINGLE_CPU		:=	1
+PROGRAMMABLE_RESET_ADDRESS	:=	1
+
+# Process flags
+$(eval $(call add_define,CRASH_CONSOLE_BASE))
+$(eval $(call FIP_ADD_IMG,SCP_BL2,--scp-fw))
+
+ENABLE_PLAT_COMPAT	:=	0
+
+USE_COHERENT_MEM	:=	1
+
+PLAT_INCLUDES		:=	-Iinclude/common/tbbr			\
+				-Iplat/hisilicon/hikey960/include
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/arm/pl011/pl011_console.S	\
+				drivers/delay_timer/delay_timer.c	\
+				drivers/delay_timer/generic_delay_timer.c \
+				lib/aarch64/xlat_tables.c		\
+				plat/hisilicon/hikey960/aarch64/hikey960_common.c \
+				plat/hisilicon/hikey960/hikey960_boardid.c
+
+HIKEY960_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v2/gicv2_main.c		\
+				drivers/arm/gic/v2/gicv2_helpers.c	\
+				plat/common/plat_gicv2.c
+
+BL1_SOURCES		+=	bl1/tbbr/tbbr_img_desc.c		\
+				drivers/io/io_block.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_storage.c			\
+				drivers/synopsys/ufs/dw_ufs.c		\
+				drivers/ufs/ufs.c 			\
+				lib/cpus/aarch64/cortex_a53.S		\
+				plat/hisilicon/hikey960/aarch64/hikey960_helpers.S \
+				plat/hisilicon/hikey960/hikey960_bl1_setup.c 	\
+				plat/hisilicon/hikey960/hikey960_io_storage.c \
+				${HIKEY960_GIC_SOURCES}
+
+BL2_SOURCES		+=	drivers/io/io_block.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_storage.c			\
+				drivers/ufs/ufs.c			\
+				plat/hisilicon/hikey960/hikey960_bl2_setup.c \
+				plat/hisilicon/hikey960/hikey960_io_storage.c \
+				plat/hisilicon/hikey960/hikey960_mcu_load.c
+
+BL31_SOURCES		+=	drivers/arm/cci/cci.c			\
+				lib/cpus/aarch64/cortex_a53.S           \
+				lib/cpus/aarch64/cortex_a72.S		\
+				lib/cpus/aarch64/cortex_a73.S		\
+				plat/common/aarch64/plat_psci_common.c  \
+				plat/hisilicon/hikey960/aarch64/hikey960_helpers.S \
+				plat/hisilicon/hikey960/hikey960_bl31_setup.c \
+				plat/hisilicon/hikey960/hikey960_pm.c	\
+				plat/hisilicon/hikey960/hikey960_topology.c \
+				plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c \
+				plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c \
+				${HIKEY960_GIC_SOURCES}
diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c
index c8fc28a..bc16857 100644
--- a/plat/nvidia/tegra/common/tegra_bl31_setup.c
+++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c
@@ -122,7 +122,7 @@
 {
 	plat_params_from_bl2_t *plat_params =
 		(plat_params_from_bl2_t *)plat_params_from_bl2;
-#if DEBUG
+#if LOG_LEVEL >= LOG_LEVEL_INFO
 	int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
 #endif
 	image_info_t bl32_img_info = { {0} };
diff --git a/plat/rockchip/common/aarch64/platform_common.c b/plat/rockchip/common/aarch64/platform_common.c
index 9c68b3b..a756f40 100644
--- a/plat/rockchip/common/aarch64/platform_common.c
+++ b/plat/rockchip/common/aarch64/platform_common.c
@@ -44,7 +44,7 @@
 				coh_limit - coh_start,			\
 				MT_DEVICE | MT_RW | MT_SECURE);		\
 		mmap_add(plat_rk_mmap);					\
-		rockchip_plat_sram_mmu_el##_el();			\
+		rockchip_plat_mmu_el##_el();				\
 		init_xlat_tables();					\
 									\
 		enable_mmu_el ## _el(0);				\
diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c
index 71d66c9..f7564e8 100644
--- a/plat/rockchip/common/bl31_plat_setup.c
+++ b/plat/rockchip/common/bl31_plat_setup.c
@@ -83,8 +83,6 @@
 	bl32_ep_info = *from_bl2->bl32_ep_info;
 	bl33_ep_info = *from_bl2->bl33_ep_info;
 
-	plat_rockchip_pmusram_prepare();
-
 	/* there may have some board sepcific message need to initialize */
 	params_early_setup(plat_params_from_bl2);
 }
diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
index 867d9ad..b9540f2 100644
--- a/plat/rockchip/common/include/plat_private.h
+++ b/plat/rockchip/common/include/plat_private.h
@@ -15,12 +15,18 @@
 
 #define __sramdata __attribute__((section(".sram.data")))
 #define __sramconst __attribute__((section(".sram.rodata")))
-#define __sramfunc __attribute__((section(".sram.text")))	\
-			__attribute__((noinline))
+#define __sramfunc __attribute__((section(".sram.text")))
+
+#define __pmusramdata __attribute__((section(".pmusram.data")))
+#define __pmusramconst __attribute__((section(".pmusram.rodata")))
+#define __pmusramfunc __attribute__((section(".pmusram.text")))
 
 extern uint32_t __bl31_sram_text_start, __bl31_sram_text_end;
 extern uint32_t __bl31_sram_data_start, __bl31_sram_data_end;
+extern uint32_t __bl31_sram_stack_start, __bl31_sram_stack_end;
+extern uint32_t __bl31_sram_text_real_end, __bl31_sram_data_real_end;
 extern uint32_t __sram_incbin_start, __sram_incbin_end;
+extern uint32_t __sram_incbin_real_end;
 
 
 /******************************************************************************
@@ -73,7 +79,6 @@
 void plat_rockchip_gic_cpuif_disable(void);
 void plat_rockchip_gic_pcpu_init(void);
 
-void plat_rockchip_pmusram_prepare(void);
 void plat_rockchip_pmu_init(void);
 void plat_rockchip_soc_init(void);
 uintptr_t plat_get_sec_entrypoint(void);
@@ -110,15 +115,13 @@
 
 extern const unsigned char rockchip_power_domain_tree_desc[];
 
-extern void *pmu_cpuson_entrypoint_start;
-extern void *pmu_cpuson_entrypoint_end;
+extern void *pmu_cpuson_entrypoint;
 extern uint64_t cpuson_entry_point[PLATFORM_CORE_COUNT];
 extern uint32_t cpuson_flags[PLATFORM_CORE_COUNT];
 
 extern const mmap_region_t plat_rk_mmap[];
 
-void rockchip_plat_sram_mmu_el3(void);
-void plat_rockchip_mem_prepare(void);
+void rockchip_plat_mmu_el3(void);
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/plat/rockchip/common/pmusram/pmu_sram.c b/plat/rockchip/common/pmusram/pmu_sram.c
deleted file mode 100644
index 05ee762..0000000
--- a/plat/rockchip/common/pmusram/pmu_sram.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <console.h>
-#include <debug.h>
-#include <platform.h>
-#include <plat_private.h>
-
-/*****************************************************************************
- * sram only surpport 32-bits access
- ******************************************************************************/
-void u32_align_cpy(uint32_t *dst, const uint32_t *src, size_t bytes)
-{
-	uint32_t i;
-
-	for (i = 0; i < bytes; i++)
-		dst[i] = src[i];
-}
-
-void rockchip_plat_sram_mmu_el3(void)
-{
-#ifdef PLAT_EXTRA_LD_SCRIPT
-	size_t sram_size;
-
-	/* sram.text size */
-	sram_size = (char *)&__bl31_sram_text_end -
-		    (char *)&__bl31_sram_text_start;
-	mmap_add_region((unsigned long)&__bl31_sram_text_start,
-			(unsigned long)&__bl31_sram_text_start,
-			sram_size, MT_MEMORY | MT_RO | MT_SECURE);
-
-	/* sram.data size */
-	sram_size = (char *)&__bl31_sram_data_end -
-		    (char *)&__bl31_sram_data_start;
-	mmap_add_region((unsigned long)&__bl31_sram_data_start,
-			(unsigned long)&__bl31_sram_data_start,
-			sram_size, MT_MEMORY | MT_RW | MT_SECURE);
-
-	/* sram.incbin size */
-	sram_size = (char *)&__sram_incbin_end - (char *)&__sram_incbin_start;
-	mmap_add_region((unsigned long)&__sram_incbin_start,
-			(unsigned long)&__sram_incbin_start,
-			sram_size, MT_NON_CACHEABLE | MT_RW | MT_SECURE);
-#else
-	/* TODO: Support other SoCs, Just support RK3399 now */
-	return;
-#endif
-}
-
-void plat_rockchip_mem_prepare(void)
-{
-	/* The code for resuming cpu from suspend must be excuted in pmusram */
-	plat_rockchip_pmusram_prepare();
-}
diff --git a/plat/rockchip/common/pmusram/pmu_sram.h b/plat/rockchip/common/pmusram/pmu_sram.h
deleted file mode 100644
index 24a1c25..0000000
--- a/plat/rockchip/common/pmusram/pmu_sram.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef __PMU_SRAM_H__
-#define __PMU_SRAM_H__
-
-/*****************************************************************************
- * define data offset in struct psram_data
- *****************************************************************************/
-#define PSRAM_DT_SP		0x0
-#define PSRAM_DT_DDR_FUNC	0x8
-#define PSRAM_DT_DDR_DATA	0x10
-#define PSRAM_DT_DDRFLAG	0x18
-#define PSRAM_DT_MPIDR		0x1c
-#define PSRAM_DT_END		0x20
-/******************************************************************************
- * Allocate data region for struct psram_data_t in pmusram
- ******************************************************************************/
-/* Needed aligned 16 bytes for sp stack top */
-#define PSRAM_DT_SIZE		(((PSRAM_DT_END + 16) / 16) * 16)
-#define PSRAM_DT_BASE		((PMUSRAM_BASE + PMUSRAM_RSIZE) - PSRAM_DT_SIZE)
-#define PSRAM_SP_TOP		PSRAM_DT_BASE
-
-#ifndef __ASSEMBLY__
-
-struct psram_data_t {
-	uint64_t sp;
-	uint64_t ddr_func;
-	uint64_t ddr_data;
-	uint32_t ddr_flag;
-	uint32_t boot_mpidr;
-};
-
-CASSERT(sizeof(struct psram_data_t) <= PSRAM_DT_SIZE,
-	assert_psram_dt_size_mismatch);
-CASSERT(__builtin_offsetof(struct psram_data_t, sp) == PSRAM_DT_SP,
-	assert_psram_dt_sp_offset_mistmatch);
-CASSERT(__builtin_offsetof(struct psram_data_t, ddr_func) == PSRAM_DT_DDR_FUNC,
-	assert_psram_dt_ddr_func_offset_mistmatch);
-CASSERT(__builtin_offsetof(struct psram_data_t, ddr_data) == PSRAM_DT_DDR_DATA,
-	assert_psram_dt_ddr_data_offset_mistmatch);
-CASSERT(__builtin_offsetof(struct psram_data_t, ddr_flag) == PSRAM_DT_DDRFLAG,
-	assert_psram_dt_ddr_flag_offset_mistmatch);
-CASSERT(__builtin_offsetof(struct psram_data_t, boot_mpidr) == PSRAM_DT_MPIDR,
-	assert_psram_dt_mpidr_offset_mistmatch);
-void u32_align_cpy(uint32_t *dst, const uint32_t *src, size_t bytes);
-
-#endif  /* __ASSEMBLY__ */
-
-#endif
diff --git a/plat/rockchip/common/pmusram/pmu_sram_cpus_on.S b/plat/rockchip/common/pmusram/pmu_sram_cpus_on.S
index 8f175c3..22bdffc 100644
--- a/plat/rockchip/common/pmusram/pmu_sram_cpus_on.S
+++ b/plat/rockchip/common/pmusram/pmu_sram_cpus_on.S
@@ -7,23 +7,30 @@
 #include <arch.h>
 #include <asm_macros.S>
 #include <platform_def.h>
-#include <pmu_sram.h>
 
-	.globl pmu_cpuson_entrypoint_start
-	.globl pmu_cpuson_entrypoint_end
+	.globl pmu_cpuson_entrypoint
+	.macro pmusram_entry_func _name
+	.section .pmusram.entry, "ax"
+	.type \_name, %function
+	.func \_name
+	.cfi_startproc
+	\_name:
+	.endm
 
-func pmu_cpuson_entrypoint
-pmu_cpuson_entrypoint_start:
-	ldr	x5, psram_data
+pmusram_entry_func pmu_cpuson_entrypoint
+
+#if PSRAM_CHECK_WAKEUP_CPU
 check_wake_cpus:
 	mrs	x0, MPIDR_EL1
 	and	x1, x0, #MPIDR_CPU_MASK
 	and	x0, x0, #MPIDR_CLUSTER_MASK
 	orr	x0, x0, x1
+
 	/* primary_cpu */
-	ldr	w1, [x5, #PSRAM_DT_MPIDR]
+	ldr	w1, boot_mpidr
 	cmp	w0, w1
 	b.eq	sys_wakeup
+
 	/*
 	 * If the core is not the primary cpu,
 	 * force the core into wfe.
@@ -32,25 +39,15 @@
 	wfe
 	b	wfe_loop
 sys_wakeup:
-	/* check ddr flag for resume ddr */
-	ldr	w2, [x5, #PSRAM_DT_DDRFLAG]
-	cmp	w2, #0x0
-	b.eq	sys_resume
+#endif
+
+#if PSRAM_DO_DDR_RESUME
 ddr_resume:
-	ldr	x2, [x5, #PSRAM_DT_SP]
-	mov	sp, x2
-	ldr	x1, [x5, #PSRAM_DT_DDR_FUNC]
-	ldr	x0, [x5, #PSRAM_DT_DDR_DATA]
-	blr	x1
+	ldr	x2, =__bl31_sram_stack_end
+	mov     sp, x2
+	bl	dmc_restore
+#endif
+	bl	sram_restore
 sys_resume:
-	ldr	x1, sys_wakeup_entry
-	br	x1
-
-	.align	3
-psram_data:
-	.quad	PSRAM_DT_BASE
-sys_wakeup_entry:
-	.quad	psci_entrypoint
-pmu_cpuson_entrypoint_end:
-	.word	0
+	bl	psci_entrypoint
 endfunc pmu_cpuson_entrypoint
diff --git a/plat/rockchip/rk3328/drivers/pmu/pmu.c b/plat/rockchip/rk3328/drivers/pmu/pmu.c
index 59d399b..60f36d3 100644
--- a/plat/rockchip/rk3328/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3328/drivers/pmu/pmu.c
@@ -16,16 +16,12 @@
 #include <platform.h>
 #include <platform_def.h>
 #include <plat_private.h>
-#include <pmu_sram.h>
 #include <pmu.h>
 #include <rk3328_def.h>
 #include <pmu_com.h>
 
 DEFINE_BAKERY_LOCK(rockchip_pd_lock);
 
-static struct psram_data_t *psram_sleep_cfg =
-		(struct psram_data_t *)PSRAM_DT_BASE;
-
 static struct rk3328_sleep_ddr_data ddr_data;
 static __sramdata struct rk3328_sleep_sram_data sram_data;
 
@@ -34,22 +30,6 @@
 #pragma weak rk3328_pmic_suspend
 #pragma weak rk3328_pmic_resume
 
-void plat_rockchip_pmusram_prepare(void)
-{
-	uint32_t *sram_dst, *sram_src;
-	size_t sram_size = 2;
-	/*
-	 * pmu sram code and data prepare
-	 */
-	sram_dst = (uint32_t *)PMUSRAM_BASE;
-	sram_src = (uint32_t *)&pmu_cpuson_entrypoint_start;
-	sram_size = (uint32_t *)&pmu_cpuson_entrypoint_end -
-		    (uint32_t *)sram_src;
-	u32_align_cpy(sram_dst, sram_src, sram_size);
-
-	psram_sleep_cfg->sp = PSRAM_DT_BASE;
-}
-
 static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
 {
 	uint32_t pd_reg, apm_reg;
@@ -140,6 +120,16 @@
 	}
 }
 
+void sram_save(void)
+{
+	/* TODO: support the sdram save for rk3328 SoCs*/
+}
+
+void sram_restore(void)
+{
+	/* TODO: support the sdram restore for rk3328 SoCs */
+}
+
 int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
 {
 	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
@@ -495,11 +485,6 @@
 	sram_udelay(100);
 }
 
-static inline void rockchip_set_sram_sp(uint64_t set_sp)
-{
-	__asm volatile("mov sp, %0\n"::"r" (set_sp) : "sp");
-}
-
 static __sramfunc void ddr_suspend(void)
 {
 	sram_data.pd_sr_idle_save = mmio_read_32(DDR_UPCTL_BASE +
@@ -538,7 +523,7 @@
 	dpll_suspend();
 }
 
-static __sramfunc  void ddr_resume(void)
+__sramfunc  void dmc_restore(void)
 {
 	dpll_resume();
 
@@ -574,7 +559,7 @@
 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(2), 0x00040004);
 }
 
-static __sramfunc void sram_dbg_uart_resume(void)
+__sramfunc void sram_dbg_uart_resume(void)
 {
 	/* restore uart clk and reset fifo */
 	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(16), 0x20000000);
@@ -610,7 +595,7 @@
 	disable_mmu_icache_el3();
 
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
-		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
+		      ((uintptr_t)&pmu_cpuson_entrypoint >> CPU_BOOT_ADDR_ALIGN) |
 		      CPU_BOOT_ADDR_WMASK);
 
 	/* ddr self-refresh and gating phy */
@@ -623,28 +608,8 @@
 	sram_soc_enter_lp();
 }
 
-static __sramfunc void sys_resume_first(void)
-{
-	sram_dbg_uart_resume();
-
-	rk3328_pmic_resume();
-
-	/* ddr self-refresh exit */
-	ddr_resume();
-
-	/* disable apm cfg */
-	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(0), CORES_PM_DISABLE);
-
-	/* the warm booting address of cpus */
-	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
-		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
-		      CPU_BOOT_ADDR_WMASK);
-}
-
 void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
 {
-	rockchip_set_sram_sp(PSRAM_DT_BASE);
-
 	sram_suspend();
 
 	/* should never reach here */
@@ -671,6 +636,11 @@
 	return 0;
 }
 
+void rockchip_plat_mmu_el3(void)
+{
+	/* TODO: support the el3 for rk3328 SoCs */
+}
+
 void plat_rockchip_pmu_init(void)
 {
 	uint32_t cpu;
@@ -679,10 +649,6 @@
 		cpuson_flags[cpu] = 0;
 
 	cpu_warm_boot_addr = (uint64_t)platform_cpu_warmboot;
-	psram_sleep_cfg->ddr_func = (uint64_t)sys_resume_first;
-	psram_sleep_cfg->ddr_data = 0x00;
-	psram_sleep_cfg->ddr_flag = 0x01;
-	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
 
 	/* the warm booting address of cpus */
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
diff --git a/plat/rockchip/rk3328/include/plat.ld.S b/plat/rockchip/rk3328/include/plat.ld.S
index ff17572..b3559b2 100644
--- a/plat/rockchip/rk3328/include/plat.ld.S
+++ b/plat/rockchip/rk3328/include/plat.ld.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,39 +7,31 @@
 #define __ROCKCHIP_PLAT_LD_S__
 
 MEMORY {
-    SRAM (rwx): ORIGIN = SRAM_LDS_BASE, LENGTH = SRAM_LDS_SIZE
+    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
 }
 
 SECTIONS
 {
-	. = SRAM_LDS_BASE;
-	ASSERT(. == ALIGN(4096),
-		"SRAM_BASE address is not aligned on a page boundary.")
+	. = PMUSRAM_BASE;
 
 	/*
-	 * The SRAM space allocation for RK3328
-	 * ----------------
-	 * | sram text
-	 * ----------------
-	 * | sram data
-	 * ----------------
+	 * pmu_cpuson_entrypoint request address
+	 * align 64K when resume, so put it in the
+	 * start of pmusram
 	 */
-	.text_sram : ALIGN(4096) {
-		__bl31_sram_text_start = .;
-		*(.sram.text)
-		*(.sram.rodata)
-		. = ALIGN(4096);
-		__bl31_sram_text_end = .;
-	} >SRAM
+	.text_pmusram : {
+		ASSERT(. == ALIGN(64 * 1024),
+			".pmusram.entry request 64K aligned.");
+		*(.pmusram.entry)
+		__bl31_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		__bl31_pmusram_text_end = .;
+		__bl31_pmusram_data_start = .;
+		*(.pmusram.data)
+		__bl31_pmusram_data_end = .;
 
-	.data_sram : ALIGN(4096) {
-		__bl31_sram_data_start = .;
-		*(.sram.data)
-		. = ALIGN(4096);
-		__bl31_sram_data_end = .;
-	} >SRAM
-	__sram_incbin_start = .;
-	__sram_incbin_end = .;
+	} >PMUSRAM
 }
 
 #endif /* __ROCKCHIP_PLAT_LD_S__ */
diff --git a/plat/rockchip/rk3328/include/platform_def.h b/plat/rockchip/rk3328/include/platform_def.h
index 1f49fcd..7304dcf 100644
--- a/plat/rockchip/rk3328/include/platform_def.h
+++ b/plat/rockchip/rk3328/include/platform_def.h
@@ -120,4 +120,7 @@
 
 #define PLAT_RK_PRIMARY_CPU	0x0
 
+#define PSRAM_DO_DDR_RESUME	0
+#define PSRAM_CHECK_WAKEUP_CPU	0
+
 #endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/rockchip/rk3328/platform.mk b/plat/rockchip/rk3328/platform.mk
index b81d746..8863fb4 100644
--- a/plat/rockchip/rk3328/platform.mk
+++ b/plat/rockchip/rk3328/platform.mk
@@ -41,7 +41,6 @@
 				${RK_PLAT_COMMON}/drivers/parameter/ddr_parameter.c	\
 				${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
 				${RK_PLAT_COMMON}/bl31_plat_setup.c		\
-				${RK_PLAT_COMMON}/pmusram/pmu_sram.c            \
 				${RK_PLAT_COMMON}/pmusram/pmu_sram_cpus_on.S	\
 				${RK_PLAT_COMMON}/plat_pm.c			\
 				${RK_PLAT_COMMON}/plat_topology.c		\
diff --git a/plat/rockchip/rk3368/drivers/pmu/pmu.c b/plat/rockchip/rk3368/drivers/pmu/pmu.c
index e5e6805..1767967 100644
--- a/plat/rockchip/rk3368/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3368/drivers/pmu/pmu.c
@@ -14,7 +14,6 @@
 #include <platform_def.h>
 #include <plat_private.h>
 #include <rk3368_def.h>
-#include <pmu_sram.h>
 #include <soc.h>
 #include <pmu.h>
 #include <ddr_rk3368.h>
@@ -22,9 +21,6 @@
 
 DEFINE_BAKERY_LOCK(rockchip_pd_lock);
 
-static struct psram_data_t *psram_sleep_cfg =
-	(struct psram_data_t *)PSRAM_DT_BASE;
-
 static uint32_t cpu_warm_boot_addr;
 
 void rk3368_flash_l2_b(void)
@@ -223,54 +219,19 @@
 	dsb();
 }
 
-static void ddr_suspend_save(void)
-{
-	ddr_reg_save(1, psram_sleep_cfg->ddr_data);
-}
-
 static void pmu_set_sleep_mode(void)
 {
-	ddr_suspend_save();
 	pmu_sleep_mode_config();
 	soc_sleep_config();
 	regs_updata_bit_set(PMU_BASE + PMU_PWRMD_CORE, pmu_mdcr_global_int_dis);
 	regs_updata_bit_set(PMU_BASE + PMU_SFT_CON, pmu_sft_glbl_int_dis_b);
 	pmu_scu_b_pwrdn();
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
-		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
-		      CPU_BOOT_ADDR_WMASK);
+		      ((uintptr_t)&pmu_cpuson_entrypoint >>
+			CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK);
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(2),
-		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
-		      CPU_BOOT_ADDR_WMASK);
-}
-
-void plat_rockchip_pmusram_prepare(void)
-{
-	uint32_t *sram_dst, *sram_src;
-	size_t sram_size = 2;
-	uint32_t code_size;
-
-	/* pmu sram code and data prepare */
-	sram_dst = (uint32_t *)PMUSRAM_BASE;
-	sram_src = (uint32_t *)&pmu_cpuson_entrypoint_start;
-	sram_size = (uint32_t *)&pmu_cpuson_entrypoint_end -
-		    (uint32_t *)sram_src;
-	u32_align_cpy(sram_dst, sram_src, sram_size);
-
-	/* ddr code */
-	sram_dst += sram_size;
-	sram_src = ddr_get_resume_code_base();
-	code_size = ddr_get_resume_code_size();
-	u32_align_cpy(sram_dst, sram_src, code_size / 4);
-	psram_sleep_cfg->ddr_func = (uint64_t)sram_dst;
-
-	/* ddr data */
-	sram_dst += (code_size / 4);
-	psram_sleep_cfg->ddr_data = (uint64_t)sram_dst;
-
-	assert((uint64_t)(sram_dst + ddr_get_resume_data_size() / 4)
-						 < PSRAM_SP_BOTTOM);
-	psram_sleep_cfg->sp = PSRAM_SP_TOP;
+		      ((uintptr_t)&pmu_cpuson_entrypoint >>
+			CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK);
 }
 
 static int cpus_id_power_domain(uint32_t cluster,
@@ -319,6 +280,16 @@
 	}
 }
 
+void sram_save(void)
+{
+	/* TODO: support the sdram save for rk3368 SoCs*/
+}
+
+void sram_restore(void)
+{
+	/* TODO: support the sdram restore for rk3368 SoCs */
+}
+
 int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
 {
 	uint32_t cpu, cluster;
@@ -375,11 +346,14 @@
 	nonboot_cpus_off();
 	pmu_set_sleep_mode();
 
-	psram_sleep_cfg->ddr_flag = 0;
-
 	return 0;
 }
 
+void rockchip_plat_mmu_el3(void)
+{
+	/* TODO: support the el3 for rk3368 SoCs */
+}
+
 void plat_rockchip_pmu_init(void)
 {
 	uint32_t cpu;
@@ -390,8 +364,6 @@
 	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
 		cpuson_flags[cpu] = 0;
 
-	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
-
 	nonboot_cpus_off();
 	INFO("%s(%d): pd status %x\n", __func__, __LINE__,
 	     mmio_read_32(PMU_BASE + PMU_PWRDN_ST));
diff --git a/plat/rockchip/rk3368/include/plat.ld.S b/plat/rockchip/rk3368/include/plat.ld.S
new file mode 100644
index 0000000..b3559b2
--- /dev/null
+++ b/plat/rockchip/rk3368/include/plat.ld.S
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __ROCKCHIP_PLAT_LD_S__
+#define __ROCKCHIP_PLAT_LD_S__
+
+MEMORY {
+    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
+}
+
+SECTIONS
+{
+	. = PMUSRAM_BASE;
+
+	/*
+	 * pmu_cpuson_entrypoint request address
+	 * align 64K when resume, so put it in the
+	 * start of pmusram
+	 */
+	.text_pmusram : {
+		ASSERT(. == ALIGN(64 * 1024),
+			".pmusram.entry request 64K aligned.");
+		*(.pmusram.entry)
+		__bl31_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		__bl31_pmusram_text_end = .;
+		__bl31_pmusram_data_start = .;
+		*(.pmusram.data)
+		__bl31_pmusram_data_end = .;
+
+	} >PMUSRAM
+}
+
+#endif /* __ROCKCHIP_PLAT_LD_S__ */
diff --git a/plat/rockchip/rk3368/include/platform_def.h b/plat/rockchip/rk3368/include/platform_def.h
index 053f6fe..07b91e2 100644
--- a/plat/rockchip/rk3368/include/platform_def.h
+++ b/plat/rockchip/rk3368/include/platform_def.h
@@ -122,4 +122,7 @@
 
 #define PLAT_RK_PRIMARY_CPU	0x0
 
+#define PSRAM_DO_DDR_RESUME	0
+#define PSRAM_CHECK_WAKEUP_CPU	0
+
 #endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/rockchip/rk3368/platform.mk b/plat/rockchip/rk3368/platform.mk
index 7837af9..f6960cf 100644
--- a/plat/rockchip/rk3368/platform.mk
+++ b/plat/rockchip/rk3368/platform.mk
@@ -39,7 +39,6 @@
 				${RK_PLAT_COMMON}/bl31_plat_setup.c		\
 				${RK_PLAT_COMMON}/params_setup.c                \
 				${RK_PLAT_COMMON}/pmusram/pmu_sram_cpus_on.S		\
-				${RK_PLAT_COMMON}/pmusram/pmu_sram.c		\
 				${RK_PLAT_COMMON}/plat_pm.c			\
 				${RK_PLAT_COMMON}/plat_topology.c		\
 				${RK_PLAT_COMMON}/aarch64/platform_common.c	\
@@ -50,3 +49,5 @@
 				${RK_PLAT_SOC}/drivers/ddr/ddr_rk3368.c		\
 
 ENABLE_PLAT_COMPAT	:=      0
+
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
diff --git a/plat/rockchip/rk3399/drivers/dram/dfs.c b/plat/rockchip/rk3399/drivers/dram/dfs.c
index 28d0d6a..481dcc6 100644
--- a/plat/rockchip/rk3399/drivers/dram/dfs.c
+++ b/plat/rockchip/rk3399/drivers/dram/dfs.c
@@ -54,6 +54,7 @@
 static struct rk3399_dram_status rk3399_dram_status;
 static struct rk3399_saved_status rk3399_suspend_status;
 static uint32_t wrdqs_delay_val[2][2][4];
+static uint32_t rddqs_delay_ps;
 
 static struct rk3399_sdram_default_config ddr3_default_config = {
 	.bl = 8,
@@ -1599,7 +1600,7 @@
 		mmio_clrsetbits_32(PHY_REG(i, 394), 0xf, tmp);
 		/* PHY_GTLVL_LAT_ADJ_START */
 		/* DENALI_PHY_80/208/336/464 4bits offset_16 */
-		tmp = delay_frac_ps / 1000;
+		tmp = rddqs_delay_ps / (1000000 / pdram_timing->mhz) + 2;
 		mmio_clrsetbits_32(PHY_REG(i, 80), 0xf << 16, tmp << 16);
 		mmio_clrsetbits_32(PHY_REG(i, 208), 0xf << 16, tmp << 16);
 		mmio_clrsetbits_32(PHY_REG(i, 336), 0xf << 16, tmp << 16);
@@ -1830,6 +1831,7 @@
 void dram_dfs_init(void)
 {
 	uint32_t trefi0, trefi1, boot_freq;
+	uint32_t rddqs_adjust, rddqs_slave;
 
 	/* get sdram config for os reg */
 	get_dram_drv_odt_val(sdram_config.dramtype,
@@ -1875,8 +1877,31 @@
 	/* Disable multicast */
 	mmio_clrbits_32(PHY_REG(0, 896), 1);
 	mmio_clrbits_32(PHY_REG(1, 896), 1);
-
 	dram_low_power_config();
+
+	/*
+	 * If boot_freq isn't in the bypass mode, it can get the
+	 * rddqs_delay_ps from the result of gate training
+	 */
+	if (((mmio_read_32(PHY_REG(0, 86)) >> 8) & 0xf) != 0xc) {
+
+		/*
+		 * Select PHY's frequency set to current_index
+		 * index for get the result of gate Training
+		 * from registers
+		 */
+		mmio_clrsetbits_32(PHY_REG(0, 896), 0x3 << 8,
+				   rk3399_dram_status.current_index << 8);
+		rddqs_slave = (mmio_read_32(PHY_REG(0, 77)) >> 16) & 0x3ff;
+		rddqs_slave = rddqs_slave * 1000000 / boot_freq / 512;
+
+		rddqs_adjust = mmio_read_32(PHY_REG(0, 78)) & 0xf;
+		rddqs_adjust = rddqs_adjust * 1000000 / boot_freq;
+		rddqs_delay_ps = rddqs_slave + rddqs_adjust -
+				(1000000 / boot_freq / 2);
+	} else {
+		rddqs_delay_ps = 3500;
+	}
 }
 
 /*
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.c b/plat/rockchip/rk3399/drivers/dram/dram.c
index fbf3110..ad79f9e 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram.c
+++ b/plat/rockchip/rk3399/drivers/dram/dram.c
@@ -10,7 +10,7 @@
 #include <soc.h>
 #include <rk3399_def.h>
 
-__sramdata struct rk3399_sdram_params sdram_config;
+__pmusramdata struct rk3399_sdram_params sdram_config;
 
 void dram_init(void)
 {
diff --git a/plat/rockchip/rk3399/drivers/dram/dram.h b/plat/rockchip/rk3399/drivers/dram/dram.h
index 08893d4..fede7ee 100644
--- a/plat/rockchip/rk3399/drivers/dram/dram.h
+++ b/plat/rockchip/rk3399/drivers/dram/dram.h
@@ -24,7 +24,17 @@
 };
 
 struct rk3399_ddr_publ_regs {
-	uint32_t denali_phy[PHY_REG_NUM];
+	/*
+	 * PHY registers from 0 to 511.
+	 * Only registers 0-90 of each 128 register range are used.
+	 */
+	uint32_t phy0[4][91];
+	/*
+	 * PHY registers from 512 to 895.
+	 * Only registers 0-37 of each 128 register range are used.
+	 */
+	uint32_t phy512[3][38];
+	uint32_t phy896[63];
 };
 
 struct rk3399_ddr_pi_regs {
diff --git a/plat/rockchip/rk3399/drivers/dram/suspend.c b/plat/rockchip/rk3399/drivers/dram/suspend.c
index 1ed3f54..617e39b 100644
--- a/plat/rockchip/rk3399/drivers/dram/suspend.c
+++ b/plat/rockchip/rk3399/drivers/dram/suspend.c
@@ -45,7 +45,8 @@
 /*
  * Copy @num registers from @src to @dst
  */
-__sramfunc void sram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num)
+static __pmusramfunc void sram_regcpy(uintptr_t dst, uintptr_t src,
+		uint32_t num)
 {
 	while (num--) {
 		mmio_write_32(dst, mmio_read_32(src));
@@ -54,7 +55,21 @@
 	}
 }
 
-static __sramfunc uint32_t sram_get_timer_value(void)
+/*
+ * Copy @num registers from @src to @dst
+ * This is intentionally a copy of the sram_regcpy function. PMUSRAM functions
+ * cannot be called from code running in DRAM.
+ */
+static void dram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num)
+{
+	while (num--) {
+		mmio_write_32(dst, mmio_read_32(src));
+		dst += sizeof(uint32_t);
+		src += sizeof(uint32_t);
+	}
+}
+
+static __pmusramfunc uint32_t sram_get_timer_value(void)
 {
 	/*
 	 * Generic delay timer implementation expects the timer to be a down
@@ -64,7 +79,7 @@
 	return (uint32_t)(~read_cntpct_el0());
 }
 
-static __sramfunc void sram_udelay(uint32_t usec)
+static __pmusramfunc void sram_udelay(uint32_t usec)
 {
 	uint32_t start, cnt, delta, delta_us;
 
@@ -81,7 +96,7 @@
 	} while (delta_us < usec);
 }
 
-static __sramfunc void configure_sgrf(void)
+static __pmusramfunc void configure_sgrf(void)
 {
 	/*
 	 * SGRF_DDR_RGN_DPLL_CLK and SGRF_DDR_RGN_RTC_CLK:
@@ -98,7 +113,7 @@
 		      SGRF_DDR_RGN_BYPS);
 }
 
-static __sramfunc void rkclk_ddr_reset(uint32_t channel, uint32_t ctl,
+static __pmusramfunc void rkclk_ddr_reset(uint32_t channel, uint32_t ctl,
 		uint32_t phy)
 {
 	channel &= 0x1;
@@ -109,7 +124,7 @@
 		      CRU_SFTRST_DDR_PHY(channel, phy));
 }
 
-static __sramfunc void phy_pctrl_reset(uint32_t ch)
+static __pmusramfunc void phy_pctrl_reset(uint32_t ch)
 {
 	rkclk_ddr_reset(ch, 1, 1);
 	sram_udelay(10);
@@ -119,76 +134,45 @@
 	sram_udelay(10);
 }
 
-static __sramfunc void phy_dll_bypass_set(uint32_t ch, uint32_t hz)
+static __pmusramfunc void set_cs_training_index(uint32_t ch, uint32_t rank)
 {
-	if (hz <= 125 * MHz) {
-		/* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
-		mmio_setbits_32(PHY_REG(ch, 86), (0x3 << 2) << 8);
-		mmio_setbits_32(PHY_REG(ch, 214), (0x3 << 2) << 8);
-		mmio_setbits_32(PHY_REG(ch, 342), (0x3 << 2) << 8);
-		mmio_setbits_32(PHY_REG(ch, 470), (0x3 << 2) << 8);
-		/* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
-		mmio_setbits_32(PHY_REG(ch, 547), (0x3 << 2) << 16);
-		mmio_setbits_32(PHY_REG(ch, 675), (0x3 << 2) << 16);
-		mmio_setbits_32(PHY_REG(ch, 803), (0x3 << 2) << 16);
-	} else {
-		/* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */
-		mmio_clrbits_32(PHY_REG(ch, 86), (0x3 << 2) << 8);
-		mmio_clrbits_32(PHY_REG(ch, 214), (0x3 << 2) << 8);
-		mmio_clrbits_32(PHY_REG(ch, 342), (0x3 << 2) << 8);
-		mmio_clrbits_32(PHY_REG(ch, 470), (0x3 << 2) << 8);
-		/* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */
-		mmio_clrbits_32(PHY_REG(ch, 547), (0x3 << 2) << 16);
-		mmio_clrbits_32(PHY_REG(ch, 675), (0x3 << 2) << 16);
-		mmio_clrbits_32(PHY_REG(ch, 803), (0x3 << 2) << 16);
-	}
-}
+	uint32_t byte;
 
-static __sramfunc void set_cs_training_index(uint32_t ch, uint32_t rank)
-{
 	/* PHY_8/136/264/392 phy_per_cs_training_index_X 1bit offset_24 */
-	mmio_clrsetbits_32(PHY_REG(ch, 8), 0x1 << 24, rank << 24);
-	mmio_clrsetbits_32(PHY_REG(ch, 136), 0x1 << 24, rank << 24);
-	mmio_clrsetbits_32(PHY_REG(ch, 264), 0x1 << 24, rank << 24);
-	mmio_clrsetbits_32(PHY_REG(ch, 392), 0x1 << 24, rank << 24);
+	for (byte = 0; byte < 4; byte++)
+		mmio_clrsetbits_32(PHY_REG(ch, 8 + (128 * byte)), 0x1 << 24,
+				   rank << 24);
 }
 
-static __sramfunc void select_per_cs_training_index(uint32_t ch, uint32_t rank)
+static __pmusramfunc void select_per_cs_training_index(uint32_t ch,
+		uint32_t rank)
 {
 	/* PHY_84 PHY_PER_CS_TRAINING_EN_0 1bit offset_16 */
 	if ((mmio_read_32(PHY_REG(ch, 84)) >> 16) & 1)
 		set_cs_training_index(ch, rank);
 }
 
-static void override_write_leveling_value(uint32_t ch)
+static __pmusramfunc void override_write_leveling_value(uint32_t ch)
 {
 	uint32_t byte;
 
-	/* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */
-	mmio_setbits_32(PHY_REG(ch, 896), 1);
-
-	/*
-	 * PHY_8/136/264/392
-	 * phy_per_cs_training_multicast_en_X 1bit offset_16
-	 */
-	mmio_clrsetbits_32(PHY_REG(ch, 8), 0x1 << 16, 1 << 16);
-	mmio_clrsetbits_32(PHY_REG(ch, 136), 0x1 << 16, 1 << 16);
-	mmio_clrsetbits_32(PHY_REG(ch, 264), 0x1 << 16, 1 << 16);
-	mmio_clrsetbits_32(PHY_REG(ch, 392), 0x1 << 16, 1 << 16);
-
-	for (byte = 0; byte < 4; byte++)
+	for (byte = 0; byte < 4; byte++) {
+		/*
+		 * PHY_8/136/264/392
+		 * phy_per_cs_training_multicast_en_X 1bit offset_16
+		 */
+		mmio_clrsetbits_32(PHY_REG(ch, 8 + (128 * byte)), 0x1 << 16,
+				   1 << 16);
 		mmio_clrsetbits_32(PHY_REG(ch, 63 + (128 * byte)),
 				   0xffff << 16,
 				   0x200 << 16);
-
-	/* PHY_896 PHY_FREQ_SEL_MULTICAST_EN 1bit offset_0 */
-	mmio_clrbits_32(PHY_REG(ch, 896), 1);
+	}
 
 	/* CTL_200 ctrlupd_req 1bit offset_8 */
 	mmio_clrsetbits_32(CTL_REG(ch, 200), 0x1 << 8, 0x1 << 8);
 }
 
-static __sramfunc int data_training(uint32_t ch,
+static __pmusramfunc int data_training(uint32_t ch,
 		struct rk3399_sdram_params *sdram_params,
 		uint32_t training_flag)
 {
@@ -433,7 +417,8 @@
 	return 0;
 }
 
-static __sramfunc void set_ddrconfig(struct rk3399_sdram_params *sdram_params,
+static __pmusramfunc void set_ddrconfig(
+		struct rk3399_sdram_params *sdram_params,
 		unsigned char channel, uint32_t ddrconfig)
 {
 	/* only need to set ddrconfig */
@@ -455,7 +440,8 @@
 		      ((cs0_cap / 32) & 0xff) | (((cs1_cap / 32) & 0xff) << 8));
 }
 
-static __sramfunc void dram_all_config(struct rk3399_sdram_params *sdram_params)
+static __pmusramfunc void dram_all_config(
+		struct rk3399_sdram_params *sdram_params)
 {
 	unsigned int i;
 
@@ -491,13 +477,13 @@
 	mmio_clrsetbits_32(CRU_BASE + CRU_GLB_RST_CON, 0x3, 0x3);
 }
 
-static __sramfunc void pctl_cfg(uint32_t ch,
+static __pmusramfunc void pctl_cfg(uint32_t ch,
 		struct rk3399_sdram_params *sdram_params)
 {
 	const uint32_t *params_ctl = sdram_params->pctl_regs.denali_ctl;
-	const uint32_t *params_phy = sdram_params->phy_regs.denali_phy;
 	const uint32_t *params_pi = sdram_params->pi_regs.denali_pi;
-	uint32_t tmp, tmp1, tmp2;
+	const struct rk3399_ddr_publ_regs *phy_regs = &sdram_params->phy_regs;
+	uint32_t tmp, tmp1, tmp2, i;
 
 	/*
 	 * Workaround controller bug:
@@ -509,9 +495,8 @@
 	sram_regcpy(PI_REG(ch, 0), (uintptr_t)&params_pi[0],
 		    PI_REG_NUM);
 
-	mmio_write_32(PHY_REG(ch, 910), params_phy[910]);
-	mmio_write_32(PHY_REG(ch, 911), params_phy[911]);
-	mmio_write_32(PHY_REG(ch, 912), params_phy[912]);
+	sram_regcpy(PHY_REG(ch, 910), (uintptr_t)&phy_regs->phy896[910 - 896],
+		    3);
 
 	mmio_clrsetbits_32(CTL_REG(ch, 68), PWRUP_SREFRESH_EXIT,
 				PWRUP_SREFRESH_EXIT);
@@ -538,17 +523,18 @@
 			break;
 	}
 
+	sram_regcpy(PHY_REG(ch, 896), (uintptr_t)&phy_regs->phy896[0], 63);
+
-	sram_regcpy(PHY_REG(ch, 896), (uintptr_t)&params_phy[896], 63);
-	sram_regcpy(PHY_REG(ch, 0), (uintptr_t)&params_phy[0], 91);
-	sram_regcpy(PHY_REG(ch, 128), (uintptr_t)&params_phy[128], 91);
-	sram_regcpy(PHY_REG(ch, 256), (uintptr_t)&params_phy[256], 91);
-	sram_regcpy(PHY_REG(ch, 384), (uintptr_t)&params_phy[384], 91);
-	sram_regcpy(PHY_REG(ch, 512), (uintptr_t)&params_phy[512], 38);
-	sram_regcpy(PHY_REG(ch, 640), (uintptr_t)&params_phy[640], 38);
-	sram_regcpy(PHY_REG(ch, 768), (uintptr_t)&params_phy[768], 38);
+	for (i = 0; i < 4; i++)
+		sram_regcpy(PHY_REG(ch, 128 * i),
+			    (uintptr_t)&phy_regs->phy0[i][0], 91);
+
+	for (i = 0; i < 3; i++)
+		sram_regcpy(PHY_REG(ch, 512 + 128 * i),
+				(uintptr_t)&phy_regs->phy512[i][0], 38);
 }
 
-static __sramfunc int dram_switch_to_next_index(
+static __pmusramfunc int dram_switch_to_next_index(
 		struct rk3399_sdram_params *sdram_params)
 {
 	uint32_t ch, ch_count;
@@ -583,7 +569,7 @@
  * Needs to be done for both channels at once in case of a shared reset signal
  * between channels.
  */
-static __sramfunc int pctl_start(uint32_t channel_mask,
+static __pmusramfunc int pctl_start(uint32_t channel_mask,
 		struct rk3399_sdram_params *sdram_params)
 {
 	uint32_t count;
@@ -652,15 +638,15 @@
 void dmc_save(void)
 {
 	struct rk3399_sdram_params *sdram_params = &sdram_config;
+	struct rk3399_ddr_publ_regs *phy_regs;
 	uint32_t *params_ctl;
 	uint32_t *params_pi;
-	uint32_t *params_phy;
 	uint32_t refdiv, postdiv2, postdiv1, fbdiv;
-	uint32_t tmp, ch, byte;
+	uint32_t tmp, ch, byte, i;
 
+	phy_regs = &sdram_params->phy_regs;
 	params_ctl = sdram_params->pctl_regs.denali_ctl;
 	params_pi = sdram_params->pi_regs.denali_pi;
-	params_phy = sdram_params->phy_regs.denali_phy;
 
 	fbdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 0)) & 0xfff;
 	tmp = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1));
@@ -676,25 +662,26 @@
 			       0x7) != 0) ? 1 : 0;
 
 	/* copy the registers CTL PI and PHY */
-	sram_regcpy((uintptr_t)&params_ctl[0], CTL_REG(0, 0), CTL_REG_NUM);
+	dram_regcpy((uintptr_t)&params_ctl[0], CTL_REG(0, 0), CTL_REG_NUM);
 
 	/* mask DENALI_CTL_00_DATA.START, only copy here, will trigger later */
 	params_ctl[0] &= ~(0x1 << 0);
 
-	sram_regcpy((uintptr_t)&params_pi[0], PI_REG(0, 0),
+	dram_regcpy((uintptr_t)&params_pi[0], PI_REG(0, 0),
 		    PI_REG_NUM);
 
 	/* mask DENALI_PI_00_DATA.START, only copy here, will trigger later*/
 	params_pi[0] &= ~(0x1 << 0);
 
-	sram_regcpy((uintptr_t)&params_phy[0], PHY_REG(0, 0), 91);
-	sram_regcpy((uintptr_t)&params_phy[128], PHY_REG(0, 128), 91);
-	sram_regcpy((uintptr_t)&params_phy[256], PHY_REG(0, 256), 91);
-	sram_regcpy((uintptr_t)&params_phy[384], PHY_REG(0, 384), 91);
-	sram_regcpy((uintptr_t)&params_phy[512], PHY_REG(0, 512), 38);
-	sram_regcpy((uintptr_t)&params_phy[640], PHY_REG(0, 640), 38);
-	sram_regcpy((uintptr_t)&params_phy[768], PHY_REG(0, 768), 38);
-	sram_regcpy((uintptr_t)&params_phy[896], PHY_REG(0, 896), 63);
+	for (i = 0; i < 4; i++)
+		dram_regcpy((uintptr_t)&phy_regs->phy0[i][0],
+			    PHY_REG(0, 128 * i), 91);
+
+	for (i = 0; i < 3; i++)
+		dram_regcpy((uintptr_t)&phy_regs->phy512[i][0],
+			    PHY_REG(0, 512 + 128 * i), 38);
+
+	dram_regcpy((uintptr_t)&phy_regs->phy896[0], PHY_REG(0, 896), 63);
 
 	for (ch = 0; ch < sdram_params->num_channels; ch++) {
 		for (byte = 0; byte < 4; byte++)
@@ -703,13 +690,13 @@
 	}
 
 	/* set DENALI_PHY_957_DATA.PHY_DLL_RST_EN = 0x1 */
-	params_phy[957] &= ~(0x3 << 24);
-	params_phy[957] |= 1 << 24;
-	params_phy[896] |= 1;
-	params_phy[896] &= ~(0x3 << 8);
+	phy_regs->phy896[957 - 896] &= ~(0x3 << 24);
+	phy_regs->phy896[957 - 896] |= 1 << 24;
+	phy_regs->phy896[0] |= 1;
+	phy_regs->phy896[0] &= ~(0x3 << 8);
 }
 
-__sramfunc void dmc_restore(void)
+__pmusramfunc void dmc_restore(void)
 {
 	struct rk3399_sdram_params *sdram_params = &sdram_config;
 	uint32_t channel_mask = 0;
@@ -720,10 +707,6 @@
 retry:
 	for (channel = 0; channel < sdram_params->num_channels; channel++) {
 		phy_pctrl_reset(channel);
-		phy_dll_bypass_set(channel, sdram_params->ddr_freq);
-		if (channel >= sdram_params->num_channels)
-			continue;
-
 		pctl_cfg(channel, sdram_params);
 	}
 
diff --git a/plat/rockchip/rk3399/drivers/dram/suspend.h b/plat/rockchip/rk3399/drivers/dram/suspend.h
index 03df421..77f9c31 100644
--- a/plat/rockchip/rk3399/drivers/dram/suspend.h
+++ b/plat/rockchip/rk3399/drivers/dram/suspend.h
@@ -20,7 +20,6 @@
 #define PI_FULL_TRAINING	(0xff)
 
 void dmc_save(void);
-__sramfunc void dmc_restore(void);
-__sramfunc void sram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num);
+__pmusramfunc void dmc_restore(void);
 
 #endif /* __DRAM_H__ */
diff --git a/plat/rockchip/rk3399/drivers/pmu/pmu.c b/plat/rockchip/rk3399/drivers/pmu/pmu.c
index 9c0a29c..f6c47f4 100644
--- a/plat/rockchip/rk3399/drivers/pmu/pmu.c
+++ b/plat/rockchip/rk3399/drivers/pmu/pmu.c
@@ -19,9 +19,9 @@
 #include <plat_params.h>
 #include <plat_private.h>
 #include <rk3399_def.h>
-#include <pmu_sram.h>
 #include <secure.h>
 #include <soc.h>
+#include <string.h>
 #include <pmu.h>
 #include <pmu_com.h>
 #include <pwm.h>
@@ -30,10 +30,8 @@
 
 DEFINE_BAKERY_LOCK(rockchip_pd_lock);
 
-static struct psram_data_t *psram_sleep_cfg =
-	(struct psram_data_t *)PSRAM_DT_BASE;
-
 static uint32_t cpu_warm_boot_addr;
+static char store_sram[SRAM_BIN_LIMIT + SRAM_TEXT_LIMIT + SRAM_DATA_LIMIT];
 
 /*
  * There are two ways to powering on or off on core.
@@ -411,24 +409,6 @@
 	mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(ACINACTM_CLUSTER_B_CFG));
 }
 
-void plat_rockchip_pmusram_prepare(void)
-{
-	uint32_t *sram_dst, *sram_src;
-	size_t sram_size;
-
-	/*
-	 * pmu sram code and data prepare
-	 */
-	sram_dst = (uint32_t *)PMUSRAM_BASE;
-	sram_src = (uint32_t *)&pmu_cpuson_entrypoint_start;
-	sram_size = (uint32_t *)&pmu_cpuson_entrypoint_end -
-		    (uint32_t *)sram_src;
-
-	u32_align_cpy(sram_dst, sram_src, sram_size);
-
-	psram_sleep_cfg->sp = PSRAM_DT_BASE;
-}
-
 static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id)
 {
 	assert(cpu_id < PLATFORM_CORE_COUNT);
@@ -782,14 +762,24 @@
 	mmio_write_32(PMU_BASE + PMU_CENTER_PWRUP_CNT, CYCL_24M_CNT_MS(1));
 
 	/*
+	 * when we enable PMU_CLR_PERILP, it will shut down the SRAM, but
+	 * M0 code run in SRAM, and we need it to check whether cpu enter
+	 * FSM status, so we must wait M0 finish their code and enter WFI,
+	 * then we can shutdown SRAM, according FSM order:
+	 * ST_NORMAL->..->ST_SCU_L_PWRDN->..->ST_CENTER_PWRDN->ST_PERILP_PWRDN
+	 * we can add delay when shutdown ST_SCU_L_PWRDN to guarantee M0 get
+	 * the FSM status and enter WFI, then enable PMU_CLR_PERILP.
+	 */
+	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRDN_CNT, CYCL_24M_CNT_MS(5));
+	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRUP_CNT, CYCL_24M_CNT_US(1));
+
+	/*
 	 * Set CPU/GPU to 1 us.
 	 *
 	 * NOTE: Even though ATF doesn't configure the GPU we'll still setup
 	 * counts here.  After all ATF controls all these other bits and also
 	 * chooses which clock these counters use.
 	 */
-	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRDN_CNT, CYCL_24M_CNT_US(1));
-	mmio_write_32(PMU_BASE + PMU_SCU_L_PWRUP_CNT, CYCL_24M_CNT_US(1));
 	mmio_write_32(PMU_BASE + PMU_SCU_B_PWRDN_CNT, CYCL_24M_CNT_US(1));
 	mmio_write_32(PMU_BASE + PMU_SCU_B_PWRUP_CNT, CYCL_24M_CNT_US(1));
 	mmio_write_32(PMU_BASE + PMU_GPU_PWRDN_CNT, CYCL_24M_CNT_US(1));
@@ -837,6 +827,8 @@
 		       BIT(PMU_DDRIO1_RET_EN) |
 		       BIT(PMU_DDRIO_RET_HW_DE_REQ) |
 		       BIT(PMU_CENTER_PD_EN) |
+		       BIT(PMU_PERILP_PD_EN) |
+		       BIT(PMU_CLK_PERILP_SRC_GATE_EN) |
 		       BIT(PMU_PLL_PD_EN) |
 		       BIT(PMU_CLK_CENTER_SRC_GATE_EN) |
 		       BIT(PMU_OSC_DIS) |
@@ -1050,6 +1042,36 @@
 	mmio_write_32(M0_PARAM_ADDR + PARAM_M0_FUNC, M0_FUNC_SUSPEND);
 }
 
+void sram_save(void)
+{
+	size_t text_size = (char *)&__bl31_sram_text_real_end -
+			   (char *)&__bl31_sram_text_start;
+	size_t data_size = (char *)&__bl31_sram_data_real_end -
+			   (char *)&__bl31_sram_data_start;
+	size_t incbin_size = (char *)&__sram_incbin_real_end -
+			     (char *)&__sram_incbin_start;
+
+	memcpy(&store_sram[0], &__bl31_sram_text_start, text_size);
+	memcpy(&store_sram[text_size], &__bl31_sram_data_start, data_size);
+	memcpy(&store_sram[text_size + data_size], &__sram_incbin_start,
+	       incbin_size);
+}
+
+void sram_restore(void)
+{
+	size_t text_size = (char *)&__bl31_sram_text_real_end -
+			   (char *)&__bl31_sram_text_start;
+	size_t data_size = (char *)&__bl31_sram_data_real_end -
+			   (char *)&__bl31_sram_data_start;
+	size_t incbin_size = (char *)&__sram_incbin_real_end -
+			     (char *)&__sram_incbin_start;
+
+	memcpy(&__bl31_sram_text_start, &store_sram[0], text_size);
+	memcpy(&__bl31_sram_data_start, &store_sram[text_size], data_size);
+	memcpy(&__sram_incbin_start, &store_sram[text_size + data_size],
+	       incbin_size);
+}
+
 int rockchip_soc_sys_pwr_dm_suspend(void)
 {
 	uint32_t wait_cnt = 0;
@@ -1067,6 +1089,8 @@
 		    BIT(PMU_CLR_CCIM0) |
 		    BIT(PMU_CLR_CCIM1) |
 		    BIT(PMU_CLR_CENTER) |
+		    BIT(PMU_CLR_PERILP) |
+		    BIT(PMU_CLR_PERILPM0) |
 		    BIT(PMU_CLR_GIC));
 
 	sys_slp_config();
@@ -1077,8 +1101,8 @@
 	pmu_sgrf_rst_hld();
 
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
-		      (PMUSRAM_BASE >> CPU_BOOT_ADDR_ALIGN) |
-		      CPU_BOOT_ADDR_WMASK);
+		      ((uintptr_t)&pmu_cpuson_entrypoint >>
+			CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK);
 
 	mmio_write_32(PMU_BASE + PMU_ADB400_CON,
 		      BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) |
@@ -1112,6 +1136,7 @@
 	suspend_apio();
 	suspend_gpio();
 
+	sram_save();
 	return 0;
 }
 
@@ -1193,6 +1218,8 @@
 				BIT(PMU_CLR_CCIM0) |
 				BIT(PMU_CLR_CCIM1) |
 				BIT(PMU_CLR_CENTER) |
+				BIT(PMU_CLR_PERILP) |
+				BIT(PMU_CLR_PERILPM0) |
 				BIT(PMU_CLR_GIC));
 
 	plat_rockchip_gic_cpuif_enable();
@@ -1245,6 +1272,36 @@
 		;
 }
 
+void rockchip_plat_mmu_el3(void)
+{
+	size_t sram_size;
+
+	/* sram.text size */
+	sram_size = (char *)&__bl31_sram_text_end -
+		    (char *)&__bl31_sram_text_start;
+	mmap_add_region((unsigned long)&__bl31_sram_text_start,
+			(unsigned long)&__bl31_sram_text_start,
+			sram_size, MT_MEMORY | MT_RO | MT_SECURE);
+
+	/* sram.data size */
+	sram_size = (char *)&__bl31_sram_data_end -
+		    (char *)&__bl31_sram_data_start;
+	mmap_add_region((unsigned long)&__bl31_sram_data_start,
+			(unsigned long)&__bl31_sram_data_start,
+			sram_size, MT_MEMORY | MT_RW | MT_SECURE);
+
+	sram_size = (char *)&__bl31_sram_stack_end -
+		    (char *)&__bl31_sram_stack_start;
+	mmap_add_region((unsigned long)&__bl31_sram_stack_start,
+			(unsigned long)&__bl31_sram_stack_start,
+			sram_size, MT_MEMORY | MT_RW | MT_SECURE);
+
+	sram_size = (char *)&__sram_incbin_end - (char *)&__sram_incbin_start;
+	mmap_add_region((unsigned long)&__sram_incbin_start,
+			(unsigned long)&__sram_incbin_start,
+			sram_size, MT_NON_CACHEABLE | MT_RW | MT_SECURE);
+}
+
 void plat_rockchip_pmu_init(void)
 {
 	uint32_t cpu;
@@ -1260,12 +1317,6 @@
 	for (cpu = 0; cpu < PLATFORM_CLUSTER_COUNT; cpu++)
 		clst_warmboot_data[cpu] = 0;
 
-	psram_sleep_cfg->ddr_func = (uint64_t)dmc_restore;
-	psram_sleep_cfg->ddr_data = (uint64_t)&sdram_config;
-	psram_sleep_cfg->ddr_flag = 0x01;
-
-	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
-
 	/* config cpu's warm boot address */
 	mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1),
 		      (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) |
diff --git a/plat/rockchip/rk3399/include/plat.ld.S b/plat/rockchip/rk3399/include/plat.ld.S
index 49206be..c42d9a9 100644
--- a/plat/rockchip/rk3399/include/plat.ld.S
+++ b/plat/rockchip/rk3399/include/plat.ld.S
@@ -8,6 +8,7 @@
 
 MEMORY {
     SRAM (rwx): ORIGIN = SRAM_BASE, LENGTH = SRAM_SIZE
+    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
 }
 
 SECTIONS
@@ -29,24 +30,60 @@
 	.incbin_sram : ALIGN(4096) {
 		__sram_incbin_start = .;
 		*(.sram.incbin)
+		 __sram_incbin_real_end = .;
 		. = ALIGN(4096);
 		__sram_incbin_end = .;
 	} >SRAM
+	ASSERT((__sram_incbin_real_end - __sram_incbin_start) <=
+		SRAM_BIN_LIMIT, ".incbin_sram has exceeded its limit")
 
 	.text_sram : ALIGN(4096) {
 		__bl31_sram_text_start = .;
 		*(.sram.text)
 		*(.sram.rodata)
+		__bl31_sram_text_real_end = .;
 		. = ALIGN(4096);
 		__bl31_sram_text_end = .;
 	} >SRAM
+	ASSERT((__bl31_sram_text_real_end - __bl31_sram_text_start) <=
+		SRAM_TEXT_LIMIT, ".text_sram has exceeded its limit")
 
 	.data_sram : ALIGN(4096) {
 		__bl31_sram_data_start = .;
 		*(.sram.data)
+		__bl31_sram_data_real_end = .;
 		. = ALIGN(4096);
 		__bl31_sram_data_end = .;
 	} >SRAM
+	ASSERT((__bl31_sram_data_real_end - __bl31_sram_data_start) <=
+		SRAM_DATA_LIMIT, ".data_sram has exceeded its limit")
+
+	.stack_sram : ALIGN(4096) {
+		__bl31_sram_stack_start = .;
+		. += 4096;
+		__bl31_sram_stack_end = .;
+	} >SRAM
+
+	. = PMUSRAM_BASE;
+
+	/*
+	 * pmu_cpuson_entrypoint request address
+	 * align 64K when resume, so put it in the
+	 * start of pmusram
+	 */
+	.pmusram : {
+		ASSERT(. == ALIGN(64 * 1024),
+			".pmusram.entry request 64K aligned.");
+		*(.pmusram.entry)
+		__bl31_pmusram_text_start = .;
+		*(.pmusram.text)
+		*(.pmusram.rodata)
+		__bl31_pmusram_text_end = .;
+		__bl31_pmusram_data_start = .;
+		*(.pmusram.data)
+		__bl31_pmusram_data_end = .;
+
+	} >PMUSRAM
 }
 
 #endif /* __ROCKCHIP_PLAT_LD_S__ */
diff --git a/plat/rockchip/rk3399/include/platform_def.h b/plat/rockchip/rk3399/include/platform_def.h
index f4427d0..3df2f7d 100644
--- a/plat/rockchip/rk3399/include/platform_def.h
+++ b/plat/rockchip/rk3399/include/platform_def.h
@@ -107,4 +107,7 @@
 
 #define PLAT_RK_PRIMARY_CPU		0x0
 
+#define PSRAM_DO_DDR_RESUME	1
+#define PSRAM_CHECK_WAKEUP_CPU	0
+
 #endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/rockchip/rk3399/include/shared/addressmap_shared.h b/plat/rockchip/rk3399/include/shared/addressmap_shared.h
index d72633e..fe23e56 100644
--- a/plat/rockchip/rk3399/include/shared/addressmap_shared.h
+++ b/plat/rockchip/rk3399/include/shared/addressmap_shared.h
@@ -9,6 +9,9 @@
 
 #define SIZE_K(n)		((n) * 1024)
 #define SIZE_M(n)		((n) * 1024 * 1024)
+#define SRAM_TEXT_LIMIT		(4 * 1024)
+#define SRAM_DATA_LIMIT		(4 * 1024)
+#define SRAM_BIN_LIMIT		(4 * 1024)
 
 /*
  * The parts of the shared defined registers address with AP and M0,
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
index be3e11b..cb7999b 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -44,7 +44,6 @@
 			${RK_PLAT_COMMON}/bl31_plat_setup.c		\
 			${RK_PLAT_COMMON}/params_setup.c		\
 			${RK_PLAT_COMMON}/pmusram/pmu_sram_cpus_on.S	\
-			${RK_PLAT_COMMON}/pmusram/pmu_sram.c		\
 			${RK_PLAT_COMMON}/plat_pm.c			\
 			${RK_PLAT_COMMON}/plat_topology.c		\
 			${RK_PLAT_COMMON}/aarch64/platform_common.c	\
diff --git a/tools/cert_create/src/cert.c b/tools/cert_create/src/cert.c
index 80ccfe9..9775664 100644
--- a/tools/cert_create/src/cert.c
+++ b/tools/cert_create/src/cert.c
@@ -10,6 +10,7 @@
 
 #include <openssl/conf.h>
 #include <openssl/err.h>
+#include <openssl/opensslv.h>
 #include <openssl/pem.h>
 #include <openssl/sha.h>
 #include <openssl/x509v3.h>
@@ -27,6 +28,7 @@
 #include "sha.h"
 
 #define SERIAL_RAND_BITS	64
+#define RSA_SALT_LEN		32
 
 int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
 {
@@ -77,7 +79,6 @@
 	return 1;
 }
 
-
 int cert_new(cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSION) * sk)
 {
 	EVP_PKEY *pkey = keys[cert->key].key;
@@ -88,7 +89,9 @@
 	X509_EXTENSION *ex;
 	X509_NAME *name;
 	ASN1_INTEGER *sno;
-	int i, num;
+	int i, num, rc = 0;
+	EVP_MD_CTX  mdCtx;
+	EVP_PKEY_CTX *pKeyCtx = NULL;
 
 	/* Create the certificate structure */
 	x = X509_new();
@@ -108,6 +111,27 @@
 		issuer = x;
 	}
 
+	EVP_MD_CTX_init(&mdCtx);
+	if (!EVP_DigestSignInit(&mdCtx, &pKeyCtx, EVP_sha256(), NULL, ikey)) {
+		ERR_print_errors_fp(stdout);
+		goto END;
+	}
+
+	if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) {
+		ERR_print_errors_fp(stdout);
+		goto END;
+	}
+
+	if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, RSA_SALT_LEN)) {
+		ERR_print_errors_fp(stdout);
+		goto END;
+	}
+
+	if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, EVP_sha256())) {
+		ERR_print_errors_fp(stdout);
+		goto END;
+	}
+
 	/* x509.v3 */
 	X509_set_version(x, 2);
 
@@ -152,14 +176,18 @@
 		}
 	}
 
-	/* Sign the certificate with the issuer key */
-	if (!X509_sign(x, ikey, EVP_sha256())) {
+	if (!X509_sign_ctx(x, &mdCtx)) {
 		ERR_print_errors_fp(stdout);
-		return 0;
+		goto END;
 	}
 
+	/* X509 certificate signed successfully */
+	rc = 1;
 	cert->x = x;
-	return 1;
+
+END:
+	EVP_MD_CTX_cleanup(&mdCtx);
+	return rc;
 }
 
 int cert_init(void)