Merge "AArch32: Disable Secure Cycle Counter" into integration
diff --git a/common/fdt_fixup.c b/common/fdt_fixup.c
index 8843404..99d0eee 100644
--- a/common/fdt_fixup.c
+++ b/common/fdt_fixup.c
@@ -29,6 +29,33 @@
 	return fdt_appendprop(fdt, offs, "compatible", str, strlen(str) + 1);
 }
 
+/*
+ * Those defines are for PSCI v0.1 legacy clients, which we expect to use
+ * the same execution state (AArch32/AArch64) as TF-A.
+ * Kernels running in AArch32 on an AArch64 TF-A should use PSCI v0.2.
+ */
+#ifdef __aarch64__
+#define PSCI_CPU_SUSPEND_FNID	PSCI_CPU_SUSPEND_AARCH64
+#define PSCI_CPU_ON_FNID	PSCI_CPU_ON_AARCH64
+#else
+#define PSCI_CPU_SUSPEND_FNID	PSCI_CPU_SUSPEND_AARCH32
+#define PSCI_CPU_ON_FNID	PSCI_CPU_ON_AARCH32
+#endif
+
+/*******************************************************************************
+ * dt_add_psci_node() - Add a PSCI node into an existing device tree
+ * @fdt:	pointer to the device tree blob in memory
+ *
+ * Add a device tree node describing PSCI into the root level of an existing
+ * device tree blob in memory.
+ * This will add v0.1, v0.2 and v1.0 compatible strings and the standard
+ * function IDs for v0.1 compatibility.
+ * An existing PSCI node will not be touched, the function will return success
+ * in this case. This function will not touch the /cpus enable methods, use
+ * dt_add_psci_cpu_enable_methods() for that.
+ *
+ * Return: 0 on success, -1 otherwise.
+ ******************************************************************************/
 int dt_add_psci_node(void *fdt)
 {
 	int offs;
@@ -52,15 +79,11 @@
 		return -1;
 	if (fdt_setprop_string(fdt, offs, "method", "smc"))
 		return -1;
-	if (fdt_setprop_u32(fdt, offs, "cpu_suspend", PSCI_CPU_SUSPEND_AARCH64))
+	if (fdt_setprop_u32(fdt, offs, "cpu_suspend", PSCI_CPU_SUSPEND_FNID))
 		return -1;
 	if (fdt_setprop_u32(fdt, offs, "cpu_off", PSCI_CPU_OFF))
 		return -1;
-	if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON_AARCH64))
-		return -1;
-	if (fdt_setprop_u32(fdt, offs, "sys_poweroff", PSCI_SYSTEM_OFF))
-		return -1;
-	if (fdt_setprop_u32(fdt, offs, "sys_reset", PSCI_SYSTEM_RESET))
+	if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON_FNID))
 		return -1;
 	return 0;
 }
@@ -113,6 +136,17 @@
 	return offs;
 }
 
+/*******************************************************************************
+ * dt_add_psci_cpu_enable_methods() - switch CPU nodes in DT to use PSCI
+ * @fdt:	pointer to the device tree blob in memory
+ *
+ * Iterate over all CPU device tree nodes (/cpus/cpu@x) in memory to change
+ * the enable-method to PSCI. This will add the enable-method properties, if
+ * required, or will change existing properties to read "psci".
+ *
+ * Return: 0 on success, or a negative error value otherwise.
+ ******************************************************************************/
+
 int dt_add_psci_cpu_enable_methods(void *fdt)
 {
 	int offs, ret;
@@ -130,6 +164,25 @@
 
 #define HIGH_BITS(x) ((sizeof(x) > 4) ? ((x) >> 32) : (typeof(x))0)
 
+/*******************************************************************************
+ * fdt_add_reserved_memory() - reserve (secure) memory regions in DT
+ * @dtb:	pointer to the device tree blob in memory
+ * @node_name:	name of the subnode to be used
+ * @base:	physical base address of the reserved region
+ * @size:	size of the reserved region
+ *
+ * Add a region of memory to the /reserved-memory node in a device tree in
+ * memory, creating that node if required. Each region goes into a subnode
+ * of that node and has a @node_name, a @base address and a @size.
+ * This will prevent any device tree consumer from using that memory. It
+ * can be used to announce secure memory regions, as it adds the "no-map"
+ * property to prevent mapping and speculative operations on that region.
+ *
+ * See reserved-memory/reserved-memory.txt in the (Linux kernel) DT binding
+ * documentation for details.
+ *
+ * Return: 0 on success, a negative error value otherwise.
+ ******************************************************************************/
 int fdt_add_reserved_memory(void *dtb, const char *node_name,
 			    uintptr_t base, size_t size)
 {
diff --git a/docs/getting_started/porting-guide.rst b/docs/getting_started/porting-guide.rst
index 97ed1fa..9eb7c17 100644
--- a/docs/getting_started/porting-guide.rst
+++ b/docs/getting_started/porting-guide.rst
@@ -2209,6 +2209,19 @@
 above the CPU might require initialization due to having previously been in
 low power states. The generic code expects the handler to succeed.
 
+plat_psci_ops.pwr_domain_on_finish_late() [optional]
+...........................................................
+
+This optional function is called by the PSCI implementation after the calling
+CPU is fully powered on with respective data caches enabled. The calling CPU and
+the associated cluster are guaranteed to be participating in coherency. This
+function gives the flexibility to perform any platform-specific actions safely,
+such as initialization or modification of shared data structures, without the
+overhead of explicit cache maintainace operations.
+
+The ``target_state`` has a similar meaning as described in the ``pwr_domain_on_finish()``
+operation. The generic code expects the handler to succeed.
+
 plat_psci_ops.pwr_domain_suspend_finish()
 .........................................
 
diff --git a/docs/maintainers.rst b/docs/maintainers.rst
index 7731c72..d997baa 100644
--- a/docs/maintainers.rst
+++ b/docs/maintainers.rst
@@ -48,6 +48,14 @@
 :F: drivers/amlogic/gxl
 :F: plat/amlogic/gxl/
 
+Amlogic Meson S905X2 (G12A) platform port
+---------------------------------------
+:M: Carlo Caione <ccaione@baylibre.com>
+:G: `carlo.caione`_
+:F: docs/plat/meson-g12a.rst
+:F: drivers/amlogic/g12a
+:F: plat/amlogic/g12a/
+
 Armv7-A architecture port
 -------------------------
 :M: Etienne Carriere <etienne.carriere@linaro.org>
diff --git a/docs/plat/hikey.rst b/docs/plat/hikey.rst
index 74ff2f4..372d388 100644
--- a/docs/plat/hikey.rst
+++ b/docs/plat/hikey.rst
@@ -1,15 +1,15 @@
-Description
-===========
+HiKey
+=====
 
 HiKey is one of 96boards. Hisilicon Kirin6220 processor is installed on HiKey.
 
 More information are listed in `link`_.
 
 How to build
-============
+------------
 
 Code Locations
---------------
+~~~~~~~~~~~~~~
 
 -  Trusted Firmware-A:
    `link <https://github.com/ARM-software/arm-trusted-firmware>`__
@@ -33,7 +33,7 @@
    `link <https://github.com/96boards-hikey/atf-fastboot/tree/master>`__
 
 Build Procedure
----------------
+~~~~~~~~~~~~~~~
 
 -  Fetch all the above repositories into local host.
    Make all the repositories in the same ${BUILD\_PATH}.
diff --git a/docs/plat/hikey960.rst b/docs/plat/hikey960.rst
index 7ddb0b1..3d42a77 100644
--- a/docs/plat/hikey960.rst
+++ b/docs/plat/hikey960.rst
@@ -1,15 +1,15 @@
-Description
-===========
+HiKey960
+========
 
 HiKey960 is one of 96boards. Hisilicon Hi3660 processor is installed on HiKey960.
 
 More information are listed in `link`_.
 
 How to build
-============
+------------
 
 Code Locations
---------------
+~~~~~~~~~~~~~~
 
 -  Trusted Firmware-A:
    `link <https://github.com/ARM-software/arm-trusted-firmware>`__
@@ -30,7 +30,7 @@
    `link <https://git.linaro.org/uefi/uefi-tools.git>`__
 
 Build Procedure
----------------
+~~~~~~~~~~~~~~~
 
 -  Fetch all the above 5 repositories into local host.
    Make all the repositories in the same ${BUILD\_PATH}.
diff --git a/docs/plat/index.rst b/docs/plat/index.rst
index eaeee84..2695d4e 100644
--- a/docs/plat/index.rst
+++ b/docs/plat/index.rst
@@ -7,24 +7,28 @@
    :numbered:
 
    allwinner
-   fvp_ve
-   imx8
-   imx8m
-   intel-stratix10
-   ls1043a
-   marvell/index
    meson-gxbb
    meson-gxl
+   fvp_ve
+   hikey
+   hikey960
+   intel-agilex
+   intel-stratix10
+   marvell/index
    mt8183
    nvidia-tegra
+   warp7
+   imx8
+   imx8m
+   ls1043a
+   poplar
    qemu
+   rpi3
    rcar-gen3
    rockchip
-   rpi3
    socionext-uniphier
-   stm32mp1
    synquacer
+   stm32mp1
    ti-k3
-   warp7
    xilinx-versal
    xilinx-zynqmp
diff --git a/docs/plat/intel-agilex.rst b/docs/plat/intel-agilex.rst
index 015a195..ff27b6b 100644
--- a/docs/plat/intel-agilex.rst
+++ b/docs/plat/intel-agilex.rst
@@ -67,6 +67,7 @@
 ----------
 
 ::
+
         INFO:    DDR: DRAM calibration success.
         INFO:    ECC is disabled.
         NOTICE:  BL2: v2.1(debug)
diff --git a/docs/plat/intel-stratix10.rst b/docs/plat/intel-stratix10.rst
index 77a45a4..7f8d18e 100644
--- a/docs/plat/intel-stratix10.rst
+++ b/docs/plat/intel-stratix10.rst
@@ -67,6 +67,7 @@
 ----------
 
 ::
+
          INFO:    DDR: DRAM calibration success.
          INFO:    ECC is disabled.
          INFO:    Init HPS NOC's DDR Scheduler.
diff --git a/docs/plat/meson-g12a.rst b/docs/plat/meson-g12a.rst
new file mode 100644
index 0000000..1021da4
--- /dev/null
+++ b/docs/plat/meson-g12a.rst
@@ -0,0 +1,27 @@
+Amlogic Meson S905X2 (G12A)
+==========================
+
+The Amlogic Meson S905X2 is a SoC with a quad core Arm Cortex-A53 running at
+~1.8GHz. It also contains a Cortex-M3 used as SCP.
+
+This port is a minimal implementation of BL31 capable of booting mainline U-Boot
+and Linux:
+
+- SCPI support.
+- Basic PSCI support (CPU_ON, CPU_OFF, SYSTEM_RESET, SYSTEM_OFF). Note that CPU0
+  can't be turned off, so there is a workaround to hide this from the caller.
+- GICv2 driver set up.
+- Basic SIP services (read efuse data, enable/disable JTAG).
+
+In order to build it:
+
+.. code:: shell
+
+    CROSS_COMPILE=aarch64-linux-gnu- make DEBUG=1 PLAT=g12a
+
+This port has been tested on a SEI510 board. After building it, follow the
+instructions in the `gxlimg repository` or `U-Boot repository`_, replacing the
+mentioned **bl31.img** by the one built from this port.
+
+.. _gxlimg repository: https://github.com/repk/gxlimg/blob/master/README.g12a
+.. _U-Boot repository: https://github.com/u-boot/u-boot/blob/master/board/amlogic/sei510/README
diff --git a/docs/plat/poplar.rst b/docs/plat/poplar.rst
index 5884ed9..215f551 100644
--- a/docs/plat/poplar.rst
+++ b/docs/plat/poplar.rst
@@ -1,5 +1,5 @@
-Description
-===========
+Poplar
+======
 
 Poplar is the first development board compliant with the 96Boards Enterprise
 Edition TV Platform specification.
@@ -35,10 +35,10 @@
     l-loader --> Trusted Firmware-A --> u-boot
 
 How to build
-============
+------------
 
 Code Locations
---------------
+~~~~~~~~~~~~~~
 
 -  Trusted Firmware-A:
    `link <https://github.com/ARM-software/arm-trusted-firmware>`__
@@ -50,7 +50,7 @@
    `link <http://git.denx.de/u-boot.git>`__
 
 Build Procedure
----------------
+~~~~~~~~~~~~~~~
 
 -  Fetch all the above 3 repositories into local host.
    Make all the repositories in the same ${BUILD\_PATH}.
@@ -89,7 +89,7 @@
 working firmware to eMMC.
 
 Boot trace
-==========
+----------
 
 ::
 
diff --git a/docs/plat/rpi4.rst b/docs/plat/rpi4.rst
new file mode 100644
index 0000000..0f529c1
--- /dev/null
+++ b/docs/plat/rpi4.rst
@@ -0,0 +1,85 @@
+Raspberry Pi 4
+==============
+
+The `Raspberry Pi 4`_ is an inexpensive single-board computer that contains four
+Arm Cortex-A72 cores. Also in contrast to previous Raspberry Pi versions this
+model has a GICv2 interrupt controller.
+
+This port is a minimal port to support loading non-secure EL2 payloads such
+as a 64-bit Linux kernel. Other payloads such as U-Boot or EDK-II should work
+as well, but have not been tested at this point.
+
+**IMPORTANT NOTE**: This port isn't secure. All of the memory used is DRAM,
+which is available from both the Non-secure and Secure worlds. The SoC does
+not seem to feature a secure memory controller of any kind, so portions of
+DRAM can't be protected properly from the Non-secure world.
+
+Build Instructions
+------------------
+
+There are no real configuration options at this point, so there is only
+one universal binary (bl31.bin), which can be built with:
+
+.. code:: shell
+
+    CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi4 DEBUG=1
+
+Copy the generated build/rpi4/debug/bl31.bin to the SD card, either
+renaming it to ``armstub8.bin`` or adding an entry starting with ``armstub=``,
+then followed by the respective file name to ``config.txt``.
+You should have AArch64 code in the file loaded as the "kernel", as BL31
+will drop into AArch64/EL2 to the respective load address.
+arm64 Linux kernels are known to work this way.
+
+Other options that should be set in ``config.txt`` to properly boot 64-bit
+kernels are:
+
+::
+
+    enable_uart=1
+    arm_64bit=1
+    enable_gic=1
+
+The BL31 code will patch the provided device tree blob in memory to advertise
+PSCI support, also will add a reserved-memory node to the DT to tell the
+non-secure payload to not touch the resident TF-A code.
+
+If you connect a serial cable between the Mini UART and your computer, and
+connect to it (for example, with ``screen /dev/ttyUSB0 115200``) you should
+see some text from BL31, followed by the output of the EL2 payload.
+The command line provided is read from the ``cmdline.txt`` file on the SD card.
+
+TF-A port design
+----------------
+
+In contrast to the existing Raspberry Pi 3 port this one here is a BL31-only
+port, also it deviates quite a lot from the RPi3 port in many other ways.
+There is not so much difference between the two models, so eventually those
+two could be (more) unified in the future.
+
+As with the previous models, the GPU and its firmware are the first entity to
+run after the SoC gets its power. The on-chip Boot ROM loads the next stage
+(bootcode.bin) from flash (EEPROM), which is again GPU code.
+This part knows how to access the MMC controller and how to parse a FAT
+filesystem, so it will load further compononents and configuration files
+from the first FAT partition on the SD card.
+
+To accommodate this existing way of configuring and setting up the board,
+we use as much of this workflow as possible.
+If bootcode.bin finds a file called ``armstub8.bin`` on the SD card or it gets
+pointed to such code by finding a ``armstub=`` key in ``config.txt``, it will
+load this file to the beginning of DRAM (address 0) and execute it in
+AArch64 EL3.
+But before doing that, it will also load a "kernel" and the device tree into
+memory. The load addresses have a default, but can also be changed by
+setting them in ``config.txt``. If the GPU firmware finds a magic value in the
+armstub image file, it will put those two load addresses in memory locations
+near the beginning of memory, where TF-A code picks them up.
+
+To keep things simple, we will just use the kernel load address as the BL33
+entry point, also put the DTB address in the x0 register, as requested by
+the arm64 Linux kernel boot protocol. This does not necessarily mean that
+the EL2 payload needs to be a Linux kernel, a bootloader or any other kernel
+would work as well, as long as it can cope with having the DT address in
+register x0. If the payload has other means of finding the device tree, it
+could ignore this address as well.
diff --git a/drivers/amlogic/crypto/sha_dma.c b/drivers/amlogic/crypto/sha_dma.c
index d48ded9..fceb1c0 100644
--- a/drivers/amlogic/crypto/sha_dma.c
+++ b/drivers/amlogic/crypto/sha_dma.c
@@ -9,10 +9,7 @@
 #include <crypto/sha_dma.h>
 #include <lib/mmio.h>
 
-#define AML_SHA_DMA_BASE 0xc883e000
-
-#define AML_SHA_DMA_DESC (AML_SHA_DMA_BASE + 0x08)
-#define AML_SHA_DMA_STATUS (AML_SHA_DMA_BASE + 0x18)
+#include "aml_private.h"
 
 #define ASD_MODE_SHA224 0x7
 #define ASD_MODE_SHA256 0x6
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c
index 94a20ba..fb49a57 100644
--- a/drivers/arm/gic/v3/gicv3_main.c
+++ b/drivers/arm/gic/v3/gicv3_main.c
@@ -16,7 +16,6 @@
 #include "gicv3_private.h"
 
 const gicv3_driver_data_t *gicv3_driver_data;
-static unsigned int gicv2_compat;
 
 /*
  * Spinlock to guard registers needing read-modify-write. APIs protected by this
@@ -60,51 +59,61 @@
 void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data)
 {
 	unsigned int gic_version;
+	unsigned int gicv2_compat;
 
 	assert(plat_driver_data != NULL);
 	assert(plat_driver_data->gicd_base != 0U);
-	assert(plat_driver_data->gicr_base != 0U);
 	assert(plat_driver_data->rdistif_num != 0U);
 	assert(plat_driver_data->rdistif_base_addrs != NULL);
 
 	assert(IS_IN_EL3());
 
-	assert(plat_driver_data->interrupt_props_num > 0 ?
-	       plat_driver_data->interrupt_props != NULL : 1);
+	assert((plat_driver_data->interrupt_props_num != 0U) ?
+	       (plat_driver_data->interrupt_props != NULL) : 1);
 
 	/* Check for system register support */
-#ifdef __aarch64__
+#ifndef __aarch64__
+	assert((read_id_pfr1() &
+			(ID_PFR1_GIC_MASK << ID_PFR1_GIC_SHIFT)) != 0U);
+#else
 	assert((read_id_aa64pfr0_el1() &
 			(ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT)) != 0U);
-#else
-	assert((read_id_pfr1() & (ID_PFR1_GIC_MASK << ID_PFR1_GIC_SHIFT)) != 0U);
-#endif /* __aarch64__ */
+#endif /* !__aarch64__ */
 
 	/* The GIC version should be 3.0 */
 	gic_version = gicd_read_pidr2(plat_driver_data->gicd_base);
-	gic_version >>=	PIDR2_ARCH_REV_SHIFT;
+	gic_version >>= PIDR2_ARCH_REV_SHIFT;
 	gic_version &= PIDR2_ARCH_REV_MASK;
 	assert(gic_version == ARCH_REV_GICV3);
 
 	/*
-	 * Find out whether the GIC supports the GICv2 compatibility mode. The
-	 * ARE_S bit resets to 0 if supported
+	 * Find out whether the GIC supports the GICv2 compatibility mode.
+	 * The ARE_S bit resets to 0 if supported
 	 */
 	gicv2_compat = gicd_read_ctlr(plat_driver_data->gicd_base);
 	gicv2_compat >>= CTLR_ARE_S_SHIFT;
-	gicv2_compat = !(gicv2_compat & CTLR_ARE_S_MASK);
+	gicv2_compat = gicv2_compat & CTLR_ARE_S_MASK;
 
-	/*
-	 * Find the base address of each implemented Redistributor interface.
-	 * The number of interfaces should be equal to the number of CPUs in the
-	 * system. The memory for saving these addresses has to be allocated by
-	 * the platform port
-	 */
-	gicv3_rdistif_base_addrs_probe(plat_driver_data->rdistif_base_addrs,
-					   plat_driver_data->rdistif_num,
-					   plat_driver_data->gicr_base,
-					   plat_driver_data->mpidr_to_core_pos);
-
+	if (plat_driver_data->gicr_base != 0U) {
+		/*
+		 * Find the base address of each implemented Redistributor interface.
+		 * The number of interfaces should be equal to the number of CPUs in the
+		 * system. The memory for saving these addresses has to be allocated by
+		 * the platform port
+		 */
+		gicv3_rdistif_base_addrs_probe(plat_driver_data->rdistif_base_addrs,
+						   plat_driver_data->rdistif_num,
+						   plat_driver_data->gicr_base,
+						   plat_driver_data->mpidr_to_core_pos);
+#if !HW_ASSISTED_COHERENCY
+		/*
+		 * Flush the rdistif_base_addrs[] contents linked to the GICv3 driver.
+		 */
+		flush_dcache_range((uintptr_t)(plat_driver_data->rdistif_base_addrs),
+			plat_driver_data->rdistif_num *
+			sizeof(*(plat_driver_data->rdistif_base_addrs)));
+#endif
+	}
 	gicv3_driver_data = plat_driver_data;
 
 	/*
@@ -112,19 +121,19 @@
 	 * 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
-	 * platform has HW_ASSISTED_COHERENCY or WARMBOOT_ENABLE_DCACHE_EARLY
-	 * enabled.
+	 * platform has HW_ASSISTED_COHERENCY enabled.
 	 */
-#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY)
-	flush_dcache_range((uintptr_t) &gicv3_driver_data,
-			sizeof(gicv3_driver_data));
-	flush_dcache_range((uintptr_t) gicv3_driver_data,
-			sizeof(*gicv3_driver_data));
+#if !HW_ASSISTED_COHERENCY
+	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."
-			" ARM GICV3 driver initialized in EL3\n",
-			gicv2_compat ? "with" : "without");
+	INFO("GICv3 with%s legacy support detected."
+			" ARM GICv3 driver initialized in EL3\n",
+			(gicv2_compat == 0U) ? "" : "out");
+
 }
 
 /*******************************************************************************
@@ -192,6 +201,7 @@
 	gicv3_rdistif_on(proc_num);
 
 	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+	assert(gicr_base != 0U);
 
 	/* Set the default attribute of all SGIs and PPIs */
 	gicv3_ppi_sgi_config_defaults(gicr_base);
@@ -313,6 +323,7 @@
 
 	/* Mark the connected core as asleep */
 	gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num];
+	assert(gicr_base != 0U);
 	gicv3_rdistif_mark_core_asleep(gicr_base);
 }
 
@@ -629,7 +640,9 @@
 	num_ints &= TYPER_IT_LINES_NO_MASK;
 	num_ints = (num_ints + 1U) << 5;
 
-	assert(num_ints <= (MAX_SPI_ID + 1U));
+	/* Filter out special INTIDs 1020-1023 */
+	if (num_ints > (MAX_SPI_ID + 1U))
+		num_ints = MAX_SPI_ID + 1U;
 
 	/* Wait for pending write to complete */
 	gicd_wait_for_pending_write(gicd_base);
@@ -637,31 +650,31 @@
 	/* Save the GICD_CTLR */
 	dist_ctx->gicd_ctlr = gicd_read_ctlr(gicd_base);
 
-	/* Save GICD_IGROUPR for INTIDs 32 - 1020 */
+	/* Save GICD_IGROUPR for INTIDs 32 - 1019 */
 	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
 
-	/* Save GICD_ISENABLER for INT_IDs 32 - 1020 */
+	/* Save GICD_ISENABLER for INT_IDs 32 - 1019 */
 	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
 
-	/* Save GICD_ISPENDR for INTIDs 32 - 1020 */
+	/* Save GICD_ISPENDR for INTIDs 32 - 1019 */
 	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
 
-	/* Save GICD_ISACTIVER for INTIDs 32 - 1020 */
+	/* Save GICD_ISACTIVER for INTIDs 32 - 1019 */
 	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
 
-	/* Save GICD_IPRIORITYR for INTIDs 32 - 1020 */
+	/* Save GICD_IPRIORITYR for INTIDs 32 - 1019 */
 	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
 
-	/* Save GICD_ICFGR for INTIDs 32 - 1020 */
+	/* Save GICD_ICFGR for INTIDs 32 - 1019 */
 	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
 
-	/* Save GICD_IGRPMODR for INTIDs 32 - 1020 */
+	/* Save GICD_IGRPMODR for INTIDs 32 - 1019 */
 	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
 
-	/* Save GICD_NSACR for INTIDs 32 - 1020 */
+	/* Save GICD_NSACR for INTIDs 32 - 1019 */
 	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
 
-	/* Save GICD_IROUTER for INTIDs 32 - 1024 */
+	/* Save GICD_IROUTER for INTIDs 32 - 1019 */
 	SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
 
 	/*
@@ -707,24 +720,26 @@
 	num_ints &= TYPER_IT_LINES_NO_MASK;
 	num_ints = (num_ints + 1U) << 5;
 
-	assert(num_ints <= (MAX_SPI_ID + 1U));
+	/* Filter out special INTIDs 1020-1023 */
+	if (num_ints > (MAX_SPI_ID + 1U))
+		num_ints = MAX_SPI_ID + 1U;
 
-	/* Restore GICD_IGROUPR for INTIDs 32 - 1020 */
+	/* Restore GICD_IGROUPR for INTIDs 32 - 1019 */
 	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR);
 
-	/* Restore GICD_IPRIORITYR for INTIDs 32 - 1020 */
+	/* Restore GICD_IPRIORITYR for INTIDs 32 - 1019 */
 	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR);
 
-	/* Restore GICD_ICFGR for INTIDs 32 - 1020 */
+	/* Restore GICD_ICFGR for INTIDs 32 - 1019 */
 	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR);
 
-	/* Restore GICD_IGRPMODR for INTIDs 32 - 1020 */
+	/* Restore GICD_IGRPMODR for INTIDs 32 - 1019 */
 	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR);
 
-	/* Restore GICD_NSACR for INTIDs 32 - 1020 */
+	/* Restore GICD_NSACR for INTIDs 32 - 1019 */
 	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR);
 
-	/* Restore GICD_IROUTER for INTIDs 32 - 1020 */
+	/* Restore GICD_IROUTER for INTIDs 32 - 1019 */
 	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER);
 
 	/*
@@ -732,13 +747,13 @@
 	 * configured.
 	 */
 
-	/* Restore GICD_ISENABLER for INT_IDs 32 - 1020 */
+	/* Restore GICD_ISENABLER for INT_IDs 32 - 1019 */
 	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER);
 
-	/* Restore GICD_ISPENDR for INTIDs 32 - 1020 */
+	/* Restore GICD_ISPENDR for INTIDs 32 - 1019 */
 	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR);
 
-	/* Restore GICD_ISACTIVER for INTIDs 32 - 1020 */
+	/* Restore GICD_ISACTIVER for INTIDs 32 - 1019 */
 	RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER);
 
 	/* Restore the GICD_CTLR */
@@ -1081,3 +1096,71 @@
 
 	return old_mask;
 }
+
+/*******************************************************************************
+ * This function delegates the responsibility of discovering the corresponding
+ * Redistributor frames to each CPU itself. It is a modified version of
+ * gicv3_rdistif_base_addrs_probe() and is executed by each CPU in the platform
+ * unlike the previous way in which only the Primary CPU did the discovery of
+ * all the Redistributor frames for every CPU. It also handles the scenario in
+ * which the frames of various CPUs are not contiguous in physical memory.
+ ******************************************************************************/
+int gicv3_rdistif_probe(const uintptr_t gicr_frame)
+{
+	u_register_t mpidr;
+	unsigned int proc_num, proc_self;
+	uint64_t typer_val;
+	uintptr_t rdistif_base;
+	bool gicr_frame_found = false;
+
+	assert(gicv3_driver_data->gicr_base == 0U);
+
+	/* Ensure this function is called with Data Cache enabled */
+#ifndef __aarch64__
+	assert((read_sctlr() & SCTLR_C_BIT) != 0U);
+#else
+	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+#endif /* !__aarch64__ */
+
+	proc_self = gicv3_driver_data->mpidr_to_core_pos(read_mpidr_el1());
+	rdistif_base = gicr_frame;
+	do {
+		typer_val = gicr_read_typer(rdistif_base);
+		if (gicv3_driver_data->mpidr_to_core_pos != NULL) {
+			mpidr = mpidr_from_gicr_typer(typer_val);
+			proc_num = gicv3_driver_data->mpidr_to_core_pos(mpidr);
+		} else {
+			proc_num = (unsigned int)(typer_val >> TYPER_PROC_NUM_SHIFT) &
+					TYPER_PROC_NUM_MASK;
+		}
+		if (proc_num == proc_self) {
+			/* The base address doesn't need to be initialized on
+			 * every warm boot.
+			 */
+			if (gicv3_driver_data->rdistif_base_addrs[proc_num] != 0U)
+				return 0;
+			gicv3_driver_data->rdistif_base_addrs[proc_num] =
+			rdistif_base;
+			gicr_frame_found = true;
+			break;
+		}
+		rdistif_base += (uintptr_t)(ULL(1) << GICR_PCPUBASE_SHIFT);
+	} while ((typer_val & TYPER_LAST_BIT) == 0U);
+
+	if (!gicr_frame_found)
+		return -1;
+
+	/*
+	 * Flush the driver data to ensure coherency. This is
+	 * not required if platform has HW_ASSISTED_COHERENCY
+	 * enabled.
+	 */
+#if !HW_ASSISTED_COHERENCY
+	/*
+	 * Flush the rdistif_base_addrs[] contents linked to the GICv3 driver.
+	 */
+	flush_dcache_range((uintptr_t)&(gicv3_driver_data->rdistif_base_addrs[proc_num]),
+		sizeof(*(gicv3_driver_data->rdistif_base_addrs)));
+#endif
+	return 0; /* Found matching GICR frame */
+}
diff --git a/drivers/st/bsec/bsec.c b/drivers/st/bsec/bsec.c
index b3c15ee..01c369e 100644
--- a/drivers/st/bsec/bsec.c
+++ b/drivers/st/bsec/bsec.c
@@ -841,22 +841,6 @@
 }
 
 /*
- * bsec_mode_is_closed_device: read OTP secure sub-mode.
- * return: false if open_device and true of closed_device.
- */
-bool bsec_mode_is_closed_device(void)
-{
-	uint32_t value;
-
-	if ((bsec_shadow_register(DATA0_OTP) != BSEC_OK) ||
-	    (bsec_read_otp(&value, DATA0_OTP) != BSEC_OK)) {
-		return true;
-	}
-
-	return (value & DATA0_OTP_SECURED) == DATA0_OTP_SECURED;
-}
-
-/*
  * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value
  * otp_value: read value.
  * word: OTP number.
@@ -894,7 +878,7 @@
 
 	if (otp >= STM32MP1_UPPER_OTP_START) {
 		/* Check if BSEC is in OTP-SECURED closed_device state. */
-		if (bsec_mode_is_closed_device()) {
+		if (stm32mp_is_closed_device()) {
 			if (!non_secure_can_access(otp)) {
 				return BSEC_ERROR;
 			}
diff --git a/drivers/st/crypto/stm32_hash.c b/drivers/st/crypto/stm32_hash.c
new file mode 100644
index 0000000..f72787d
--- /dev/null
+++ b/drivers/st/crypto/stm32_hash.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_hash.h>
+#include <drivers/st/stm32mp_reset.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#define DT_HASH_COMPAT			"st,stm32f756-hash"
+
+#define HASH_CR				0x00U
+#define HASH_DIN			0x04U
+#define HASH_STR			0x08U
+#define HASH_SR				0x24U
+#define HASH_HREG(x)			(0x310U + ((x) * 0x04U))
+
+/* Control Register */
+#define HASH_CR_INIT			BIT(2)
+#define HASH_CR_DATATYPE_SHIFT		U(4)
+
+#define HASH_CR_ALGO_SHA1		0x0U
+#define HASH_CR_ALGO_MD5		BIT(7)
+#define HASH_CR_ALGO_SHA224		BIT(18)
+#define HASH_CR_ALGO_SHA256		(BIT(18) | BIT(7))
+
+/* Status Flags */
+#define HASH_SR_DCIS			BIT(1)
+#define HASH_SR_BUSY			BIT(3)
+
+/* STR Register */
+#define HASH_STR_NBLW_MASK		GENMASK(4, 0)
+#define HASH_STR_DCAL			BIT(8)
+
+#define MD5_DIGEST_SIZE			16U
+#define SHA1_DIGEST_SIZE		20U
+#define SHA224_DIGEST_SIZE		28U
+#define SHA256_DIGEST_SIZE		32U
+
+#define HASH_TIMEOUT_US			10000U
+
+enum stm32_hash_data_format {
+	HASH_DATA_32_BITS,
+	HASH_DATA_16_BITS,
+	HASH_DATA_8_BITS,
+	HASH_DATA_1_BIT
+};
+
+struct stm32_hash_instance {
+	uintptr_t base;
+	unsigned int clock;
+	size_t digest_size;
+};
+
+struct stm32_hash_remain {
+	uint32_t buffer;
+	size_t length;
+};
+
+/* Expect a single HASH peripheral */
+static struct stm32_hash_instance stm32_hash;
+static struct stm32_hash_remain stm32_remain;
+
+static uintptr_t hash_base(void)
+{
+	return stm32_hash.base;
+}
+
+static int hash_wait_busy(void)
+{
+	uint64_t timeout = timeout_init_us(HASH_TIMEOUT_US);
+
+	while ((mmio_read_32(hash_base() + HASH_SR) & HASH_SR_BUSY) != 0U) {
+		if (timeout_elapsed(timeout)) {
+			ERROR("%s: busy timeout\n", __func__);
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static int hash_wait_computation(void)
+{
+	uint64_t timeout = timeout_init_us(HASH_TIMEOUT_US);
+
+	while ((mmio_read_32(hash_base() + HASH_SR) & HASH_SR_DCIS) == 0U) {
+		if (timeout_elapsed(timeout)) {
+			ERROR("%s: busy timeout\n", __func__);
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static int hash_write_data(uint32_t data)
+{
+	int ret;
+
+	ret = hash_wait_busy();
+	if (ret != 0) {
+		return ret;
+	}
+
+	mmio_write_32(hash_base() + HASH_DIN, data);
+
+	return 0;
+}
+
+static void hash_hw_init(enum stm32_hash_algo_mode mode)
+{
+	uint32_t reg;
+
+	reg = HASH_CR_INIT | (HASH_DATA_8_BITS << HASH_CR_DATATYPE_SHIFT);
+
+	switch (mode) {
+	case HASH_MD5SUM:
+		reg |= HASH_CR_ALGO_MD5;
+		stm32_hash.digest_size = MD5_DIGEST_SIZE;
+		break;
+	case HASH_SHA1:
+		reg |= HASH_CR_ALGO_SHA1;
+		stm32_hash.digest_size = SHA1_DIGEST_SIZE;
+		break;
+	case HASH_SHA224:
+		reg |= HASH_CR_ALGO_SHA224;
+		stm32_hash.digest_size = SHA224_DIGEST_SIZE;
+		break;
+	/* Default selected algo is SHA256 */
+	case HASH_SHA256:
+	default:
+		reg |= HASH_CR_ALGO_SHA256;
+		stm32_hash.digest_size = SHA256_DIGEST_SIZE;
+		break;
+	}
+
+	mmio_write_32(hash_base() + HASH_CR, reg);
+}
+
+static int hash_get_digest(uint8_t *digest)
+{
+	int ret;
+	uint32_t i;
+	uint32_t dsg;
+
+	ret = hash_wait_computation();
+	if (ret != 0) {
+		return ret;
+	}
+
+	for (i = 0U; i < (stm32_hash.digest_size / sizeof(uint32_t)); i++) {
+		dsg = __builtin_bswap32(mmio_read_32(hash_base() +
+						     HASH_HREG(i)));
+		memcpy(digest + (i * sizeof(uint32_t)), &dsg, sizeof(uint32_t));
+	}
+
+#if defined(IMAGE_BL2)
+	/*
+	 * Clean hardware context as HASH could be used later
+	 * by non-secure software
+	 */
+	hash_hw_init(HASH_SHA256);
+#endif
+	return 0;
+}
+
+int stm32_hash_update(const uint8_t *buffer, size_t length)
+{
+	size_t remain_length = length;
+	int ret = 0;
+
+	if ((length == 0U) || (buffer == NULL)) {
+		return 0;
+	}
+
+	stm32mp_clk_enable(stm32_hash.clock);
+
+	if (stm32_remain.length != 0U) {
+		uint32_t copysize;
+
+		copysize = MIN((sizeof(uint32_t) - stm32_remain.length),
+			       length);
+		memcpy(((uint8_t *)&stm32_remain.buffer) + stm32_remain.length,
+		       buffer, copysize);
+		remain_length -= copysize;
+		buffer += copysize;
+		if (stm32_remain.length == sizeof(uint32_t)) {
+			ret = hash_write_data(stm32_remain.buffer);
+			if (ret != 0) {
+				goto exit;
+			}
+
+			zeromem(&stm32_remain, sizeof(stm32_remain));
+		}
+	}
+
+	while (remain_length / sizeof(uint32_t) != 0U) {
+		uint32_t tmp_buf;
+
+		memcpy(&tmp_buf, buffer, sizeof(uint32_t));
+		ret = hash_write_data(tmp_buf);
+		if (ret != 0) {
+			goto exit;
+		}
+
+		buffer += sizeof(uint32_t);
+		remain_length -= sizeof(uint32_t);
+	}
+
+	if (remain_length != 0U) {
+		assert(stm32_remain.length == 0U);
+
+		memcpy((uint8_t *)&stm32_remain.buffer, buffer, remain_length);
+		stm32_remain.length = remain_length;
+	}
+
+exit:
+	stm32mp_clk_disable(stm32_hash.clock);
+
+	return ret;
+}
+
+int stm32_hash_final(uint8_t *digest)
+{
+	int ret;
+
+	stm32mp_clk_enable(stm32_hash.clock);
+
+	if (stm32_remain.length != 0U) {
+		ret = hash_write_data(stm32_remain.buffer);
+		if (ret != 0) {
+			stm32mp_clk_disable(stm32_hash.clock);
+			return ret;
+		}
+
+		mmio_clrsetbits_32(hash_base() + HASH_STR, HASH_STR_NBLW_MASK,
+				   8U * stm32_remain.length);
+		zeromem(&stm32_remain, sizeof(stm32_remain));
+	}
+
+	mmio_setbits_32(hash_base() + HASH_STR, HASH_STR_DCAL);
+
+	ret = hash_get_digest(digest);
+
+	stm32mp_clk_disable(stm32_hash.clock);
+
+	return ret;
+}
+
+int stm32_hash_final_update(const uint8_t *buffer, uint32_t length,
+			    uint8_t *digest)
+{
+	int ret;
+
+	ret = stm32_hash_update(buffer, length);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return stm32_hash_final(digest);
+}
+
+void stm32_hash_init(enum stm32_hash_algo_mode mode)
+{
+	stm32mp_clk_enable(stm32_hash.clock);
+
+	hash_hw_init(mode);
+
+	stm32mp_clk_disable(stm32_hash.clock);
+
+	zeromem(&stm32_remain, sizeof(stm32_remain));
+}
+
+int stm32_hash_register(void)
+{
+	struct dt_node_info hash_info;
+	int node;
+
+	for (node = dt_get_node(&hash_info, -1, DT_HASH_COMPAT);
+	     node != -FDT_ERR_NOTFOUND;
+	     node = dt_get_node(&hash_info, node, DT_HASH_COMPAT)) {
+#if defined(IMAGE_BL2)
+		if (hash_info.status != DT_DISABLED) {
+			break;
+		}
+#else
+		if (hash_info.status == DT_SECURE) {
+			break;
+		}
+#endif
+	}
+
+	if (node == -FDT_ERR_NOTFOUND) {
+		return -ENODEV;
+	}
+
+	if (hash_info.clock < 0) {
+		return -EINVAL;
+	}
+
+	stm32_hash.base = hash_info.base;
+	stm32_hash.clock = hash_info.clock;
+
+	stm32mp_clk_enable(stm32_hash.clock);
+
+	if (hash_info.reset >= 0) {
+		stm32mp_reset_assert((unsigned long)hash_info.reset);
+		udelay(20);
+		stm32mp_reset_deassert((unsigned long)hash_info.reset);
+	}
+
+	stm32mp_clk_disable(stm32_hash.clock);
+
+	return 0;
+}
diff --git a/drivers/st/io/io_stm32image.c b/drivers/st/io/io_stm32image.c
index 971dcce..413521b 100644
--- a/drivers/st/io/io_stm32image.c
+++ b/drivers/st/io/io_stm32image.c
@@ -246,7 +246,7 @@
 static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
 				     size_t length, size_t *length_read)
 {
-	int result = 0;
+	int result;
 	uint8_t *local_buffer = (uint8_t *)buffer;
 	boot_api_image_header_t *header =
 		(boot_api_image_header_t *)first_lba_buffer;
@@ -341,6 +341,12 @@
 			header->magic = 0;
 		}
 
+		result = stm32mp_auth_image(header, buffer);
+		if (result != 0) {
+			ERROR("Authentication Failed (%i)\n", result);
+			return result;
+		}
+
 		io_close(backend_handle);
 	}
 
diff --git a/fdts/a5ds.dts b/fdts/a5ds.dts
index 8bc4adf..91212e8 100644
--- a/fdts/a5ds.dts
+++ b/fdts/a5ds.dts
@@ -12,14 +12,40 @@
 	interrupt-parent = <&gic>;
 	#address-cells = <1>;
 	#size-cells = <1>;
+
+	psci {
+		compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
+		method = "smc";
+		cpu_on = <0x84000003>;
+	};
+
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
 		cpu@0 {
 			device_type = "cpu";
 			compatible = "arm,cortex-a5";
+			enable-method = "psci";
 			reg = <0>;
 		};
+		cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			enable-method = "psci";
+			reg = <1>;
+		};
+		cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			enable-method = "psci";
+			reg = <2>;
+		};
+		cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a5";
+			enable-method = "psci";
+			reg = <3>;
+		};
 	};
 
 	memory@80000000 {
diff --git a/fdts/stm32mp157c-security.dtsi b/fdts/stm32mp157c-security.dtsi
index f7e55b3..165ffa0 100644
--- a/fdts/stm32mp157c-security.dtsi
+++ b/fdts/stm32mp157c-security.dtsi
@@ -28,6 +28,10 @@
 	};
 };
 
+&hash1 {
+	secure-status = "okay";
+};
+
 &sdmmc1 {
 	compatible = "st,stm32-sdmmc2";
 };
diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h
index 9c72d4d..c4f42d0 100644
--- a/include/drivers/arm/gicv3.h
+++ b/include/drivers/arm/gicv3.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -366,6 +366,7 @@
  * GICv3 EL3 driver API
  ******************************************************************************/
 void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data);
+int gicv3_rdistif_probe(const uintptr_t gicr_frame);
 void gicv3_distif_init(void);
 void gicv3_rdistif_init(unsigned int proc_num);
 void gicv3_rdistif_on(unsigned int proc_num);
diff --git a/include/drivers/st/bsec.h b/include/drivers/st/bsec.h
index 2171550..d833e7a 100644
--- a/include/drivers/st/bsec.h
+++ b/include/drivers/st/bsec.h
@@ -199,7 +199,6 @@
 bool bsec_wr_lock(uint32_t otp);
 uint32_t bsec_otp_lock(uint32_t service, uint32_t value);
 
-bool bsec_mode_is_closed_device(void);
 uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word);
 uint32_t bsec_check_nsec_access_rights(uint32_t otp);
 
diff --git a/include/drivers/st/stm32_hash.h b/include/drivers/st/stm32_hash.h
new file mode 100644
index 0000000..969d7aa
--- /dev/null
+++ b/include/drivers/st/stm32_hash.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_HASH_H
+#define STM32_HASH_H
+
+enum stm32_hash_algo_mode {
+	HASH_MD5SUM,
+	HASH_SHA1,
+	HASH_SHA224,
+	HASH_SHA256
+};
+
+int stm32_hash_update(const uint8_t *buffer, uint32_t length);
+int stm32_hash_final(uint8_t *digest);
+int stm32_hash_final_update(const uint8_t *buffer, uint32_t buf_length,
+			    uint8_t *digest);
+void stm32_hash_init(enum stm32_hash_algo_mode mode);
+int stm32_hash_register(void);
+
+#endif /* STM32_HASH_H */
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
index 04e5e3d..7f7b7e3 100644
--- a/include/lib/psci/psci.h
+++ b/include/lib/psci/psci.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -301,6 +301,8 @@
 				const psci_power_state_t *target_state);
 	void (*pwr_domain_suspend)(const psci_power_state_t *target_state);
 	void (*pwr_domain_on_finish)(const psci_power_state_t *target_state);
+	void (*pwr_domain_on_finish_late)(
+				const psci_power_state_t *target_state);
 	void (*pwr_domain_suspend_finish)(
 				const psci_power_state_t *target_state);
 	void __dead2 (*pwr_domain_pwr_down_wfi)(
diff --git a/include/plat/arm/css/common/css_pm.h b/include/plat/arm/css/common/css_pm.h
index b82ff47..93f8616 100644
--- a/include/plat/arm/css/common/css_pm.h
+++ b/include/plat/arm/css/common/css_pm.h
@@ -27,6 +27,7 @@
 
 int css_pwr_domain_on(u_register_t mpidr);
 void css_pwr_domain_on_finish(const psci_power_state_t *target_state);
+void css_pwr_domain_on_finish_late(const psci_power_state_t *target_state);
 void css_pwr_domain_off(const psci_power_state_t *target_state);
 void css_pwr_domain_suspend(const psci_power_state_t *target_state);
 void css_pwr_domain_suspend_finish(
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index a05ee5a..d65e02d 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -142,11 +142,11 @@
 	 * world, and only for the secure world when CTX_INCLUDE_MTE_REGS is
 	 * set.
 	 */
-	unsigned int mte = get_armv8_5_mte_support();
 #if CTX_INCLUDE_MTE_REGS
-	assert(mte == MTE_IMPLEMENTED_ELX);
+	assert(get_armv8_5_mte_support() == MTE_IMPLEMENTED_ELX);
 	scr_el3 |= SCR_ATA_BIT;
 #else
+	unsigned int mte = get_armv8_5_mte_support();
 	if (mte == MTE_IMPLEMENTED_EL0) {
 		/*
 		 * Can enable MTE across both worlds as no MTE registers are
diff --git a/lib/psci/psci_on.c b/lib/psci/psci_on.c
index aa6b324..470b4f3 100644
--- a/lib/psci/psci_on.c
+++ b/lib/psci/psci_on.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -182,6 +182,14 @@
 #endif
 
 	/*
+	 * Plat. management: Perform any platform specific actions which
+	 * can only be done with the cpu and the cluster guaranteed to
+	 * be coherent.
+	 */
+	if (psci_plat_pm_ops->pwr_domain_on_finish_late != NULL)
+		psci_plat_pm_ops->pwr_domain_on_finish_late(state_info);
+
+	/*
 	 * All the platform specific actions for turning this cpu
 	 * on have completed. Perform enough arch.initialization
 	 * to run in the non-secure address space.
diff --git a/plat/amlogic/g12a/g12a_bl31_setup.c b/plat/amlogic/g12a/g12a_bl31_setup.c
new file mode 100644
index 0000000..77057a1
--- /dev/null
+++ b/plat/amlogic/g12a/g12a_bl31_setup.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <common/bl_common.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "aml_private.h"
+
+/*
+ * Placeholder variables for copying the arguments that have been passed to
+ * BL31 from BL2.
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+static image_info_t bl30_image_info;
+static image_info_t bl301_image_info;
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ?
+			  &bl33_image_ep_info : &bl32_image_ep_info;
+
+	/* None of the images can have 0x0 as the entrypoint. */
+	if (next_image_info->pc != 0U)
+		return next_image_info;
+
+	return NULL;
+}
+
+/*******************************************************************************
+ * Perform any BL31 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before
+ * they are lost (potentially). This needs to be done before the MMU is
+ * initialized so that the memory layout can be used while creating page
+ * tables. BL2 has flushed this information to memory, so we are guaranteed
+ * to pick up good data.
+ ******************************************************************************/
+struct g12a_bl31_param {
+	param_header_t h;
+	image_info_t *bl31_image_info;
+	entry_point_info_t *bl32_ep_info;
+	image_info_t *bl32_image_info;
+	entry_point_info_t *bl33_ep_info;
+	image_info_t *bl33_image_info;
+	image_info_t *scp_image_info[];
+};
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	struct g12a_bl31_param *from_bl2;
+
+	/* Initialize the console to provide early debug support */
+	aml_console_init();
+
+	from_bl2 = (struct g12a_bl31_param *)arg0;
+
+	/* Check params passed from BL2 are not NULL. */
+	assert(from_bl2 != NULL);
+	assert(from_bl2->h.type == PARAM_BL31);
+	assert(from_bl2->h.version >= VERSION_1);
+
+	/*
+	 * Copy BL32 and BL33 entry point information. It is stored in Secure
+	 * RAM, in BL2's address space.
+	 */
+	bl32_image_ep_info = *from_bl2->bl32_ep_info;
+	bl33_image_ep_info = *from_bl2->bl33_ep_info;
+
+	if (bl33_image_ep_info.pc == 0U) {
+		ERROR("BL31: BL33 entrypoint not obtained from BL2\n");
+		panic();
+	}
+
+	bl30_image_info = *from_bl2->scp_image_info[0];
+	bl301_image_info = *from_bl2->scp_image_info[1];
+}
+
+void bl31_plat_arch_setup(void)
+{
+	aml_setup_page_tables();
+
+	enable_mmu_el3(0);
+}
+
+/*******************************************************************************
+ * GICv2 driver setup information
+ ******************************************************************************/
+static const interrupt_prop_t g12a_interrupt_props[] = {
+	INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),
+	INTR_PROP_DESC(IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY,
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL)
+};
+
+static const gicv2_driver_data_t g12a_gic_data = {
+	.gicd_base = AML_GICD_BASE,
+	.gicc_base = AML_GICC_BASE,
+	.interrupt_props = g12a_interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(g12a_interrupt_props)
+};
+
+void bl31_platform_setup(void)
+{
+	aml_mhu_secure_init();
+
+	gicv2_driver_init(&g12a_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
diff --git a/plat/amlogic/g12a/g12a_common.c b/plat/amlogic/g12a/g12a_common.c
new file mode 100644
index 0000000..e74ed04
--- /dev/null
+++ b/plat/amlogic/g12a/g12a_common.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <common/ep_info.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <platform_def.h>
+#include <stdint.h>
+
+/*******************************************************************************
+ * Platform memory map regions
+ ******************************************************************************/
+#define MAP_NSDRAM0		MAP_REGION_FLAT(AML_NSDRAM0_BASE,		\
+						AML_NSDRAM0_SIZE,		\
+						MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_NS_SHARE_MEM	MAP_REGION_FLAT(AML_NS_SHARE_MEM_BASE,		\
+						AML_NS_SHARE_MEM_SIZE,		\
+						MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_SEC_SHARE_MEM	MAP_REGION_FLAT(AML_SEC_SHARE_MEM_BASE,		\
+						AML_SEC_SHARE_MEM_SIZE,		\
+						MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_SEC_DEVICE0		MAP_REGION_FLAT(AML_SEC_DEVICE0_BASE,		\
+						AML_SEC_DEVICE0_SIZE,		\
+						MT_DEVICE | MT_RW)
+
+#define MAP_HDCP_RX		MAP_REGION_FLAT(AML_HDCP_RX_BASE,		\
+						AML_HDCP_RX_SIZE,		\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_HDCP_TX		MAP_REGION_FLAT(AML_HDCP_TX_BASE,		\
+						AML_HDCP_TX_SIZE,		\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_GIC_DEVICE		MAP_REGION_FLAT(AML_GIC_DEVICE_BASE,		\
+						AML_GIC_DEVICE_SIZE,		\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SEC_DEVICE1		MAP_REGION_FLAT(AML_SEC_DEVICE1_BASE,		\
+						AML_SEC_DEVICE1_SIZE,		\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SEC_DEVICE2		MAP_REGION_FLAT(AML_SEC_DEVICE2_BASE,		\
+						AML_SEC_DEVICE2_SIZE,		\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_TZRAM		MAP_REGION_FLAT(AML_TZRAM_BASE,			\
+						AML_TZRAM_SIZE,			\
+						MT_DEVICE | MT_RW | MT_SECURE)
+
+static const mmap_region_t g12a_mmap[] = {
+	MAP_NSDRAM0,
+	MAP_NS_SHARE_MEM,
+	MAP_SEC_SHARE_MEM,
+	MAP_SEC_DEVICE0,
+	MAP_HDCP_RX,
+	MAP_HDCP_TX,
+	MAP_GIC_DEVICE,
+	MAP_SEC_DEVICE1,
+	MAP_SEC_DEVICE2,
+	MAP_TZRAM,
+	{0}
+};
+
+/*******************************************************************************
+ * Per-image regions
+ ******************************************************************************/
+#define MAP_BL31	MAP_REGION_FLAT(BL31_BASE,					\
+					BL31_END - BL31_BASE,				\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+#define MAP_BL_CODE	MAP_REGION_FLAT(BL_CODE_BASE,					\
+					BL_CODE_END - BL_CODE_BASE,			\
+					MT_CODE | MT_SECURE)
+
+#define MAP_BL_RO_DATA	MAP_REGION_FLAT(BL_RO_DATA_BASE,				\
+					BL_RO_DATA_END - BL_RO_DATA_BASE,		\
+					MT_RO_DATA | MT_SECURE)
+
+#define MAP_BL_COHERENT	MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,				\
+					BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, 	\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+/*******************************************************************************
+ * Function that sets up the translation tables.
+ ******************************************************************************/
+void aml_setup_page_tables(void)
+{
+#if IMAGE_BL31
+	const mmap_region_t g12a_bl_mmap[] = {
+		MAP_BL31,
+		MAP_BL_CODE,
+		MAP_BL_RO_DATA,
+#if USE_COHERENT_MEM
+		MAP_BL_COHERENT,
+#endif
+		{0}
+	};
+#endif
+
+	mmap_add(g12a_bl_mmap);
+
+	mmap_add(g12a_mmap);
+
+	init_xlat_tables();
+}
+
+/*******************************************************************************
+ * Function that returns the system counter frequency
+ ******************************************************************************/
+unsigned int plat_get_syscnt_freq2(void)
+{
+	mmio_clrbits_32(AML_SYS_CPU_CFG7, ~0xFDFFFFFF);
+	mmio_clrbits_32(AML_AO_TIMESTAMP_CNTL, ~0xFFFFFE00);
+
+	return AML_OSC24M_CLK_IN_HZ;
+}
diff --git a/plat/amlogic/g12a/g12a_def.h b/plat/amlogic/g12a/g12a_def.h
new file mode 100644
index 0000000..d032815
--- /dev/null
+++ b/plat/amlogic/g12a/g12a_def.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef G12A_DEF_H
+#define G12A_DEF_H
+
+#include <lib/utils_def.h>
+
+/*******************************************************************************
+ * System oscillator
+ ******************************************************************************/
+#define AML_OSC24M_CLK_IN_HZ			ULL(24000000) /* 24 MHz */
+
+/*******************************************************************************
+ * Memory regions
+ ******************************************************************************/
+#define AML_HDCP_RX_BASE			UL(0xFFE0D000)
+#define AML_HDCP_RX_SIZE			UL(0x00002000)
+
+#define AML_HDCP_TX_BASE			UL(0xFFE01000)
+#define AML_HDCP_TX_SIZE			UL(0x00001000)
+
+#define AML_NS_SHARE_MEM_BASE			UL(0x05000000)
+#define AML_NS_SHARE_MEM_SIZE			UL(0x00100000)
+
+#define AML_SEC_SHARE_MEM_BASE			UL(0x05200000)
+#define AML_SEC_SHARE_MEM_SIZE			UL(0x00100000)
+
+#define AML_GIC_DEVICE_BASE			UL(0xFFC00000)
+#define AML_GIC_DEVICE_SIZE			UL(0x00008000)
+
+#define AML_NSDRAM0_BASE			UL(0x01000000)
+#define AML_NSDRAM0_SIZE			UL(0x0F000000)
+
+#define BL31_BASE				UL(0x05100000)
+#define BL31_SIZE				UL(0x00100000)
+#define BL31_LIMIT				(BL31_BASE + BL31_SIZE)
+
+/* Shared memory used for SMC services */
+#define AML_SHARE_MEM_INPUT_BASE		UL(0x050FE000)
+#define AML_SHARE_MEM_OUTPUT_BASE		UL(0x050FF000)
+
+#define AML_SEC_DEVICE0_BASE			UL(0xFFD00000)
+#define AML_SEC_DEVICE0_SIZE			UL(0x00026000)
+
+#define AML_SEC_DEVICE1_BASE			UL(0xFF800000)
+#define AML_SEC_DEVICE1_SIZE			UL(0x0000A000)
+
+#define AML_TZRAM_BASE				UL(0xFFFA0000)
+#define AML_TZRAM_SIZE				UL(0x00048000)
+
+/* Mailboxes */
+#define AML_MHU_SECURE_SCP_TO_AP_PAYLOAD	UL(0xFFFE7800)
+#define AML_MHU_SECURE_AP_TO_SCP_PAYLOAD	UL(0xFFFE7A00)
+#define AML_PSCI_MAILBOX_BASE			UL(0xFFFE7F00)
+
+#define AML_SEC_DEVICE2_BASE			UL(0xFF620000)
+#define AML_SEC_DEVICE2_SIZE			UL(0x00028000)
+
+/*******************************************************************************
+ * GIC-400 and interrupt handling related constants
+ ******************************************************************************/
+#define AML_GICD_BASE				UL(0xFFC01000)
+#define AML_GICC_BASE				UL(0xFFC02000)
+
+#define IRQ_SEC_PHY_TIMER			29
+
+#define IRQ_SEC_SGI_0				8
+#define IRQ_SEC_SGI_1				9
+#define IRQ_SEC_SGI_2				10
+#define IRQ_SEC_SGI_3				11
+#define IRQ_SEC_SGI_4				12
+#define IRQ_SEC_SGI_5				13
+#define IRQ_SEC_SGI_6				14
+#define IRQ_SEC_SGI_7				15
+#define IRQ_SEC_SGI_8				16
+
+/*******************************************************************************
+ * UART definitions
+ ******************************************************************************/
+#define AML_UART0_AO_BASE			UL(0xFF803000)
+#define AML_UART0_AO_CLK_IN_HZ			AML_OSC24M_CLK_IN_HZ
+#define AML_UART_BAUDRATE			U(115200)
+
+/*******************************************************************************
+ * Memory-mapped I/O Registers
+ ******************************************************************************/
+#define AML_AO_TIMESTAMP_CNTL			UL(0xFF8000B4)
+
+#define AML_SYS_CPU_CFG7			UL(0xFF634664)
+
+#define AML_AO_RTI_STATUS_REG3			UL(0xFF80001C)
+#define AML_AO_RTI_SCP_STAT			UL(0xFF80023C)
+#define AML_AO_RTI_SCP_READY_OFF		U(0x14)
+#define AML_A0_RTI_SCP_READY_MASK		U(3)
+#define AML_AO_RTI_SCP_IS_READY(v)					\
+	((((v) >> AML_AO_RTI_SCP_READY_OFF) &				\
+	AML_A0_RTI_SCP_READY_MASK) == AML_A0_RTI_SCP_READY_MASK)
+
+#define AML_HIU_MAILBOX_SET_0			UL(0xFF63C404)
+#define AML_HIU_MAILBOX_STAT_0			UL(0xFF63C408)
+#define AML_HIU_MAILBOX_CLR_0			UL(0xFF63C40C)
+#define AML_HIU_MAILBOX_SET_3			UL(0xFF63C428)
+#define AML_HIU_MAILBOX_STAT_3			UL(0xFF63C42C)
+#define AML_HIU_MAILBOX_CLR_3			UL(0xFF63C430)
+
+#define AML_SHA_DMA_BASE			UL(0xFF63E000)
+#define AML_SHA_DMA_DESC			(AML_SHA_DMA_BASE + 0x08)
+#define AML_SHA_DMA_STATUS			(AML_SHA_DMA_BASE + 0x28)
+
+/*******************************************************************************
+ * System Monitor Call IDs and arguments
+ ******************************************************************************/
+#define AML_SM_GET_SHARE_MEM_INPUT_BASE		U(0x82000020)
+#define AML_SM_GET_SHARE_MEM_OUTPUT_BASE	U(0x82000021)
+
+#define AML_SM_EFUSE_READ			U(0x82000030)
+#define AML_SM_EFUSE_USER_MAX			U(0x82000033)
+
+#define AML_SM_JTAG_ON				U(0x82000040)
+#define AML_SM_JTAG_OFF				U(0x82000041)
+#define AML_SM_GET_CHIP_ID			U(0x82000044)
+
+#define AML_JTAG_STATE_ON			U(0)
+#define AML_JTAG_STATE_OFF			U(1)
+
+#define AML_JTAG_M3_AO				U(0)
+#define AML_JTAG_M3_EE				U(1)
+#define AML_JTAG_A53_AO				U(2)
+#define AML_JTAG_A53_EE				U(3)
+
+#endif /* G12A_DEF_H */
diff --git a/plat/amlogic/g12a/g12a_pm.c b/plat/amlogic/g12a/g12a_pm.c
new file mode 100644
index 0000000..c9fe3e9
--- /dev/null
+++ b/plat/amlogic/g12a/g12a_pm.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/console.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include "aml_private.h"
+
+#define SCPI_POWER_ON		0
+#define SCPI_POWER_RETENTION	1
+#define SCPI_POWER_OFF		3
+
+#define SCPI_SYSTEM_SHUTDOWN	0
+#define SCPI_SYSTEM_REBOOT	1
+
+static uintptr_t g12a_sec_entrypoint;
+static volatile uint32_t g12a_cpu0_go;
+
+static void g12a_pm_set_reset_addr(u_register_t mpidr, uint64_t value)
+{
+	unsigned int core = plat_calc_core_pos(mpidr);
+	uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4);
+
+	mmio_write_64(cpu_mailbox_addr, value);
+}
+
+static void g12a_pm_reset(u_register_t mpidr)
+{
+	unsigned int core = plat_calc_core_pos(mpidr);
+	uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4) + 8;
+
+	mmio_write_32(cpu_mailbox_addr, 0);
+}
+
+static void __dead2 g12a_system_reset(void)
+{
+	INFO("BL31: PSCI_SYSTEM_RESET\n");
+
+	u_register_t mpidr = read_mpidr_el1();
+	uint32_t status = mmio_read_32(AML_AO_RTI_STATUS_REG3);
+	int ret;
+
+	NOTICE("BL31: Reboot reason: 0x%x\n", status);
+
+	status &= 0xFFFF0FF0;
+
+	console_flush();
+
+	mmio_write_32(AML_AO_RTI_STATUS_REG3, status);
+
+	ret = aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT);
+
+	if (ret != 0) {
+		ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %i\n", ret);
+		panic();
+	}
+
+	g12a_pm_reset(mpidr);
+
+	wfi();
+
+	ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n");
+	panic();
+}
+
+static void __dead2 g12a_system_off(void)
+{
+	INFO("BL31: PSCI_SYSTEM_OFF\n");
+
+	u_register_t mpidr = read_mpidr_el1();
+	int ret;
+
+	ret = aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN);
+
+	if (ret != 0) {
+		ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %i\n", ret);
+		panic();
+	}
+
+	g12a_pm_set_reset_addr(mpidr, 0);
+	g12a_pm_reset(mpidr);
+
+	wfi();
+
+	ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n");
+	panic();
+}
+
+static int32_t g12a_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int core = plat_calc_core_pos(mpidr);
+
+	/* CPU0 can't be turned OFF */
+	if (core == AML_PRIMARY_CPU) {
+		VERBOSE("BL31: Releasing CPU0 from wait loop...\n");
+
+		g12a_cpu0_go = 1;
+		flush_dcache_range((uintptr_t)&g12a_cpu0_go,
+				sizeof(g12a_cpu0_go));
+		dsb();
+		isb();
+
+		sev();
+
+		return PSCI_E_SUCCESS;
+	}
+
+	g12a_pm_set_reset_addr(mpidr, g12a_sec_entrypoint);
+	aml_scpi_set_css_power_state(mpidr,
+				     SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON);
+	dmbsy();
+	sev();
+
+	return PSCI_E_SUCCESS;
+}
+
+static void g12a_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	unsigned int core = plat_calc_core_pos(read_mpidr_el1());
+
+	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
+					PLAT_LOCAL_STATE_OFF);
+
+	if (core == AML_PRIMARY_CPU) {
+		g12a_cpu0_go = 0;
+		flush_dcache_range((uintptr_t)&g12a_cpu0_go,
+				sizeof(g12a_cpu0_go));
+		dsb();
+		isb();
+	}
+
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
+
+static void g12a_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int core = plat_calc_core_pos(mpidr);
+
+	gicv2_cpuif_disable();
+
+	/* CPU0 can't be turned OFF */
+	if (core == AML_PRIMARY_CPU)
+		return;
+
+	aml_scpi_set_css_power_state(mpidr,
+				     SCPI_POWER_OFF, SCPI_POWER_ON,
+				     SCPI_POWER_ON);
+}
+
+static void __dead2 g12a_pwr_domain_pwr_down_wfi(const psci_power_state_t
+						 *target_state)
+{
+	u_register_t mpidr = read_mpidr_el1();
+	unsigned int core = plat_calc_core_pos(mpidr);
+
+	/* CPU0 can't be turned OFF, emulate it with a WFE loop */
+	if (core == AML_PRIMARY_CPU) {
+		VERBOSE("BL31: CPU0 entering wait loop...\n");
+
+		while (g12a_cpu0_go == 0)
+			wfe();
+
+		VERBOSE("BL31: CPU0 resumed.\n");
+
+		/*
+		 * Because setting CPU0's warm reset entrypoint through PSCI
+		 * mailbox and/or mmio mapped RVBAR (0xda834650) does not seem
+		 * to work, jump to it manually.
+		 * In order to avoid an assert, MMU has to be disabled.
+		 */
+		disable_mmu_el3();
+		((void(*)(void))g12a_sec_entrypoint)();
+	}
+
+	dsbsy();
+	g12a_pm_set_reset_addr(mpidr, 0);
+	g12a_pm_reset(mpidr);
+
+	for (;;)
+		wfi();
+}
+
+/*******************************************************************************
+ * Platform handlers and setup function.
+ ******************************************************************************/
+static const plat_psci_ops_t g12a_ops = {
+	.pwr_domain_on			= g12a_pwr_domain_on,
+	.pwr_domain_on_finish		= g12a_pwr_domain_on_finish,
+	.pwr_domain_off			= g12a_pwr_domain_off,
+	.pwr_domain_pwr_down_wfi	= g12a_pwr_domain_pwr_down_wfi,
+	.system_off			= g12a_system_off,
+	.system_reset			= g12a_system_reset
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	g12a_sec_entrypoint = sec_entrypoint;
+	*psci_ops = &g12a_ops;
+	g12a_cpu0_go = 0;
+	return 0;
+}
diff --git a/plat/amlogic/g12a/include/platform_def.h b/plat/amlogic/g12a/include/platform_def.h
new file mode 100644
index 0000000..23d816d
--- /dev/null
+++ b/plat/amlogic/g12a/include/platform_def.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <lib/utils_def.h>
+
+#include "../g12a_def.h"
+
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+#define PLATFORM_STACK_SIZE		UL(0x1000)
+
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	U(4)
+#define PLATFORM_CLUSTER_COUNT		U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT	PLATFORM_MAX_CPUS_PER_CLUSTER
+#define PLATFORM_CORE_COUNT		PLATFORM_CLUSTER0_CORE_COUNT
+
+#define AML_PRIMARY_CPU			U(0)
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL1
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CLUSTER_COUNT + \
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/* Local power state for power domains in Run state. */
+#define PLAT_LOCAL_STATE_RUN		U(0)
+/* Local power state for retention. Valid only for CPU power domains */
+#define PLAT_LOCAL_STATE_RET		U(1)
+/* Local power state for power-down. Valid for CPU and cluster power domains. */
+#define PLAT_LOCAL_STATE_OFF		U(2)
+
+/*
+ * Macros used to parse state information from State-ID if it is using the
+ * recommended encoding for State-ID.
+ */
+#define PLAT_LOCAL_PSTATE_WIDTH		U(4)
+#define PLAT_LOCAL_PSTATE_MASK		((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_SHIFT		U(6)
+#define CACHE_WRITEBACK_GRANULE		(U(1) << CACHE_WRITEBACK_SHIFT)
+
+/* Memory-related defines */
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 32)
+
+#define MAX_MMAP_REGIONS		16
+#define MAX_XLAT_TABLES			8
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/amlogic/g12a/platform.mk b/plat/amlogic/g12a/platform.mk
new file mode 100644
index 0000000..b0c91b0
--- /dev/null
+++ b/plat/amlogic/g12a/platform.mk
@@ -0,0 +1,91 @@
+#
+# Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/xlat_tables_v2/xlat_tables.mk
+
+AML_PLAT		:=	plat/amlogic
+AML_PLAT_SOC		:=	${AML_PLAT}/${PLAT}
+AML_PLAT_COMMON		:=	${AML_PLAT}/common
+
+DOIMAGEPATH		?=	tools/amlogic
+DOIMAGETOOL		?=	${DOIMAGEPATH}/doimage
+
+PLAT_INCLUDES		:=	-Iinclude/drivers/amlogic/			\
+				-I${AML_PLAT_SOC}/include			\
+				-I${AML_PLAT_COMMON}/include
+
+GIC_SOURCES		:=	drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v2/gicv2_main.c			\
+				drivers/arm/gic/v2/gicv2_helpers.c		\
+				plat/common/plat_gicv2.c
+
+BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S			\
+				plat/common/plat_psci_common.c			\
+				drivers/amlogic/console/aarch64/meson_console.S	\
+				${AML_PLAT_SOC}/${PLAT}_bl31_setup.c		\
+				${AML_PLAT_SOC}/${PLAT}_pm.c			\
+				${AML_PLAT_SOC}/${PLAT}_common.c		\
+				${AML_PLAT_COMMON}/aarch64/aml_helpers.S	\
+				${AML_PLAT_COMMON}/aml_efuse.c			\
+				${AML_PLAT_COMMON}/aml_mhu.c			\
+				${AML_PLAT_COMMON}/aml_scpi.c			\
+				${AML_PLAT_COMMON}/aml_sip_svc.c		\
+				${AML_PLAT_COMMON}/aml_thermal.c		\
+				${AML_PLAT_COMMON}/aml_topology.c		\
+				${AML_PLAT_COMMON}/aml_console.c		\
+				drivers/amlogic/crypto/sha_dma.c		\
+				${XLAT_TABLES_LIB_SRCS}				\
+				${GIC_SOURCES}
+
+# Tune compiler for Cortex-A53
+ifeq ($(notdir $(CC)),armclang)
+    TF_CFLAGS_aarch64	+=	-mcpu=cortex-a53
+else ifneq ($(findstring clang,$(notdir $(CC))),)
+    TF_CFLAGS_aarch64	+=	-mcpu=cortex-a53
+else
+    TF_CFLAGS_aarch64	+=	-mtune=cortex-a53
+endif
+
+# Build config flags
+# ------------------
+
+# Enable all errata workarounds for Cortex-A53
+ERRATA_A53_855873		:= 1
+ERRATA_A53_819472		:= 1
+ERRATA_A53_824069		:= 1
+ERRATA_A53_827319		:= 1
+
+WORKAROUND_CVE_2017_5715	:= 0
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA	:= 1
+
+# Use Coherent memory
+USE_COHERENT_MEM		:= 1
+
+# Verify build config
+# -------------------
+
+ifneq (${RESET_TO_BL31}, 0)
+  $(error Error: ${PLAT} needs RESET_TO_BL31=0)
+endif
+
+ifeq (${ARCH},aarch32)
+  $(error Error: AArch32 not supported on ${PLAT})
+endif
+
+all: ${BUILD_PLAT}/bl31.img
+distclean realclean clean: cleanimage
+
+cleanimage:
+	${Q}${MAKE} -C ${DOIMAGEPATH} clean
+
+${DOIMAGETOOL}:
+	${Q}${MAKE} -C ${DOIMAGEPATH}
+
+${BUILD_PLAT}/bl31.img: ${BUILD_PLAT}/bl31.bin ${DOIMAGETOOL}
+	${DOIMAGETOOL} ${BUILD_PLAT}/bl31.bin ${BUILD_PLAT}/bl31.img
+
diff --git a/plat/amlogic/gxbb/gxbb_def.h b/plat/amlogic/gxbb/gxbb_def.h
index 59d9cc9..fa5e4fa 100644
--- a/plat/amlogic/gxbb/gxbb_def.h
+++ b/plat/amlogic/gxbb/gxbb_def.h
@@ -95,6 +95,10 @@
 #define AML_HIU_MAILBOX_STAT_3			UL(0xDA83C42C)
 #define AML_HIU_MAILBOX_CLR_3			UL(0xDA83C430)
 
+#define AML_SHA_DMA_BASE			UL(0xC883E000)
+#define AML_SHA_DMA_DESC			(AML_SHA_DMA_BASE + 0x08)
+#define AML_SHA_DMA_STATUS			(AML_SHA_DMA_BASE + 0x18)
+
 /*******************************************************************************
  * System Monitor Call IDs and arguments
  ******************************************************************************/
diff --git a/plat/amlogic/gxbb/platform.mk b/plat/amlogic/gxbb/platform.mk
index 57167b0..62384d2 100644
--- a/plat/amlogic/gxbb/platform.mk
+++ b/plat/amlogic/gxbb/platform.mk
@@ -22,9 +22,9 @@
 BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S			\
 				plat/common/plat_psci_common.c			\
 				drivers/amlogic/console/aarch64/meson_console.S	\
-				${AML_PLAT_SOC}/gxbb_bl31_setup.c		\
-				${AML_PLAT_SOC}/gxbb_pm.c			\
-				${AML_PLAT_SOC}/gxbb_common.c			\
+				${AML_PLAT_SOC}/${PLAT}_bl31_setup.c		\
+				${AML_PLAT_SOC}/${PLAT}_pm.c			\
+				${AML_PLAT_SOC}/${PLAT}_common.c		\
 				${AML_PLAT_COMMON}/aarch64/aml_helpers.S	\
 				${AML_PLAT_COMMON}/aml_efuse.c			\
 				${AML_PLAT_COMMON}/aml_mhu.c			\
diff --git a/plat/amlogic/gxl/gxl_def.h b/plat/amlogic/gxl/gxl_def.h
index 1e1a934..f30eb28 100644
--- a/plat/amlogic/gxl/gxl_def.h
+++ b/plat/amlogic/gxl/gxl_def.h
@@ -105,6 +105,10 @@
 #define AML_HIU_MAILBOX_STAT_3			UL(0xDA83C42C)
 #define AML_HIU_MAILBOX_CLR_3			UL(0xDA83C430)
 
+#define AML_SHA_DMA_BASE			UL(0xC883E000)
+#define AML_SHA_DMA_DESC			(AML_SHA_DMA_BASE + 0x08)
+#define AML_SHA_DMA_STATUS			(AML_SHA_DMA_BASE + 0x18)
+
 /*******************************************************************************
  * System Monitor Call IDs and arguments
  ******************************************************************************/
diff --git a/plat/amlogic/gxl/platform.mk b/plat/amlogic/gxl/platform.mk
index 2e47670..641d177 100644
--- a/plat/amlogic/gxl/platform.mk
+++ b/plat/amlogic/gxl/platform.mk
@@ -25,9 +25,9 @@
 BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S			\
 				plat/common/plat_psci_common.c			\
 				drivers/amlogic/console/aarch64/meson_console.S	\
-				${AML_PLAT_SOC}/gxl_bl31_setup.c		\
-				${AML_PLAT_SOC}/gxl_pm.c			\
-				${AML_PLAT_SOC}/gxl_common.c			\
+				${AML_PLAT_SOC}/${PLAT}_bl31_setup.c		\
+				${AML_PLAT_SOC}/${PLAT}_pm.c			\
+				${AML_PLAT_SOC}/${PLAT}_common.c		\
 				${AML_PLAT_COMMON}/aarch64/aml_helpers.S	\
 				${AML_PLAT_COMMON}/aml_efuse.c			\
 				${AML_PLAT_COMMON}/aml_mhu.c			\
diff --git a/plat/arm/board/a5ds/a5ds_pm.c b/plat/arm/board/a5ds/a5ds_pm.c
index 5fd443b..98de77d 100644
--- a/plat/arm/board/a5ds/a5ds_pm.c
+++ b/plat/arm/board/a5ds/a5ds_pm.c
@@ -6,6 +6,38 @@
 
 #include <lib/psci/psci.h>
 #include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <drivers/arm/gicv2.h>
+
+/*******************************************************************************
+ * Platform handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ ******************************************************************************/
+static int a5ds_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int pos = plat_core_pos_by_mpidr(mpidr);
+	uint64_t *hold_base = (uint64_t *)A5DS_HOLD_BASE;
+
+	hold_base[pos] = A5DS_HOLD_STATE_GO;
+	dsbish();
+	sev();
+
+	return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * Platform handler called when a power domain has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from.
+ ******************************************************************************/
+void a5ds_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	/* TODO: This setup is needed only after a cold boot*/
+	gicv2_pcpu_distif_init();
+
+	/* Enable the gic cpu interface */
+	gicv2_cpuif_enable();
+}
 
 /*******************************************************************************
  * Export the platform handlers via a5ds_psci_pm_ops. The ARM Standard
@@ -14,11 +46,16 @@
 plat_psci_ops_t a5ds_psci_pm_ops = {
 	/* dummy struct */
 	.validate_ns_entrypoint = NULL,
+	.pwr_domain_on = a5ds_pwr_domain_on,
+	.pwr_domain_on_finish = a5ds_pwr_domain_on_finish
 };
 
 int __init plat_setup_psci_ops(uintptr_t sec_entrypoint,
 				const plat_psci_ops_t **psci_ops)
 {
+	uintptr_t *mailbox = (void *)A5DS_TRUSTED_MAILBOX_BASE;
+	*mailbox = sec_entrypoint;
+
 	*psci_ops = &a5ds_psci_pm_ops;
 
 	return 0;
diff --git a/plat/arm/board/a5ds/aarch32/a5ds_helpers.S b/plat/arm/board/a5ds/aarch32/a5ds_helpers.S
index 23a22d9..ed7ad9c 100644
--- a/plat/arm/board/a5ds/aarch32/a5ds_helpers.S
+++ b/plat/arm/board/a5ds/aarch32/a5ds_helpers.S
@@ -12,17 +12,36 @@
 	.globl	plat_get_my_entrypoint
 	.globl	plat_is_my_cpu_primary
 
-	/* --------------------------------------------------------------------
+	/* -----------------------------------------------------
 	 * void plat_secondary_cold_boot_setup (void);
 	 *
-	 * For AArch32, cold-booting secondary CPUs is not yet
-	 * implemented and they panic.
-	 * --------------------------------------------------------------------
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * -----------------------------------------------------
 	 */
 func plat_secondary_cold_boot_setup
-cb_panic:
-	wfi
-	b	cb_panic
+	/* Calculate address of our hold entry */
+	bl	plat_my_core_pos
+	lsl	r0, r0, #A5DS_HOLD_ENTRY_SHIFT
+	mov_imm	r2, A5DS_HOLD_BASE
+	/* Clear the value stored in the hold address for the specific core */
+	mov_imm	r3, A5DS_HOLD_STATE_WAIT
+	str	r3, [r2, r0]
+	dmb	ish
+
+	/* Wait until we have a go */
+poll_mailbox:
+	ldr	r1, [r2, r0]
+	cmp	r1, #A5DS_HOLD_STATE_WAIT
+	beq	1f
+	mov_imm	r0, A5DS_TRUSTED_MAILBOX_BASE
+	ldr	r1, [r0]
+	bx	r1
+1:
+	wfe
+	b	poll_mailbox
 endfunc plat_secondary_cold_boot_setup
 
 	/* ---------------------------------------------------------------------
@@ -56,3 +75,52 @@
 	movne	r0, #0
 	bx	lr
 endfunc plat_is_my_cpu_primary
+
+	/* ---------------------------------------------------------------------
+	 * Loads MPIDR in r0 and calls plat_arm_calc_core_pos
+	 * ---------------------------------------------------------------------
+	 */
+func plat_my_core_pos
+	ldcopr	r0, MPIDR
+	b	plat_arm_calc_core_pos
+
+endfunc plat_my_core_pos
+
+	/* ---------------------------------------------------------------------
+	 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
+	 *
+	 * Function to calculate the core position on A5DS.
+	 *
+	 * (ClusterId * A5DS_MAX_CPUS_PER_CLUSTER * A5DS_MAX_PE_PER_CPU) +
+	 * (CPUId * A5DS_MAX_PE_PER_CPU) +
+	 * ThreadId
+	 *
+	 * which can be simplified as:
+	 *
+	 * ((ClusterId * A5DS_MAX_CPUS_PER_CLUSTER + CPUId) * A5DS_MAX_PE_PER_CPU)
+	 * + ThreadId
+	 * ---------------------------------------------------------------------
+	 */
+func plat_arm_calc_core_pos
+	mov	r3, r0
+
+	/*
+	 * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it
+	 * look as if in a multi-threaded implementation
+	 */
+	tst	r0, #MPIDR_MT_MASK
+	lsleq	r3, r0, #MPIDR_AFFINITY_BITS
+
+	/* Extract individual affinity fields from MPIDR */
+	ubfx	r0, r3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx	r1, r3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
+	ubfx	r2, r3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
+
+	/* Compute linear position */
+	mov	r3, #A5DS_MAX_CPUS_PER_CLUSTER
+	mla	r1, r2, r3, r1
+	mov	r3, #A5DS_MAX_PE_PER_CPU
+	mla	r0, r1, r3, r0
+
+	bx	lr
+endfunc plat_arm_calc_core_pos
diff --git a/plat/arm/board/a5ds/include/platform_def.h b/plat/arm/board/a5ds/include/platform_def.h
index db65c37..e9e4b9a 100644
--- a/plat/arm/board/a5ds/include/platform_def.h
+++ b/plat/arm/board/a5ds/include/platform_def.h
@@ -97,9 +97,9 @@
 /* Default number of threads per CPU on A5DS */
 #define A5DS_MAX_PE_PER_CPU	1
 
-#define A5DS_CORE_COUNT 1
+#define A5DS_CORE_COUNT		4
 
-#define A5DS_PRIMARY_CPU			0x0
+#define A5DS_PRIMARY_CPU	0x0
 
 #define FLASH1_BASE			UL(0x8000000)
 #define FLASH1_SIZE			UL(0x2800000)
@@ -229,11 +229,11 @@
 #define BL32_LIMIT			(ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)
 
 /* Required platform porting definitions */
-#define PLATFORM_CORE_COUNT 1
-#define PLAT_NUM_PWR_DOMAINS		(A5DS_CLUSTER_COUNT + \
+#define PLATFORM_CORE_COUNT	A5DS_CORE_COUNT
+#define PLAT_NUM_PWR_DOMAINS	(A5DS_CLUSTER_COUNT + \
 					PLATFORM_CORE_COUNT) + 1
 
-#define PLAT_MAX_PWR_LVL		2
+#define PLAT_MAX_PWR_LVL	2
 
 /*
  * Other platform porting definitions are provided by included headers
@@ -325,6 +325,14 @@
 
 /* Mailbox base address */
 #define A5DS_TRUSTED_MAILBOX_BASE	A5DS_SHARED_RAM_BASE
+#define A5DS_TRUSTED_MAILBOX_SIZE	(8 + A5DS_HOLD_SIZE)
+#define A5DS_HOLD_BASE		(A5DS_TRUSTED_MAILBOX_BASE + 8)
+#define A5DS_HOLD_SIZE		(PLATFORM_CORE_COUNT * \
+					 A5DS_HOLD_ENTRY_SIZE)
+#define A5DS_HOLD_ENTRY_SHIFT	3
+#define A5DS_HOLD_ENTRY_SIZE	(1 << A5DS_HOLD_ENTRY_SHIFT)
+#define A5DS_HOLD_STATE_WAIT	0
+#define A5DS_HOLD_STATE_GO	1
 
 /*
  * GIC related constants to cater for GICv2
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
index 42dec8d..0a62543 100644
--- a/plat/arm/board/fvp/fvp_pm.c
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -247,10 +247,19 @@
 {
 	fvp_power_domain_on_finish_common(target_state);
 
-	/* Enable the gic cpu interface */
+}
+
+/*******************************************************************************
+ * FVP handler called when a power domain has just been powered on and the cpu
+ * and its cluster are fully participating in coherent transaction on the
+ * interconnect. Data cache must be enabled for CPU at this point.
+ ******************************************************************************/
+static void fvp_pwr_domain_on_finish_late(const psci_power_state_t *target_state)
+{
+	/* Program GIC per-cpu distributor or re-distributor interface */
 	plat_arm_gic_pcpu_init();
 
-	/* Program the gic per-cpu distributor or re-distributor interface */
+	/* Enable GIC CPU interface */
 	plat_arm_gic_cpuif_enable();
 }
 
@@ -272,7 +281,7 @@
 
 	fvp_power_domain_on_finish_common(target_state);
 
-	/* Enable the gic cpu interface */
+	/* Enable GIC CPU interface */
 	plat_arm_gic_cpuif_enable();
 }
 
@@ -397,6 +406,7 @@
 	.pwr_domain_off = fvp_pwr_domain_off,
 	.pwr_domain_suspend = fvp_pwr_domain_suspend,
 	.pwr_domain_on_finish = fvp_pwr_domain_on_finish,
+	.pwr_domain_on_finish_late = fvp_pwr_domain_on_finish_late,
 	.pwr_domain_suspend_finish = fvp_pwr_domain_suspend_finish,
 	.system_off = fvp_system_off,
 	.system_reset = fvp_system_reset,
diff --git a/plat/arm/common/arm_gicv3.c b/plat/arm/common/arm_gicv3.c
index 7f4957f..fef5376 100644
--- a/plat/arm/common/arm_gicv3.c
+++ b/plat/arm/common/arm_gicv3.c
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <assert.h>
 #include <platform_def.h>
 
 #include <common/interrupt_props.h>
@@ -67,7 +68,7 @@
 
 static const gicv3_driver_data_t arm_gic_data __unused = {
 	.gicd_base = PLAT_ARM_GICD_BASE,
-	.gicr_base = PLAT_ARM_GICR_BASE,
+	.gicr_base = 0U,
 	.interrupt_props = arm_interrupt_props,
 	.interrupt_props_num = ARRAY_SIZE(arm_interrupt_props),
 	.rdistif_num = PLATFORM_CORE_COUNT,
@@ -86,6 +87,11 @@
 #if (!defined(__aarch64__) && defined(IMAGE_BL32)) || \
 	(defined(__aarch64__) && defined(IMAGE_BL31))
 	gicv3_driver_init(&arm_gic_data);
+
+	if (gicv3_rdistif_probe(PLAT_ARM_GICR_BASE) == -1) {
+		ERROR("No GICR base frame found for Primary CPU\n");
+		panic();
+	}
 #endif
 }
 
@@ -116,10 +122,20 @@
 }
 
 /******************************************************************************
- * ARM common helper to initialize the per-cpu redistributor interface in GICv3
+ * ARM common helper function to iterate over all GICR frames and discover the
+ * corresponding per-cpu redistributor frame as well as initialize the
+ * corresponding interface in GICv3. At the moment, Arm platforms do not have
+ * non-contiguous GICR frames.
  *****************************************************************************/
 void plat_arm_gic_pcpu_init(void)
 {
+	int result;
+
+	result = gicv3_rdistif_probe(PLAT_ARM_GICR_BASE);
+	if (result == -1) {
+		ERROR("No GICR base frame found for CPU 0x%lx\n", read_mpidr());
+		panic();
+	}
 	gicv3_rdistif_init(plat_my_core_pos());
 }
 
diff --git a/plat/arm/css/common/css_pm.c b/plat/arm/css/common/css_pm.c
index f6fc6aa..01c674f 100644
--- a/plat/arm/css/common/css_pm.c
+++ b/plat/arm/css/common/css_pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -76,9 +76,6 @@
 {
 	assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
 
-	/* Enable the gic cpu interface */
-	plat_arm_gic_cpuif_enable();
-
 	/*
 	 * Perform the common cluster specific operations i.e enable coherency
 	 * if this cluster was off.
@@ -100,10 +97,21 @@
 	/* Assert that the system power domain need not be initialized */
 	assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN);
 
+	css_pwr_domain_on_finisher_common(target_state);
+}
+
+/*******************************************************************************
+ * Handler called when a power domain has just been powered on and the cpu
+ * and its cluster are fully participating in coherent transaction on the
+ * interconnect. Data cache must be enabled for CPU at this point.
+ ******************************************************************************/
+void css_pwr_domain_on_finish_late(const psci_power_state_t *target_state)
+{
 	/* Program the gic per-cpu distributor or re-distributor interface */
 	plat_arm_gic_pcpu_init();
 
-	css_pwr_domain_on_finisher_common(target_state);
+	/* Enable the gic cpu interface */
+	plat_arm_gic_cpuif_enable();
 }
 
 /*******************************************************************************
@@ -185,6 +193,9 @@
 		arm_system_pwr_domain_resume();
 
 	css_pwr_domain_on_finisher_common(target_state);
+
+	/* Enable the gic cpu interface */
+	plat_arm_gic_cpuif_enable();
 }
 
 /*******************************************************************************
@@ -306,6 +317,7 @@
 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_on_finish_late = css_pwr_domain_on_finish_late,
 	.pwr_domain_off		= css_pwr_domain_off,
 	.cpu_standby		= css_cpu_standby,
 	.pwr_domain_suspend	= css_pwr_domain_suspend,
diff --git a/plat/rpi/common/include/rpi_shared.h b/plat/rpi/common/include/rpi_shared.h
index 6863438..de83571 100644
--- a/plat/rpi/common/include/rpi_shared.h
+++ b/plat/rpi/common/include/rpi_shared.h
@@ -14,7 +14,7 @@
  ******************************************************************************/
 
 /* Utility functions */
-void rpi3_console_init(void);
+void rpi3_console_init(unsigned int base_clk_rate);
 void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size,
 			    uintptr_t code_start, uintptr_t code_limit,
 			    uintptr_t rodata_start, uintptr_t rodata_limit
diff --git a/plat/rpi/common/rpi3_common.c b/plat/rpi/common/rpi3_common.c
index ab63d98..ff33694 100644
--- a/plat/rpi/common/rpi3_common.c
+++ b/plat/rpi/common/rpi3_common.c
@@ -104,14 +104,14 @@
  ******************************************************************************/
 static console_16550_t rpi3_console;
 
-void rpi3_console_init(void)
+void rpi3_console_init(unsigned int base_clk_rate)
 {
 	int console_scope = CONSOLE_FLAG_BOOT;
 #if RPI3_RUNTIME_UART != -1
 	console_scope |= CONSOLE_FLAG_RUNTIME;
 #endif
 	int rc = console_16550_register(PLAT_RPI3_UART_BASE,
-					PLAT_RPI3_UART_CLK_IN_HZ,
+					base_clk_rate,
 					PLAT_RPI3_UART_BAUDRATE,
 					&rpi3_console);
 	if (rc == 0) {
@@ -176,18 +176,6 @@
 }
 
 /*******************************************************************************
- * Return entrypoint of BL33.
- ******************************************************************************/
-uintptr_t plat_get_ns_image_entrypoint(void)
-{
-#ifdef PRELOADED_BL33_BASE
-	return PRELOADED_BL33_BASE;
-#else
-	return PLAT_RPI3_NS_IMAGE_OFFSET;
-#endif
-}
-
-/*******************************************************************************
  * Gets SPSR for BL32 entry
  ******************************************************************************/
 uint32_t rpi3_get_spsr_for_bl32_entry(void)
diff --git a/plat/rpi/rpi3/rpi3_bl1_setup.c b/plat/rpi/rpi3/rpi3_bl1_setup.c
index 3ac30e0..dcce76e 100644
--- a/plat/rpi/rpi3/rpi3_bl1_setup.c
+++ b/plat/rpi/rpi3/rpi3_bl1_setup.c
@@ -35,7 +35,7 @@
 		      0x80000000);
 
 	/* Initialize the console to provide early debug support */
-	rpi3_console_init();
+	rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ);
 
 	/* Allow BL1 to see the whole Trusted RAM */
 	bl1_tzram_layout.total_base = BL_RAM_BASE;
diff --git a/plat/rpi/rpi3/rpi3_bl2_setup.c b/plat/rpi/rpi3/rpi3_bl2_setup.c
index 991c0fc..44827c6 100644
--- a/plat/rpi/rpi3/rpi3_bl2_setup.c
+++ b/plat/rpi/rpi3/rpi3_bl2_setup.c
@@ -62,7 +62,7 @@
 	meminfo_t *mem_layout = (meminfo_t *) arg1;
 
 	/* Initialize the console to provide early debug support */
-	rpi3_console_init();
+	rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ);
 
 	/* Enable arch timer */
 	generic_delay_timer_init();
diff --git a/plat/rpi/rpi3/rpi3_bl31_setup.c b/plat/rpi/rpi3/rpi3_bl31_setup.c
index a9efc52..24a5613 100644
--- a/plat/rpi/rpi3/rpi3_bl31_setup.c
+++ b/plat/rpi/rpi3/rpi3_bl31_setup.c
@@ -48,6 +48,18 @@
 }
 
 /*******************************************************************************
+ * Return entrypoint of BL33.
+ ******************************************************************************/
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#ifdef PRELOADED_BL33_BASE
+	return PRELOADED_BL33_BASE;
+#else
+	return PLAT_RPI3_NS_IMAGE_OFFSET;
+#endif
+}
+
+/*******************************************************************************
  * Perform any BL31 early platform setup. Here is an opportunity to copy
  * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before
  * they are lost (potentially). This needs to be done before the MMU is
@@ -60,7 +72,7 @@
 
 {
 	/* Initialize the console to provide early debug support */
-	rpi3_console_init();
+	rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ);
 
 	/*
 	 * In debug builds, a special value is passed in 'arg1' to verify
diff --git a/plat/rpi/rpi4/aarch64/armstub8_header.S b/plat/rpi/rpi4/aarch64/armstub8_header.S
new file mode 100644
index 0000000..246358d
--- /dev/null
+++ b/plat/rpi/rpi4/aarch64/armstub8_header.S
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * armstub8.bin header to let the GPU firmware recognise this code.
+ * It will then write the load address of the kernel image and the DT
+ * after the header magic in RAM, so we can read those addresses at runtime.
+ */
+
+.text
+	b	armstub8_end
+
+.global stub_magic
+.global dtb_ptr32
+.global kernel_entry32
+
+.org 0xf0
+armstub8:
+stub_magic:
+	.word 0x5afe570b
+stub_version:
+	.word 0
+dtb_ptr32:
+	.word 0x0
+kernel_entry32:
+	.word 0x0
+
+/*
+ * Technically an offset of 0x100 would suffice, but the follow-up code
+ * (bl31_entrypoint.S at BL31_BASE) needs to be page aligned, so pad here
+ * till the end of the first 4K page.
+ */
+.org 0x1000
+armstub8_end:
diff --git a/plat/rpi/rpi4/aarch64/plat_helpers.S b/plat/rpi/rpi4/aarch64/plat_helpers.S
new file mode 100644
index 0000000..46073b7
--- /dev/null
+++ b/plat/rpi/rpi4/aarch64/plat_helpers.S
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+#include <cortex_a72.h>
+
+#include "../include/rpi_hw.h"
+
+	.globl	plat_crash_console_flush
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	platform_mem_init
+	.globl	plat_get_my_entrypoint
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_my_core_pos
+	.globl	plat_reset_handler
+	.globl	plat_rpi3_calc_core_pos
+	.globl	plat_secondary_cold_boot_setup
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_my_core_pos(void)
+	 *
+	 *  This function uses the plat_rpi3_calc_core_pos()
+	 *  definition to get the index of the calling CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	plat_rpi3_calc_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr);
+	 *
+	 *  CorePos = (ClusterId * 4) + CoreId
+	 * -----------------------------------------------------
+	 */
+func plat_rpi3_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	add	x0, x1, x0, LSR #6
+	ret
+endfunc plat_rpi3_calc_core_pos
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_is_my_cpu_primary (void);
+	 *
+	 * Find out whether the current cpu is the primary
+	 * cpu.
+	 * -----------------------------------------------------
+	 */
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #RPI4_PRIMARY_CPU
+	cset	w0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	/* Calculate address of our hold entry */
+	bl	plat_my_core_pos
+	lsl	x0, x0, #3
+	mov_imm	x2, PLAT_RPI3_TM_HOLD_BASE
+	add	x0, x0, x2
+
+	/*
+	 * This code runs way before requesting the warmboot of this core,
+	 * so it is possible to clear the mailbox before getting a request
+	 * to boot.
+	 */
+	mov	x1, PLAT_RPI3_TM_HOLD_STATE_WAIT
+	str	x1,[x0]
+
+	/* Wait until we have a go */
+poll_mailbox:
+	wfe
+	ldr	x1, [x0]
+	cmp	x1, PLAT_RPI3_TM_HOLD_STATE_GO
+	bne	poll_mailbox
+
+	/* Jump to the provided entrypoint */
+	mov_imm	x0, PLAT_RPI3_TM_ENTRYPOINT
+	ldr	x1, [x0]
+	br	x1
+endfunc plat_secondary_cold_boot_setup
+
+	/* ---------------------------------------------------------------------
+	 * uintptr_t plat_get_my_entrypoint (void);
+	 *
+	 * Main job of this routine is to distinguish between a cold and a warm
+	 * boot.
+	 *
+	 * This functions returns:
+	 *  - 0 for a cold boot.
+	 *  - Any other value for a warm boot.
+	 * ---------------------------------------------------------------------
+	 */
+func plat_get_my_entrypoint
+	/* TODO: support warm boot */
+	mov	x0, #0
+	ret
+endfunc plat_get_my_entrypoint
+
+	/* ---------------------------------------------
+	 * void platform_mem_init (void);
+	 *
+	 * No need to carry out any memory initialization.
+	 * ---------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_init(void)
+	 * Function to initialize the crash console
+	 * without a C Runtime to print crash report.
+	 * Clobber list : x0 - x3
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_init
+	mov_imm	x0, PLAT_RPI3_UART_BASE
+	mov_imm	x1, PLAT_RPI4_VPU_CLK_RATE
+	mov_imm	x2, PLAT_RPI3_UART_BAUDRATE
+	b	console_16550_core_init
+endfunc plat_crash_console_init
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_putc(int c)
+	 * Function to print a character on the crash
+	 * console without a C Runtime.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_putc
+	mov_imm	x1, PLAT_RPI3_UART_BASE
+	b	console_16550_core_putc
+endfunc plat_crash_console_putc
+
+	/* ---------------------------------------------
+	 * int plat_crash_console_flush()
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func plat_crash_console_flush
+	mov_imm	x0, PLAT_RPI3_UART_BASE
+	b	console_16550_core_flush
+endfunc plat_crash_console_flush
+
+	/* ---------------------------------------------
+	 * void plat_reset_handler(void);
+	 * ---------------------------------------------
+	 */
+func plat_reset_handler
+	/* ------------------------------------------------
+	 * Set L2 read/write cache latency:
+	 * - L2 Data RAM latency: 3 cycles (0b010)
+	 * - L2 Data RAM setup: 1 cycle (bit 5)
+	 * ------------------------------------------------
+	 */
+	mrs	x0, CORTEX_A72_L2CTLR_EL1
+	mov	x1, #0x22
+	orr	x0, x0, x1
+	msr	CORTEX_A72_L2CTLR_EL1, x0
+	isb
+
+	ret
+endfunc plat_reset_handler
diff --git a/plat/rpi/rpi4/include/plat.ld.S b/plat/rpi/rpi4/include/plat.ld.S
new file mode 100644
index 0000000..9262fad
--- /dev/null
+++ b/plat/rpi/rpi4/include/plat.ld.S
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Stub linker script to provide the armstub8.bin header before the actual
+ * code. If the GPU firmware finds a magic value at offset 240 in
+ * armstub8.bin, it will put the DTB and kernel load address in subsequent
+ * words. We can then read those values to find the proper NS entry point
+ * and find our DTB more flexibly.
+ */
+
+MEMORY {
+    PRERAM (rwx): ORIGIN = 0, LENGTH = 4096
+}
+
+SECTIONS
+{
+    .armstub8 . : {
+        *armstub8_header.o(.text*)
+        KEEP(*(.armstub8))
+    } >PRERAM
+}
diff --git a/plat/rpi/rpi4/include/plat_macros.S b/plat/rpi/rpi4/include/plat_macros.S
new file mode 100644
index 0000000..6007d03
--- /dev/null
+++ b/plat/rpi/rpi4/include/plat_macros.S
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant platform registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/rpi/rpi4/include/platform_def.h b/plat/rpi/rpi4/include/platform_def.h
new file mode 100644
index 0000000..a9ecdba
--- /dev/null
+++ b/plat/rpi/rpi4/include/platform_def.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+#include "rpi_hw.h"
+
+/* Special value used to verify platform parameters from BL2 to BL31 */
+#define RPI3_BL31_PLAT_PARAM_VAL	ULL(0x0F1E2D3C4B5A6978)
+
+#define PLATFORM_STACK_SIZE		ULL(0x1000)
+
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	U(4)
+#define PLATFORM_CLUSTER_COUNT		U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT	PLATFORM_MAX_CPUS_PER_CLUSTER
+#define PLATFORM_CORE_COUNT		PLATFORM_CLUSTER0_CORE_COUNT
+
+#define RPI4_PRIMARY_CPU		U(0)
+
+#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL1
+#define PLAT_NUM_PWR_DOMAINS		(PLATFORM_CLUSTER_COUNT + \
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/* Local power state for power domains in Run state. */
+#define PLAT_LOCAL_STATE_RUN		U(0)
+/* Local power state for retention. Valid only for CPU power domains */
+#define PLAT_LOCAL_STATE_RET		U(1)
+/*
+ * Local power state for OFF/power-down. Valid for CPU and cluster power
+ * domains.
+ */
+#define PLAT_LOCAL_STATE_OFF		U(2)
+
+/*
+ * Macros used to parse state information from State-ID if it is using the
+ * recommended encoding for State-ID.
+ */
+#define PLAT_LOCAL_PSTATE_WIDTH		U(4)
+#define PLAT_LOCAL_PSTATE_MASK		((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1)
+
+/*
+ * Some data must be aligned on the biggest cache line size in the platform.
+ * This is known only to the platform as it might have a combination of
+ * integrated and external caches.
+ */
+#define CACHE_WRITEBACK_SHIFT		U(6)
+#define CACHE_WRITEBACK_GRANULE		(U(1) << CACHE_WRITEBACK_SHIFT)
+
+/*
+ * I/O registers.
+ */
+#define DEVICE0_BASE			RPI_IO_BASE
+#define DEVICE0_SIZE			RPI_IO_SIZE
+
+/*
+ * Mailbox to control the secondary cores. All secondary cores are held in a
+ * wait loop in cold boot. To release them perform the following steps (plus
+ * any additional barriers that may be needed):
+ *
+ *     uint64_t *entrypoint = (uint64_t *)PLAT_RPI3_TM_ENTRYPOINT;
+ *     *entrypoint = ADDRESS_TO_JUMP_TO;
+ *
+ *     uint64_t *mbox_entry = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE;
+ *     mbox_entry[cpu_id] = PLAT_RPI3_TM_HOLD_STATE_GO;
+ *
+ *     sev();
+ */
+/* The secure entry point to be used on warm reset by all CPUs. */
+#define PLAT_RPI3_TM_ENTRYPOINT		0x100
+#define PLAT_RPI3_TM_ENTRYPOINT_SIZE	ULL(8)
+
+/* Hold entries for each CPU. */
+#define PLAT_RPI3_TM_HOLD_BASE		(PLAT_RPI3_TM_ENTRYPOINT + \
+					 PLAT_RPI3_TM_ENTRYPOINT_SIZE)
+#define PLAT_RPI3_TM_HOLD_ENTRY_SIZE	ULL(8)
+#define PLAT_RPI3_TM_HOLD_SIZE		(PLAT_RPI3_TM_HOLD_ENTRY_SIZE * \
+					 PLATFORM_CORE_COUNT)
+
+#define PLAT_RPI3_TRUSTED_MAILBOX_SIZE	(PLAT_RPI3_TM_ENTRYPOINT_SIZE + \
+					 PLAT_RPI3_TM_HOLD_SIZE)
+
+#define PLAT_RPI3_TM_HOLD_STATE_WAIT	ULL(0)
+#define PLAT_RPI3_TM_HOLD_STATE_GO	ULL(1)
+
+/*
+ * BL31 specific defines.
+ *
+ * Put BL31 at the top of the Trusted SRAM. BL31_BASE is calculated using the
+ * current BL31 debug size plus a little space for growth.
+ */
+#define PLAT_MAX_BL31_SIZE		ULL(0x80000)
+
+#define BL31_BASE			ULL(0x1000)
+#define BL31_LIMIT			ULL(0x80000)
+#define BL31_PROGBITS_LIMIT		ULL(0x80000)
+
+#define SEC_SRAM_ID			0
+#define SEC_DRAM_ID			1
+
+/*
+ * Other memory-related defines.
+ */
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 32)
+
+#define MAX_MMAP_REGIONS		8
+#define MAX_XLAT_TABLES			4
+
+#define MAX_IO_DEVICES			U(3)
+#define MAX_IO_HANDLES			U(4)
+
+#define MAX_IO_BLOCK_DEVICES		U(1)
+
+/*
+ * Serial-related constants.
+ */
+#define PLAT_RPI3_UART_BASE		RPI3_MINI_UART_BASE
+#define PLAT_RPI3_UART_BAUDRATE		ULL(115200)
+
+/*
+ * System counter
+ */
+#define SYS_COUNTER_FREQ_IN_TICKS	ULL(54000000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/rpi/rpi4/include/rpi_hw.h b/plat/rpi/rpi4/include/rpi_hw.h
new file mode 100644
index 0000000..ed367ee
--- /dev/null
+++ b/plat/rpi/rpi4/include/rpi_hw.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI_HW_H
+#define RPI_HW_H
+
+#include <lib/utils_def.h>
+
+/*
+ * Peripherals
+ */
+
+#define RPI_IO_BASE			ULL(0xFE000000)
+#define RPI_IO_SIZE			ULL(0x02000000)
+
+/*
+ * ARM <-> VideoCore mailboxes
+ */
+#define RPI3_MBOX_OFFSET		ULL(0x0000B880)
+#define RPI3_MBOX_BASE			(RPI_IO_BASE + RPI3_MBOX_OFFSET)
+/* VideoCore -> ARM */
+#define RPI3_MBOX0_READ_OFFSET		ULL(0x00000000)
+#define RPI3_MBOX0_PEEK_OFFSET		ULL(0x00000010)
+#define RPI3_MBOX0_SENDER_OFFSET	ULL(0x00000014)
+#define RPI3_MBOX0_STATUS_OFFSET	ULL(0x00000018)
+#define RPI3_MBOX0_CONFIG_OFFSET	ULL(0x0000001C)
+/* ARM -> VideoCore */
+#define RPI3_MBOX1_WRITE_OFFSET		ULL(0x00000020)
+#define RPI3_MBOX1_PEEK_OFFSET		ULL(0x00000030)
+#define RPI3_MBOX1_SENDER_OFFSET	ULL(0x00000034)
+#define RPI3_MBOX1_STATUS_OFFSET	ULL(0x00000038)
+#define RPI3_MBOX1_CONFIG_OFFSET	ULL(0x0000003C)
+/* Mailbox status constants */
+#define RPI3_MBOX_STATUS_FULL_MASK	U(0x80000000) /* Set if full */
+#define RPI3_MBOX_STATUS_EMPTY_MASK	U(0x40000000) /* Set if empty */
+
+/*
+ * Power management, reset controller, watchdog.
+ */
+#define RPI3_IO_PM_OFFSET		ULL(0x00100000)
+#define RPI3_PM_BASE			(RPI_IO_BASE + RPI3_IO_PM_OFFSET)
+/* Registers on top of RPI3_PM_BASE. */
+#define RPI3_PM_RSTC_OFFSET		ULL(0x0000001C)
+#define RPI3_PM_RSTS_OFFSET		ULL(0x00000020)
+#define RPI3_PM_WDOG_OFFSET		ULL(0x00000024)
+/* Watchdog constants */
+#define RPI3_PM_PASSWORD		U(0x5A000000)
+#define RPI3_PM_RSTC_WRCFG_MASK		U(0x00000030)
+#define RPI3_PM_RSTC_WRCFG_FULL_RESET	U(0x00000020)
+/*
+ * The RSTS register is used by the VideoCore firmware when booting the
+ * Raspberry Pi to know which partition to boot from. The partition value is
+ * formed by bits 0, 2, 4, 6, 8 and 10. Partition 63 is used by said firmware
+ * to indicate halt.
+ */
+#define RPI3_PM_RSTS_WRCFG_HALT		U(0x00000555)
+
+/*
+ * Clock controller
+ */
+#define RPI4_IO_CLOCK_OFFSET		ULL(0x00101000)
+#define RPI4_CLOCK_BASE			(RPI_IO_BASE + RPI4_IO_CLOCK_OFFSET)
+#define RPI4_VPU_CLOCK_DIVIDER		ULL(0x0000000c)
+
+/*
+ * Hardware random number generator.
+ */
+#define RPI3_IO_RNG_OFFSET		ULL(0x00104000)
+#define RPI3_RNG_BASE			(RPI_IO_BASE + RPI3_IO_RNG_OFFSET)
+#define RPI3_RNG_CTRL_OFFSET		ULL(0x00000000)
+#define RPI3_RNG_STATUS_OFFSET		ULL(0x00000004)
+#define RPI3_RNG_DATA_OFFSET		ULL(0x00000008)
+#define RPI3_RNG_INT_MASK_OFFSET	ULL(0x00000010)
+/* Enable/disable RNG */
+#define RPI3_RNG_CTRL_ENABLE		U(0x1)
+#define RPI3_RNG_CTRL_DISABLE		U(0x0)
+/* Number of currently available words */
+#define RPI3_RNG_STATUS_NUM_WORDS_SHIFT	U(24)
+#define RPI3_RNG_STATUS_NUM_WORDS_MASK	U(0xFF)
+/* Value to mask interrupts caused by the RNG */
+#define RPI3_RNG_INT_MASK_DISABLE	U(0x1)
+
+/*
+ * Serial port (called 'Mini UART' in the Broadcom documentation).
+ */
+#define RPI3_IO_MINI_UART_OFFSET	ULL(0x00215040)
+#define RPI3_MINI_UART_BASE		(RPI_IO_BASE + RPI3_IO_MINI_UART_OFFSET)
+#define PLAT_RPI4_VPU_CLK_RATE		ULL(1000000000)
+
+/*
+ * GPIO controller
+ */
+#define RPI3_IO_GPIO_OFFSET		ULL(0x00200000)
+#define RPI3_GPIO_BASE			(RPI_IO_BASE + RPI3_IO_GPIO_OFFSET)
+
+/*
+ * SDHost controller
+ */
+#define RPI3_IO_SDHOST_OFFSET           ULL(0x00202000)
+#define RPI3_SDHOST_BASE                (RPI_IO_BASE + RPI3_IO_SDHOST_OFFSET)
+
+/*
+ * GIC interrupt controller
+ */
+#define RPI_HAVE_GIC
+#define RPI4_GIC_GICD_BASE		ULL(0xff841000)
+#define RPI4_GIC_GICC_BASE		ULL(0xff842000)
+
+#define	RPI4_LOCAL_CONTROL_BASE_ADDRESS		ULL(0xff800000)
+#define	RPI4_LOCAL_CONTROL_PRESCALER		ULL(0xff800008)
+
+#endif /* RPI_HW_H */
diff --git a/plat/rpi/rpi4/platform.mk b/plat/rpi/rpi4/platform.mk
new file mode 100644
index 0000000..2038021
--- /dev/null
+++ b/plat/rpi/rpi4/platform.mk
@@ -0,0 +1,103 @@
+#
+# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/libfdt/libfdt.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_INCLUDES		:=	-Iplat/rpi/common/include		\
+				-Iplat/rpi/rpi4/include
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/ti/uart/aarch64/16550_console.S	\
+				plat/rpi/common/rpi3_common.c		\
+				${XLAT_TABLES_LIB_SRCS}
+
+BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a72.S		\
+				plat/rpi/rpi4/aarch64/plat_helpers.S	\
+				plat/rpi/rpi4/aarch64/armstub8_header.S	\
+				drivers/arm/gic/common/gic_common.c     \
+				drivers/arm/gic/v2/gicv2_helpers.c      \
+				drivers/arm/gic/v2/gicv2_main.c         \
+				plat/common/plat_gicv2.c                \
+				plat/rpi/rpi4/rpi4_bl31_setup.c		\
+				plat/rpi/common/rpi3_pm.c		\
+				plat/common/plat_psci_common.c		\
+				plat/rpi/common/rpi3_topology.c		\
+				common/fdt_fixup.c			\
+				${LIBFDT_SRCS}
+
+# For now we only support BL31, using the kernel loaded by the GPU firmware.
+RESET_TO_BL31		:=	1
+
+# All CPUs enter armstub8.bin.
+COLD_BOOT_SINGLE_CPU	:=	0
+
+# Tune compiler for Cortex-A72
+ifeq ($(notdir $(CC)),armclang)
+    TF_CFLAGS_aarch64	+=	-mcpu=cortex-a72
+else ifneq ($(findstring clang,$(notdir $(CC))),)
+    TF_CFLAGS_aarch64	+=	-mcpu=cortex-a72
+else
+    TF_CFLAGS_aarch64	+=	-mtune=cortex-a72
+endif
+
+# Add support for platform supplied linker script for BL31 build
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+
+# Enable all errata workarounds for Cortex-A72
+ERRATA_A72_859971		:= 1
+
+WORKAROUND_CVE_2017_5715	:= 1
+
+# Add new default target when compiling this platform
+all: bl31
+
+# Build config flags
+# ------------------
+
+# Disable stack protector by default
+ENABLE_STACK_PROTECTOR	 	:= 0
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA	:= 1
+
+# Use Coherent memory
+USE_COHERENT_MEM		:= 1
+
+# Platform build flags
+# --------------------
+
+# There is not much else than a Linux kernel to load at the moment.
+RPI3_DIRECT_LINUX_BOOT		:= 1
+
+# BL33 images are in AArch64 by default
+RPI3_BL33_IN_AARCH32		:= 0
+
+# UART to use at runtime. -1 means the runtime UART is disabled.
+# Any other value means the default UART will be used.
+RPI3_RUNTIME_UART		:= 0
+
+# Use normal memory mapping for ROM, FIP, SRAM and DRAM
+RPI3_USE_UEFI_MAP		:= 0
+
+# Process platform flags
+# ----------------------
+
+$(eval $(call add_define,RPI3_BL33_IN_AARCH32))
+$(eval $(call add_define,RPI3_DIRECT_LINUX_BOOT))
+ifdef RPI3_PRELOADED_DTB_BASE
+$(eval $(call add_define,RPI3_PRELOADED_DTB_BASE))
+endif
+$(eval $(call add_define,RPI3_RUNTIME_UART))
+$(eval $(call add_define,RPI3_USE_UEFI_MAP))
+
+ifeq (${ARCH},aarch32)
+  $(error Error: AArch32 not supported on rpi4)
+endif
+
+ifneq ($(ENABLE_STACK_PROTECTOR), 0)
+PLAT_BL_COMMON_SOURCES	+=	drivers/rpi3/rng/rpi3_rng.c		\
+				plat/rpi/common/rpi3_stack_protector.c
+endif
diff --git a/plat/rpi/rpi4/rpi4_bl31_setup.c b/plat/rpi/rpi4/rpi4_bl31_setup.c
new file mode 100644
index 0000000..53ab0c2
--- /dev/null
+++ b/plat/rpi/rpi4/rpi4_bl31_setup.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <common/fdt_fixup.h>
+#include <libfdt.h>
+
+#include <drivers/arm/gicv2.h>
+
+#include <rpi_shared.h>
+
+/*
+ * Fields at the beginning of armstub8.bin.
+ * While building the BL31 image, we put the stub magic into the binary.
+ * The GPU firmware detects this at boot time, clears that field as a
+ * confirmation and puts the kernel and DT address in the following words.
+ */
+extern uint32_t stub_magic;
+extern uint32_t dtb_ptr32;
+extern uint32_t kernel_entry32;
+
+static const gicv2_driver_data_t rpi4_gic_data = {
+	.gicd_base = RPI4_GIC_GICD_BASE,
+	.gicc_base = RPI4_GIC_GICC_BASE,
+};
+
+/*
+ * To be filled by the code below. At the moment BL32 is not supported.
+ * In the future these might be passed down from BL2.
+ */
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	assert(sec_state_is_valid(type) != 0);
+
+	next_image_info = (type == NON_SECURE)
+			? &bl33_image_ep_info : &bl32_image_ep_info;
+
+	/* None of the images can have 0x0 as the entrypoint. */
+	if (next_image_info->pc) {
+		return next_image_info;
+	} else {
+		return NULL;
+	}
+}
+
+uintptr_t plat_get_ns_image_entrypoint(void)
+{
+#ifdef PRELOADED_BL33_BASE
+	return PRELOADED_BL33_BASE;
+#else
+	/* Cleared by the GPU if kernel address is valid. */
+	if (stub_magic == 0)
+		return kernel_entry32;
+
+	WARN("Stub magic failure, using default kernel address 0x80000\n");
+	return 0x80000;
+#endif
+}
+
+static uintptr_t rpi4_get_dtb_address(void)
+{
+#ifdef RPI3_PRELOADED_DTB_BASE
+	return RPI3_PRELOADED_DTB_BASE;
+#else
+	/* Cleared by the GPU if DTB address is valid. */
+	if (stub_magic == 0)
+		return dtb_ptr32;
+
+	WARN("Stub magic failure, DTB address unknown\n");
+	return 0;
+#endif
+}
+
+static void ldelay(register_t delay)
+{
+	__asm__ volatile (
+		"1:\tcbz %0, 2f\n\t"
+		"sub %0, %0, #1\n\t"
+		"b 1b\n"
+		"2:"
+		: "=&r" (delay) : "0" (delay)
+	);
+}
+
+/*******************************************************************************
+ * Perform any BL31 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before
+ * they are lost (potentially). This needs to be done before the MMU is
+ * initialized so that the memory layout can be used while creating page
+ * tables. BL2 has flushed this information to memory, so we are guaranteed
+ * to pick up good data.
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+
+{
+	uint32_t div_reg;
+
+	/*
+	 * LOCAL_CONTROL:
+	 * Bit 9 clear: Increment by 1 (vs. 2).
+	 * Bit 8 clear: Timer source is 19.2MHz crystal (vs. APB).
+	 */
+	mmio_write_32(RPI4_LOCAL_CONTROL_BASE_ADDRESS, 0);
+
+	/* LOCAL_PRESCALER; divide-by (0x80000000 / register_val) == 1 */
+	mmio_write_32(RPI4_LOCAL_CONTROL_PRESCALER, 0x80000000);
+
+	/* Early GPU firmware revisions need a little break here. */
+	ldelay(100000);
+
+	/*
+	 * Initialize the console to provide early debug support.
+	 * Different GPU firmware revisions set up the VPU divider differently,
+	 * so read the actual divider register to learn the UART base clock
+	 * rate. The divider is encoded as a 12.12 fixed point number, but we
+	 * just care about the integer part of it.
+	 */
+	div_reg = mmio_read_32(RPI4_CLOCK_BASE + RPI4_VPU_CLOCK_DIVIDER);
+	div_reg = (div_reg >> 12) & 0xfff;
+	if (div_reg == 0)
+		div_reg = 1;
+	rpi3_console_init(PLAT_RPI4_VPU_CLK_RATE / div_reg);
+
+	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+	bl33_image_ep_info.spsr = rpi3_get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+#if RPI3_DIRECT_LINUX_BOOT
+# if RPI3_BL33_IN_AARCH32
+	/*
+	 * According to the file ``Documentation/arm/Booting`` of the Linux
+	 * kernel tree, Linux expects:
+	 * r0 = 0
+	 * r1 = machine type number, optional in DT-only platforms (~0 if so)
+	 * r2 = Physical address of the device tree blob
+	 */
+	VERBOSE("rpi4: Preparing to boot 32-bit Linux kernel\n");
+	bl33_image_ep_info.args.arg0 = 0U;
+	bl33_image_ep_info.args.arg1 = ~0U;
+	bl33_image_ep_info.args.arg2 = rpi4_get_dtb_address();
+# else
+	/*
+	 * According to the file ``Documentation/arm64/booting.txt`` of the
+	 * Linux kernel tree, Linux expects the physical address of the device
+	 * tree blob (DTB) in x0, while x1-x3 are reserved for future use and
+	 * must be 0.
+	 */
+	VERBOSE("rpi4: Preparing to boot 64-bit Linux kernel\n");
+	bl33_image_ep_info.args.arg0 = rpi4_get_dtb_address();
+	bl33_image_ep_info.args.arg1 = 0ULL;
+	bl33_image_ep_info.args.arg2 = 0ULL;
+	bl33_image_ep_info.args.arg3 = 0ULL;
+# endif /* RPI3_BL33_IN_AARCH32 */
+#endif /* RPI3_DIRECT_LINUX_BOOT */
+}
+
+void bl31_plat_arch_setup(void)
+{
+	/*
+	 * Is the dtb_ptr32 pointer valid? If yes, map the DTB region.
+	 * We map the 2MB region the DTB start address lives in, plus
+	 * the next 2MB, to have enough room for expansion.
+	 */
+	if (stub_magic == 0) {
+		unsigned long long dtb_region = dtb_ptr32;
+
+		dtb_region &= ~0x1fffff;	/* Align to 2 MB. */
+		mmap_add_region(dtb_region, dtb_region, 4U << 20,
+				MT_MEMORY | MT_RW | MT_NS);
+	}
+	/*
+	 * Add the first page of memory, which holds the stub magic,
+	 * the kernel and the DT address.
+	 * This also holds the secondary CPU's entrypoints and mailboxes.
+	 */
+	mmap_add_region(0, 0, 4096, MT_NON_CACHEABLE | MT_RW | MT_SECURE);
+
+	rpi3_setup_page_tables(BL31_BASE, BL31_END - BL31_BASE,
+			       BL_CODE_BASE, BL_CODE_END,
+			       BL_RO_DATA_BASE, BL_RO_DATA_END
+#if USE_COHERENT_MEM
+			       , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END
+#endif
+			      );
+
+	enable_mmu_el3(0);
+}
+
+static uint32_t dtb_size(const void *dtb)
+{
+	const uint32_t *dtb_header = dtb;
+
+	return fdt32_to_cpu(dtb_header[1]);
+}
+
+static void rpi4_prepare_dtb(void)
+{
+	void *dtb = (void *)rpi4_get_dtb_address();
+	uint32_t gic_int_prop[3];
+	int ret, offs;
+
+	/* Return if no device tree is detected */
+	if (fdt_check_header(dtb) != 0)
+		return;
+
+	ret = fdt_open_into(dtb, dtb, 0x100000);
+	if (ret < 0) {
+		ERROR("Invalid Device Tree at %p: error %d\n", dtb, ret);
+		return;
+	}
+
+	if (dt_add_psci_node(dtb)) {
+		ERROR("Failed to add PSCI Device Tree node\n");
+		return;
+	}
+
+	if (dt_add_psci_cpu_enable_methods(dtb)) {
+		ERROR("Failed to add PSCI cpu enable methods in Device Tree\n");
+		return;
+	}
+
+	/* Reserve memory used by Trusted Firmware. */
+	if (fdt_add_reserved_memory(dtb, "atf@0", 0, 0x80000))
+		WARN("Failed to add reserved memory nodes to DT.\n");
+
+	offs = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-400");
+	gic_int_prop[0] = cpu_to_fdt32(1);		// PPI
+	gic_int_prop[1] = cpu_to_fdt32(9);		// PPI #9
+	gic_int_prop[2] = cpu_to_fdt32(0x0f04);		// all cores, level high
+	fdt_setprop(dtb, offs, "interrupts", gic_int_prop, 12);
+
+	offs = fdt_path_offset(dtb, "/chosen");
+	fdt_setprop_string(dtb, offs, "stdout-path", "serial0");
+
+	ret = fdt_pack(dtb);
+	if (ret < 0)
+		ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, ret);
+
+	clean_dcache_range((uintptr_t)dtb, dtb_size(dtb));
+	INFO("Changed device tree to advertise PSCI.\n");
+}
+
+void bl31_platform_setup(void)
+{
+	rpi4_prepare_dtb();
+
+	/* Configure the interrupt controller */
+	gicv2_driver_init(&rpi4_gic_data);
+	gicv2_distif_init();
+	gicv2_pcpu_distif_init();
+	gicv2_cpuif_enable();
+}
diff --git a/plat/st/common/include/stm32mp_auth.h b/plat/st/common/include/stm32mp_auth.h
new file mode 100644
index 0000000..3075d18
--- /dev/null
+++ b/plat/st/common/include/stm32mp_auth.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32MP_AUTH_H
+#define STM32MP_AUTH_H
+
+struct stm32mp_auth_ops {
+	uint32_t (*check_key)(uint8_t *pubkey_in, uint8_t *pubkey_out);
+	uint32_t (*verify_signature)(uint8_t *hash_in, uint8_t *pubkey_in,
+				     uint8_t *signature, uint32_t ecc_algo);
+};
+
+void stm32mp_init_auth(struct stm32mp_auth_ops *init_ptr);
+int stm32mp_auth_image(boot_api_image_header_t *header, uintptr_t buffer);
+
+#endif /* STM32MP_AUTH_H */
diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h
index e20308e..59657fd 100644
--- a/plat/st/common/include/stm32mp_common.h
+++ b/plat/st/common/include/stm32mp_common.h
@@ -19,6 +19,7 @@
 uintptr_t stm32mp_get_boot_ctx_address(void);
 
 bool stm32mp_is_single_core(void);
+bool stm32mp_is_closed_device(void);
 
 /* Return the base address of the DDR controller */
 uintptr_t stm32mp_ddrctrl_base(void);
diff --git a/plat/st/common/stm32mp_auth.c b/plat/st/common/stm32mp_auth.c
new file mode 100644
index 0000000..0ef6d54
--- /dev/null
+++ b/plat/st/common/stm32mp_auth.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <drivers/io/io_storage.h>
+#include <drivers/st/bsec.h>
+#include <drivers/st/stm32_hash.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+static const struct stm32mp_auth_ops *auth_ops;
+
+void stm32mp_init_auth(struct stm32mp_auth_ops *init_ptr)
+{
+	if ((init_ptr == NULL) ||
+	    (init_ptr->check_key == NULL) ||
+	    (init_ptr->verify_signature == NULL) ||
+	    (stm32_hash_register() != 0)) {
+		panic();
+	}
+
+	auth_ops = init_ptr;
+}
+
+int stm32mp_auth_image(boot_api_image_header_t *header, uintptr_t buffer)
+{
+	int ret;
+	uint8_t image_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES];
+	uint32_t header_skip_cksum = sizeof(header->magic) +
+				     sizeof(header->image_signature) +
+				     sizeof(header->payload_checksum);
+
+	/* Check Security Status */
+	if (!stm32mp_is_closed_device()) {
+		if (header->option_flags != 0U) {
+			WARN("Skip signature check (header option)\n");
+			return 0;
+		}
+		INFO("Check signature on Open device\n");
+	}
+
+	ret = mmap_add_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_BASE,
+				      STM32MP_ROM_SIZE, MT_CODE | MT_SECURE);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Check Public Key */
+	if (auth_ops->check_key(header->ecc_pubk, NULL) != BOOT_API_RETURN_OK) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* Compute end of header hash and payload hash */
+	stm32_hash_init(HASH_SHA256);
+
+	ret = stm32_hash_update((uint8_t *)&header->header_version,
+				sizeof(boot_api_image_header_t) -
+				header_skip_cksum);
+	if (ret != 0) {
+		ERROR("Hash of header failed, %i\n", ret);
+		goto err;
+	}
+
+	ret = stm32_hash_final_update((uint8_t *)buffer,
+			       header->image_length, image_hash);
+	if (ret != 0) {
+		ERROR("Hash of payload failed\n");
+		goto err;
+	}
+
+	/* Verify signature */
+	if (auth_ops->verify_signature(image_hash, header->ecc_pubk,
+				       header->image_signature,
+				       header->ecc_algo_type) !=
+	    BOOT_API_RETURN_OK) {
+		ret = -EINVAL;
+	}
+
+err:
+	mmap_remove_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_SIZE);
+	return ret;
+}
diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c
index c6aefe3..d9e29b4 100644
--- a/plat/st/stm32mp1/bl2_plat_setup.c
+++ b/plat/st/stm32mp1/bl2_plat_setup.c
@@ -32,6 +32,7 @@
 #include <stm32mp1_dbgmcu.h>
 
 static struct console_stm32 console;
+static struct stm32mp_auth_ops stm32mp1_auth_ops;
 
 static void print_reset_reason(void)
 {
@@ -284,6 +285,12 @@
 
 	stm32mp_print_boardinfo();
 
+	if (boot_context->auth_status != BOOT_API_CTX_AUTH_NO) {
+		NOTICE("Bootrom authentication %s\n",
+		       (boot_context->auth_status == BOOT_API_CTX_AUTH_FAILED) ?
+		       "failed" : "succeeded");
+	}
+
 skip_console_init:
 	if (stm32_iwdg_init() < 0) {
 		panic();
@@ -302,6 +309,12 @@
 		ERROR("Cannot save boot interface\n");
 	}
 
+	stm32mp1_auth_ops.check_key = boot_context->bootrom_ecdsa_check_key;
+	stm32mp1_auth_ops.verify_signature =
+		boot_context->bootrom_ecdsa_verify_signature;
+
+	stm32mp_init_auth(&stm32mp1_auth_ops);
+
 	stm32mp1_arch_security_setup();
 
 	print_reset_reason();
diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h
index c841a74..2284970 100644
--- a/plat/st/stm32mp1/include/boot_api.h
+++ b/plat/st/stm32mp1/include/boot_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,6 +11,16 @@
 #include <stdio.h>
 
 /*
+ * Possible value of boot context field 'auth_status'
+ */
+/* No authentication done */
+#define BOOT_API_CTX_AUTH_NO					0x0U
+/* Authentication done and failed */
+#define BOOT_API_CTX_AUTH_FAILED				0x1U
+/* Authentication done and succeeded */
+#define BOOT_API_CTX_AUTH_SUCCESS				0x2U
+
+/*
  * Possible value of boot context field 'boot_interface_sel'
  */
 
@@ -114,6 +124,8 @@
 /* Closed = OTP_CFG0[6] */
 #define BOOT_API_OTP_MODE_CLOSED_BIT_POS			6
 
+#define BOOT_API_RETURN_OK					0x66U
+
 /*
  * Boot Context related definitions
  */
@@ -132,7 +144,27 @@
 	uint16_t boot_interface_instance;
 	uint32_t reserved1[13];
 	uint32_t otp_afmux_values[3];
-	uint32_t reserved[9];
+	uint32_t reserved[5];
+	uint32_t auth_status;
+
+	/*
+	 * Pointers to bootROM External Secure Services
+	 * - ECDSA check key
+	 * - ECDSA verify signature
+	 * - ECDSA verify signature and go
+	 */
+	uint32_t (*bootrom_ecdsa_check_key)(uint8_t *pubkey_in,
+					    uint8_t *pubkey_out);
+	uint32_t (*bootrom_ecdsa_verify_signature)(uint8_t *hash_in,
+						   uint8_t *pubkey_in,
+						   uint8_t *signature,
+						   uint32_t ecc_algo);
+	uint32_t (*bootrom_ecdsa_verify_and_go)(uint8_t *hash_in,
+						uint8_t *pub_key_in,
+						uint8_t *signature,
+						uint32_t ecc_algo,
+						uint32_t *entry_in);
+
 	/*
 	 * Information specific to an SD boot
 	 * Updated each time an SD boot is at least attempted,
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index 83d9770..90b3e3c 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -71,7 +71,9 @@
 BL2_SOURCES		+=	drivers/io/io_block.c					\
 				drivers/io/io_dummy.c					\
 				drivers/io/io_storage.c					\
+				drivers/st/crypto/stm32_hash.c				\
 				drivers/st/io/io_stm32image.c				\
+				plat/st/common/stm32mp_auth.c				\
 				plat/st/common/bl2_io_storage.c				\
 				plat/st/stm32mp1/bl2_plat_setup.c
 
@@ -103,6 +105,8 @@
 STM32_TF_DTBFILE	:=      ${BUILD_PLAT}/fdts/${DTB_FILE_NAME}
 STM32_TF_OBJS		:=	${BUILD_PLAT}/stm32mp1.o
 
+BL2_CFLAGS	+=	-DPLAT_XLAT_TABLES_DYNAMIC=1
+
 # Variables for use with stm32image
 STM32IMAGEPATH		?= tools/stm32image
 STM32IMAGE		?= ${STM32IMAGEPATH}/stm32image${BIN_EXT}
diff --git a/plat/st/stm32mp1/stm32mp1_def.h b/plat/st/stm32mp1/stm32mp1_def.h
index 0eba8a6..a40852b 100644
--- a/plat/st/stm32mp1/stm32mp1_def.h
+++ b/plat/st/stm32mp1/stm32mp1_def.h
@@ -19,6 +19,7 @@
 #include <drivers/st/stm32mp1_clk.h>
 
 #include <boot_api.h>
+#include <stm32mp_auth.h>
 #include <stm32mp_common.h>
 #include <stm32mp_dt.h>
 #include <stm32mp_shres_helpers.h>
@@ -49,6 +50,8 @@
 /*******************************************************************************
  * STM32MP1 memory map related constants
  ******************************************************************************/
+#define STM32MP_ROM_BASE		U(0x00000000)
+#define STM32MP_ROM_SIZE		U(0x00020000)
 
 #define STM32MP_SYSRAM_BASE		U(0x2FFC0000)
 #define STM32MP_SYSRAM_SIZE		U(0x00040000)
diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c
index 38ebcef..e2dcd2a 100644
--- a/plat/st/stm32mp1/stm32mp1_private.c
+++ b/plat/st/stm32mp1/stm32mp1_private.c
@@ -278,6 +278,19 @@
 	return ret;
 }
 
+/* Return true when device is in closed state */
+bool stm32mp_is_closed_device(void)
+{
+	uint32_t value;
+
+	if ((bsec_shadow_register(DATA0_OTP) != BSEC_OK) ||
+	    (bsec_read_otp(&value, DATA0_OTP) != BSEC_OK)) {
+		return true;
+	}
+
+	return (value & DATA0_OTP_SECURED) == DATA0_OTP_SECURED;
+}
+
 uint32_t stm32_iwdg_get_instance(uintptr_t base)
 {
 	switch (base) {