diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index d766490d17312825296e37c2bcacbd7cb9a3042f..4b323d335025ebb49251625b8fc02e77f4b17780 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -261,6 +261,16 @@
 #define DISABLE_ALL_EXCEPTIONS \
 		(DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT | DAIF_DBG_BIT)
 
+/*
+ * RMR_EL3 definitions
+ */
+#define RMR_EL3_RR_BIT		(1 << 1)
+#define RMR_EL3_AA64_BIT	(1 << 0)
+
+/*
+ * HI-VECTOR address for AArch32 state
+ */
+#define HI_VECTOR_BASE	(0xFFFF0000)
 
 /*
  * TCR defintions
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index b24af78d9442b7a921acba449261238d8208ef39..d68a3e3bd79775061b9c5be5b8ecab77b4951019 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -157,6 +157,7 @@ void arm_bl2_platform_setup(void);
 void arm_bl2_plat_arch_setup(void);
 uint32_t arm_get_spsr_for_bl32_entry(void);
 uint32_t arm_get_spsr_for_bl33_entry(void);
+int arm_bl2_handle_post_image_load(unsigned int image_id);
 
 /* BL2U utility functions */
 void arm_bl2u_early_platform_setup(struct meminfo *mem_layout,
diff --git a/include/plat/arm/soc/common/soc_css_def.h b/include/plat/arm/soc/common/soc_css_def.h
index 3b4cc79f8e3661df85f293cc93dc7f128b7cdab8..efd78f04454f0f0dc30bc5eb053ebef76568979e 100644
--- a/include/plat/arm/soc/common/soc_css_def.h
+++ b/include/plat/arm/soc/common/soc_css_def.h
@@ -96,9 +96,16 @@
 /*
  * Required platform porting definitions common to all ARM CSS SoCs
  */
-
+#if JUNO_AARCH32_EL3_RUNTIME
+/*
+ * Following change is required to initialize TZC
+ * for enabling access to the HI_VECTOR (0xFFFF0000)
+ * location needed for JUNO AARCH32 support.
+ */
+#define PLAT_ARM_SCP_TZC_DRAM1_SIZE	ULL(0x8000)
+#else
 /* 2MB used for SCP DDR retraining */
 #define PLAT_ARM_SCP_TZC_DRAM1_SIZE	ULL(0x00200000)
-
+#endif
 
 #endif /* __SOC_CSS_DEF_H__ */
diff --git a/plat/arm/board/juno/aarch64/juno_helpers.S b/plat/arm/board/juno/aarch64/juno_helpers.S
index ac54ac9b3779e4ad042bbb09652e78e42582ac2b..49fef16ff0847366697e86fc8f3f8995ff118f2f 100644
--- a/plat/arm/board/juno/aarch64/juno_helpers.S
+++ b/plat/arm/board/juno/aarch64/juno_helpers.S
@@ -34,12 +34,18 @@
 #include <cortex_a53.h>
 #include <cortex_a57.h>
 #include <cortex_a72.h>
+#include <cpu_macros.S>
+#include <css_def.h>
 #include <v2m_def.h>
 #include "../juno_def.h"
 
 
 	.globl	plat_reset_handler
 	.globl	plat_arm_calc_core_pos
+#if JUNO_AARCH32_EL3_RUNTIME
+	.globl	plat_get_my_entrypoint
+	.globl	juno_reset_to_aarch32_state
+#endif
 
 #define JUNO_REVISION(rev)	REV_JUNO_R##rev
 #define JUNO_HANDLER(rev)	plat_reset_handler_juno_r##rev
@@ -205,6 +211,20 @@ func plat_reset_handler
 
 endfunc plat_reset_handler
 
+	/* -----------------------------------------------------
+	 *  void juno_do_reset_to_aarch32_state(void);
+	 *
+	 *  Request warm reset to AArch32 mode.
+	 * -----------------------------------------------------
+	 */
+func juno_do_reset_to_aarch32_state
+	mov	x0, #RMR_EL3_RR_BIT
+	dsb	sy
+	msr	rmr_el3, x0
+	isb
+	wfi
+endfunc juno_do_reset_to_aarch32_state
+
 	/* -----------------------------------------------------
 	 *  unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
 	 *  Helper function to calculate the core position.
@@ -213,3 +233,77 @@ endfunc plat_reset_handler
 func plat_arm_calc_core_pos
 	b	css_calc_core_pos_swap_cluster
 endfunc plat_arm_calc_core_pos
+
+#if JUNO_AARCH32_EL3_RUNTIME
+	/* ---------------------------------------------------------------------
+	 * uintptr_t plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between a cold and a warm
+	 * boot. On JUNO platform, this distinction is based on the contents of
+	 * the Trusted Mailbox. It is initialised to zero by the SCP before the
+	 * AP cores are released from reset. Therefore, a zero mailbox means
+	 * it's a cold reset. If it is a warm boot then a request to reset to
+	 * AArch32 state is issued. This is the only way to reset to AArch32
+	 * in EL3 on Juno. A trampoline located at the high vector address
+	 * has already been prepared by BL1.
+	 *
+	 * This functions returns the contents of the mailbox, i.e.:
+	 *  - 0 for a cold boot;
+	 *  - request warm reset in AArch32 state for warm boot case;
+	 * ---------------------------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	mov_imm	x0, PLAT_ARM_TRUSTED_MAILBOX_BASE
+	ldr	x0, [x0]
+	cbz	x0, return
+	b	juno_do_reset_to_aarch32_state
+1:
+	b	1b
+return:
+	ret
+endfunc plat_get_my_entrypoint
+
+/*
+ * Emit a "movw r0, #imm16" which moves the lower
+ * 16 bits of `_val` into r0.
+ */
+.macro emit_movw _reg_d, _val
+	mov_imm	\_reg_d, (0xe3000000 | \
+			((\_val & 0xfff) | \
+			((\_val & 0xf000) << 4)))
+.endm
+
+/*
+ * Emit a "movt r0, #imm16" which moves the upper
+ * 16 bits of `_val` into r0.
+ */
+.macro emit_movt _reg_d, _val
+	mov_imm	\_reg_d, (0xe3400000 | \
+			(((\_val & 0x0fff0000) >> 16) | \
+			((\_val & 0xf0000000) >> 12)))
+.endm
+
+/*
+ * This function writes the trampoline code at HI-VEC (0xFFFF0000)
+ * address which loads r0 with the entrypoint address for
+ * BL32 (a.k.a SP_MIN) when EL3 is in AArch32 mode. A warm reset
+ * to AArch32 mode is then requested by writing into RMR_EL3.
+ */
+func juno_reset_to_aarch32_state
+	emit_movw	w0, BL32_BASE
+	emit_movt	w1, BL32_BASE
+	/* opcode "bx r0" to branch using r0 in AArch32 mode */
+	mov_imm	w2, 0xe12fff10
+
+	/* Write the above opcodes at HI-VECTOR location */
+	mov_imm	x3, HI_VECTOR_BASE
+	str	w0, [x3], #4
+	str	w1, [x3], #4
+	str	w2, [x3]
+
+	bl	juno_do_reset_to_aarch32_state
+1:
+	b	1b
+endfunc juno_reset_to_aarch32_state
+
+#endif /* JUNO_AARCH32_EL3_RUNTIME */
diff --git a/plat/arm/board/juno/juno_bl1_setup.c b/plat/arm/board/juno/juno_bl1_setup.c
index e805c9a38594f41826feead5f62050ca92d581f4..93ca1c319617d5d91f26a6fab8a0c02b632e2047 100644
--- a/plat/arm/board/juno/juno_bl1_setup.c
+++ b/plat/arm/board/juno/juno_bl1_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -32,11 +32,15 @@
 #include <errno.h>
 #include <platform.h>
 #include <plat_arm.h>
+#include <sp805.h>
 #include <tbbr_img_def.h>
 #include <v2m_def.h>
 
 #define RESET_REASON_WDOG_RESET		(0x2)
 
+void juno_reset_to_aarch32_state(void);
+
+
 /*******************************************************************************
  * The following function checks if Firmware update is needed,
  * by checking if TOC in FIP image is valid or watchdog reset happened.
@@ -85,3 +89,15 @@ __dead2 void bl1_plat_fwu_done(void *client_cookie, void *reserved)
 	while (1)
 		wfi();
 }
+
+#if JUNO_AARCH32_EL3_RUNTIME
+void bl1_plat_prepare_exit(entry_point_info_t *ep_info)
+{
+#if !ARM_DISABLE_TRUSTED_WDOG
+	/* Disable watchdog before leaving BL1 */
+	sp805_stop(ARM_SP805_TWDG_BASE);
+#endif
+
+	juno_reset_to_aarch32_state();
+}
+#endif /* JUNO_AARCH32_EL3_RUNTIME */
diff --git a/plat/arm/board/juno/juno_bl2_setup.c b/plat/arm/board/juno/juno_bl2_setup.c
new file mode 100644
index 0000000000000000000000000000000000000000..ffb6387e057f9234929428d9138bd5611c318a05
--- /dev/null
+++ b/plat/arm/board/juno/juno_bl2_setup.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <bl_common.h>
+#include <desc_image_load.h>
+#include <plat_arm.h>
+
+#if JUNO_AARCH32_EL3_RUNTIME
+/*******************************************************************************
+ * This function changes the spsr for BL32 image to bypass
+ * the check in BL1 AArch64 exception handler. This is needed in the aarch32
+ * boot flow as the core comes up in aarch64 and to enter the BL32 image a warm
+ * reset in aarch32 state is required.
+ ******************************************************************************/
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	int err = arm_bl2_handle_post_image_load(image_id);
+
+	if (!err && (image_id == BL32_IMAGE_ID)) {
+		bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+		assert(bl_mem_params);
+		bl_mem_params->ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+			DISABLE_ALL_EXCEPTIONS);
+	}
+
+	return err;
+}
+#endif /* JUNO_AARCH32_EL3_RUNTIME */
diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk
index 39977240bcfc8ff3f4fe2191f494f3339cae6d3b..0855438139b1340070f2f7ccfefcc12e2ff189cf 100644
--- a/plat/arm/board/juno/platform.mk
+++ b/plat/arm/board/juno/platform.mk
@@ -48,8 +48,14 @@ endif
 
 PLAT_INCLUDES		:=	-Iplat/arm/board/juno/include
 
-PLAT_BL_COMMON_SOURCES	:=	plat/arm/board/juno/aarch64/juno_helpers.S
+PLAT_BL_COMMON_SOURCES	:=	plat/arm/board/juno/${ARCH}/juno_helpers.S
 
+# Flag to enable support for AArch32 state on JUNO
+JUNO_AARCH32_EL3_RUNTIME	:=	0
+$(eval $(call assert_boolean,JUNO_AARCH32_EL3_RUNTIME))
+$(eval $(call add_define,JUNO_AARCH32_EL3_RUNTIME))
+
+ifeq (${ARCH},aarch64)
 BL1_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
 				lib/cpus/aarch64/cortex_a57.S		\
 				lib/cpus/aarch64/cortex_a72.S		\
@@ -59,6 +65,7 @@ BL1_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
 				${JUNO_SECURITY_SOURCES}
 
 BL2_SOURCES		+=	plat/arm/board/juno/juno_err.c		\
+				plat/arm/board/juno/juno_bl2_setup.c	\
 				${JUNO_SECURITY_SOURCES}
 
 BL2U_SOURCES		+=	${JUNO_SECURITY_SOURCES}
@@ -71,6 +78,7 @@ BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
 				${JUNO_GIC_SOURCES}			\
 				${JUNO_INTERCONNECT_SOURCES}		\
 				${JUNO_SECURITY_SOURCES}
+endif
 
 # Enable workarounds for selected Cortex-A53 and A57 errata.
 ERRATA_A53_855873		:=	1
diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c
index 8c1fde43fda74915ecdf34f28705b033f155339e..ffbf113b1d2c4ca1726d0de0501f98083360dd3f 100644
--- a/plat/arm/common/arm_bl1_setup.c
+++ b/plat/arm/common/arm_bl1_setup.c
@@ -44,6 +44,7 @@
 #pragma weak bl1_plat_arch_setup
 #pragma weak bl1_platform_setup
 #pragma weak bl1_plat_sec_mem_layout
+#pragma weak bl1_plat_prepare_exit
 
 
 /* Data structure which holds the extents of the trusted SRAM for BL1*/
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index 007108d12039dcb4921cdc4514ffa3b4c5df39e6..66e350aad4892b8822fbb1509a2f54bdb639a743 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -249,11 +249,7 @@ void bl2_plat_arch_setup(void)
 }
 
 #if LOAD_IMAGE_V2
-/*******************************************************************************
- * This function can be used by the platforms to update/use image
- * information for given `image_id`.
- ******************************************************************************/
-int bl2_plat_handle_post_image_load(unsigned int image_id)
+int arm_bl2_handle_post_image_load(unsigned int image_id)
 {
 	int err = 0;
 	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
@@ -286,6 +282,15 @@ int bl2_plat_handle_post_image_load(unsigned int image_id)
 	return err;
 }
 
+/*******************************************************************************
+ * This function can be used by the platforms to update/use image
+ * information for given `image_id`.
+ ******************************************************************************/
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	return arm_bl2_handle_post_image_load(image_id);
+}
+
 #else /* LOAD_IMAGE_V2 */
 
 /*******************************************************************************
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 891e2fbd46f950bf85797fc11873da07e88d19a5..f7ec57ef7e190ce423903658f36935efd219eebb 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -137,8 +137,14 @@ BL2_SOURCES		+=	drivers/io/io_fip.c				\
 				plat/arm/common/arm_bl2_setup.c			\
 				plat/arm/common/arm_io_storage.c
 ifeq (${LOAD_IMAGE_V2},1)
-BL2_SOURCES		+=	plat/arm/common/${ARCH}/arm_bl2_mem_params_desc.c\
-				plat/arm/common/arm_image_load.c		\
+# Because BL1/BL2 execute in AArch64 mode but BL32 in AArch32 we need to use
+# the AArch32 descriptors.
+ifeq (${JUNO_AARCH32_EL3_RUNTIME},1)
+BL2_SOURCES		+=	plat/arm/common/aarch32/arm_bl2_mem_params_desc.c
+else
+BL2_SOURCES		+=	plat/arm/common/${ARCH}/arm_bl2_mem_params_desc.c
+endif
+BL2_SOURCES		+=	plat/arm/common/arm_image_load.c		\
 				common/desc_image_load.c
 endif