Merge pull request #1566 from EvanLloyd/non_secure_uart

ARM Platforms:Enable non-secure access to UART1
diff --git a/include/plat/arm/board/common/board_arm_def.h b/include/plat/arm/board/common/board_arm_def.h
index 86c8512..9af8f8c 100644
--- a/include/plat/arm/board/common/board_arm_def.h
+++ b/include/plat/arm/board/common/board_arm_def.h
@@ -102,7 +102,7 @@
  * little space for growth.
  */
 #if TRUSTED_BOARD_BOOT
-# define PLAT_ARM_MAX_BL2_SIZE		0x1C000
+# define PLAT_ARM_MAX_BL2_SIZE		0x1D000
 #else
 # define PLAT_ARM_MAX_BL2_SIZE		0x11000
 #endif
diff --git a/include/plat/arm/board/common/v2m_def.h b/include/plat/arm/board/common/v2m_def.h
index e5f5373..ce436d2 100644
--- a/include/plat/arm/board/common/v2m_def.h
+++ b/include/plat/arm/board/common/v2m_def.h
@@ -32,6 +32,9 @@
 #define V2M_FUNC_SHUTDOWN		0x08
 #define V2M_FUNC_REBOOT			0x09
 
+/* NVFLAGS in the V2M motherboard which is preserved after a watchdog reset */
+ #define V2M_SYS_NVFLAGS_ADDR		(V2M_SYSREGS_BASE + V2M_SYS_NVFLAGS)
+
 /*
  * V2M sysled bit definitions. The values written to this
  * register are defined in arch.h & runtime_svc.h. Only
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index 0770c0e..53b4a45 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -245,6 +245,8 @@
 void plat_arm_interconnect_enter_coherency(void);
 void plat_arm_interconnect_exit_coherency(void);
 void plat_arm_program_trusted_mailbox(uintptr_t address);
+int plat_arm_bl1_fwu_needed(void);
+void plat_arm_error_handler(int err);
 
 #if ARM_PLAT_MT
 unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr);
diff --git a/plat/arm/board/juno/juno_bl1_setup.c b/plat/arm/board/juno/juno_bl1_setup.c
index 836a672..3dd2a22 100644
--- a/plat/arm/board/juno/juno_bl1_setup.c
+++ b/plat/arm/board/juno/juno_bl1_setup.c
@@ -5,15 +5,72 @@
  */
 
 #include <bl_common.h>
+#include <debug.h>
 #include <errno.h>
 #include <plat_arm.h>
 #include <platform.h>
+#include <sds.h>
 #include <sp805.h>
 #include <tbbr_img_def.h>
 #include <v2m_def.h>
 
 void juno_reset_to_aarch32_state(void);
 
+static int is_watchdog_reset(void)
+{
+#if !CSS_USE_SCMI_SDS_DRIVER
+	#define RESET_REASON_WDOG_RESET		(0x2)
+	const uint32_t *reset_flags_ptr = (const uint32_t *)SSC_GPRETN;
+
+	if ((*reset_flags_ptr & RESET_REASON_WDOG_RESET) != 0)
+		return 1;
+
+	return 0;
+#else
+	int ret;
+	uint32_t scp_reset_synd_flags;
+
+	ret = sds_init();
+	if (ret != SDS_OK) {
+		ERROR("SCP SDS initialization failed\n");
+		panic();
+	}
+
+	ret = sds_struct_read(SDS_RESET_SYNDROME_STRUCT_ID,
+					SDS_RESET_SYNDROME_OFFSET,
+					&scp_reset_synd_flags,
+					SDS_RESET_SYNDROME_SIZE,
+					SDS_ACCESS_MODE_NON_CACHED);
+	if (ret != SDS_OK) {
+		ERROR("Getting reset reason from SDS failed\n");
+		panic();
+	}
+
+	/* Check if the WATCHDOG_RESET_BIT is set in the reset syndrome */
+	if (scp_reset_synd_flags & SDS_RESET_SYNDROME_AP_WD_RESET_BIT)
+		return 1;
+
+	return 0;
+#endif
+}
+
+/*******************************************************************************
+ * The following function checks if Firmware update is needed,
+ * by checking if TOC in FIP image is valid or watchdog reset happened.
+ ******************************************************************************/
+int plat_arm_bl1_fwu_needed(void)
+{
+	const uint32_t *nv_flags_ptr = (const uint32_t *)V2M_SYS_NVFLAGS_ADDR;
+
+	/* Check if TOC is invalid or watchdog reset happened. */
+	if ((arm_io_is_toc_valid() != 1) ||
+		(((*nv_flags_ptr == -EAUTH) || (*nv_flags_ptr == -ENOENT))
+		&& is_watchdog_reset()))
+		return 1;
+
+	return 0;
+}
+
 /*******************************************************************************
  * On JUNO update the arg2 with address of SCP_BL2U image info.
  ******************************************************************************/
diff --git a/plat/arm/board/juno/juno_err.c b/plat/arm/board/juno/juno_err.c
new file mode 100644
index 0000000..dd8e278
--- /dev/null
+++ b/plat/arm/board/juno/juno_err.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <errno.h>
+#include <platform.h>
+#include <v2m_def.h>
+
+/*
+ * Juno error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+	uint32_t *flags_ptr = (uint32_t *)V2M_SYS_NVFLAGS_ADDR;
+
+	/* Propagate the err code in the NV-flags register */
+	*flags_ptr = err;
+
+	/* Loop until the watchdog resets the system */
+	for (;;)
+		wfi();
+}
diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk
index 16390fa..481844f 100644
--- a/plat/arm/board/juno/platform.mk
+++ b/plat/arm/board/juno/platform.mk
@@ -22,7 +22,12 @@
 JUNO_SECURITY_SOURCES	+=	plat/arm/board/juno/juno_stack_protector.c
 endif
 
-PLAT_INCLUDES		:=	-Iplat/arm/board/juno/include
+# Select SCMI/SDS drivers instead of SCPI/BOM driver for communicating with the
+# SCP during power management operations and for SCP RAM Firmware transfer.
+CSS_USE_SCMI_SDS_DRIVER		:=	1
+
+PLAT_INCLUDES		:=	-Iplat/arm/board/juno/include		\
+				-Iplat/arm/css/drivers/sds
 
 PLAT_BL_COMMON_SOURCES	:=	plat/arm/board/juno/${ARCH}/juno_helpers.S
 
@@ -55,11 +60,13 @@
 BL1_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
 				lib/cpus/aarch64/cortex_a57.S		\
 				lib/cpus/aarch64/cortex_a72.S		\
+				plat/arm/board/juno/juno_err.c		\
 				plat/arm/board/juno/juno_bl1_setup.c	\
 				${JUNO_INTERCONNECT_SOURCES}		\
 				${JUNO_SECURITY_SOURCES}
 
 BL2_SOURCES		+=	lib/utils/mem_region.c			\
+				plat/arm/board/juno/juno_err.c		\
 				plat/arm/board/juno/juno_bl2_setup.c	\
 				plat/arm/common/arm_nor_psci_mem_protect.c \
 				${JUNO_SECURITY_SOURCES}
@@ -76,8 +83,13 @@
 				${JUNO_GIC_SOURCES}			\
 				${JUNO_INTERCONNECT_SOURCES}		\
 				${JUNO_SECURITY_SOURCES}
+
+ifeq (${CSS_USE_SCMI_SDS_DRIVER},1)
+BL1_SOURCES		+=	plat/arm/css/drivers/sds/sds.c
 endif
 
+endif
+
 # Errata workarounds for Cortex-A53:
 ERRATA_A53_826319		:=	1
 ERRATA_A53_835769		:=	1
@@ -112,10 +124,6 @@
 # Do not enable SVE
 ENABLE_SVE_FOR_NS		:=	0
 
-# Select SCMI/SDS drivers instead of SCPI/BOM driver for communicating with the
-# SCP during power management operations and for SCP RAM Firmware transfer.
-CSS_USE_SCMI_SDS_DRIVER		:=	1
-
 include plat/arm/board/common/board_css.mk
 include plat/arm/common/arm_common.mk
 include plat/arm/soc/common/soc_css.mk
diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c
index a4d2b44..d9104ee 100644
--- a/plat/arm/common/arm_bl1_setup.c
+++ b/plat/arm/common/arm_bl1_setup.c
@@ -23,6 +23,8 @@
 #pragma weak bl1_platform_setup
 #pragma weak bl1_plat_sec_mem_layout
 #pragma weak bl1_plat_prepare_exit
+#pragma weak bl1_plat_get_next_image_id
+#pragma weak plat_arm_bl1_fwu_needed
 
 #define MAP_BL1_TOTAL		MAP_REGION_FLAT(			\
 					bl1_tzram_layout.total_base,	\
@@ -186,13 +188,22 @@
 #endif
 }
 
+/*
+ * On Arm platforms, the FWU process is triggered when the FIP image has
+ * been tampered with.
+ */
+int plat_arm_bl1_fwu_needed(void)
+{
+	return (arm_io_is_toc_valid() != 1);
+}
+
 /*******************************************************************************
  * The following function checks if Firmware update is needed,
  * by checking if TOC in FIP image is valid or not.
  ******************************************************************************/
 unsigned int bl1_plat_get_next_image_id(void)
 {
-	if (!arm_io_is_toc_valid())
+	if (plat_arm_bl1_fwu_needed() != 0)
 		return NS_BL1U_IMAGE_ID;
 
 	return BL2_IMAGE_ID;
diff --git a/plat/arm/common/arm_dyn_cfg.c b/plat/arm/common/arm_dyn_cfg.c
index f2570a8..95fe2c5 100644
--- a/plat/arm/common/arm_dyn_cfg.c
+++ b/plat/arm/common/arm_dyn_cfg.c
@@ -21,6 +21,7 @@
 
 /* Variable to store the address of TB_FW_CONFIG file */
 static void *tb_fw_cfg_dtb;
+static size_t tb_fw_cfg_dtb_size;
 
 
 #if TRUSTED_BOARD_BOOT
@@ -62,11 +63,15 @@
 	int err;
 
 	/* If in BL2, retrieve the already allocated heap's info from DTB */
-	err = arm_get_dtb_mbedtls_heap_info(tb_fw_cfg_dtb, heap_addr,
-		heap_size);
-	if (err < 0) {
-		ERROR("BL2: unable to retrieve shared Mbed TLS heap "
-			"information from DTB\n");
+	if (tb_fw_cfg_dtb != NULL) {
+		err = arm_get_dtb_mbedtls_heap_info(tb_fw_cfg_dtb, heap_addr,
+			heap_size);
+		if (err < 0) {
+			ERROR("BL2: unable to retrieve shared Mbed TLS heap information from DTB\n");
+			panic();
+		}
+	} else {
+		ERROR("BL2: DTB missing, cannot get Mbed TLS heap\n");
 		panic();
 	}
 #endif
@@ -98,10 +103,16 @@
 		err = arm_set_dtb_mbedtls_heap_info(tb_fw_cfg_dtb,
 			mbedtls_heap_addr, mbedtls_heap_size);
 		if (err < 0) {
-			ERROR("BL1: unable to write shared Mbed TLS heap "
-				"information to DTB\n");
+			ERROR("BL1: unable to write shared Mbed TLS heap information to DTB\n");
 			panic();
 		}
+		/*
+		 * Ensure that the info written to the DTB is visible to other
+		 * images. It's critical because BL2 won't be able to proceed
+		 * without the heap info.
+		 */
+		flush_dcache_range((uintptr_t)tb_fw_cfg_dtb,
+			tb_fw_cfg_dtb_size);
 	}
 }
 
@@ -122,7 +133,8 @@
 		SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
 				VERSION_2, image_info_t, 0),
 		.image_info.image_base = ARM_TB_FW_CONFIG_BASE,
-		.image_info.image_max_size = ARM_TB_FW_CONFIG_LIMIT - ARM_TB_FW_CONFIG_BASE,
+		.image_info.image_max_size =
+			ARM_TB_FW_CONFIG_LIMIT - ARM_TB_FW_CONFIG_BASE
 	};
 
 	VERBOSE("BL1: Loading TB_FW_CONFIG\n");
@@ -136,6 +148,7 @@
 	/* At this point we know that a DTB is indeed available */
 	config_base = arm_tb_fw_info.image_info.image_base;
 	tb_fw_cfg_dtb = (void *)config_base;
+	tb_fw_cfg_dtb_size = (size_t)arm_tb_fw_info.image_info.image_max_size;
 
 	/* The BL2 ep_info arg0 is modified to point to TB_FW_CONFIG */
 	image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
diff --git a/plat/arm/common/arm_dyn_cfg_helpers.c b/plat/arm/common/arm_dyn_cfg_helpers.c
index e610903..d12d09c 100644
--- a/plat/arm/common/arm_dyn_cfg_helpers.c
+++ b/plat/arm/common/arm_dyn_cfg_helpers.c
@@ -167,8 +167,6 @@
 	return 0;
 }
 
-
-#if TRUSTED_BOARD_BOOT && LOAD_IMAGE_V2
 /*
  * Reads and returns the Mbed TLS shared heap information from the DTB.
  * This function is supposed to be called *only* when a DTB is present.
@@ -187,8 +185,7 @@
 	/* Verify the DTB is valid and get the root node */
 	err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root);
 	if (err < 0) {
-		ERROR("%s: Invalid TB_FW_CONFIG. Cannot retrieve Mbed TLS "
-			"heap information from DTB\n", __func__);
+		ERROR("Invalid TB_FW_CONFIG. Cannot retrieve Mbed TLS heap information from DTB\n");
 		return -1;
 	}
 
@@ -196,14 +193,14 @@
 	err = fdtw_read_cells(dtb, dtb_root,
 		DTB_PROP_MBEDTLS_HEAP_ADDR, 2, heap_addr);
 	if (err < 0) {
-		ERROR("%s: error while reading %s from DTB\n", __func__,
+		ERROR("Error while reading %s from DTB\n",
 			DTB_PROP_MBEDTLS_HEAP_ADDR);
 		return -1;
 	}
 	err = fdtw_read_cells(dtb, dtb_root,
 		DTB_PROP_MBEDTLS_HEAP_SIZE, 1, heap_size);
 	if (err < 0) {
-		ERROR("%s: error while reading %s from DTB\n", __func__,
+		ERROR("Error while reading %s from DTB\n",
 			DTB_PROP_MBEDTLS_HEAP_SIZE);
 		return -1;
 	}
@@ -234,8 +231,7 @@
 	 */
 	err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root);
 	if (err < 0) {
-		ERROR("%s: Invalid TB_FW_CONFIG loaded. Unable to get "
-			"root node\n", __func__);
+		ERROR("Invalid TB_FW_CONFIG loaded. Unable to get root node\n");
 		return -1;
 	}
 
@@ -249,19 +245,18 @@
 	err = fdtw_write_inplace_cells(dtb, dtb_root,
 		DTB_PROP_MBEDTLS_HEAP_ADDR, 2, &heap_addr);
 	if (err < 0) {
-		ERROR("%s: unable to write DTB property %s\n",
-			__func__, DTB_PROP_MBEDTLS_HEAP_ADDR);
+		ERROR("Unable to write DTB property %s\n",
+			DTB_PROP_MBEDTLS_HEAP_ADDR);
 		return -1;
 	}
 
 	err = fdtw_write_inplace_cells(dtb, dtb_root,
 		DTB_PROP_MBEDTLS_HEAP_SIZE, 1, &heap_size);
 	if (err < 0) {
-		ERROR("%s: unable to write DTB property %s\n",
-			__func__, DTB_PROP_MBEDTLS_HEAP_SIZE);
+		ERROR("Unable to write DTB property %s\n",
+			DTB_PROP_MBEDTLS_HEAP_SIZE);
 		return -1;
 	}
 
 	return 0;
 }
-#endif /* TRUSTED_BOARD_BOOT && LOAD_IMAGE_V2 */
diff --git a/plat/arm/common/arm_err.c b/plat/arm/common/arm_err.c
index 66568e7..e13e51f 100644
--- a/plat/arm/common/arm_err.c
+++ b/plat/arm/common/arm_err.c
@@ -13,10 +13,12 @@
 #include <platform_def.h>
 #include <stdint.h>
 
+#pragma weak plat_arm_error_handler
+
 /*
  * ARM common implementation for error handler
  */
-void plat_error_handler(int err)
+void __dead2 plat_arm_error_handler(int err)
 {
 	int ret;
 
@@ -44,3 +46,8 @@
 	for (;;)
 		wfi();
 }
+
+void __dead2 plat_error_handler(int err)
+{
+	plat_arm_error_handler(err);
+}
diff --git a/services/std_svc/sdei/sdei_main.c b/services/std_svc/sdei/sdei_main.c
index 9b78d7f..990d028 100644
--- a/services/std_svc/sdei/sdei_main.c
+++ b/services/std_svc/sdei/sdei_main.c
@@ -81,6 +81,17 @@
 	return NULL;
 }
 
+/* CPU initialisation after wakeup from suspend */
+static void *sdei_cpu_wakeup_init(const void *arg)
+{
+	SDEI_LOG("Events masked on %lx\n", read_mpidr_el1());
+
+	/* All PEs wake up with SDEI events masked */
+	sdei_pe_mask();
+
+	return 0;
+}
+
 /* Initialise an SDEI class */
 static void sdei_class_init(sdei_class_t class)
 {
@@ -1075,3 +1086,6 @@
 
 /* Subscribe to PSCI CPU on to initialize per-CPU SDEI configuration */
 SUBSCRIBE_TO_EVENT(psci_cpu_on_finish, sdei_cpu_on_init);
+
+/* Subscribe to PSCI CPU suspend finisher for per-CPU configuration */
+SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, sdei_cpu_wakeup_init);