Merge pull request #424 from jcastillo-arm/jc/tf-issues/327

IMF: postpone SCR_EL3 update if context is not initialized
diff --git a/Makefile b/Makefile
index ac059e8..6c062b2 100644
--- a/Makefile
+++ b/Makefile
@@ -262,6 +262,16 @@
 
 include ${PLAT_MAKEFILE_FULL}
 
+# If the platform has not defined ENABLE_PLAT_COMPAT, then enable it by default
+ifndef ENABLE_PLAT_COMPAT
+ENABLE_PLAT_COMPAT := 1
+endif
+
+# Include the platform compatibility helpers for PSCI
+ifneq (${ENABLE_PLAT_COMPAT}, 0)
+include plat/compat/plat_compat.mk
+endif
+
 # Include the CPU specific operations makefile. By default all CPU errata
 # workarounds and CPU specifc optimisations are disabled. This can be
 # overridden by the platform.
@@ -331,6 +341,7 @@
 $(eval $(call assert_boolean,PROGRAMMABLE_RESET_ADDRESS))
 $(eval $(call assert_boolean,PSCI_EXTENDED_STATE_ID))
 $(eval $(call assert_boolean,WARN_DEPRECATED))
+$(eval $(call assert_boolean,ENABLE_PLAT_COMPAT))
 
 
 ################################################################################
@@ -352,6 +363,7 @@
 $(eval $(call add_define,PROGRAMMABLE_RESET_ADDRESS))
 $(eval $(call add_define,PSCI_EXTENDED_STATE_ID))
 $(eval $(call add_define,WARN_DEPRECATED))
+$(eval $(call add_define,ENABLE_PLAT_COMPAT))
 
 
 ################################################################################
diff --git a/bl1/aarch64/bl1_exceptions.S b/bl1/aarch64/bl1_exceptions.S
index ef390d4..0bd0485 100644
--- a/bl1/aarch64/bl1_exceptions.S
+++ b/bl1/aarch64/bl1_exceptions.S
@@ -195,7 +195,7 @@
 	b.ne	unexpected_sync_exception
 
 	mov	x0, x20
-	bl	display_boot_progress
+	bl	bl1_print_bl31_ep_info
 
 	ldp	x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET]
 	msr	elr_el3, x0
diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c
index 50cf4e0..f62f31d 100644
--- a/bl1/bl1_main.c
+++ b/bl1/bl1_main.c
@@ -57,6 +57,9 @@
 	write_spsr_el3(bl2_ep->spsr);
 	write_elr_el3(bl2_ep->pc);
 
+	NOTICE("BL1: Booting BL2\n");
+	print_entry_point_info(bl2_ep);
+
 	eret(bl2_ep->args.arg0,
 		bl2_ep->args.arg1,
 		bl2_ep->args.arg2,
@@ -190,31 +193,18 @@
 
 	bl1_plat_set_bl2_ep_info(&bl2_image_info, &bl2_ep);
 	bl2_ep.args.arg1 = (unsigned long)bl2_tzram_layout;
-	NOTICE("BL1: Booting BL2\n");
-	INFO("BL1: BL2 address = 0x%llx\n",
-		(unsigned long long) bl2_ep.pc);
-	INFO("BL1: BL2 spsr = 0x%x\n", bl2_ep.spsr);
-	VERBOSE("BL1: BL2 memory layout address = 0x%llx\n",
-		(unsigned long long) bl2_tzram_layout);
-
 	bl1_run_bl2(&bl2_ep);
 
 	return;
 }
 
 /*******************************************************************************
- * Temporary function to print the fact that BL2 has done its job and BL31 is
- * about to be loaded. This is needed as long as printfs cannot be used
+ * Function called just before handing over to BL31 to inform the user about
+ * the boot progress. In debug mode, also print details about the BL31 image's
+ * execution context.
  ******************************************************************************/
-void display_boot_progress(entry_point_info_t *bl31_ep_info)
+void bl1_print_bl31_ep_info(const entry_point_info_t *bl31_ep_info)
 {
 	NOTICE("BL1: Booting BL3-1\n");
-	INFO("BL1: BL3-1 address = 0x%llx\n",
-		(unsigned long long)bl31_ep_info->pc);
-	INFO("BL1: BL3-1 spsr = 0x%llx\n",
-		(unsigned long long)bl31_ep_info->spsr);
-	INFO("BL1: BL3-1 params address = 0x%llx\n",
-		(unsigned long long)bl31_ep_info->args.arg0);
-	INFO("BL1: BL3-1 plat params address = 0x%llx\n",
-		(unsigned long long)bl31_ep_info->args.arg1);
+	print_entry_point_info(bl31_ep_info);
 }
diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c
index a244a5c..9abc395 100644
--- a/bl31/bl31_main.c
+++ b/bl31/bl31_main.c
@@ -149,9 +149,7 @@
 
 	INFO("BL3-1: Preparing for EL3 exit to %s world\n",
 		(image_type == SECURE) ? "secure" : "normal");
-	INFO("BL3-1: Next image address = 0x%llx\n",
-		(unsigned long long) next_image_info->pc);
-	INFO("BL3-1: Next image spsr = 0x%x\n", next_image_info->spsr);
+	print_entry_point_info(next_image_info);
 	cm_init_my_context(next_image_info);
 	cm_prepare_el3_exit(image_type);
 }
diff --git a/common/bl_common.c b/common/bl_common.c
index 91a0ae8..0eeef83 100644
--- a/common/bl_common.c
+++ b/common/bl_common.c
@@ -151,11 +151,11 @@
 	uintptr_t image_handle;
 	uintptr_t image_spec;
 	size_t image_size = 0;
-	int io_result = IO_FAIL;
+	int io_result;
 
 	/* Obtain a reference to the image by querying the platform layer */
 	io_result = plat_get_image_source(image_id, &dev_handle, &image_spec);
-	if (io_result != IO_SUCCESS) {
+	if (io_result != 0) {
 		WARN("Failed to obtain reference to image id=%u (%i)\n",
 			image_id, io_result);
 		return 0;
@@ -163,7 +163,7 @@
 
 	/* Attempt to access the image */
 	io_result = io_open(dev_handle, image_spec, &image_handle);
-	if (io_result != IO_SUCCESS) {
+	if (io_result != 0) {
 		WARN("Failed to access image id=%u (%i)\n",
 			image_id, io_result);
 		return 0;
@@ -171,7 +171,7 @@
 
 	/* Find the size of the image */
 	io_result = io_size(image_handle, &image_size);
-	if ((io_result != IO_SUCCESS) || (image_size == 0)) {
+	if ((io_result != 0) || (image_size == 0)) {
 		WARN("Failed to determine the size of the image id=%u (%i)\n",
 			image_id, io_result);
 	}
@@ -352,3 +352,27 @@
 
 	return 0;
 }
+
+/*******************************************************************************
+ * Print the content of an entry_point_info_t structure.
+ ******************************************************************************/
+void print_entry_point_info(const entry_point_info_t *ep_info)
+{
+	INFO("Entry point address = 0x%llx\n",
+		(unsigned long long) ep_info->pc);
+	INFO("SPSR = 0x%lx\n", (unsigned long) ep_info->spsr);
+
+#define PRINT_IMAGE_ARG(n)					\
+	VERBOSE("Argument #" #n " = 0x%llx\n",			\
+		(unsigned long long) ep_info->args.arg##n)
+
+	PRINT_IMAGE_ARG(0);
+	PRINT_IMAGE_ARG(1);
+	PRINT_IMAGE_ARG(2);
+	PRINT_IMAGE_ARG(3);
+	PRINT_IMAGE_ARG(4);
+	PRINT_IMAGE_ARG(5);
+	PRINT_IMAGE_ARG(6);
+	PRINT_IMAGE_ARG(7);
+#undef PRINT_IMAGE_ARG
+}
diff --git a/docs/user-guide.md b/docs/user-guide.md
index 8f271cf..7987d10 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -1084,6 +1084,52 @@
 *   Install and run the Juno binaries on the board
 *   Obtain any other Juno software information
 
+### Testing SYSTEM SUSPEND on Juno
+
+The SYSTEM SUSPEND is a PSCI API which can be used to implement system suspend
+to RAM. For more details refer to section 5.16 of [PSCI]. The [Linaro releases]
+contains the required SCP and motherboard firmware support for this feature on
+Juno. The mainline linux kernel does not yet have support for this feature on
+Juno but it is queued to be merged in v4.4. Till that becomes available, the
+feature can be tested by using a custom kernel built from the following repo:
+
+    git clone git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux.git
+    cd linux
+    git checkout firmware/psci-1.0
+
+Configure the linux kernel:
+
+    export CROSS_COMPILE=<path-to-aarch64-gcc>/bin/aarch64-linux-gnu-
+    make ARCH=arm64 defconfig
+
+The feature is tested conveniently by using the RTC. Enable the RTC driver in
+menuconfig
+
+    make ARCH=arm64 menuconfig
+
+The PL031 RTC driver can be enabled at the following location in menuconfig
+
+    ARM AMBA PL031 RTC
+      |   Location:
+      |     -> Device Drivers
+      |       -> Real Time Clock
+
+Build the kernel
+
+    make ARCH=arm64 Image -j8
+
+Replace the kernel image in `SOFTWARE/` directory of Juno with the `Image` from
+arch/arm64/boot/ of the linux directory as explained in the
+[Juno Software Guide].
+
+Reset the board and wait for it to boot. At the shell prompt issue the
+following command:
+
+    echo +10 > /sys/class/rtc/rtc1/wakealarm
+    echo -n mem > /sys/power/state
+
+The Juno board should suspend to RAM and then wakeup after 10 seconds due to
+wakeup interrupt from RTC.
 
 - - - - - - - - - - - - - - - - - - - - - - - - - -
 
@@ -1098,4 +1144,5 @@
 [DS-5]:                        http://www.arm.com/products/tools/software-tools/ds-5/index.php
 [mbedTLS Repository]:          https://github.com/ARMmbed/mbedtls.git
 [Porting Guide]:               ./porting-guide.md
+[PSCI]:                        http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf "Power State Coordination Interface PDD (ARM DEN 0022C)"
 [Trusted Board Boot]:          trusted-board-boot.md
diff --git a/drivers/io/io_fip.c b/drivers/io/io_fip.c
index 5a8a294..d291423 100644
--- a/drivers/io/io_fip.c
+++ b/drivers/io/io_fip.c
@@ -134,14 +134,14 @@
 	assert(dev_info != NULL);
 	*dev_info = (io_dev_info_t *)&fip_dev_info; /* cast away const */
 
-	return IO_SUCCESS;
+	return 0;
 }
 
 
 /* Do some basic package checks. */
 static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
 {
-	int result = IO_FAIL;
+	int result;
 	unsigned int image_id = (unsigned int)init_params;
 	uintptr_t backend_handle;
 	fip_toc_header_t header;
@@ -150,28 +150,28 @@
 	/* Obtain a reference to the image by querying the platform layer */
 	result = plat_get_image_source(image_id, &backend_dev_handle,
 				       &backend_image_spec);
-	if (result != IO_SUCCESS) {
+	if (result != 0) {
 		WARN("Failed to obtain reference to image id=%u (%i)\n",
 			image_id, result);
-		result = IO_FAIL;
+		result = -ENOENT;
 		goto fip_dev_init_exit;
 	}
 
 	/* Attempt to access the FIP image */
 	result = io_open(backend_dev_handle, backend_image_spec,
 			 &backend_handle);
-	if (result != IO_SUCCESS) {
+	if (result != 0) {
 		WARN("Failed to access image id=%u (%i)\n", image_id, result);
-		result = IO_FAIL;
+		result = -ENOENT;
 		goto fip_dev_init_exit;
 	}
 
 	result = io_read(backend_handle, (uintptr_t)&header, sizeof(header),
 			&bytes_read);
-	if (result == IO_SUCCESS) {
+	if (result == 0) {
 		if (!is_valid_header(&header)) {
 			WARN("Firmware Image Package header check failed.\n");
-			result = IO_FAIL;
+			result = -ENOENT;
 		} else {
 			VERBOSE("FIP header looks OK.\n");
 		}
@@ -192,7 +192,7 @@
 	backend_dev_handle = (uintptr_t)NULL;
 	backend_image_spec = (uintptr_t)NULL;
 
-	return IO_SUCCESS;
+	return 0;
 }
 
 
@@ -200,7 +200,7 @@
 static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
 			 io_entity_t *entity)
 {
-	int result = IO_FAIL;
+	int result;
 	uintptr_t backend_handle;
 	const io_uuid_spec_t *uuid_spec = (io_uuid_spec_t *)spec;
 	size_t bytes_read;
@@ -217,23 +217,23 @@
 	 */
 	if (current_file.entry.offset_address != 0) {
 		WARN("fip_file_open : Only one open file at a time.\n");
-		return IO_RESOURCES_EXHAUSTED;
+		return -ENOMEM;
 	}
 
 	/* Attempt to access the FIP image */
 	result = io_open(backend_dev_handle, backend_image_spec,
 			 &backend_handle);
-	if (result != IO_SUCCESS) {
+	if (result != 0) {
 		WARN("Failed to open Firmware Image Package (%i)\n", result);
-		result = IO_FAIL;
+		result = -ENOENT;
 		goto fip_file_open_exit;
 	}
 
 	/* Seek past the FIP header into the Table of Contents */
 	result = io_seek(backend_handle, IO_SEEK_SET, sizeof(fip_toc_header_t));
-	if (result != IO_SUCCESS) {
+	if (result != 0) {
 		WARN("fip_file_open: failed to seek\n");
-		result = IO_FAIL;
+		result = -ENOENT;
 		goto fip_file_open_close;
 	}
 
@@ -243,7 +243,7 @@
 				 (uintptr_t)&current_file.entry,
 				 sizeof(current_file.entry),
 				 &bytes_read);
-		if (result == IO_SUCCESS) {
+		if (result == 0) {
 			if (compare_uuids(&current_file.entry.uuid,
 					  &uuid_spec->uuid) == 0) {
 				found_file = 1;
@@ -265,7 +265,7 @@
 	} else {
 		/* Did not find the file in the FIP. */
 		current_file.entry.offset_address = 0;
-		result = IO_FAIL;
+		result = -ENOENT;
 	}
 
  fip_file_open_close:
@@ -284,7 +284,7 @@
 
 	*length =  ((file_state_t *)entity->info)->entry.size;
 
-	return IO_SUCCESS;
+	return 0;
 }
 
 
@@ -292,7 +292,7 @@
 static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
 			  size_t *length_read)
 {
-	int result = IO_FAIL;
+	int result;
 	file_state_t *fp;
 	size_t file_offset;
 	size_t bytes_read;
@@ -306,9 +306,9 @@
 	/* Open the backend, attempt to access the blob image */
 	result = io_open(backend_dev_handle, backend_image_spec,
 			 &backend_handle);
-	if (result != IO_SUCCESS) {
+	if (result != 0) {
 		WARN("Failed to open FIP (%i)\n", result);
-		result = IO_FAIL;
+		result = -ENOENT;
 		goto fip_file_read_exit;
 	}
 
@@ -317,17 +317,17 @@
 	/* Seek to the position in the FIP where the payload lives */
 	file_offset = fp->entry.offset_address + fp->file_pos;
 	result = io_seek(backend_handle, IO_SEEK_SET, file_offset);
-	if (result != IO_SUCCESS) {
+	if (result != 0) {
 		WARN("fip_file_read: failed to seek\n");
-		result = IO_FAIL;
+		result = -ENOENT;
 		goto fip_file_read_close;
 	}
 
 	result = io_read(backend_handle, buffer, length, &bytes_read);
-	if (result != IO_SUCCESS) {
+	if (result != 0) {
 		/* We cannot read our data. Fail. */
 		WARN("Failed to read payload (%i)\n", result);
-		result = IO_FAIL;
+		result = -ENOENT;
 		goto fip_file_read_close;
 	} else {
 		/* Set caller length and new file position. */
@@ -357,7 +357,7 @@
 	/* Clear the Entity info. */
 	entity->info = 0;
 
-	return IO_SUCCESS;
+	return 0;
 }
 
 /* Exported functions */
@@ -365,11 +365,11 @@
 /* Register the Firmware Image Package driver with the IO abstraction */
 int register_io_dev_fip(const io_dev_connector_t **dev_con)
 {
-	int result = IO_FAIL;
+	int result;
 	assert(dev_con != NULL);
 
 	result = io_register_device(&fip_dev_info);
-	if (result == IO_SUCCESS)
+	if (result == 0)
 		*dev_con = &fip_dev_connector;
 
 	return result;
diff --git a/drivers/io/io_memmap.c b/drivers/io/io_memmap.c
index fc06fbb..d45107e 100644
--- a/drivers/io/io_memmap.c
+++ b/drivers/io/io_memmap.c
@@ -101,7 +101,7 @@
 	assert(dev_info != NULL);
 	*dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */
 
-	return IO_SUCCESS;
+	return 0;
 }
 
 
@@ -111,7 +111,7 @@
 {
 	/* NOP */
 	/* TODO: Consider tracking open files and cleaning them up here */
-	return IO_SUCCESS;
+	return 0;
 }
 
 
@@ -120,7 +120,7 @@
 static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
 			     io_entity_t *entity)
 {
-	int result = IO_FAIL;
+	int result = -ENOMEM;
 	const io_block_spec_t *block_spec = (io_block_spec_t *)spec;
 
 	/* Since we need to track open state for seek() we only allow one open
@@ -136,10 +136,9 @@
 		/* File cursor offset for seek and incremental reads etc. */
 		current_file.file_pos = 0;
 		entity->info = (uintptr_t)&current_file;
-		result = IO_SUCCESS;
+		result = 0;
 	} else {
 		WARN("A Memmap device is already active. Close first.\n");
-		result = IO_RESOURCES_EXHAUSTED;
 	}
 
 	return result;
@@ -149,7 +148,7 @@
 /* Seek to a particular file offset on the memmap device */
 static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset)
 {
-	int result = IO_FAIL;
+	int result = -ENOENT;
 
 	/* We only support IO_SEEK_SET for the moment. */
 	if (mode == IO_SEEK_SET) {
@@ -157,9 +156,7 @@
 
 		/* TODO: can we do some basic limit checks on seek? */
 		((file_state_t *)entity->info)->file_pos = offset;
-		result = IO_SUCCESS;
-	} else {
-		result = IO_FAIL;
+		result = 0;
 	}
 
 	return result;
@@ -184,7 +181,7 @@
 	/* advance the file 'cursor' for incremental reads */
 	fp->file_pos += length;
 
-	return IO_SUCCESS;
+	return 0;
 }
 
 
@@ -207,7 +204,7 @@
 	/* advance the file 'cursor' for incremental writes */
 	fp->file_pos += length;
 
-	return IO_SUCCESS;
+	return 0;
 }
 
 
@@ -221,7 +218,7 @@
 	/* This would be a mem free() if we had malloc.*/
 	memset((void *)&current_file, 0, sizeof(current_file));
 
-	return IO_SUCCESS;
+	return 0;
 }
 
 
@@ -230,11 +227,11 @@
 /* Register the memmap driver with the IO abstraction */
 int register_io_dev_memmap(const io_dev_connector_t **dev_con)
 {
-	int result = IO_FAIL;
+	int result;
 	assert(dev_con != NULL);
 
 	result = io_register_device(&memmap_dev_info);
-	if (result == IO_SUCCESS)
+	if (result == 0)
 		*dev_con = &memmap_dev_connector;
 
 	return result;
diff --git a/drivers/io/io_semihosting.c b/drivers/io/io_semihosting.c
index 8e62be1..63d0f68 100644
--- a/drivers/io/io_semihosting.c
+++ b/drivers/io/io_semihosting.c
@@ -84,10 +84,9 @@
 static int sh_dev_open(const uintptr_t dev_spec __unused,
 		io_dev_info_t **dev_info)
 {
-	int result = IO_SUCCESS;
 	assert(dev_info != NULL);
 	*dev_info = (io_dev_info_t *)&sh_dev_info; /* cast away const */
-	return result;
+	return 0;
 }
 
 
@@ -95,7 +94,7 @@
 static int sh_file_open(io_dev_info_t *dev_info __attribute__((unused)),
 		const uintptr_t spec, io_entity_t *entity)
 {
-	int result = IO_FAIL;
+	int result = -ENOENT;
 	long sh_result = -1;
 	const io_file_spec_t *file_spec = (const io_file_spec_t *)spec;
 
@@ -106,9 +105,7 @@
 
 	if (sh_result > 0) {
 		entity->info = (uintptr_t)sh_result;
-		result = IO_SUCCESS;
-	} else {
-		result = IO_FAIL;
+		result = 0;
 	}
 	return result;
 }
@@ -117,7 +114,6 @@
 /* Seek to a particular file offset on the semi-hosting device */
 static int sh_file_seek(io_entity_t *entity, int mode, ssize_t offset)
 {
-	int result = IO_FAIL;
 	long file_handle, sh_result;
 
 	assert(entity != NULL);
@@ -126,16 +122,14 @@
 
 	sh_result = semihosting_file_seek(file_handle, offset);
 
-	result = (sh_result == 0) ? IO_SUCCESS : IO_FAIL;
-
-	return result;
+	return (sh_result == 0) ? 0 : -ENOENT;
 }
 
 
 /* Return the size of a file on the semi-hosting device */
 static int sh_file_len(io_entity_t *entity, size_t *length)
 {
-	int result = IO_FAIL;
+	int result = -ENOENT;
 
 	assert(entity != NULL);
 	assert(length != NULL);
@@ -144,7 +138,7 @@
 	long sh_result = semihosting_file_length(sh_handle);
 
 	if (sh_result >= 0) {
-		result = IO_SUCCESS;
+		result = 0;
 		*length = (size_t)sh_result;
 	}
 
@@ -156,7 +150,7 @@
 static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
 		size_t *length_read)
 {
-	int result = IO_FAIL;
+	int result = -ENOENT;
 	long sh_result = -1;
 	size_t bytes = length;
 	long file_handle;
@@ -171,9 +165,8 @@
 
 	if (sh_result >= 0) {
 		*length_read = (bytes != length) ? bytes : length;
-		result = IO_SUCCESS;
-	} else
-		result = IO_FAIL;
+		result = 0;
+	}
 
 	return result;
 }
@@ -197,14 +190,13 @@
 
 	*length_written = length - bytes;
 
-	return (sh_result == 0) ? IO_SUCCESS : IO_FAIL;
+	return (sh_result == 0) ? 0 : -ENOENT;
 }
 
 
 /* Close a file on the semi-hosting device */
 static int sh_file_close(io_entity_t *entity)
 {
-	int result = IO_FAIL;
 	long sh_result = -1;
 	long file_handle;
 
@@ -214,9 +206,7 @@
 
 	sh_result = semihosting_file_close(file_handle);
 
-	result = (sh_result >= 0) ? IO_SUCCESS : IO_FAIL;
-
-	return result;
+	return (sh_result >= 0) ? 0 : -ENOENT;
 }
 
 
@@ -225,11 +215,11 @@
 /* Register the semi-hosting driver with the IO abstraction */
 int register_io_dev_sh(const io_dev_connector_t **dev_con)
 {
-	int result = IO_FAIL;
+	int result;
 	assert(dev_con != NULL);
 
 	result = io_register_device(&sh_dev_info);
-	if (result == IO_SUCCESS)
+	if (result == 0)
 		*dev_con = &sh_dev_connector;
 
 	return result;
diff --git a/drivers/io/io_storage.c b/drivers/io/io_storage.c
index a3a8186..7cb1a6a 100644
--- a/drivers/io/io_storage.c
+++ b/drivers/io/io_storage.c
@@ -96,7 +96,7 @@
 static int dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec,
 		io_dev_info_t **dev_info)
 {
-	int result = IO_FAIL;
+	int result;
 	assert(dev_info != NULL);
 	assert(is_valid_dev_connector(dev_con));
 
@@ -116,10 +116,10 @@
 /* Locate an entity in the pool, specified by address */
 static int find_first_entity(const io_entity_t *entity, unsigned int *index_out)
 {
-	int result = IO_FAIL;
+	int result = -ENOENT;
 	for (int index = 0; index < MAX_IO_HANDLES; ++index) {
 		if (entity_map[index] == entity) {
-			result = IO_SUCCESS;
+			result = 0;
 			*index_out = index;
 			break;
 		}
@@ -131,17 +131,16 @@
 /* Allocate an entity from the pool and return a pointer to it */
 static int allocate_entity(io_entity_t **entity)
 {
-	int result = IO_FAIL;
+	int result = -ENOMEM;
 	assert(entity != NULL);
 
 	if (entity_count < MAX_IO_HANDLES) {
 		unsigned int index = 0;
 		result = find_first_entity(NULL, &index);
-		assert(result == IO_SUCCESS);
+		assert(result == 0);
 		*entity = entity_map[index] = &entity_pool[index];
 		++entity_count;
-	} else
-		result = IO_RESOURCES_EXHAUSTED;
+	}
 
 	return result;
 }
@@ -150,12 +149,12 @@
 /* Release an entity back to the pool */
 static int free_entity(const io_entity_t *entity)
 {
-	int result = IO_FAIL;
+	int result;
 	unsigned int index = 0;
 	assert(entity != NULL);
 
 	result = find_first_entity(entity, &index);
-	if (result ==  IO_SUCCESS) {
+	if (result ==  0) {
 		entity_map[index] = NULL;
 		--entity_count;
 	}
@@ -169,15 +168,13 @@
 /* Register a device driver */
 int io_register_device(const io_dev_info_t *dev_info)
 {
-	int result = IO_FAIL;
+	int result = -ENOMEM;
 	assert(dev_info != NULL);
 
 	if (dev_count < MAX_IO_DEVICES) {
 		devices[dev_count] = dev_info;
 		dev_count++;
-		result = IO_SUCCESS;
-	} else {
-		result = IO_RESOURCES_EXHAUSTED;
+		result = 0;
 	}
 
 	return result;
@@ -188,7 +185,7 @@
 int io_dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec,
 		uintptr_t *handle)
 {
-	int result = IO_FAIL;
+	int result;
 	assert(handle != NULL);
 
 	result = dev_open(dev_con, dev_spec, (io_dev_info_t **)handle);
@@ -200,18 +197,17 @@
  * re-initialisation */
 int io_dev_init(uintptr_t dev_handle, const uintptr_t init_params)
 {
-	int result = IO_FAIL;
+	int result = 0;
 	assert(dev_handle != (uintptr_t)NULL);
 	assert(is_valid_dev(dev_handle));
 
 	io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
 
+	/* Absence of registered function implies NOP here */
 	if (dev->funcs->dev_init != NULL) {
 		result = dev->funcs->dev_init(dev, init_params);
-	} else {
-		/* Absence of registered function implies NOP here */
-		result = IO_SUCCESS;
 	}
+
 	return result;
 }
 
@@ -221,17 +217,15 @@
 /* Close a connection to a device */
 int io_dev_close(uintptr_t dev_handle)
 {
-	int result = IO_FAIL;
+	int result = 0;
 	assert(dev_handle != (uintptr_t)NULL);
 	assert(is_valid_dev(dev_handle));
 
 	io_dev_info_t *dev = (io_dev_info_t *)dev_handle;
 
+	/* Absence of registered function implies NOP here */
 	if (dev->funcs->dev_close != NULL) {
 		result = dev->funcs->dev_close(dev);
-	} else {
-		/* Absence of registered function implies NOP here */
-		result = IO_SUCCESS;
 	}
 
 	return result;
@@ -244,7 +238,7 @@
 /* Open an IO entity */
 int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle)
 {
-	int result = IO_FAIL;
+	int result;
 	assert((spec != (uintptr_t)NULL) && (handle != NULL));
 	assert(is_valid_dev(dev_handle));
 
@@ -253,11 +247,11 @@
 
 	result = allocate_entity(&entity);
 
-	if (result == IO_SUCCESS) {
+	if (result == 0) {
 		assert(dev->funcs->open != NULL);
 		result = dev->funcs->open(dev, spec, entity);
 
-		if (result == IO_SUCCESS) {
+		if (result == 0) {
 			entity->dev_handle = dev;
 			set_handle(handle, entity);
 		} else
@@ -270,7 +264,7 @@
 /* Seek to a specific position in an IO entity */
 int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset)
 {
-	int result = IO_FAIL;
+	int result = -ENODEV;
 	assert(is_valid_entity(handle) && is_valid_seek_mode(mode));
 
 	io_entity_t *entity = (io_entity_t *)handle;
@@ -279,8 +273,6 @@
 
 	if (dev->funcs->seek != NULL)
 		result = dev->funcs->seek(entity, mode, offset);
-	else
-		result = IO_NOT_SUPPORTED;
 
 	return result;
 }
@@ -289,7 +281,7 @@
 /* Determine the length of an IO entity */
 int io_size(uintptr_t handle, size_t *length)
 {
-	int result = IO_FAIL;
+	int result = -ENODEV;
 	assert(is_valid_entity(handle) && (length != NULL));
 
 	io_entity_t *entity = (io_entity_t *)handle;
@@ -298,8 +290,6 @@
 
 	if (dev->funcs->size != NULL)
 		result = dev->funcs->size(entity, length);
-	else
-		result = IO_NOT_SUPPORTED;
 
 	return result;
 }
@@ -311,7 +301,7 @@
 		size_t length,
 		size_t *length_read)
 {
-	int result = IO_FAIL;
+	int result = -ENODEV;
 	assert(is_valid_entity(handle) && (buffer != (uintptr_t)NULL));
 
 	io_entity_t *entity = (io_entity_t *)handle;
@@ -320,8 +310,6 @@
 
 	if (dev->funcs->read != NULL)
 		result = dev->funcs->read(entity, buffer, length, length_read);
-	else
-		result = IO_NOT_SUPPORTED;
 
 	return result;
 }
@@ -333,7 +321,7 @@
 		size_t length,
 		size_t *length_written)
 {
-	int result = IO_FAIL;
+	int result = -ENODEV;
 	assert(is_valid_entity(handle) && (buffer != (uintptr_t)NULL));
 
 	io_entity_t *entity = (io_entity_t *)handle;
@@ -343,8 +331,7 @@
 	if (dev->funcs->write != NULL) {
 		result = dev->funcs->write(entity, buffer, length,
 				length_written);
-	} else
-		result = IO_NOT_SUPPORTED;
+	}
 
 	return result;
 }
@@ -353,19 +340,17 @@
 /* Close an IO entity */
 int io_close(uintptr_t handle)
 {
-	int result = IO_FAIL;
+	int result = 0;
 	assert(is_valid_entity(handle));
 
 	io_entity_t *entity = (io_entity_t *)handle;
 
 	io_dev_info_t *dev = entity->dev_handle;
 
+	/* Absence of registered function implies NOP here */
 	if (dev->funcs->close != NULL)
 		result = dev->funcs->close(entity);
-	else {
-		/* Absence of registered function implies NOP here */
-		result = IO_SUCCESS;
-	}
+
 	/* Ignore improbable free_entity failure */
 	(void)free_entity(entity);
 
diff --git a/include/common/bl_common.h b/include/common/bl_common.h
index c687b35..c9a7a3d 100644
--- a/include/common/bl_common.h
+++ b/include/common/bl_common.h
@@ -242,6 +242,8 @@
 void reserve_mem(uint64_t *free_base, size_t *free_size,
 		uint64_t addr, size_t size);
 
+void print_entry_point_info(const entry_point_info_t *ep_info);
+
 #endif /*__ASSEMBLY__*/
 
 #endif /* __BL_COMMON_H__ */
diff --git a/include/drivers/io/io_storage.h b/include/drivers/io/io_storage.h
index 4c3526e..970ab2c 100644
--- a/include/drivers/io/io_storage.h
+++ b/include/drivers/io/io_storage.h
@@ -89,15 +89,6 @@
 #define IO_MODE_RW	(1 << 1)
 
 
-/* Return codes reported by 'io_*' APIs.
- * IMPORTANT: these definitions are deprecated. Callers should use standard
- * errno definitions when checking the return value of io_* APIs. */
-#define IO_SUCCESS		(0)
-#define IO_FAIL			(-ENOENT)
-#define IO_NOT_SUPPORTED	(-ENODEV)
-#define IO_RESOURCES_EXHAUSTED	(-ENOMEM)
-
-
 /* Open a connection to a device */
 int io_dev_open(const struct io_dev_connector *dev_con,
 		const uintptr_t dev_spec,
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
index c236970..452c385 100644
--- a/include/plat/arm/common/arm_def.h
+++ b/include/plat/arm/common/arm_def.h
@@ -44,7 +44,8 @@
 /* Special value used to verify platform parameters from BL2 to BL3-1 */
 #define ARM_BL31_PLAT_PARAM_VAL		0x0f1e2d3c4b5a6978ULL
 
-#define ARM_CLUSTER_COUNT		2ull
+#define ARM_CLUSTER_COUNT		2
+#define ARM_SYSTEM_COUNT		1
 
 #define ARM_CACHE_WRITEBACK_SHIFT	6
 
@@ -54,6 +55,7 @@
  */
 #define ARM_PWR_LVL0		MPIDR_AFFLVL0
 #define ARM_PWR_LVL1		MPIDR_AFFLVL1
+#define ARM_PWR_LVL2		MPIDR_AFFLVL2
 
 /*
  *  Macros for local power states in ARM platforms encoded by State-ID field
@@ -179,10 +181,6 @@
 
 #define ADDR_SPACE_SIZE			(1ull << 32)
 
-#define PLAT_NUM_PWR_DOMAINS		(ARM_CLUSTER_COUNT + \
-					 PLATFORM_CORE_COUNT)
-#define PLAT_MAX_PWR_LVL		ARM_PWR_LVL1
-
 /*
  * This macro defines the deepest retention state possible. A higher state
  * id will represent an invalid or a power down state.
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index ad41f4f..044e18e 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -35,6 +35,7 @@
 #include <cassert.h>
 #include <cpu_data.h>
 #include <stdint.h>
+#include <xlat_tables.h>
 
 
 /*
@@ -123,6 +124,11 @@
 		(((lvl1_state) << ARM_LOCAL_PSTATE_WIDTH) | \
 		arm_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type))
 
+/* Make composite power state parameter till power level 2 */
+#define arm_make_pwrstate_lvl2(lvl2_state, lvl1_state, lvl0_state, pwr_lvl, type) \
+		(((lvl2_state) << (ARM_LOCAL_PSTATE_WIDTH * 2)) | \
+		arm_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type))
+
 #endif /* __ARM_RECOM_STATE_ID_ENC__ */
 
 
@@ -135,10 +141,14 @@
 /* Security utility functions */
 void arm_tzc_setup(void);
 
+/* Systimer utility function */
+void arm_configure_sys_timer(void);
+
 /* PM utility functions */
 int arm_validate_power_state(unsigned int power_state,
 			    psci_power_state_t *req_state);
 int arm_validate_ns_entrypoint(uintptr_t entrypoint);
+void arm_system_pwr_domain_resume(void);
 
 /* Topology utility function */
 int arm_check_mpidr(u_register_t mpidr);
diff --git a/include/plat/arm/css/common/css_pm.h b/include/plat/arm/css/common/css_pm.h
index c19df92..ea6a5d2 100644
--- a/include/plat/arm/css/common/css_pm.h
+++ b/include/plat/arm/css/common/css_pm.h
@@ -44,5 +44,6 @@
 void __dead2 css_system_off(void);
 void __dead2 css_system_reset(void);
 void css_cpu_standby(plat_local_state_t cpu_state);
+void css_get_sys_suspend_power_state(psci_power_state_t *req_state);
 
 #endif /* __CSS_PM_H__ */
diff --git a/plat/arm/board/fvp/fvp_io_storage.c b/plat/arm/board/fvp/fvp_io_storage.c
index e9d847f..0b74de2 100644
--- a/plat/arm/board/fvp/fvp_io_storage.c
+++ b/plat/arm/board/fvp/fvp_io_storage.c
@@ -114,14 +114,14 @@
 
 static int open_semihosting(const uintptr_t spec)
 {
-	int result = IO_FAIL;
+	int result;
 	uintptr_t local_image_handle;
 
 	/* See if the file exists on semi-hosting.*/
 	result = io_dev_init(sh_dev_handle, (uintptr_t)NULL);
-	if (result == IO_SUCCESS) {
+	if (result == 0) {
 		result = io_open(sh_dev_handle, spec, &local_image_handle);
-		if (result == IO_SUCCESS) {
+		if (result == 0) {
 			VERBOSE("Using Semi-hosting IO\n");
 			io_close(local_image_handle);
 		}
@@ -137,11 +137,11 @@
 
 	/* Register the additional IO devices on this platform */
 	io_result = register_io_dev_sh(&sh_dev_con);
-	assert(io_result == IO_SUCCESS);
+	assert(io_result == 0);
 
 	/* Open connections to devices and cache the handles */
 	io_result = io_dev_open(sh_dev_con, (uintptr_t)NULL, &sh_dev_handle);
-	assert(io_result == IO_SUCCESS);
+	assert(io_result == 0);
 
 	/* Ignore improbable errors in release builds */
 	(void)io_result;
@@ -154,7 +154,7 @@
 				  uintptr_t *image_spec)
 {
 	int result = open_semihosting((const uintptr_t)&sh_file_spec[image_id]);
-	if (result == IO_SUCCESS) {
+	if (result == 0) {
 		*dev_handle = sh_dev_handle;
 		*image_spec = (uintptr_t)&sh_file_spec[image_id];
 	}
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index 840676c..9ada6b2 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -38,9 +38,13 @@
 #include <v2m_def.h>
 #include "../fvp_def.h"
 
+/* Required platform porting definitions */
+#define PLAT_NUM_PWR_DOMAINS		(ARM_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT)
+#define PLAT_MAX_PWR_LVL		ARM_PWR_LVL1
 
 /*
- * Most platform porting definitions provided by included headers
+ * Other platform porting definitions are provided by included headers
  */
 
 /*
diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h
index ba93254..39283c5 100644
--- a/plat/arm/board/juno/include/platform_def.h
+++ b/plat/arm/board/juno/include/platform_def.h
@@ -41,9 +41,13 @@
 #include <v2m_def.h>
 #include "../juno_def.h"
 
-
+/* Juno supports system power domain */
+#define PLAT_MAX_PWR_LVL		ARM_PWR_LVL2
+#define PLAT_NUM_PWR_DOMAINS		(ARM_SYSTEM_COUNT + \
+					ARM_CLUSTER_COUNT + \
+					PLATFORM_CORE_COUNT)
 /*
- * Most platform porting definitions provided by included headers
+ * Other platform porting definitions are provided by included headers
  */
 
 /*
diff --git a/plat/arm/board/juno/juno_pm.c b/plat/arm/board/juno/juno_pm.c
new file mode 100644
index 0000000..4b956d2
--- /dev/null
+++ b/plat/arm/board/juno/juno_pm.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <css_pm.h>
+#include <plat_arm.h>
+
+/*
+ * Custom `validate_power_state` handler for Juno. According to PSCI
+ * Specification, interrupts targeted to cores in PSCI CPU SUSPEND should
+ * be able to resume it. On Juno, when the system power domain is suspended,
+ * the GIC is also powered down. The SCP resumes the final core to be suspend
+ * when an external wake-up event is received. But the other cores cannot be
+ * woken up by a targeted interrupt, because GIC doesn't forward these
+ * interrupts to the SCP. Due to this hardware limitation, we down-grade PSCI
+ * CPU SUSPEND requests targeted to the system power domain level
+ * to cluster power domain level.
+ *
+ * The system power domain suspend on Juno is only supported only via
+ * PSCI SYSTEM SUSPEND API.
+ */
+static int juno_validate_power_state(unsigned int power_state,
+			    psci_power_state_t *req_state)
+{
+	int rc;
+	rc = arm_validate_power_state(power_state, req_state);
+
+	/*
+	 * Ensure that the system power domain level is never suspended
+	 * via PSCI CPU SUSPEND API. Currently system suspend is only
+	 * supported via PSCI SYSTEM SUSPEND API.
+	 */
+	req_state->pwr_domain_state[ARM_PWR_LVL2] = ARM_LOCAL_STATE_RUN;
+	return rc;
+}
+
+/*******************************************************************************
+ * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
+ * platform will take care of registering the handlers with PSCI.
+ ******************************************************************************/
+const plat_psci_ops_t plat_arm_psci_pm_ops = {
+	.pwr_domain_on			= css_pwr_domain_on,
+	.pwr_domain_on_finish		= css_pwr_domain_on_finish,
+	.pwr_domain_off			= css_pwr_domain_off,
+	.cpu_standby			= css_cpu_standby,
+	.pwr_domain_suspend		= css_pwr_domain_suspend,
+	.pwr_domain_suspend_finish	= css_pwr_domain_suspend_finish,
+	.system_off			= css_system_off,
+	.system_reset			= css_system_reset,
+	.validate_power_state		= juno_validate_power_state,
+	.validate_ns_entrypoint		= arm_validate_ns_entrypoint,
+	.get_sys_suspend_power_state	= css_get_sys_suspend_power_state
+};
diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk
index b80cfb3..b711f3d 100644
--- a/plat/arm/board/juno/platform.mk
+++ b/plat/arm/board/juno/platform.mk
@@ -33,12 +33,16 @@
 PLAT_BL_COMMON_SOURCES	:=	plat/arm/board/juno/aarch64/juno_helpers.S
 
 BL1_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
-				lib/cpus/aarch64/cortex_a57.S
+				lib/cpus/aarch64/cortex_a57.S		\
+				lib/cpus/aarch64/cortex_a72.S
 
 BL2_SOURCES		+=	plat/arm/board/juno/juno_security.c	\
 
 BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
-				lib/cpus/aarch64/cortex_a57.S
+				lib/cpus/aarch64/cortex_a57.S		\
+				lib/cpus/aarch64/cortex_a72.S		\
+				plat/arm/board/juno/juno_pm.c		\
+				plat/arm/board/juno/juno_security.c
 
 # Enable workarounds for selected Cortex-A57 erratas.
 ERRATA_A57_806969	:=	0
diff --git a/plat/arm/common/aarch64/arm_common.c b/plat/arm/common/aarch64/arm_common.c
index 48b4ac8..4264183 100644
--- a/plat/arm/common/aarch64/arm_common.c
+++ b/plat/arm/common/aarch64/arm_common.c
@@ -32,6 +32,7 @@
 #include <cci.h>
 #include <mmio.h>
 #include <plat_arm.h>
+#include <platform_def.h>
 #include <xlat_tables.h>
 
 
@@ -142,3 +143,19 @@
 {
 	cci_init(PLAT_ARM_CCI_BASE, cci_map, ARRAY_SIZE(cci_map));
 }
+
+/*******************************************************************************
+ * Configures access to the system counter timer module.
+ ******************************************************************************/
+void arm_configure_sys_timer(void)
+{
+	unsigned int reg_val;
+
+	reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT);
+	reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT);
+	reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT);
+	mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTACR_BASE(PLAT_ARM_NSTIMER_FRAME_ID), reg_val);
+
+	reg_val = (1 << CNTNSAR_NS_SHIFT(PLAT_ARM_NSTIMER_FRAME_ID));
+	mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTNSAR, reg_val);
+}
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index 899463e..923c333 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -40,7 +40,6 @@
 #include <mmio.h>
 #include <plat_arm.h>
 #include <platform.h>
-#include <platform_def.h>
 
 
 /*
@@ -197,8 +196,6 @@
  ******************************************************************************/
 void arm_bl31_platform_setup(void)
 {
-	unsigned int reg_val;
-
 	/* Initialize the gic cpu and distributor interfaces */
 	plat_arm_gic_init();
 	arm_gic_setup();
@@ -217,13 +214,7 @@
 			CNTCR_FCREQ(0) | CNTCR_EN);
 
 	/* Allow access to the System counter timer module */
-	reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT);
-	reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT);
-	reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT);
-	mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTACR_BASE(PLAT_ARM_NSTIMER_FRAME_ID), reg_val);
-
-	reg_val = (1 << CNTNSAR_NS_SHIFT(PLAT_ARM_NSTIMER_FRAME_ID));
-	mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTNSAR, reg_val);
+	arm_configure_sys_timer();
 
 	/* Initialize power controller before setting up topology */
 	plat_arm_pwrc_setup();
diff --git a/plat/arm/common/arm_io_storage.c b/plat/arm/common/arm_io_storage.c
index 8488f12..ae67cde 100644
--- a/plat/arm/common/arm_io_storage.c
+++ b/plat/arm/common/arm_io_storage.c
@@ -220,9 +220,9 @@
 
 	/* See if a Firmware Image Package is available */
 	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
-	if (result == IO_SUCCESS) {
+	if (result == 0) {
 		result = io_open(fip_dev_handle, spec, &local_image_handle);
-		if (result == IO_SUCCESS) {
+		if (result == 0) {
 			VERBOSE("Using FIP\n");
 			io_close(local_image_handle);
 		}
@@ -237,9 +237,9 @@
 	uintptr_t local_image_handle;
 
 	result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL);
-	if (result == IO_SUCCESS) {
+	if (result == 0) {
 		result = io_open(memmap_dev_handle, spec, &local_image_handle);
-		if (result == IO_SUCCESS) {
+		if (result == 0) {
 			VERBOSE("Using Memmap\n");
 			io_close(local_image_handle);
 		}
@@ -253,19 +253,19 @@
 	int io_result;
 
 	io_result = register_io_dev_fip(&fip_dev_con);
-	assert(io_result == IO_SUCCESS);
+	assert(io_result == 0);
 
 	io_result = register_io_dev_memmap(&memmap_dev_con);
-	assert(io_result == IO_SUCCESS);
+	assert(io_result == 0);
 
 	/* Open connections to devices and cache the handles */
 	io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
 				&fip_dev_handle);
-	assert(io_result == IO_SUCCESS);
+	assert(io_result == 0);
 
 	io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
 				&memmap_dev_handle);
-	assert(io_result == IO_SUCCESS);
+	assert(io_result == 0);
 
 	/* Ignore improbable errors in release builds */
 	(void)io_result;
@@ -282,7 +282,7 @@
 	uintptr_t *image_spec __attribute__((unused)))
 {
 	/* By default do not try an alternative */
-	return IO_FAIL;
+	return -ENOENT;
 }
 
 /* Return an IO device handle and specification which can be used to access
@@ -290,14 +290,14 @@
 int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
 			  uintptr_t *image_spec)
 {
-	int result = IO_FAIL;
+	int result;
 	const struct plat_io_policy *policy;
 
 	assert(image_id < ARRAY_SIZE(policies));
 
 	policy = &policies[image_id];
 	result = policy->check(policy->image_spec);
-	if (result == IO_SUCCESS) {
+	if (result == 0) {
 		*image_spec = policy->image_spec;
 		*dev_handle = *(policy->dev_handle);
 	} else {
diff --git a/plat/arm/common/arm_pm.c b/plat/arm/common/arm_pm.c
index 2497588..d13d268 100644
--- a/plat/arm/common/arm_pm.c
+++ b/plat/arm/common/arm_pm.c
@@ -30,7 +30,9 @@
 
 #include <arch_helpers.h>
 #include <arm_def.h>
+#include <arm_gic.h>
 #include <assert.h>
+#include <console.h>
 #include <errno.h>
 #include <plat_arm.h>
 #include <platform_def.h>
@@ -148,6 +150,26 @@
 	return PSCI_E_INVALID_ADDRESS;
 }
 
+/******************************************************************************
+ * Helper function to resume the platform from system suspend. Reinitialize
+ * the system components which are not in the Always ON power domain.
+ * TODO: Unify the platform setup when waking up from cold boot and system
+ * resume in arm_bl31_platform_setup().
+ *****************************************************************************/
+void arm_system_pwr_domain_resume(void)
+{
+	console_init(PLAT_ARM_BOOT_UART_BASE, PLAT_ARM_BOOT_UART_CLK_IN_HZ,
+						ARM_CONSOLE_BAUDRATE);
+
+	/* Assert system power domain is available on the platform */
+	assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
+
+	arm_gic_setup();
+	plat_arm_security_setup();
+
+	arm_configure_sys_timer();
+}
+
 /*******************************************************************************
  * Private function to program the mailbox for a cpu before it is released
  * from reset. This function assumes that the Trusted mail box base is within
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index c0c615b..3f46857 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -31,6 +31,7 @@
 #include <arch_helpers.h>
 #include <assert.h>
 #include <arm_gic.h>
+#include <cassert.h>
 #include <cci.h>
 #include <css_pm.h>
 #include <debug.h>
@@ -51,18 +52,30 @@
  *  The table must be terminated by a NULL entry.
  */
 const unsigned int arm_pm_idle_states[] = {
-	/* State-id - 0x01 */
-	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RET,
-			ARM_PWR_LVL0, PSTATE_TYPE_STANDBY),
-	/* State-id - 0x02 */
-	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF,
-			ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN),
-	/* State-id - 0x22 */
-	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
-			ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN),
+	/* State-id - 0x001 */
+	arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN,
+		ARM_LOCAL_STATE_RET, ARM_PWR_LVL0, PSTATE_TYPE_STANDBY),
+	/* State-id - 0x002 */
+	arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN,
+		ARM_LOCAL_STATE_OFF, ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN),
+	/* State-id - 0x022 */
+	arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF,
+		ARM_LOCAL_STATE_OFF, ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN),
+#if PLAT_MAX_PWR_LVL > ARM_PWR_LVL1
+	/* State-id - 0x222 */
+	arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
+		ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN),
+#endif
 	0,
 };
-#endif
+#endif /* __ARM_RECOM_STATE_ID_ENC__ */
+
+/*
+ * All the power management helpers in this file assume at least cluster power
+ * level is supported.
+ */
+CASSERT(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL1,
+		assert_max_pwr_lvl_supported_mismatch);
 
 /*******************************************************************************
  * Handler called when a power domain is about to be turned on. The
@@ -90,6 +103,16 @@
 	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
 						ARM_LOCAL_STATE_OFF);
 
+	if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) {
+		/*
+		 * Perform system initialization if woken up from system
+		 * suspend.
+		 */
+		if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
+							ARM_LOCAL_STATE_OFF)
+			arm_system_pwr_domain_resume();
+	}
+
 	/*
 	 * Perform the common cluster specific operations i.e enable coherency
 	 * if this cluster was off.
@@ -98,6 +121,18 @@
 						ARM_LOCAL_STATE_OFF)
 		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
 
+
+	if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) {
+		/*
+		 * Skip GIC CPU interface and per-CPU Distributor interface
+		 * setups if woken up from system suspend as it is done as
+		 * part of css_system_pwr_domain_resume().
+		 */
+		if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
+							ARM_LOCAL_STATE_OFF)
+			return;
+	}
+
 	/* Enable the gic cpu interface */
 	arm_gic_cpuif_setup();
 
@@ -114,10 +149,21 @@
 static void css_power_down_common(const psci_power_state_t *target_state)
 {
 	uint32_t cluster_state = scpi_power_on;
+	uint32_t system_state = scpi_power_on;
 
 	/* Prevent interrupts from spuriously waking up this cpu */
 	arm_gic_cpuif_deactivate();
 
+	if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) {
+		/*
+		 * Check if power down at system power domain level is
+		 * requested.
+		 */
+		if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
+							ARM_LOCAL_STATE_OFF)
+			system_state = scpi_power_retention;
+	}
+
 	/* Cluster is to be turned off, so disable coherency */
 	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
 						ARM_LOCAL_STATE_OFF) {
@@ -132,7 +178,7 @@
 	scpi_set_css_power_state(read_mpidr_el1(),
 				 scpi_power_off,
 				 cluster_state,
-				 scpi_power_on);
+				 system_state);
 }
 
 /*******************************************************************************
@@ -246,6 +292,23 @@
 }
 
 /*******************************************************************************
+ * Handler called to return the 'req_state' for system suspend.
+ ******************************************************************************/
+void css_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	unsigned int i;
+
+	/*
+	 * System Suspend is supported only if the system power domain node
+	 * is implemented.
+	 */
+	assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2);
+
+	for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF;
+}
+
+/*******************************************************************************
  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
  * platform will take care of registering the handlers with PSCI.
  ******************************************************************************/
diff --git a/plat/arm/css/common/css_topology.c b/plat/arm/css/common/css_topology.c
index 381e786..03f81e6 100644
--- a/plat/arm/css/common/css_topology.c
+++ b/plat/arm/css/common/css_topology.c
@@ -31,26 +31,28 @@
 #include <plat_arm.h>
 
 /*
- * On ARM platforms, by default the cluster power level is treated as the
+ * On ARM CSS platforms, by default, the system power level is treated as the
  * highest. The first entry in the power domain descriptor specifies the
- * number of cluster power domains i.e. 2.
+ * number of system power domains i.e. 1.
  */
-#define CSS_PWR_DOMAINS_AT_MAX_PWR_LVL	ARM_CLUSTER_COUNT
+#define CSS_PWR_DOMAINS_AT_MAX_PWR_LVL	ARM_SYSTEM_COUNT
 
 /*
- * The CSS power domain tree descriptor. The cluster power domains are
- * arranged so that when the PSCI generic code creates the power domain tree,
- * the indices of the CPU power domain nodes it allocates match the linear
- * indices returned by plat_core_pos_by_mpidr() i.e.
- * CLUSTER1 CPUs are allocated indices from 0 to 3 and the higher indices for
- * CLUSTER0 CPUs.
+ * The CSS power domain tree descriptor for dual cluster CSS platforms.
+ * The cluster power domains are arranged so that when the PSCI generic
+ * code creates the power domain tree, the indices of the CPU power
+ * domain nodes it allocates match the linear indices returned by
+ * plat_core_pos_by_mpidr() i.e. CLUSTER1 CPUs are allocated indices
+ * from 0 to 3 and the higher indices for CLUSTER0 CPUs.
  */
 const unsigned char arm_power_domain_tree_desc[] = {
 	/* No of root nodes */
 	CSS_PWR_DOMAINS_AT_MAX_PWR_LVL,
-	/* No of children for the first node */
+	/* No of children for the root node */
+	ARM_CLUSTER_COUNT,
+	/* No of children for the first cluster node */
 	PLAT_ARM_CLUSTER1_CORE_COUNT,
-	/* No of children for the second node */
+	/* No of children for the second cluster node */
 	PLAT_ARM_CLUSTER0_CORE_COUNT
 };
 
diff --git a/plat/arm/soc/common/soc_css.mk b/plat/arm/soc/common/soc_css.mk
index fd51b7f..d8a99a8 100644
--- a/plat/arm/soc/common/soc_css.mk
+++ b/plat/arm/soc/common/soc_css.mk
@@ -37,4 +37,4 @@
 
 BL2_SOURCES		+=	plat/arm/soc/common/soc_css_security.c
 
-#BL31_SOURCES		+=
+BL31_SOURCES		+=	plat/arm/soc/common/soc_css_security.c