Merge pull request #969 from Summer-ARM/sq/update-doc

Update the path for firmware_image_package.h in firmware-design.md
diff --git a/Makefile b/Makefile
index 299ff30..aec10c9 100644
--- a/Makefile
+++ b/Makefile
@@ -163,6 +163,7 @@
 
 BL_COMMON_SOURCES	+=	common/bl_common.c			\
 				common/tf_printf.c			\
+				common/tf_snprintf.c			\
 				common/${ARCH}/debug.S			\
 				lib/${ARCH}/cache_helpers.S		\
 				lib/${ARCH}/misc_helpers.S		\
@@ -335,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/common/tf_snprintf.c b/common/tf_snprintf.c
new file mode 100644
index 0000000..a99ab7a
--- /dev/null
+++ b/common/tf_snprintf.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <platform.h>
+#include <stdarg.h>
+
+static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed,
+			       unsigned int unum)
+{
+	/* Enough for a 32-bit unsigned decimal integer (4294967295). */
+	unsigned char num_buf[10];
+	int i = 0, rem;
+
+	do {
+		rem = unum % 10;
+		num_buf[i++] = '0' + rem;
+	} while (unum /= 10);
+
+	while (--i >= 0) {
+		if (*chars_printed < n)
+			*(*s)++ = num_buf[i];
+		(*chars_printed)++;
+	}
+}
+
+/*******************************************************************
+ * Reduced snprintf to be used for Trusted firmware.
+ * The following type specifiers are supported:
+ *
+ * %d or %i - signed decimal format
+ * %u - unsigned decimal format
+ *
+ * The function panics on all other formats specifiers.
+ *
+ * It returns the number of characters that would be written if the
+ * buffer was big enough. If it returns a value lower than n, the
+ * whole string has been written.
+ *******************************************************************/
+int tf_snprintf(char *s, size_t n, const char *fmt, ...)
+{
+	va_list args;
+	int num;
+	unsigned int unum;
+	size_t chars_printed = 0;
+
+	if (n == 1) {
+		/* Buffer is too small to actually write anything else. */
+		*s = '\0';
+		n = 0;
+	} else if (n >= 2) {
+		/* Reserve space for the terminator character. */
+		n--;
+	}
+
+	va_start(args, fmt);
+	while (*fmt) {
+
+		if (*fmt == '%') {
+			fmt++;
+			/* Check the format specifier. */
+			switch (*fmt) {
+			case 'i':
+			case 'd':
+				num = va_arg(args, int);
+
+				if (num < 0) {
+					if (chars_printed < n)
+						*s++ = '-';
+					chars_printed++;
+
+					unum = (unsigned int)-num;
+				} else {
+					unum = (unsigned int)num;
+				}
+
+				unsigned_dec_print(&s, n, &chars_printed, unum);
+				break;
+			case 'u':
+				unum = va_arg(args, unsigned int);
+				unsigned_dec_print(&s, n, &chars_printed, unum);
+				break;
+			default:
+				/* Panic on any other format specifier. */
+				ERROR("tf_snprintf: specifier with ASCII code '%d' not supported.",
+				      *fmt);
+				plat_panic_handler();
+			}
+			fmt++;
+			continue;
+		}
+
+		if (chars_printed < n)
+			*s++ = *fmt;
+		fmt++;
+		chars_printed++;
+	}
+
+	va_end(args);
+
+	if (n > 0)
+		*s = '\0';
+
+	return chars_printed;
+}
diff --git a/docs/auth-framework.md b/docs/auth-framework.md
index 531505b..b416acf 100644
--- a/docs/auth-framework.md
+++ b/docs/auth-framework.md
@@ -909,9 +909,13 @@
 ```
 
 The key algorithm (rsa, ecdsa) must be specified in the build system using the
-`MBEDTLS_KEY_ALG` variable, so the Makefile can include the corresponding
+`TF_MBEDTLS_KEY_ALG` variable, so the Makefile can include the corresponding
 sources in the build.
 
+Note: If code size is a concern, the build option `MBEDTLS_SHA256_SMALLER` can
+be defined in the platform Makefile. It will make mbed TLS use an implementation
+of SHA-256 with smaller memory footprint (~1.5 KB less) but slower (~30%).
+
 - - - - - - - - - - - - - - - - - - - - - - - - - -
 
 _Copyright (c) 2015, ARM Limited and Contributors. All rights reserved._
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/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 aad49a7..3799d41 100644
--- a/drivers/auth/mbedtls/mbedtls_common.c
+++ b/drivers/auth/mbedtls/mbedtls_common.c
@@ -4,10 +4,11 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#include <assert.h>
+#include <debug.h>
 
 /* mbed TLS headers */
 #include <mbedtls/memory_buffer_alloc.h>
+#include <mbedtls/platform.h>
 
 /*
  * mbed TLS heap
@@ -15,7 +16,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		(8*1024)
+#define MBEDTLS_HEAP_SIZE		(7*1024)
 #endif
 static unsigned char heap[MBEDTLS_HEAP_SIZE];
 
@@ -29,6 +30,10 @@
 	if (!ready) {
 		/* Initialize the mbed TLS heap */
 		mbedtls_memory_buffer_alloc_init(heap, MBEDTLS_HEAP_SIZE);
+
+		/* Use reduced version of snprintf to save space. */
+		mbedtls_platform_set_snprintf(tf_snprintf);
+
 		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/drivers/synopsys/ufs/dw_ufs.c b/drivers/synopsys/ufs/dw_ufs.c
new file mode 100644
index 0000000..d8ed5b6
--- /dev/null
+++ b/drivers/synopsys/ufs/dw_ufs.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <dw_ufs.h>
+#include <mmio.h>
+#include <stdint.h>
+#include <string.h>
+#include <ufs.h>
+
+static int dwufs_phy_init(ufs_params_t *params)
+{
+	uintptr_t base;
+	unsigned int fsm0, fsm1;
+	unsigned int data;
+	int result;
+
+	assert((params != NULL) && (params->reg_base != 0));
+
+	base = params->reg_base;
+
+	/* Unipro VS_MPHY disable */
+	ufshc_dme_set(VS_MPHY_DISABLE_OFFSET, 0, VS_MPHY_DISABLE_MPHYDIS);
+	ufshc_dme_set(PA_HS_SERIES_OFFSET, 0, 2);
+	/* MPHY CBRATESEL */
+	ufshc_dme_set(0x8114, 0, 1);
+	/* MPHY CBOVRCTRL2 */
+	ufshc_dme_set(0x8121, 0, 0x2d);
+	/* MPHY CBOVRCTRL3 */
+	ufshc_dme_set(0x8122, 0, 0x1);
+	ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1);
+
+	/* MPHY RXOVRCTRL4 rx0 */
+	ufshc_dme_set(0x800d, 4, 0x58);
+	/* MPHY RXOVRCTRL4 rx1 */
+	ufshc_dme_set(0x800d, 5, 0x58);
+	/* MPHY RXOVRCTRL5 rx0 */
+	ufshc_dme_set(0x800e, 4, 0xb);
+	/* MPHY RXOVRCTRL5 rx1 */
+	ufshc_dme_set(0x800e, 5, 0xb);
+	/* MPHY RXSQCONTROL rx0 */
+	ufshc_dme_set(0x8009, 4, 0x1);
+	/* MPHY RXSQCONTROL rx1 */
+	ufshc_dme_set(0x8009, 5, 0x1);
+	ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1);
+
+	ufshc_dme_set(0x8113, 0, 0x1);
+	ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1);
+
+	ufshc_dme_set(RX_HS_G3_SYNC_LENGTH_CAP_OFFSET, 4, 0x4a);
+	ufshc_dme_set(RX_HS_G3_SYNC_LENGTH_CAP_OFFSET, 5, 0x4a);
+	ufshc_dme_set(RX_HS_G2_SYNC_LENGTH_CAP_OFFSET, 4, 0x4a);
+	ufshc_dme_set(RX_HS_G2_SYNC_LENGTH_CAP_OFFSET, 5, 0x4a);
+	ufshc_dme_set(RX_MIN_ACTIVATETIME_CAP_OFFSET, 4, 0x7);
+	ufshc_dme_set(RX_MIN_ACTIVATETIME_CAP_OFFSET, 5, 0x7);
+	ufshc_dme_set(TX_HIBERN8TIME_CAP_OFFSET, 0, 0x5);
+	ufshc_dme_set(TX_HIBERN8TIME_CAP_OFFSET, 1, 0x5);
+	ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1);
+
+	result = ufshc_dme_get(VS_MPHY_DISABLE_OFFSET, 0, &data);
+	assert((result == 0) && (data == VS_MPHY_DISABLE_MPHYDIS));
+	/* enable Unipro VS MPHY */
+	ufshc_dme_set(VS_MPHY_DISABLE_OFFSET, 0, 0);
+
+	while (1) {
+		result = ufshc_dme_get(TX_FSM_STATE_OFFSET, 0, &fsm0);
+		assert(result == 0);
+		result = ufshc_dme_get(TX_FSM_STATE_OFFSET, 1, &fsm1);
+		assert(result == 0);
+		if ((fsm0 == TX_FSM_STATE_HIBERN8) &&
+		    (fsm1 == TX_FSM_STATE_HIBERN8))
+			break;
+	}
+
+	mmio_write_32(base + HCLKDIV, 0xE4);
+	mmio_clrbits_32(base + AHIT, 0x3FF);
+
+	ufshc_dme_set(PA_LOCAL_TX_LCC_ENABLE_OFFSET, 0, 0);
+	ufshc_dme_set(VS_MK2_EXTN_SUPPORT_OFFSET, 0, 0);
+
+	result = ufshc_dme_get(VS_MK2_EXTN_SUPPORT_OFFSET, 0, &data);
+	assert((result == 0) && (data == 0));
+
+	ufshc_dme_set(DL_AFC0_CREDIT_THRESHOLD_OFFSET, 0, 0);
+	ufshc_dme_set(DL_TC0_OUT_ACK_THRESHOLD_OFFSET, 0, 0);
+	ufshc_dme_set(DL_TC0_TX_FC_THRESHOLD_OFFSET, 0, 9);
+	(void)result;
+	return 0;
+}
+
+static int dwufs_phy_set_pwr_mode(ufs_params_t *params)
+{
+	int result;
+	unsigned int data, tx_lanes, rx_lanes;
+	uintptr_t base;
+
+	assert((params != NULL) && (params->reg_base != 0));
+
+	base = params->reg_base;
+
+	result = ufshc_dme_get(PA_TACTIVATE_OFFSET, 0, &data);
+	assert(result == 0);
+	if (data < 7) {
+		result = ufshc_dme_set(PA_TACTIVATE_OFFSET, 0, 7);
+		assert(result == 0);
+	}
+	result = ufshc_dme_get(PA_CONNECTED_TX_DATA_LANES_OFFSET, 0, &tx_lanes);
+	assert(result == 0);
+	result = ufshc_dme_get(PA_CONNECTED_RX_DATA_LANES_OFFSET, 0, &rx_lanes);
+	assert(result == 0);
+
+	result = ufshc_dme_set(PA_TX_SKIP_OFFSET, 0, 0);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_TX_GEAR_OFFSET, 0, 3);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_RX_GEAR_OFFSET, 0, 3);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_HS_SERIES_OFFSET, 0, 2);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_TX_TERMINATION_OFFSET, 0, 1);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_RX_TERMINATION_OFFSET, 0, 1);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_SCRAMBLING_OFFSET, 0, 0);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_ACTIVE_TX_DATA_LANES_OFFSET, 0, tx_lanes);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_ACTIVE_RX_DATA_LANES_OFFSET, 0, rx_lanes);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_PWR_MODE_USER_DATA0_OFFSET, 0, 8191);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_PWR_MODE_USER_DATA1_OFFSET, 0, 65535);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_PWR_MODE_USER_DATA2_OFFSET, 0, 32767);
+	assert(result == 0);
+	result = ufshc_dme_set(DME_FC0_PROTECTION_TIMEOUT_OFFSET, 0, 8191);
+	assert(result == 0);
+	result = ufshc_dme_set(DME_TC0_REPLAY_TIMEOUT_OFFSET, 0, 65535);
+	assert(result == 0);
+	result = ufshc_dme_set(DME_AFC0_REQ_TIMEOUT_OFFSET, 0, 32767);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_PWR_MODE_USER_DATA3_OFFSET, 0, 8191);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_PWR_MODE_USER_DATA4_OFFSET, 0, 65535);
+	assert(result == 0);
+	result = ufshc_dme_set(PA_PWR_MODE_USER_DATA5_OFFSET, 0, 32767);
+	assert(result == 0);
+	result = ufshc_dme_set(DME_FC1_PROTECTION_TIMEOUT_OFFSET, 0, 8191);
+	assert(result == 0);
+	result = ufshc_dme_set(DME_TC1_REPLAY_TIMEOUT_OFFSET, 0, 65535);
+	assert(result == 0);
+	result = ufshc_dme_set(DME_AFC1_REQ_TIMEOUT_OFFSET, 0, 32767);
+	assert(result == 0);
+
+	result = ufshc_dme_set(PA_PWR_MODE_OFFSET, 0, 0x11);
+	assert(result == 0);
+	do {
+		data = mmio_read_32(base + IS);
+	} while ((data & UFS_INT_UPMS) == 0);
+	mmio_write_32(base + IS, UFS_INT_UPMS);
+	data = mmio_read_32(base + HCS);
+	if ((data & HCS_UPMCRS_MASK) == HCS_PWR_LOCAL)
+		INFO("ufs: change power mode success\n");
+	else
+		WARN("ufs: HCS.UPMCRS error, HCS:0x%x\n", data);
+	(void)result;
+	return 0;
+}
+
+const ufs_ops_t dw_ufs_ops = {
+	.phy_init		= dwufs_phy_init,
+	.phy_set_pwr_mode	= dwufs_phy_set_pwr_mode,
+};
+
+int dw_ufs_init(dw_ufs_params_t *params)
+{
+	ufs_params_t ufs_params;
+
+	memset(&ufs_params, 0, sizeof(ufs_params));
+	ufs_params.reg_base = params->reg_base;
+	ufs_params.desc_base = params->desc_base;
+	ufs_params.desc_size = params->desc_size;
+	ufs_params.flags = params->flags;
+	ufs_init(&dw_ufs_ops, &ufs_params);
+	return 0;
+}
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
new file mode 100644
index 0000000..dbfcd0f
--- /dev/null
+++ b/drivers/ufs/ufs.c
@@ -0,0 +1,759 @@
+/*
+ * 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 <delay_timer.h>
+#include <endian.h>
+#include <errno.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <stdint.h>
+#include <string.h>
+#include <ufs.h>
+
+#define CDB_ADDR_MASK			127
+#define ALIGN_CDB(x)			(((x) + CDB_ADDR_MASK) & ~CDB_ADDR_MASK)
+#define ALIGN_8(x)			(((x) + 7) & ~7)
+
+#define UFS_DESC_SIZE			0x400
+#define MAX_UFS_DESC_SIZE		0x8000		/* 32 descriptors */
+
+#define MAX_PRDT_SIZE			0x40000		/* 256KB */
+
+static ufs_params_t ufs_params;
+static int nutrs;	/* Number of UTP Transfer Request Slots */
+
+int ufshc_send_uic_cmd(uintptr_t base, uic_cmd_t *cmd)
+{
+	unsigned int data;
+
+	data = mmio_read_32(base + HCS);
+	if ((data & HCS_UCRDY) == 0)
+		return -EBUSY;
+	mmio_write_32(base + IS, ~0);
+	mmio_write_32(base + UCMDARG1, cmd->arg1);
+	mmio_write_32(base + UCMDARG2, cmd->arg2);
+	mmio_write_32(base + UCMDARG3, cmd->arg3);
+	mmio_write_32(base + UICCMD, cmd->op);
+
+	do {
+		data = mmio_read_32(base + IS);
+	} while ((data & UFS_INT_UCCS) == 0);
+	mmio_write_32(base + IS, UFS_INT_UCCS);
+	return mmio_read_32(base + UCMDARG2) && CONFIG_RESULT_CODE_MASK;
+}
+
+int ufshc_dme_get(unsigned int attr, unsigned int idx, unsigned int *val)
+{
+	uintptr_t base;
+	unsigned int data;
+	int retries;
+
+	assert((ufs_params.reg_base != 0) && (val != NULL));
+
+	base = ufs_params.reg_base;
+	for (retries = 0; retries < 100; retries++) {
+		data = mmio_read_32(base + HCS);
+		if ((data & HCS_UCRDY) != 0)
+			break;
+		mdelay(1);
+	}
+	if (retries >= 100)
+		return -EBUSY;
+
+	mmio_write_32(base + IS, ~0);
+	mmio_write_32(base + UCMDARG1, (attr << 16) | GEN_SELECTOR_IDX(idx));
+	mmio_write_32(base + UCMDARG2, 0);
+	mmio_write_32(base + UCMDARG3, 0);
+	mmio_write_32(base + UICCMD, DME_GET);
+	do {
+		data = mmio_read_32(base + IS);
+		if (data & UFS_INT_UE)
+			return -EINVAL;
+	} while ((data & UFS_INT_UCCS) == 0);
+	mmio_write_32(base + IS, UFS_INT_UCCS);
+	data = mmio_read_32(base + UCMDARG2) && CONFIG_RESULT_CODE_MASK;
+	assert(data == 0);
+
+	*val = mmio_read_32(base + UCMDARG3);
+	return 0;
+}
+
+int ufshc_dme_set(unsigned int attr, unsigned int idx, unsigned int val)
+{
+	uintptr_t base;
+	unsigned int data;
+
+	assert((ufs_params.reg_base != 0));
+
+	base = ufs_params.reg_base;
+	data = mmio_read_32(base + HCS);
+	if ((data & HCS_UCRDY) == 0)
+		return -EBUSY;
+	mmio_write_32(base + IS, ~0);
+	mmio_write_32(base + UCMDARG1, (attr << 16) | GEN_SELECTOR_IDX(idx));
+	mmio_write_32(base + UCMDARG2, 0);
+	mmio_write_32(base + UCMDARG3, val);
+	mmio_write_32(base + UICCMD, DME_SET);
+	do {
+		data = mmio_read_32(base + IS);
+		if (data & UFS_INT_UE)
+			return -EINVAL;
+	} while ((data & UFS_INT_UCCS) == 0);
+	mmio_write_32(base + IS, UFS_INT_UCCS);
+	data = mmio_read_32(base + UCMDARG2) && CONFIG_RESULT_CODE_MASK;
+	assert(data == 0);
+	return 0;
+}
+
+static void ufshc_reset(uintptr_t base)
+{
+	unsigned int data;
+
+	/* Enable Host Controller */
+	mmio_write_32(base + HCE, HCE_ENABLE);
+	/* Wait until basic initialization sequence completed */
+	do {
+		data = mmio_read_32(base + HCE);
+	} while ((data & HCE_ENABLE) == 0);
+
+	/* Enable Interrupts */
+	data = UFS_INT_UCCS | UFS_INT_ULSS | UFS_INT_UE | UFS_INT_UTPES |
+	       UFS_INT_DFES | UFS_INT_HCFES | UFS_INT_SBFES;
+	mmio_write_32(base + IE, data);
+}
+
+static int ufshc_link_startup(uintptr_t base)
+{
+	uic_cmd_t cmd;
+	int data, result;
+	int retries;
+
+	for (retries = 10; retries > 0; retries--) {
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.op = DME_LINKSTARTUP;
+		result = ufshc_send_uic_cmd(base, &cmd);
+		if (result != 0)
+			continue;
+		while ((mmio_read_32(base + HCS) & HCS_DP) == 0)
+			;
+		data = mmio_read_32(base + IS);
+		if (data & UFS_INT_ULSS)
+			mmio_write_32(base + IS, UFS_INT_ULSS);
+		return 0;
+	}
+	return -EIO;
+}
+
+/* Check Door Bell register to get an empty slot */
+static int get_empty_slot(int *slot)
+{
+	unsigned int data;
+	int i;
+
+	data = mmio_read_32(ufs_params.reg_base + UTRLDBR);
+	for (i = 0; i < nutrs; i++) {
+		if ((data & 1) == 0)
+			break;
+		data = data >> 1;
+	}
+	if (i >= nutrs)
+		return -EBUSY;
+	*slot = i;
+	return 0;
+}
+
+static void get_utrd(utp_utrd_t *utrd)
+{
+	uintptr_t base;
+	int slot = 0, result;
+	utrd_header_t *hd;
+
+	assert(utrd != NULL);
+	result = get_empty_slot(&slot);
+	assert(result == 0);
+
+	/* clear utrd */
+	memset((void *)utrd, 0, sizeof(utp_utrd_t));
+	base = ufs_params.desc_base + (slot * UFS_DESC_SIZE);
+	/* clear the descriptor */
+	memset((void *)base, 0, UFS_DESC_SIZE);
+
+	utrd->header = base;
+	utrd->task_tag = slot + 1;
+	/* CDB address should be aligned with 128 bytes */
+	utrd->upiu = ALIGN_CDB(utrd->header + sizeof(utrd_header_t));
+	utrd->resp_upiu = ALIGN_8(utrd->upiu + sizeof(cmd_upiu_t));
+	utrd->size_upiu = utrd->resp_upiu - utrd->upiu;
+	utrd->size_resp_upiu = ALIGN_8(sizeof(resp_upiu_t));
+	utrd->prdt = utrd->resp_upiu + utrd->size_resp_upiu;
+
+	hd = (utrd_header_t *)utrd->header;
+	hd->ucdba = utrd->upiu & UINT32_MAX;
+	hd->ucdbau = (utrd->upiu >> 32) & UINT32_MAX;
+	/* Both RUL and RUO is based on DWORD */
+	hd->rul = utrd->size_resp_upiu >> 2;
+	hd->ruo = utrd->size_upiu >> 2;
+	(void)result;
+}
+
+/*
+ * Prepare UTRD, Command UPIU, Response UPIU.
+ */
+static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun,
+			   int lba, uintptr_t buf, size_t length)
+{
+	utrd_header_t *hd;
+	cmd_upiu_t *upiu;
+	prdt_t *prdt;
+	unsigned int ulba;
+	unsigned int lba_cnt;
+	int prdt_size;
+
+
+	mmio_write_32(ufs_params.reg_base + UTRLBA,
+		      utrd->header & UINT32_MAX);
+	mmio_write_32(ufs_params.reg_base + UTRLBAU,
+		      (utrd->upiu >> 32) & UINT32_MAX);
+
+	hd = (utrd_header_t *)utrd->header;
+	upiu = (cmd_upiu_t *)utrd->upiu;
+
+	hd->i = 1;
+	hd->ct = CT_UFS_STORAGE;
+	hd->ocs = OCS_MASK;
+
+	upiu->trans_type = CMD_UPIU;
+	upiu->task_tag = utrd->task_tag;
+	upiu->cdb[0] = op;
+	ulba = (unsigned int)lba;
+	lba_cnt = (unsigned int)(length >> UFS_BLOCK_SHIFT);
+	switch (op) {
+	case CDBCMD_TEST_UNIT_READY:
+		break;
+	case CDBCMD_READ_CAPACITY_10:
+		hd->dd = DD_OUT;
+		upiu->flags = UPIU_FLAGS_R | UPIU_FLAGS_ATTR_S;
+		upiu->lun = lun;
+		break;
+	case CDBCMD_READ_10:
+		hd->dd = DD_OUT;
+		upiu->flags = UPIU_FLAGS_R | UPIU_FLAGS_ATTR_S;
+		upiu->lun = lun;
+		upiu->cdb[1] = RW_WITHOUT_CACHE;
+		/* set logical block address */
+		upiu->cdb[2] = (ulba >> 24) & 0xff;
+		upiu->cdb[3] = (ulba >> 16) & 0xff;
+		upiu->cdb[4] = (ulba >> 8) & 0xff;
+		upiu->cdb[5] = ulba & 0xff;
+		/* set transfer length */
+		upiu->cdb[7] = (lba_cnt >> 8) & 0xff;
+		upiu->cdb[8] = lba_cnt & 0xff;
+		break;
+	case CDBCMD_WRITE_10:
+		hd->dd = DD_IN;
+		upiu->flags = UPIU_FLAGS_W | UPIU_FLAGS_ATTR_S;
+		upiu->lun = lun;
+		upiu->cdb[1] = RW_WITHOUT_CACHE;
+		/* set logical block address */
+		upiu->cdb[2] = (ulba >> 24) & 0xff;
+		upiu->cdb[3] = (ulba >> 16) & 0xff;
+		upiu->cdb[4] = (ulba >> 8) & 0xff;
+		upiu->cdb[5] = ulba & 0xff;
+		/* set transfer length */
+		upiu->cdb[7] = (lba_cnt >> 8) & 0xff;
+		upiu->cdb[8] = lba_cnt & 0xff;
+		break;
+	default:
+		assert(0);
+	}
+	if (hd->dd == DD_IN)
+		flush_dcache_range(buf, length);
+	else if (hd->dd == DD_OUT)
+		inv_dcache_range(buf, length);
+	if (length) {
+		upiu->exp_data_trans_len = htobe32(length);
+		assert(lba_cnt <= UINT16_MAX);
+		prdt = (prdt_t *)utrd->prdt;
+
+		prdt_size = 0;
+		while (length > 0) {
+			prdt->dba = (unsigned int)(buf & UINT32_MAX);
+			prdt->dbau = (unsigned int)((buf >> 32) & UINT32_MAX);
+			/* prdt->dbc counts from 0 */
+			if (length > MAX_PRDT_SIZE) {
+				prdt->dbc = MAX_PRDT_SIZE - 1;
+				length = length - MAX_PRDT_SIZE;
+			} else {
+				prdt->dbc = length - 1;
+				length = 0;
+			}
+			buf += MAX_PRDT_SIZE;
+			prdt++;
+			prdt_size += sizeof(prdt_t);
+		}
+		utrd->size_prdt = ALIGN_8(prdt_size);
+		hd->prdtl = utrd->size_prdt >> 2;
+		hd->prdto = (utrd->size_upiu + utrd->size_resp_upiu) >> 2;
+	}
+
+	flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
+	flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
+	return 0;
+}
+
+static int ufs_prepare_query(utp_utrd_t *utrd, uint8_t op, uint8_t idn,
+			     uint8_t index, uint8_t sel,
+			     uintptr_t buf, size_t length)
+{
+	utrd_header_t *hd;
+	query_upiu_t *query_upiu;
+
+
+	hd = (utrd_header_t *)utrd->header;
+	query_upiu = (query_upiu_t *)utrd->upiu;
+
+	mmio_write_32(ufs_params.reg_base + UTRLBA,
+		      utrd->header & UINT32_MAX);
+	mmio_write_32(ufs_params.reg_base + UTRLBAU,
+		      (utrd->header >> 32) & UINT32_MAX);
+
+
+	hd->i = 1;
+	hd->ct = CT_UFS_STORAGE;
+	hd->ocs = OCS_MASK;
+
+	query_upiu->trans_type = QUERY_REQUEST_UPIU;
+	query_upiu->task_tag = utrd->task_tag;
+	query_upiu->ts.desc.opcode = op;
+	query_upiu->ts.desc.idn = idn;
+	query_upiu->ts.desc.index = index;
+	query_upiu->ts.desc.selector = sel;
+	switch (op) {
+	case QUERY_READ_DESC:
+		query_upiu->query_func = QUERY_FUNC_STD_READ;
+		query_upiu->ts.desc.length = htobe16(length);
+		break;
+	case QUERY_WRITE_DESC:
+		query_upiu->query_func = QUERY_FUNC_STD_WRITE;
+		query_upiu->ts.desc.length = htobe16(length);
+		memcpy((void *)(utrd->upiu + sizeof(query_upiu_t)),
+		       (void *)buf, length);
+		break;
+	case QUERY_READ_ATTR:
+	case QUERY_READ_FLAG:
+		query_upiu->query_func = QUERY_FUNC_STD_READ;
+		break;
+	case QUERY_CLEAR_FLAG:
+	case QUERY_SET_FLAG:
+		query_upiu->query_func = QUERY_FUNC_STD_WRITE;
+		break;
+	case QUERY_WRITE_ATTR:
+		query_upiu->query_func = QUERY_FUNC_STD_WRITE;
+		memcpy((void *)&query_upiu->ts.attr.value, (void *)buf, length);
+		break;
+	default:
+		assert(0);
+	}
+	flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
+	flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
+	return 0;
+}
+
+static void ufs_prepare_nop_out(utp_utrd_t *utrd)
+{
+	utrd_header_t *hd;
+	nop_out_upiu_t *nop_out;
+
+	mmio_write_32(ufs_params.reg_base + UTRLBA,
+		      utrd->header & UINT32_MAX);
+	mmio_write_32(ufs_params.reg_base + UTRLBAU,
+		      (utrd->header >> 32) & UINT32_MAX);
+
+	hd = (utrd_header_t *)utrd->header;
+	nop_out = (nop_out_upiu_t *)utrd->upiu;
+
+	hd->i = 1;
+	hd->ct = CT_UFS_STORAGE;
+	hd->ocs = OCS_MASK;
+
+	nop_out->trans_type = 0;
+	nop_out->task_tag = utrd->task_tag;
+	flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
+	flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE);
+}
+
+static void ufs_send_request(int task_tag)
+{
+	unsigned int data;
+	int slot;
+
+	slot = task_tag - 1;
+	/* clear all interrupts */
+	mmio_write_32(ufs_params.reg_base + IS, ~0);
+
+	mmio_write_32(ufs_params.reg_base + UTRLRSR, 1);
+	do {
+		data = mmio_read_32(ufs_params.reg_base + UTRLRSR);
+	} while (data == 0);
+
+	data = UTRIACR_IAEN | UTRIACR_CTR | UTRIACR_IACTH(0x1F) |
+	       UTRIACR_IATOVAL(0xFF);
+	mmio_write_32(ufs_params.reg_base + UTRIACR, data);
+	/* send request */
+	mmio_setbits_32(ufs_params.reg_base + UTRLDBR, 1 << slot);
+}
+
+static int ufs_check_resp(utp_utrd_t *utrd, int trans_type)
+{
+	utrd_header_t *hd;
+	resp_upiu_t *resp;
+	unsigned int data;
+	int slot;
+
+	hd = (utrd_header_t *)utrd->header;
+	resp = (resp_upiu_t *)utrd->resp_upiu;
+	inv_dcache_range((uintptr_t)hd, UFS_DESC_SIZE);
+	inv_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t));
+	do {
+		data = mmio_read_32(ufs_params.reg_base + IS);
+		if ((data & ~(UFS_INT_UCCS | UFS_INT_UTRCS)) != 0)
+			return -EIO;
+	} while ((data & UFS_INT_UTRCS) == 0);
+	slot = utrd->task_tag - 1;
+
+	data = mmio_read_32(ufs_params.reg_base + UTRLDBR);
+	assert((data & (1 << slot)) == 0);
+	assert(hd->ocs == OCS_SUCCESS);
+	assert((resp->trans_type & TRANS_TYPE_CODE_MASK) == trans_type);
+	(void)resp;
+	(void)slot;
+	return 0;
+}
+
+#ifdef UFS_RESP_DEBUG
+static void dump_upiu(utp_utrd_t *utrd)
+{
+	utrd_header_t *hd;
+	int i;
+
+	hd = (utrd_header_t *)utrd->header;
+	INFO("utrd:0x%x, ruo:0x%x, rul:0x%x, ocs:0x%x, UTRLDBR:0x%x\n",
+		(unsigned int)(uintptr_t)utrd, hd->ruo, hd->rul, hd->ocs,
+		mmio_read_32(ufs_params.reg_base + UTRLDBR));
+	for (i = 0; i < sizeof(utrd_header_t); i += 4) {
+		INFO("[%lx]:0x%x\n",
+			(uintptr_t)utrd->header + i,
+			*(unsigned int *)((uintptr_t)utrd->header + i));
+	}
+
+	for (i = 0; i < sizeof(cmd_upiu_t); i += 4) {
+		INFO("cmd[%lx]:0x%x\n",
+			utrd->upiu + i,
+			*(unsigned int *)(utrd->upiu + i));
+	}
+	for (i = 0; i < sizeof(resp_upiu_t); i += 4) {
+		INFO("resp[%lx]:0x%x\n",
+			utrd->resp_upiu + i,
+			*(unsigned int *)(utrd->resp_upiu + i));
+	}
+	for (i = 0; i < sizeof(prdt_t); i += 4) {
+		INFO("prdt[%lx]:0x%x\n",
+			utrd->prdt + i,
+			*(unsigned int *)(utrd->prdt + i));
+	}
+}
+#endif
+
+static void ufs_verify_init(void)
+{
+	utp_utrd_t utrd;
+	int result;
+
+	get_utrd(&utrd);
+	ufs_prepare_nop_out(&utrd);
+	ufs_send_request(utrd.task_tag);
+	result = ufs_check_resp(&utrd, NOP_IN_UPIU);
+	assert(result == 0);
+	(void)result;
+}
+
+static void ufs_verify_ready(void)
+{
+	utp_utrd_t utrd;
+	int result;
+
+	get_utrd(&utrd);
+	ufs_prepare_cmd(&utrd, CDBCMD_TEST_UNIT_READY, 0, 0, 0, 0);
+	ufs_send_request(utrd.task_tag);
+	result = ufs_check_resp(&utrd, RESPONSE_UPIU);
+	assert(result == 0);
+	(void)result;
+}
+
+static void ufs_query(uint8_t op, uint8_t idn, uint8_t index, uint8_t sel,
+		      uintptr_t buf, size_t size)
+{
+	utp_utrd_t utrd;
+	query_resp_upiu_t *resp;
+	int result;
+
+	switch (op) {
+	case QUERY_READ_FLAG:
+	case QUERY_READ_ATTR:
+	case QUERY_READ_DESC:
+	case QUERY_WRITE_DESC:
+	case QUERY_WRITE_ATTR:
+		assert(((buf & 3) == 0) && (size != 0));
+		break;
+	}
+	get_utrd(&utrd);
+	ufs_prepare_query(&utrd, op, idn, index, sel, buf, size);
+	ufs_send_request(utrd.task_tag);
+	result = ufs_check_resp(&utrd, QUERY_RESPONSE_UPIU);
+	assert(result == 0);
+	resp = (query_resp_upiu_t *)utrd.resp_upiu;
+#ifdef UFS_RESP_DEBUG
+	dump_upiu(&utrd);
+#endif
+	assert(resp->query_resp == QUERY_RESP_SUCCESS);
+
+	switch (op) {
+	case QUERY_READ_FLAG:
+		*(uint32_t *)buf = (uint32_t)resp->ts.flag.value;
+		break;
+	case QUERY_READ_ATTR:
+	case QUERY_READ_DESC:
+		memcpy((void *)buf,
+		       (void *)(utrd.resp_upiu + sizeof(query_resp_upiu_t)),
+		       size);
+		break;
+	}
+	(void)result;
+}
+
+unsigned int ufs_read_attr(int idn)
+{
+	unsigned int value;
+
+	ufs_query(QUERY_READ_ATTR, idn, 0, 0,
+		  (uintptr_t)&value, sizeof(value));
+	return value;
+}
+
+void ufs_write_attr(int idn, unsigned int value)
+{
+	ufs_query(QUERY_WRITE_ATTR, idn, 0, 0,
+		  (uintptr_t)&value, sizeof(value));
+}
+
+unsigned int ufs_read_flag(int idn)
+{
+	unsigned int value;
+
+	ufs_query(QUERY_READ_FLAG, idn, 0, 0,
+		  (uintptr_t)&value, sizeof(value));
+	return value;
+}
+
+void ufs_set_flag(int idn)
+{
+	ufs_query(QUERY_SET_FLAG, idn, 0, 0, 0, 0);
+}
+
+void ufs_clear_flag(int idn)
+{
+	ufs_query(QUERY_CLEAR_FLAG, idn, 0, 0, 0, 0);
+}
+
+void ufs_read_desc(int idn, int index, uintptr_t buf, size_t size)
+{
+	ufs_query(QUERY_READ_DESC, idn, index, 0, buf, size);
+}
+
+void ufs_write_desc(int idn, int index, uintptr_t buf, size_t size)
+{
+	ufs_query(QUERY_WRITE_DESC, idn, index, 0, buf, size);
+}
+
+void ufs_read_capacity(int lun, unsigned int *num, unsigned int *size)
+{
+	utp_utrd_t utrd;
+	resp_upiu_t *resp;
+	sense_data_t *sense;
+	unsigned char data[CACHE_WRITEBACK_GRANULE << 1];
+	uintptr_t buf;
+	int result;
+	int retry;
+
+	assert((ufs_params.reg_base != 0) &&
+	       (ufs_params.desc_base != 0) &&
+	       (ufs_params.desc_size >= UFS_DESC_SIZE) &&
+	       (num != NULL) && (size != NULL));
+
+	/* align buf address */
+	buf = (uintptr_t)data;
+	buf = (buf + CACHE_WRITEBACK_GRANULE - 1) &
+	      ~(CACHE_WRITEBACK_GRANULE - 1);
+	memset((void *)buf, 0, CACHE_WRITEBACK_GRANULE);
+	flush_dcache_range(buf, CACHE_WRITEBACK_GRANULE);
+	do {
+		get_utrd(&utrd);
+		ufs_prepare_cmd(&utrd, CDBCMD_READ_CAPACITY_10, lun, 0,
+				buf, READ_CAPACITY_LENGTH);
+		ufs_send_request(utrd.task_tag);
+		result = ufs_check_resp(&utrd, RESPONSE_UPIU);
+		assert(result == 0);
+#ifdef UFS_RESP_DEBUG
+		dump_upiu(&utrd);
+#endif
+		resp = (resp_upiu_t *)utrd.resp_upiu;
+		retry = 0;
+		sense = &resp->sd.sense;
+		if (sense->resp_code == SENSE_DATA_VALID) {
+			if ((sense->sense_key == SENSE_KEY_UNIT_ATTENTION) &&
+			    (sense->asc == 0x29) && (sense->ascq == 0)) {
+				retry = 1;
+			}
+		}
+		inv_dcache_range(buf, CACHE_WRITEBACK_GRANULE);
+		/* last logical block address */
+		*num = be32toh(*(unsigned int *)buf);
+		if (*num)
+			*num += 1;
+		/* logical block length in bytes */
+		*size = be32toh(*(unsigned int *)(buf + 4));
+	} while (retry);
+	(void)result;
+}
+
+size_t ufs_read_blocks(int lun, int lba, uintptr_t buf, size_t size)
+{
+	utp_utrd_t utrd;
+	resp_upiu_t *resp;
+	int result;
+
+	assert((ufs_params.reg_base != 0) &&
+	       (ufs_params.desc_base != 0) &&
+	       (ufs_params.desc_size >= UFS_DESC_SIZE));
+
+	memset((void *)buf, 0, size);
+	get_utrd(&utrd);
+	ufs_prepare_cmd(&utrd, CDBCMD_READ_10, lun, lba, buf, size);
+	ufs_send_request(utrd.task_tag);
+	result = ufs_check_resp(&utrd, RESPONSE_UPIU);
+	assert(result == 0);
+#ifdef UFS_RESP_DEBUG
+	dump_upiu(&utrd);
+#endif
+	resp = (resp_upiu_t *)utrd.resp_upiu;
+	(void)result;
+	return size - resp->res_trans_cnt;
+}
+
+size_t ufs_write_blocks(int lun, int lba, const uintptr_t buf, size_t size)
+{
+	utp_utrd_t utrd;
+	resp_upiu_t *resp;
+	int result;
+
+	assert((ufs_params.reg_base != 0) &&
+	       (ufs_params.desc_base != 0) &&
+	       (ufs_params.desc_size >= UFS_DESC_SIZE));
+
+	memset((void *)buf, 0, size);
+	get_utrd(&utrd);
+	ufs_prepare_cmd(&utrd, CDBCMD_WRITE_10, lun, lba, buf, size);
+	ufs_send_request(utrd.task_tag);
+	result = ufs_check_resp(&utrd, RESPONSE_UPIU);
+	assert(result == 0);
+#ifdef UFS_RESP_DEBUG
+	dump_upiu(&utrd);
+#endif
+	resp = (resp_upiu_t *)utrd.resp_upiu;
+	(void)result;
+	return size - resp->res_trans_cnt;
+}
+
+static void ufs_enum(void)
+{
+	unsigned int blk_num, blk_size;
+	int i;
+
+	/* 0 means 1 slot */
+	nutrs = (mmio_read_32(ufs_params.reg_base + CAP) & CAP_NUTRS_MASK) + 1;
+	if (nutrs > (ufs_params.desc_size / UFS_DESC_SIZE))
+		nutrs = ufs_params.desc_size / UFS_DESC_SIZE;
+
+	ufs_verify_init();
+	ufs_verify_ready();
+
+	ufs_set_flag(FLAG_DEVICE_INIT);
+	mdelay(100);
+	/* dump available LUNs */
+	for (i = 0; i < UFS_MAX_LUNS; i++) {
+		ufs_read_capacity(i, &blk_num, &blk_size);
+		if (blk_num && blk_size) {
+			INFO("UFS LUN%d contains %d blocks with %d-byte size\n",
+			     i, blk_num, blk_size);
+		}
+	}
+}
+
+int ufs_init(const ufs_ops_t *ops, ufs_params_t *params)
+{
+	int result;
+	unsigned int data;
+	uic_cmd_t cmd;
+
+	assert((params != NULL) &&
+	       (params->reg_base != 0) &&
+	       (params->desc_base != 0) &&
+	       (params->desc_size >= UFS_DESC_SIZE));
+
+	memcpy(&ufs_params, params, sizeof(ufs_params_t));
+
+	if (ufs_params.flags & UFS_FLAGS_SKIPINIT) {
+		result = ufshc_dme_get(0x1571, 0, &data);
+		assert(result == 0);
+		result = ufshc_dme_get(0x41, 0, &data);
+		assert(result == 0);
+		if (data == 1) {
+			/* prepare to exit hibernate mode */
+			memset(&cmd, 0, sizeof(uic_cmd_t));
+			cmd.op = DME_HIBERNATE_EXIT;
+			result = ufshc_send_uic_cmd(ufs_params.reg_base,
+						    &cmd);
+			assert(result == 0);
+			data = mmio_read_32(ufs_params.reg_base + UCMDARG2);
+			assert(data == 0);
+			do {
+				data = mmio_read_32(ufs_params.reg_base + IS);
+			} while ((data & UFS_INT_UHXS) == 0);
+			mmio_write_32(ufs_params.reg_base + IS, UFS_INT_UHXS);
+			data = mmio_read_32(ufs_params.reg_base + HCS);
+			assert((data & HCS_UPMCRS_MASK) == HCS_PWR_LOCAL);
+		}
+		result = ufshc_dme_get(0x1568, 0, &data);
+		assert(result == 0);
+		assert((data > 0) && (data <= 3));
+	} else {
+		assert((ops != NULL) && (ops->phy_init != NULL) &&
+		       (ops->phy_set_pwr_mode != NULL));
+
+		ufshc_reset(ufs_params.reg_base);
+		ops->phy_init(&ufs_params);
+		result = ufshc_link_startup(ufs_params.reg_base);
+		assert(result == 0);
+		ops->phy_set_pwr_mode(&ufs_params);
+	}
+
+	ufs_enum();
+	(void)result;
+	return 0;
+}
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/common/debug.h b/include/common/debug.h
index 646daba..814cf84 100644
--- a/include/common/debug.h
+++ b/include/common/debug.h
@@ -64,6 +64,7 @@
 void __dead2 __stack_chk_fail(void);
 
 void tf_printf(const char *fmt, ...) __printflike(1, 2);
+int tf_snprintf(char *s, size_t n, const char *fmt, ...) __printflike(3, 4);
 
 #endif /* __ASSEMBLY__ */
 #endif /* __DEBUG_H__ */
diff --git a/include/drivers/auth/mbedtls/mbedtls_config.h b/include/drivers/auth/mbedtls/mbedtls_config.h
index 7d8d17c..0a05886 100644
--- a/include/drivers/auth/mbedtls/mbedtls_config.h
+++ b/include/drivers/auth/mbedtls/mbedtls_config.h
@@ -19,13 +19,18 @@
 
 #define MBEDTLS_PLATFORM_MEMORY
 #define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+/* 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/drivers/dw_ufs.h b/include/drivers/dw_ufs.h
new file mode 100644
index 0000000..b05c7f5
--- /dev/null
+++ b/include/drivers/dw_ufs.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __DW_UFS_H__
+#define __DW_UFS_H__
+
+#include <sys/types.h>
+
+/* Bus Throtting */
+#define BUSTHRTL				0xC0
+/* Outstanding OCP Requests */
+#define OOCPR					0xC4
+/* Fatal Error Interrupt Enable */
+#define FEIE					0xC8
+/* C-Port Direct Access Configuration register */
+#define CDACFG					0xD0
+/* C-Port Direct Access Transmit 1 register */
+#define CDATX1					0xD4
+/* C-Port Direct Access Transmit 2 register */
+#define CDATX2					0xD8
+/* C-Port Direct Access Receive 1 register */
+#define CDARX1					0xDC
+/* C-Port Direct Access Receive 2 register */
+#define CDARX2					0xE0
+/* C-Port Direct Access Status register */
+#define CDASTA					0xE4
+/* UPIU Loopback Configuration register */
+#define LBMCFG					0xF0
+/* UPIU Loopback Status */
+#define LBMSTA					0xF4
+/* Debug register */
+#define DBG					0xF8
+/* HClk Divider register */
+#define HCLKDIV					0xFC
+
+#define TX_HIBERN8TIME_CAP_OFFSET		0x000F
+#define TX_FSM_STATE_OFFSET			0x0041
+#define TX_FSM_STATE_LINE_RESET			7
+#define TX_FSM_STATE_LINE_CFG			6
+#define TX_FSM_STATE_HS_BURST			5
+#define TX_FSM_STATE_LS_BURST			4
+#define TX_FSM_STATE_STALL			3
+#define TX_FSM_STATE_SLEEP			2
+#define TX_FSM_STATE_HIBERN8			1
+#define TX_FSM_STATE_DISABLE			0
+
+#define RX_MIN_ACTIVATETIME_CAP_OFFSET		0x008F
+#define RX_HS_G2_SYNC_LENGTH_CAP_OFFSET		0x0094
+#define RX_HS_G3_SYNC_LENGTH_CAP_OFFSET		0x0095
+
+#define PA_AVAIL_TX_DATA_LANES_OFFSET		0x1520
+#define PA_TX_SKIP_OFFSET			0x155C
+#define PA_TX_SKIP_PERIOD_OFFSET		0x155D
+#define PA_LOCAL_TX_LCC_ENABLE_OFFSET		0x155E
+#define PA_ACTIVE_TX_DATA_LANES_OFFSET		0x1560
+#define PA_CONNECTED_TX_DATA_LANES_OFFSET	0x1561
+#define PA_TX_TRAILING_CLOCKS_OFFSET		0x1564
+#define PA_TX_GEAR_OFFSET			0x1568
+#define PA_TX_TERMINATION_OFFSET		0x1569
+#define PA_HS_SERIES_OFFSET			0x156A
+#define PA_PWR_MODE_OFFSET			0x1571
+#define PA_ACTIVE_RX_DATA_LANES_OFFSET		0x1580
+#define PA_CONNECTED_RX_DATA_LANES_OFFSET	0x1581
+#define PA_RX_PWR_STATUS_OFFSET			0x1582
+#define PA_RX_GEAR_OFFSET			0x1583
+#define PA_RX_TERMINATION_OFFSET		0x1584
+#define PA_SCRAMBLING_OFFSET			0x1585
+#define PA_MAX_RX_PWM_GEAR_OFFSET		0x1586
+#define PA_MAX_RX_HS_GEAR_OFFSET		0x1587
+#define PA_PACP_REQ_TIMEOUT_OFFSET		0x1590
+#define PA_PACP_REQ_EOB_TIMEOUT_OFFSET		0x1591
+#define PA_REMOTE_VER_INFO_OFFSET		0x15A0
+#define PA_LOGICAL_LANE_MAP_OFFSET		0x15A1
+#define PA_TACTIVATE_OFFSET			0x15A8
+#define PA_PWR_MODE_USER_DATA0_OFFSET		0x15B0
+#define PA_PWR_MODE_USER_DATA1_OFFSET		0x15B1
+#define PA_PWR_MODE_USER_DATA2_OFFSET		0x15B2
+#define PA_PWR_MODE_USER_DATA3_OFFSET		0x15B3
+#define PA_PWR_MODE_USER_DATA4_OFFSET		0x15B4
+#define PA_PWR_MODE_USER_DATA5_OFFSET		0x15B5
+
+#define DL_TC0_TX_FC_THRESHOLD_OFFSET		0x2040
+#define DL_AFC0_CREDIT_THRESHOLD_OFFSET		0x2044
+#define DL_TC0_OUT_ACK_THRESHOLD_OFFSET		0x2045
+
+#define DME_FC0_PROTECTION_TIMEOUT_OFFSET	0xD041
+#define DME_TC0_REPLAY_TIMEOUT_OFFSET		0xD042
+#define DME_AFC0_REQ_TIMEOUT_OFFSET		0xD043
+#define DME_FC1_PROTECTION_TIMEOUT_OFFSET	0xD044
+#define DME_TC1_REPLAY_TIMEOUT_OFFSET		0xD045
+#define DME_AFC1_REQ_TIMEOUT_OFFSET		0xD046
+
+#define VS_MPHY_CFG_UPDT_OFFSET			0xD085
+#define VS_MK2_EXTN_SUPPORT_OFFSET		0xD0AB
+#define VS_MPHY_DISABLE_OFFSET			0xD0C1
+#define VS_MPHY_DISABLE_MPHYDIS			(1 << 0)
+
+typedef struct dw_ufs_params {
+	uintptr_t		reg_base;
+	uintptr_t		desc_base;
+	size_t			desc_size;
+	unsigned long		flags;
+} dw_ufs_params_t;
+
+int dw_ufs_init(dw_ufs_params_t *params);
+
+#endif /* __DW_UFS_H__ */
diff --git a/include/drivers/ufs.h b/include/drivers/ufs.h
new file mode 100644
index 0000000..3a4f1c7
--- /dev/null
+++ b/include/drivers/ufs.h
@@ -0,0 +1,529 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __UFS_H__
+#define __UFS_H__
+
+/* register map of UFSHCI */
+/* Controller Capabilities */
+#define CAP				0x00
+#define CAP_NUTRS_MASK			0x1F
+
+/* UFS Version */
+#define VER				0x08
+/* Host Controller Identification - Product ID */
+#define HCDDID				0x10
+/* Host Controller Identification Descriptor - Manufacturer ID */
+#define HCPMID				0x14
+/* Auto-Hibernate Idle Timer */
+#define AHIT				0x18
+/* Interrupt Status */
+#define IS				0x20
+/* Interrupt Enable */
+#define IE				0x24
+/* System Bus Fatal Error Status */
+#define UFS_INT_SBFES			(1 << 17)
+/* Host Controller Fatal Error Status */
+#define UFS_INT_HCFES			(1 << 16)
+/* UTP Error Status */
+#define UFS_INT_UTPES			(1 << 12)
+/* Device Fatal Error Status */
+#define UFS_INT_DFES			(1 << 11)
+/* UIC Command Completion Status */
+#define UFS_INT_UCCS			(1 << 10)
+/* UTP Task Management Request Completion Status */
+#define UFS_INT_UTMRCS			(1 << 9)
+/* UIC Link Startup Status */
+#define UFS_INT_ULSS			(1 << 8)
+/* UIC Link Lost Status */
+#define UFS_INT_ULLS			(1 << 7)
+/* UIC Hibernate Enter Status */
+#define UFS_INT_UHES			(1 << 6)
+/* UIC Hibernate Exit Status */
+#define UFS_INT_UHXS			(1 << 5)
+/* UIC Power Mode Status */
+#define UFS_INT_UPMS			(1 << 4)
+/* UIC Test Mode Status */
+#define UFS_INT_UTMS			(1 << 3)
+/* UIC Error */
+#define UFS_INT_UE			(1 << 2)
+/* UIC DME_ENDPOINTRESET Indication */
+#define UFS_INT_UDEPRI			(1 << 1)
+/* UTP Transfer Request Completion Status */
+#define UFS_INT_UTRCS			(1 << 0)
+
+/* Host Controller Status */
+#define HCS				0x30
+#define HCS_UPMCRS_MASK			(7 << 8)
+#define HCS_PWR_LOCAL			(1 << 8)
+#define HCS_UCRDY			(1 << 3)
+#define HCS_UTMRLRDY			(1 << 2)
+#define HCS_UTRLRDY			(1 << 1)
+#define HCS_DP				(1 << 0)
+
+/* Host Controller Enable */
+#define HCE				0x34
+#define HCE_ENABLE			1
+
+/* Host UIC Error Code PHY Adapter Layer */
+#define UECPA				0x38
+/* Host UIC Error Code Data Link Layer */
+#define UECDL				0x3C
+/* Host UIC Error Code Network Layer */
+#define UECN				0x40
+/* Host UIC Error Code Transport Layer */
+#define UECT				0x44
+/* Host UIC Error Code */
+#define UECDME				0x48
+/* UTP Transfer Request Interrupt Aggregation Control Register */
+#define UTRIACR				0x4C
+#define UTRIACR_IAEN			(1 << 31)
+#define UTRIACR_IAPWEN			(1 << 24)
+#define UTRIACR_IASB			(1 << 20)
+#define UTRIACR_CTR			(1 << 16)
+#define UTRIACR_IACTH(x)		(((x) & 0x1F) << 8)
+#define UTRIACR_IATOVAL(x)		((x) & 0xFF)
+
+/* UTP Transfer Request List Base Address */
+#define UTRLBA				0x50
+/* UTP Transfer Request List Base Address Upper 32-bits */
+#define UTRLBAU				0x54
+/* UTP Transfer Request List Door Bell Register */
+#define UTRLDBR				0x58
+/* UTP Transfer Request List Clear Register */
+#define UTRLCLR				0x5C
+/* UTP Transfer Request List Run Stop Register */
+#define UTRLRSR				0x60
+#define UTMRLBA				0x70
+#define UTMRLBAU			0x74
+#define UTMRLDBR			0x78
+#define UTMRLCLR			0x7C
+#define UTMRLRSR			0x80
+/* UIC Command */
+#define UICCMD				0x90
+/* UIC Command Argument 1 */
+#define UCMDARG1			0x94
+/* UIC Command Argument 2 */
+#define UCMDARG2			0x98
+/* UIC Command Argument 3 */
+#define UCMDARG3			0x9C
+
+#define UFS_BLOCK_SHIFT			12		/* 4KB */
+#define UFS_BLOCK_SIZE			(1 << UFS_BLOCK_SHIFT)
+#define UFS_BLOCK_MASK			(UFS_BLOCK_SIZE - 1)
+#define UFS_MAX_LUNS			8
+
+/* UTP Transfer Request Descriptor */
+/* Command Type */
+#define CT_UFS_STORAGE			1
+#define CT_SCSI				0
+
+/* Data Direction */
+#define DD_OUT				2		/* Device --> Host */
+#define DD_IN				1		/* Host --> Device */
+#define DD_NO_DATA_TRANSFER		0
+
+#define UTP_TRD_SIZE			32
+
+/* Transaction Type */
+#define TRANS_TYPE_HD			(1 << 7)	/* E2ECRC */
+#define TRANS_TYPE_DD			(1 << 6)
+#define TRANS_TYPE_CODE_MASK		0x3F
+#define QUERY_RESPONSE_UPIU		(0x36 << 0)
+#define READY_TO_TRANSACTION_UPIU	(0x31 << 0)
+#define DATA_IN_UPIU			(0x22 << 0)
+#define RESPONSE_UPIU			(0x21 << 0)
+#define NOP_IN_UPIU			(0x20 << 0)
+#define QUERY_REQUEST_UPIU		(0x16 << 0)
+#define DATA_OUT_UPIU			(0x02 << 0)
+#define CMD_UPIU			(0x01 << 0)
+#define NOP_OUT_UPIU			(0x00 << 0)
+
+#define OCS_SUCCESS			0x0
+#define OCS_INVALID_FUNC_ATTRIBUTE	0x1
+#define OCS_MISMATCH_REQUEST_SIZE	0x2
+#define OCS_MISMATCH_RESPONSE_SIZE	0x3
+#define OCS_PEER_COMMUNICATION_FAILURE	0x4
+#define OCS_ABORTED			0x5
+#define OCS_FATAL_ERROR			0x6
+#define OCS_MASK			0xF
+
+/* UIC Command */
+#define DME_GET				0x01
+#define DME_SET				0x02
+#define DME_PEER_GET			0x03
+#define DME_PEER_SET			0x04
+#define DME_POWERON			0x10
+#define DME_POWEROFF			0x11
+#define DME_ENABLE			0x12
+#define DME_RESET			0x14
+#define DME_ENDPOINTRESET		0x15
+#define DME_LINKSTARTUP			0x16
+#define DME_HIBERNATE_ENTER		0x17
+#define DME_HIBERNATE_EXIT		0x18
+#define DME_TEST_MODE			0x1A
+
+#define GEN_SELECTOR_IDX(x)		((x) & 0xFFFF)
+
+#define CONFIG_RESULT_CODE_MASK		0xFF
+
+#define CDBCMD_TEST_UNIT_READY		0x00
+#define CDBCMD_READ_6			0x08
+#define CDBCMD_WRITE_6			0x0A
+#define CDBCMD_START_STOP_UNIT		0x1B
+#define CDBCMD_READ_CAPACITY_10		0x25
+#define CDBCMD_READ_10			0x28
+#define CDBCMD_WRITE_10			0x2A
+#define CDBCMD_READ_16			0x88
+#define CDBCMD_WRITE_16			0x8A
+#define CDBCMD_READ_CAPACITY_16		0x9E
+#define CDBCMD_REPORT_LUNS		0xA0
+
+#define UPIU_FLAGS_R			(1 << 6)
+#define UPIU_FLAGS_W			(1 << 5)
+#define UPIU_FLAGS_ATTR_MASK		(3 << 0)
+#define UPIU_FLAGS_ATTR_S		(0 << 0)	/* Simple */
+#define UPIU_FLAGS_ATTR_O		(1 << 0)	/* Ordered */
+#define UPIU_FLAGS_ATTR_HQ		(2 << 0)	/* Head of Queue */
+#define UPIU_FLAGS_ATTR_ACA		(3 << 0)
+#define UPIU_FLAGS_O			(1 << 6)
+#define UPIU_FLAGS_U			(1 << 5)
+#define UPIU_FLAGS_D			(1 << 4)
+
+#define QUERY_FUNC_STD_READ		0x01
+#define QUERY_FUNC_STD_WRITE		0x81
+
+#define QUERY_NOP			0x00
+#define QUERY_READ_DESC			0x01
+#define QUERY_WRITE_DESC		0x02
+#define QUERY_READ_ATTR			0x03
+#define QUERY_WRITE_ATTR		0x04
+#define QUERY_READ_FLAG			0x05
+#define QUERY_SET_FLAG			0x06
+#define QUERY_CLEAR_FLAG		0x07
+#define QUERY_TOGGLE_FLAG		0x08
+
+#define RW_WITHOUT_CACHE		0x18
+
+#define DESC_TYPE_DEVICE		0x00
+#define DESC_TYPE_CONFIGURATION		0x01
+#define DESC_TYPE_UNIT			0x02
+#define DESC_TYPE_INTERCONNECT		0x04
+#define DESC_TYPE_STRING		0x05
+
+#define ATTR_CUR_PWR_MODE		0x02	/* bCurrentPowerMode */
+#define ATTR_ACTIVECC			0x03	/* bActiveICCLevel */
+
+#define DEVICE_DESCRIPTOR_LEN		0x40
+#define UNIT_DESCRIPTOR_LEN		0x23
+
+#define QUERY_RESP_SUCCESS		0x00
+#define QUERY_RESP_OPCODE		0xFE
+#define QUERY_RESP_GENERAL_FAIL		0xFF
+
+#define SENSE_KEY_NO_SENSE		0x00
+#define SENSE_KEY_RECOVERED_ERROR	0x01
+#define SENSE_KEY_NOT_READY		0x02
+#define SENSE_KEY_MEDIUM_ERROR		0x03
+#define SENSE_KEY_HARDWARE_ERROR	0x04
+#define SENSE_KEY_ILLEGAL_REQUEST	0x05
+#define SENSE_KEY_UNIT_ATTENTION	0x06
+#define SENSE_KEY_DATA_PROTECT		0x07
+#define SENSE_KEY_BLANK_CHECK		0x08
+#define SENSE_KEY_VENDOR_SPECIFIC	0x09
+#define SENSE_KEY_COPY_ABORTED		0x0A
+#define SENSE_KEY_ABORTED_COMMAND	0x0B
+#define SENSE_KEY_VOLUME_OVERFLOW	0x0D
+#define SENSE_KEY_MISCOMPARE		0x0E
+
+#define SENSE_DATA_VALID		0x70
+#define SENSE_DATA_LENGTH		18
+
+#define READ_CAPACITY_LENGTH		8
+
+#define FLAG_DEVICE_INIT		0x01
+
+/* UFS Driver Flags */
+#define UFS_FLAGS_SKIPINIT		(1 << 0)
+
+typedef struct sense_data {
+	uint8_t		resp_code : 7;
+	uint8_t		valid : 1;
+	uint8_t		reserved0;
+	uint8_t		sense_key : 4;
+	uint8_t		reserved1 : 1;
+	uint8_t		ili : 1;
+	uint8_t		eom : 1;
+	uint8_t		file_mark : 1;
+	uint8_t		info[4];
+	uint8_t		asl;
+	uint8_t		cmd_spec_len[4];
+	uint8_t		asc;
+	uint8_t		ascq;
+	uint8_t		fruc;
+	uint8_t		sense_key_spec0 : 7;
+	uint8_t		sksv : 1;
+	uint8_t		sense_key_spec1;
+	uint8_t		sense_key_spec2;
+} sense_data_t;
+
+/* UTP Transfer Request Descriptor */
+typedef struct utrd_header {
+	uint32_t	reserved0 : 24;
+	uint32_t	i : 1;		/* interrupt */
+	uint32_t	dd : 2;		/* data direction */
+	uint32_t	reserved1 : 1;
+	uint32_t	ct : 4;		/* command type */
+	uint32_t	reserved2;
+	uint32_t	ocs : 8;	/* Overall Command Status */
+	uint32_t	reserved3 : 24;
+	uint32_t	reserved4;
+	uint32_t	ucdba;		/* aligned to 128-byte */
+	uint32_t	ucdbau;		/* Upper 32-bits */
+	uint32_t	rul : 16;	/* Response UPIU Length */
+	uint32_t	ruo : 16;	/* Response UPIU Offset */
+	uint32_t	prdtl : 16;	/* PRDT Length */
+	uint32_t	prdto : 16;	/* PRDT Offset */
+} utrd_header_t;	/* 8 words with little endian */
+
+/* UTP Task Management Request Descriptor */
+typedef struct utp_utmrd {
+	/* 4 words with little endian */
+	uint32_t	reserved0 : 24;
+	uint32_t	i : 1;		/* interrupt */
+	uint32_t	reserved1 : 7;
+	uint32_t	reserved2;
+	uint32_t	ocs : 8;	/* Overall Command Status */
+	uint32_t	reserved3 : 24;
+	uint32_t	reserved4;
+
+	/* followed by 8 words UPIU with big endian */
+
+	/* followed by 8 words Response UPIU with big endian */
+} utp_utmrd_t;
+
+/* NOP OUT UPIU */
+typedef struct nop_out_upiu {
+	uint8_t		trans_type;
+	uint8_t		flags;
+	uint8_t		reserved0;
+	uint8_t		task_tag;
+	uint8_t		reserved1;
+	uint8_t		reserved2;
+	uint8_t		reserved3;
+	uint8_t		reserved4;
+	uint8_t		total_ehs_len;
+	uint8_t		reserved5;
+	uint16_t	data_segment_len;
+	uint32_t	reserved6;
+	uint32_t	reserved7;
+	uint32_t	reserved8;
+	uint32_t	reserved9;
+	uint32_t	reserved10;
+	uint32_t	e2ecrc;
+} nop_out_upiu_t;	/* 36 bytes with big endian */
+
+/* NOP IN UPIU */
+typedef struct nop_in_upiu {
+	uint8_t		trans_type;
+	uint8_t		flags;
+	uint8_t		reserved0;
+	uint8_t		task_tag;
+	uint8_t		reserved1;
+	uint8_t		reserved2;
+	uint8_t		response;
+	uint8_t		reserved3;
+	uint8_t		total_ehs_len;
+	uint8_t		dev_info;
+	uint16_t	data_segment_len;
+	uint32_t	reserved4;
+	uint32_t	reserved5;
+	uint32_t	reserved6;
+	uint32_t	reserved7;
+	uint32_t	reserved8;
+	uint32_t	e2ecrc;
+} nop_in_upiu_t;	/* 36 bytes with big endian */
+
+/* Command UPIU */
+typedef struct cmd_upiu {
+	uint8_t		trans_type;
+	uint8_t		flags;
+	uint8_t		lun;
+	uint8_t		task_tag;
+	uint8_t		cmd_set_type;
+	uint8_t		reserved0;
+	uint8_t		reserved1;
+	uint8_t		reserved2;
+	uint8_t		total_ehs_len;
+	uint8_t		reserved3;
+	uint16_t	data_segment_len;
+	uint32_t	exp_data_trans_len;
+	/*
+	 * A CDB has a fixed length of 16bytes or a variable length
+	 * of between 12 and 260 bytes
+	 */
+	uint8_t		cdb[16];	/* little endian */
+} cmd_upiu_t;	/* 32 bytes with big endian except for cdb[] */
+
+typedef struct query_desc {
+	uint8_t		opcode;
+	uint8_t		idn;
+	uint8_t		index;
+	uint8_t		selector;
+	uint8_t		reserved0[2];
+	uint16_t	length;
+	uint32_t	reserved2[2];
+} query_desc_t;		/* 16 bytes with big endian */
+
+typedef struct query_flag {
+	uint8_t		opcode;
+	uint8_t		idn;
+	uint8_t		index;
+	uint8_t		selector;
+	uint8_t		reserved0[7];
+	uint8_t		value;
+	uint32_t	reserved8;
+} query_flag_t;		/* 16 bytes with big endian */
+
+typedef struct query_attr {
+	uint8_t		opcode;
+	uint8_t		idn;
+	uint8_t		index;
+	uint8_t		selector;
+	uint8_t		reserved0[4];
+	uint32_t	value;	/* little endian */
+	uint32_t	reserved4;
+} query_attr_t;		/* 16 bytes with big endian except for value */
+
+/* Query Request UPIU */
+typedef struct query_upiu {
+	uint8_t		trans_type;
+	uint8_t		flags;
+	uint8_t		reserved0;
+	uint8_t		task_tag;
+	uint8_t		reserved1;
+	uint8_t		query_func;
+	uint8_t		reserved2;
+	uint8_t		reserved3;
+	uint8_t		total_ehs_len;
+	uint8_t		reserved4;
+	uint16_t	data_segment_len;
+	/* Transaction Specific Fields */
+	union {
+		query_desc_t	desc;
+		query_flag_t	flag;
+		query_attr_t	attr;
+	} ts;
+	uint32_t	reserved5;
+} query_upiu_t; /* 32 bytes with big endian */
+
+/* Query Response UPIU */
+typedef struct query_resp_upiu {
+	uint8_t		trans_type;
+	uint8_t		flags;
+	uint8_t		reserved0;
+	uint8_t		task_tag;
+	uint8_t		reserved1;
+	uint8_t		query_func;
+	uint8_t		query_resp;
+	uint8_t		reserved2;
+	uint8_t		total_ehs_len;
+	uint8_t		dev_info;
+	uint16_t	data_segment_len;
+	union {
+		query_desc_t	desc;
+		query_flag_t	flag;
+		query_attr_t	attr;
+	} ts;
+	uint32_t	reserved3;
+} query_resp_upiu_t;	/* 32 bytes with big endian */
+
+/* Response UPIU */
+typedef struct resp_upiu {
+	uint8_t		trans_type;
+	uint8_t		flags;
+	uint8_t		lun;
+	uint8_t		task_tag;
+	uint8_t		cmd_set_type;
+	uint8_t		reserved0;
+	uint8_t		reserved1;
+	uint8_t		status;
+	uint8_t		total_ehs_len;
+	uint8_t		dev_info;
+	uint16_t	data_segment_len;
+	uint32_t	res_trans_cnt;	/* Residual Transfer Count */
+	uint32_t	reserved2[4];
+	uint16_t	sense_data_len;
+	union {
+		uint8_t		sense_data[18];
+		sense_data_t	sense;
+	} sd;
+} resp_upiu_t;		/* 52 bytes with big endian */
+
+typedef struct cmd_info {
+	uintptr_t	buf;
+	size_t		length;
+	int		lba;
+	uint8_t		op;
+	uint8_t		direction;
+	uint8_t		lun;
+} cmd_info_t;
+
+typedef struct utp_utrd {
+	uintptr_t	header;		/* utrd_header_t */
+	uintptr_t	upiu;
+	uintptr_t	resp_upiu;
+	uintptr_t	prdt;
+	size_t		size_upiu;
+	size_t		size_resp_upiu;
+	size_t		size_prdt;
+	int		task_tag;
+} utp_utrd_t;
+
+/* Physical Region Description Table */
+typedef struct prdt {
+	uint32_t	dba;		/* Data Base Address */
+	uint32_t	dbau;		/* Data Base Address Upper 32-bits */
+	uint32_t	reserved0;
+	uint32_t	dbc : 18;	/* Data Byte Count */
+	uint32_t	reserved1 : 14;
+} prdt_t;
+
+typedef struct uic_cmd {
+	uint32_t	op;
+	uint32_t	arg1;
+	uint32_t	arg2;
+	uint32_t	arg3;
+} uic_cmd_t;
+
+typedef struct ufs_params {
+	uintptr_t	reg_base;
+	uintptr_t	desc_base;
+	size_t		desc_size;
+	unsigned long	flags;
+} ufs_params_t;
+
+typedef struct ufs_ops {
+	int		(*phy_init)(ufs_params_t *params);
+	int		(*phy_set_pwr_mode)(ufs_params_t *params);
+} ufs_ops_t;
+
+int ufshc_send_uic_cmd(uintptr_t base, uic_cmd_t *cmd);
+int ufshc_dme_get(unsigned int attr, unsigned int idx, unsigned int *val);
+int ufshc_dme_set(unsigned int attr, unsigned int idx, unsigned int val);
+
+unsigned int ufs_read_attr(int idn);
+void ufs_write_attr(int idn, unsigned int value);
+unsigned int ufs_read_flag(int idn);
+void ufs_set_flag(int idn);
+void ufs_clear_flag(int idn);
+void ufs_read_desc(int idn, int index, uintptr_t buf, size_t size);
+void ufs_write_desc(int idn, int index, uintptr_t buf, size_t size);
+size_t ufs_read_blocks(int lun, int lba, uintptr_t buf, size_t size);
+size_t ufs_write_blocks(int lun, int lba, const uintptr_t buf, size_t size);
+int ufs_init(const ufs_ops_t *ops, ufs_params_t *params);
+
+#endif /* __UFS_H__ */
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/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/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/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 3c20769..5cc1a0a 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -76,6 +76,10 @@
 $(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1))
 $(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1))
 
+# Use an implementation of SHA-256 with a smaller memory footprint but reduced
+# speed.
+$(eval $(call add_define,MBEDTLS_SHA256_SMALLER))
+
 # Enable PSCI_STAT_COUNT/RESIDENCY APIs on ARM platforms
 ENABLE_PSCI_STAT		:=	1
 ENABLE_PMF			:=	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_ddr.c b/plat/hisilicon/hikey/hikey_ddr.c
index 6328eb6..ab572eb 100644
--- a/plat/hisilicon/hikey/hikey_ddr.c
+++ b/plat/hisilicon/hikey/hikey_ddr.c
@@ -385,7 +385,7 @@
 
 static void ddrx_wdet(void)
 {
-	unsigned int data, wdet, zero_bdl, dq[4];
+	unsigned int data, wdet, zero_bdl = 0, dq[4];
 	int i;
 
 	data = mmio_read_32((0xf712c000 + 0x0d0));
@@ -454,11 +454,11 @@
 		for (i = 0; i < 4; i++) {
 			data = mmio_read_32((0xf712c000 + 0x210 + i * 0x80));
 			if ((!(data & 0x1f)) || (!(data & 0x1f00)) ||
-					(!(data & 0x1f0000)) || (!(data & 0x1f000000)))
+			    (!(data & 0x1f0000)) || (!(data & 0x1f000000)))
 				zero_bdl = 1;
 			data = mmio_read_32((0xf712c000 + 0x214 + i * 0x80));
 			if ((!(data & 0x1f)) || (!(data & 0x1f00)) ||
-					(!(data & 0x1f0000)) || (!(data & 0x1f000000)))
+			    (!(data & 0x1f0000)) || (!(data & 0x1f000000)))
 				zero_bdl = 1;
 			data = mmio_read_32((0xf712c000 + 0x218 + i * 0x80));
 			if (!(data & 0x1f))
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/platform.mk b/plat/hisilicon/hikey/platform.mk
index ec4bb5c..fb5f852 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 \
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)