rpi3: Add "rpi" platform directory

With the incoming support for the Raspberry Pi 4 boards, one directory
to serve both versions will not end up well.

Create an additional layer by inserting a "rpi" directory betweeen /plat
and rpi3, so that we can more easily share or separate files between the
two later.

Change-Id: I75adbb054fe7902f34db0fd5e579a55612dd8a5f
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
diff --git a/plat/rpi/rpi3/aarch64/plat_helpers.S b/plat/rpi/rpi3/aarch64/plat_helpers.S
new file mode 100644
index 0000000..7974b60
--- /dev/null
+++ b/plat/rpi/rpi3/aarch64/plat_helpers.S
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015-2018, 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 "../rpi3_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, #RPI3_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_RPI3_UART_CLK_IN_HZ
+	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
+	/* use the 19.2 MHz clock for the architected timer */
+	mov	x0, #RPI3_INTC_BASE_ADDRESS
+	mov	w1, #0x80000000
+	str	wzr, [x0, #RPI3_INTC_CONTROL_OFFSET]
+	str	w1, [x0, #RPI3_INTC_PRESCALER_OFFSET]
+	ret
+endfunc plat_reset_handler
diff --git a/plat/rpi/rpi3/aarch64/rpi3_bl2_mem_params_desc.c b/plat/rpi/rpi3/aarch64/rpi3_bl2_mem_params_desc.c
new file mode 100644
index 0000000..715aec4
--- /dev/null
+++ b/plat/rpi/rpi3/aarch64/rpi3_bl2_mem_params_desc.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * Following descriptor provides BL image/ep information that gets used
+ * by BL2 to load the images and also subset of this information is
+ * passed to next BL image. The image loading sequence is managed by
+ * populating the images in required loading order. The image execution
+ * sequence is managed by populating the `next_handoff_image_id` with
+ * the next executable image id.
+ ******************************************************************************/
+static bl_mem_params_node_t bl2_mem_params_descs[] = {
+
+	/* Fill BL31 related information */
+	{
+		.image_id = BL31_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | EXECUTABLE | EP_FIRST_EXE),
+		.ep_info.pc = BL31_BASE,
+		.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+					DISABLE_ALL_EXCEPTIONS),
+#if DEBUG
+		.ep_info.args.arg1 = RPI3_BL31_PLAT_PARAM_VAL,
+#endif
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t,
+				      IMAGE_ATTRIB_PLAT_SETUP),
+		.image_info.image_base = BL31_BASE,
+		.image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+
+# ifdef BL32_BASE
+		.next_handoff_image_id = BL32_IMAGE_ID,
+# else
+		.next_handoff_image_id = BL33_IMAGE_ID,
+# endif
+	},
+
+# ifdef BL32_BASE
+	/* Fill BL32 related information */
+	{
+		.image_id = BL32_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | EXECUTABLE),
+		.ep_info.pc = BL32_BASE,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t, 0),
+		.image_info.image_base = BL32_BASE,
+		.image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+		.next_handoff_image_id = BL33_IMAGE_ID,
+	},
+
+	/*
+	 * Fill BL32 external 1 related information.
+	 * A typical use for extra1 image is with OP-TEE where it is the pager
+	 * image.
+	 */
+	{
+		.image_id = BL32_EXTRA1_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | NON_EXECUTABLE),
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t,
+				      IMAGE_ATTRIB_SKIP_LOADING),
+		.image_info.image_base = BL32_BASE,
+		.image_info.image_max_size = BL32_LIMIT - BL32_BASE,
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+
+	/*
+	 * Fill BL32 external 2 related information.
+	 * A typical use for extra2 image is with OP-TEE where it is the paged
+	 * image.
+	 */
+	{
+		.image_id = BL32_EXTRA2_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | NON_EXECUTABLE),
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t,
+				      IMAGE_ATTRIB_SKIP_LOADING),
+#ifdef SPD_opteed
+		.image_info.image_base = RPI3_OPTEE_PAGEABLE_LOAD_BASE,
+		.image_info.image_max_size = RPI3_OPTEE_PAGEABLE_LOAD_SIZE,
+#endif
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+# endif /* BL32_BASE */
+
+	/* Fill BL33 related information */
+	{
+		.image_id = BL33_IMAGE_ID,
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      NON_SECURE | EXECUTABLE),
+# ifdef PRELOADED_BL33_BASE
+		.ep_info.pc = PRELOADED_BL33_BASE,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t,
+				      IMAGE_ATTRIB_SKIP_LOADING),
+# else
+		.ep_info.pc = PLAT_RPI3_NS_IMAGE_OFFSET,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t, 0),
+		.image_info.image_base = PLAT_RPI3_NS_IMAGE_OFFSET,
+		.image_info.image_max_size = PLAT_RPI3_NS_IMAGE_MAX_SIZE,
+# endif /* PRELOADED_BL33_BASE */
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	}
+};
+
+REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs)
diff --git a/plat/rpi/rpi3/include/plat_macros.S b/plat/rpi/rpi3/include/plat_macros.S
new file mode 100644
index 0000000..c0c3967
--- /dev/null
+++ b/plat/rpi/rpi3/include/plat_macros.S
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2016-2018, 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/rpi3/include/platform_def.h b/plat/rpi/rpi3/include/platform_def.h
new file mode 100644
index 0000000..4d90222
--- /dev/null
+++ b/plat/rpi/rpi3/include/platform_def.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2015-2018, 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 "../rpi3_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 RPI3_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)
+
+/*
+ * Partition memory into secure ROM, non-secure DRAM, secure "SRAM", and
+ * secure DRAM. Note that this is all actually DRAM with different names,
+ * there is no Secure RAM in the Raspberry Pi 3.
+ */
+#if RPI3_USE_UEFI_MAP
+#define SEC_ROM_BASE			ULL(0x00000000)
+#define SEC_ROM_SIZE			ULL(0x00010000)
+
+/* FIP placed after ROM to append it to BL1 with very little padding. */
+#define PLAT_RPI3_FIP_BASE		ULL(0x00020000)
+#define PLAT_RPI3_FIP_MAX_SIZE		ULL(0x00010000)
+
+/* Reserve 2M of secure SRAM and DRAM, starting at 2M */
+#define SEC_SRAM_BASE			ULL(0x00200000)
+#define SEC_SRAM_SIZE			ULL(0x00100000)
+
+#define SEC_DRAM0_BASE			ULL(0x00300000)
+#define SEC_DRAM0_SIZE			ULL(0x00100000)
+
+/* Windows on ARM requires some RAM at 4M */
+#define NS_DRAM0_BASE			ULL(0x00400000)
+#define NS_DRAM0_SIZE			ULL(0x00C00000)
+#else
+#define SEC_ROM_BASE			ULL(0x00000000)
+#define SEC_ROM_SIZE			ULL(0x00020000)
+
+/* FIP placed after ROM to append it to BL1 with very little padding. */
+#define PLAT_RPI3_FIP_BASE		ULL(0x00020000)
+#define PLAT_RPI3_FIP_MAX_SIZE		ULL(0x001E0000)
+
+/* We have 16M of memory reserved starting at 256M */
+#define SEC_SRAM_BASE			ULL(0x10000000)
+#define SEC_SRAM_SIZE			ULL(0x00100000)
+
+#define SEC_DRAM0_BASE			ULL(0x10100000)
+#define SEC_DRAM0_SIZE			ULL(0x00F00000)
+/* End of reserved memory */
+
+#define NS_DRAM0_BASE			ULL(0x11000000)
+#define NS_DRAM0_SIZE			ULL(0x01000000)
+#endif /* RPI3_USE_UEFI_MAP */
+
+/*
+ * BL33 entrypoint.
+ */
+#define PLAT_RPI3_NS_IMAGE_OFFSET	NS_DRAM0_BASE
+#define PLAT_RPI3_NS_IMAGE_MAX_SIZE	NS_DRAM0_SIZE
+
+/*
+ * I/O registers.
+ */
+#define DEVICE0_BASE			RPI3_IO_BASE
+#define DEVICE0_SIZE			RPI3_IO_SIZE
+
+/*
+ * Arm TF lives in SRAM, partition it here
+ */
+#define SHARED_RAM_BASE			SEC_SRAM_BASE
+#define SHARED_RAM_SIZE			ULL(0x00001000)
+
+#define BL_RAM_BASE			(SHARED_RAM_BASE + SHARED_RAM_SIZE)
+#define BL_RAM_SIZE			(SEC_SRAM_SIZE - SHARED_RAM_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();
+ */
+#define PLAT_RPI3_TRUSTED_MAILBOX_BASE	SHARED_RAM_BASE
+
+/* The secure entry point to be used on warm reset by all CPUs. */
+#define PLAT_RPI3_TM_ENTRYPOINT		PLAT_RPI3_TRUSTED_MAILBOX_BASE
+#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)
+
+/*
+ * BL1 specific defines.
+ *
+ * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
+ * addresses.
+ *
+ * Put BL1 RW at the top of the Secure SRAM. BL1_RW_BASE is calculated using
+ * the current BL1 RW debug size plus a little space for growth.
+ */
+#define PLAT_MAX_BL1_RW_SIZE		ULL(0x12000)
+
+#define BL1_RO_BASE			SEC_ROM_BASE
+#define BL1_RO_LIMIT			(SEC_ROM_BASE + SEC_ROM_SIZE)
+#define BL1_RW_BASE			(BL1_RW_LIMIT - PLAT_MAX_BL1_RW_SIZE)
+#define BL1_RW_LIMIT			(BL_RAM_BASE + BL_RAM_SIZE)
+
+/*
+ * BL2 specific defines.
+ *
+ * Put BL2 just below BL31. BL2_BASE is calculated using the current BL2 debug
+ * size plus a little space for growth.
+ */
+#define PLAT_MAX_BL2_SIZE		ULL(0x2C000)
+
+#define BL2_BASE			(BL2_LIMIT - PLAT_MAX_BL2_SIZE)
+#define BL2_LIMIT			BL31_BASE
+
+/*
+ * 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(0x20000)
+
+#define BL31_BASE			(BL31_LIMIT - PLAT_MAX_BL31_SIZE)
+#define BL31_LIMIT			(BL_RAM_BASE + BL_RAM_SIZE)
+#define BL31_PROGBITS_LIMIT		BL1_RW_BASE
+
+/*
+ * BL32 specific defines.
+ *
+ * BL32 can execute from Secure SRAM or Secure DRAM.
+ */
+#define BL32_SRAM_BASE			BL_RAM_BASE
+#define BL32_SRAM_LIMIT			BL31_BASE
+#define BL32_DRAM_BASE			SEC_DRAM0_BASE
+#define BL32_DRAM_LIMIT			(SEC_DRAM0_BASE + SEC_DRAM0_SIZE)
+
+#ifdef SPD_opteed
+/* Load pageable part of OP-TEE at end of allocated DRAM space for BL32 */
+#define RPI3_OPTEE_PAGEABLE_LOAD_SIZE	0x080000 /* 512KB */
+#define RPI3_OPTEE_PAGEABLE_LOAD_BASE	(BL32_DRAM_LIMIT - \
+					 RPI3_OPTEE_PAGEABLE_LOAD_SIZE)
+#endif
+
+#define SEC_SRAM_ID			0
+#define SEC_DRAM_ID			1
+
+#if RPI3_BL32_RAM_LOCATION_ID == SEC_SRAM_ID
+# define BL32_MEM_BASE			BL_RAM_BASE
+# define BL32_MEM_SIZE			BL_RAM_SIZE
+# define BL32_BASE			BL32_SRAM_BASE
+# define BL32_LIMIT			BL32_SRAM_LIMIT
+#elif RPI3_BL32_RAM_LOCATION_ID == SEC_DRAM_ID
+# define BL32_MEM_BASE			SEC_DRAM0_BASE
+# define BL32_MEM_SIZE			SEC_DRAM0_SIZE
+# define BL32_BASE			BL32_DRAM_BASE
+# define BL32_LIMIT			BL32_DRAM_LIMIT
+#else
+# error "Unsupported RPI3_BL32_RAM_LOCATION_ID value"
+#endif
+#define BL32_SIZE			(BL32_LIMIT - BL32_BASE)
+
+#ifdef SPD_none
+#undef BL32_BASE
+#endif /* SPD_none */
+
+/*
+ * 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_CLK_IN_HZ	RPI3_MINI_UART_CLK_IN_HZ
+#define PLAT_RPI3_UART_BAUDRATE		ULL(115200)
+
+/*
+ * System counter
+ */
+#define SYS_COUNTER_FREQ_IN_TICKS	ULL(19200000)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/rpi/rpi3/platform.mk b/plat/rpi/rpi3/platform.mk
new file mode 100644
index 0000000..c011c0a
--- /dev/null
+++ b/plat/rpi/rpi3/platform.mk
@@ -0,0 +1,218 @@
+#
+# Copyright (c) 2013-2018, 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/rpi3/include
+
+PLAT_BL_COMMON_SOURCES	:=	drivers/ti/uart/aarch64/16550_console.S	\
+				plat/rpi/rpi3/rpi3_common.c		\
+				${XLAT_TABLES_LIB_SRCS}
+
+BL1_SOURCES		+=	drivers/io/io_fip.c			\
+				drivers/io/io_memmap.c			\
+				drivers/io/io_storage.c			\
+				lib/cpus/aarch64/cortex_a53.S		\
+				plat/common/aarch64/platform_mp_stack.S	\
+				plat/rpi/rpi3/aarch64/plat_helpers.S	\
+				plat/rpi/rpi3/rpi3_bl1_setup.c		\
+				plat/rpi/rpi3/rpi3_io_storage.c		\
+				plat/rpi/rpi3/rpi3_mbox.c
+
+BL2_SOURCES		+=	common/desc_image_load.c		\
+				drivers/io/io_fip.c			\
+				drivers/io/io_memmap.c			\
+				drivers/io/io_storage.c			\
+				drivers/gpio/gpio.c			\
+				drivers/delay_timer/delay_timer.c	\
+				drivers/delay_timer/generic_delay_timer.c \
+				drivers/rpi3/gpio/rpi3_gpio.c		\
+				drivers/io/io_block.c			\
+				drivers/mmc/mmc.c			\
+				drivers/rpi3/sdhost/rpi3_sdhost.c	\
+				plat/common/aarch64/platform_mp_stack.S	\
+				plat/rpi/rpi3/aarch64/plat_helpers.S	\
+				plat/rpi/rpi3/aarch64/rpi3_bl2_mem_params_desc.c \
+				plat/rpi/rpi3/rpi3_bl2_setup.c		\
+				plat/rpi/rpi3/rpi3_image_load.c		\
+				plat/rpi/rpi3/rpi3_io_storage.c
+
+BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
+				plat/common/plat_psci_common.c		\
+				plat/rpi/rpi3/aarch64/plat_helpers.S	\
+				plat/rpi/rpi3/rpi3_bl31_setup.c		\
+				plat/rpi/rpi3/rpi3_pm.c			\
+				plat/rpi/rpi3/rpi3_topology.c		\
+				${LIBFDT_SRCS}
+
+# 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
+
+# Platform Makefile target
+# ------------------------
+
+RPI3_BL1_PAD_BIN	:=	${BUILD_PLAT}/bl1_pad.bin
+RPI3_ARMSTUB8_BIN	:=	${BUILD_PLAT}/armstub8.bin
+
+# Add new default target when compiling this platform
+all: armstub
+
+# This target concatenates BL1 and the FIP so that the base addresses match the
+# ones defined in the memory map
+armstub: bl1 fip
+	@echo "  CAT     $@"
+	${Q}cp ${BUILD_PLAT}/bl1.bin ${RPI3_BL1_PAD_BIN}
+	${Q}truncate --size=131072 ${RPI3_BL1_PAD_BIN}
+	${Q}cat ${RPI3_BL1_PAD_BIN} ${BUILD_PLAT}/fip.bin > ${RPI3_ARMSTUB8_BIN}
+	@${ECHO_BLANK_LINE}
+	@echo "Built $@ successfully"
+	@${ECHO_BLANK_LINE}
+
+# Build config flags
+# ------------------
+
+# Enable all errata workarounds for Cortex-A53
+ERRATA_A53_826319		:= 1
+ERRATA_A53_835769		:= 1
+ERRATA_A53_836870		:= 1
+ERRATA_A53_843419		:= 1
+ERRATA_A53_855873		:= 1
+
+WORKAROUND_CVE_2017_5715	:= 0
+
+# Disable stack protector by default
+ENABLE_STACK_PROTECTOR	 	:= 0
+
+# Reset to BL31 isn't supported
+RESET_TO_BL31			:= 0
+
+# Have different sections for code and rodata
+SEPARATE_CODE_AND_RODATA	:= 1
+
+# Use Coherent memory
+USE_COHERENT_MEM		:= 1
+
+# Platform build flags
+# --------------------
+
+# BL33 images are in AArch64 by default
+RPI3_BL33_IN_AARCH32		:= 0
+
+# Assume that BL33 isn't the Linux kernel by default
+RPI3_DIRECT_LINUX_BOOT		:= 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		:= -1
+
+# Use normal memory mapping for ROM, FIP, SRAM and DRAM
+RPI3_USE_UEFI_MAP		:= 0
+
+# BL32 location
+RPI3_BL32_RAM_LOCATION	:= tdram
+ifeq (${RPI3_BL32_RAM_LOCATION}, tsram)
+  RPI3_BL32_RAM_LOCATION_ID = SEC_SRAM_ID
+else ifeq (${RPI3_BL32_RAM_LOCATION}, tdram)
+  RPI3_BL32_RAM_LOCATION_ID = SEC_DRAM_ID
+else
+  $(error "Unsupported RPI3_BL32_RAM_LOCATION value")
+endif
+
+# Process platform flags
+# ----------------------
+
+$(eval $(call add_define,RPI3_BL32_RAM_LOCATION_ID))
+$(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))
+
+# Verify build config
+# -------------------
+#
+ifneq (${RPI3_DIRECT_LINUX_BOOT}, 0)
+  ifndef RPI3_PRELOADED_DTB_BASE
+    $(error Error: RPI3_PRELOADED_DTB_BASE needed if RPI3_DIRECT_LINUX_BOOT=1)
+  endif
+endif
+
+ifneq (${RESET_TO_BL31}, 0)
+  $(error Error: rpi3 needs RESET_TO_BL31=0)
+endif
+
+ifeq (${ARCH},aarch32)
+  $(error Error: AArch32 not supported on rpi3)
+endif
+
+ifneq ($(ENABLE_STACK_PROTECTOR), 0)
+PLAT_BL_COMMON_SOURCES	+=	plat/rpi/rpi3/rpi3_rng.c		\
+				plat/rpi/rpi3/rpi3_stack_protector.c
+endif
+
+ifeq (${SPD},opteed)
+BL2_SOURCES	+=							\
+		lib/optee/optee_utils.c
+endif
+
+# Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images
+# in the FIP if the platform requires.
+ifneq ($(BL32_EXTRA1),)
+$(eval $(call TOOL_ADD_IMG,BL32_EXTRA1,--tos-fw-extra1))
+endif
+ifneq ($(BL32_EXTRA2),)
+$(eval $(call TOOL_ADD_IMG,BL32_EXTRA2,--tos-fw-extra2))
+endif
+
+ifneq (${TRUSTED_BOARD_BOOT},0)
+
+    include drivers/auth/mbedtls/mbedtls_crypto.mk
+    include drivers/auth/mbedtls/mbedtls_x509.mk
+
+    AUTH_SOURCES	:=	drivers/auth/auth_mod.c			\
+				drivers/auth/crypto_mod.c		\
+				drivers/auth/img_parser_mod.c		\
+				drivers/auth/tbbr/tbbr_cot.c
+
+    BL1_SOURCES		+=	${AUTH_SOURCES}				\
+				bl1/tbbr/tbbr_img_desc.c		\
+				plat/common/tbbr/plat_tbbr.c		\
+				plat/rpi/rpi3/rpi3_trusted_boot.c     	\
+				plat/rpi/rpi3/rpi3_rotpk.S
+
+    BL2_SOURCES		+=	${AUTH_SOURCES}				\
+				plat/common/tbbr/plat_tbbr.c		\
+				plat/rpi/rpi3/rpi3_trusted_boot.c     	\
+				plat/rpi/rpi3/rpi3_rotpk.S
+
+    ROT_KEY             = $(BUILD_PLAT)/rot_key.pem
+    ROTPK_HASH          = $(BUILD_PLAT)/rotpk_sha256.bin
+
+    $(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
+
+    $(BUILD_PLAT)/bl1/rpi3_rotpk.o: $(ROTPK_HASH)
+    $(BUILD_PLAT)/bl2/rpi3_rotpk.o: $(ROTPK_HASH)
+
+    certificates: $(ROT_KEY)
+
+    $(ROT_KEY):
+	@echo "  OPENSSL $@"
+	$(Q)openssl genrsa 2048 > $@ 2>/dev/null
+
+    $(ROTPK_HASH): $(ROT_KEY)
+	@echo "  OPENSSL $@"
+	$(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+	openssl dgst -sha256 -binary > $@ 2>/dev/null
+endif
diff --git a/plat/rpi/rpi3/rpi3_bl1_setup.c b/plat/rpi/rpi3/rpi3_bl1_setup.c
new file mode 100644
index 0000000..b869e9d
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_bl1_setup.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#include "rpi3_private.h"
+
+/* Data structure which holds the extents of the trusted SRAM for BL1 */
+static meminfo_t bl1_tzram_layout;
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+	return &bl1_tzram_layout;
+}
+
+/*******************************************************************************
+ * Perform any BL1 specific platform actions.
+ ******************************************************************************/
+void bl1_early_platform_setup(void)
+{
+	/* Initialize the console to provide early debug support */
+	rpi3_console_init();
+
+	/* Allow BL1 to see the whole Trusted RAM */
+	bl1_tzram_layout.total_base = BL_RAM_BASE;
+	bl1_tzram_layout.total_size = BL_RAM_SIZE;
+}
+
+/******************************************************************************
+ * Perform the very early platform specific architecture setup.  This only
+ * does basic initialization. Later architectural setup (bl1_arch_setup())
+ * does not do anything platform specific.
+ *****************************************************************************/
+void bl1_plat_arch_setup(void)
+{
+	rpi3_setup_page_tables(bl1_tzram_layout.total_base,
+			       bl1_tzram_layout.total_size,
+			       BL_CODE_BASE, BL1_CODE_END,
+			       BL1_RO_DATA_BASE, BL1_RO_DATA_END
+#if USE_COHERENT_MEM
+			       , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END
+#endif
+			      );
+
+	enable_mmu_el3(0);
+}
+
+void bl1_platform_setup(void)
+{
+	uint32_t __unused rev;
+	int __unused rc;
+
+	rc = rpi3_vc_hardware_get_board_revision(&rev);
+
+	if (rc == 0) {
+		const char __unused *model, __unused *info;
+
+		switch (rev) {
+		case 0xA02082:
+			model = "Raspberry Pi 3 Model B";
+			info = "(1GB, Sony, UK)";
+			break;
+		case 0xA22082:
+			model = "Raspberry Pi 3 Model B";
+			info = "(1GB, Embest, China)";
+			break;
+		case 0xA020D3:
+			model = "Raspberry Pi 3 Model B+";
+			info = "(1GB, Sony, UK)";
+			break;
+		default:
+			model = "Unknown";
+			info = "(Unknown)";
+			ERROR("rpi3: Unknown board revision 0x%08x\n", rev);
+			break;
+		}
+
+		NOTICE("rpi3: Detected: %s %s [0x%08x]\n", model, info, rev);
+	} else {
+		ERROR("rpi3: Unable to detect board revision\n");
+	}
+
+	/* Initialise the IO layer and register platform IO devices */
+	plat_rpi3_io_setup();
+}
diff --git a/plat/rpi/rpi3/rpi3_bl2_setup.c b/plat/rpi/rpi3/rpi3_bl2_setup.c
new file mode 100644
index 0000000..b5e5835
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_bl2_setup.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <lib/optee_utils.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/rpi3/gpio/rpi3_gpio.h>
+#include <drivers/rpi3/sdhost/rpi3_sdhost.h>
+
+#include "rpi3_private.h"
+
+/* Data structure which holds the extents of the trusted SRAM for BL2 */
+static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+
+/* rpi3 GPIO setup function. */
+static void rpi3_gpio_setup(void)
+{
+	struct rpi3_gpio_params params;
+
+	memset(&params, 0, sizeof(struct rpi3_gpio_params));
+	params.reg_base = RPI3_GPIO_BASE;
+
+	rpi3_gpio_init(&params);
+}
+
+/* Data structure which holds the MMC info */
+static struct mmc_device_info mmc_info;
+
+static void rpi3_sdhost_setup(void)
+{
+	struct rpi3_sdhost_params params;
+
+	memset(&params, 0, sizeof(struct rpi3_sdhost_params));
+	params.reg_base = RPI3_SDHOST_BASE;
+	params.bus_width = MMC_BUS_WIDTH_1;
+	params.clk_rate = 50000000;
+	mmc_info.mmc_dev_type = MMC_IS_SD_HC;
+	rpi3_sdhost_init(&params, &mmc_info);
+}
+
+/*******************************************************************************
+ * BL1 has passed the extents of the trusted SRAM that should be visible to BL2
+ * in x0. This memory layout is sitting at the base of the free trusted SRAM.
+ * Copy it to a safe location before its reclaimed by later BL2 functionality.
+ ******************************************************************************/
+
+void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+			       u_register_t arg2, u_register_t arg3)
+{
+	meminfo_t *mem_layout = (meminfo_t *) arg1;
+
+	/* Initialize the console to provide early debug support */
+	rpi3_console_init();
+
+	/* Enable arch timer */
+	generic_delay_timer_init();
+
+	/* Setup GPIO driver */
+	rpi3_gpio_setup();
+
+	/* Setup the BL2 memory layout */
+	bl2_tzram_layout = *mem_layout;
+
+	/* Setup SDHost driver */
+	rpi3_sdhost_setup();
+
+	plat_rpi3_io_setup();
+}
+
+void bl2_platform_setup(void)
+{
+	/*
+	 * This is where a TrustZone address space controller and other
+	 * security related peripherals would be configured.
+	 */
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here.
+ ******************************************************************************/
+void bl2_plat_arch_setup(void)
+{
+	rpi3_setup_page_tables(bl2_tzram_layout.total_base,
+			       bl2_tzram_layout.total_size,
+			       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_el1(0);
+}
+
+/*******************************************************************************
+ * This function can be used by the platforms to update/use image
+ * information for given `image_id`.
+ ******************************************************************************/
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	int err = 0;
+	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
+#ifdef SPD_opteed
+	bl_mem_params_node_t *pager_mem_params = NULL;
+	bl_mem_params_node_t *paged_mem_params = NULL;
+#endif
+
+	assert(bl_mem_params != NULL);
+
+	switch (image_id) {
+	case BL32_IMAGE_ID:
+#ifdef SPD_opteed
+		pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
+		assert(pager_mem_params);
+
+		paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID);
+		assert(paged_mem_params);
+
+		err = parse_optee_header(&bl_mem_params->ep_info,
+				&pager_mem_params->image_info,
+				&paged_mem_params->image_info);
+		if (err != 0)
+			WARN("OPTEE header parse error.\n");
+#endif
+		bl_mem_params->ep_info.spsr = rpi3_get_spsr_for_bl32_entry();
+		break;
+
+	case BL33_IMAGE_ID:
+		/* BL33 expects to receive the primary CPU MPID (through r0) */
+		bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr();
+		bl_mem_params->ep_info.spsr = rpi3_get_spsr_for_bl33_entry();
+
+		/* Shutting down the SDHost driver to let BL33 drives SDHost.*/
+		rpi3_sdhost_stop();
+		break;
+
+	default:
+		/* Do nothing in default case */
+		break;
+	}
+
+	return err;
+}
diff --git a/plat/rpi/rpi3/rpi3_bl31_setup.c b/plat/rpi/rpi3/rpi3_bl31_setup.c
new file mode 100644
index 0000000..2f1bc64
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_bl31_setup.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+#include <plat/common/platform.h>
+
+#include "rpi3_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;
+
+/*******************************************************************************
+ * 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;
+	}
+}
+
+/*******************************************************************************
+ * 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)
+
+{
+	/* Initialize the console to provide early debug support */
+	rpi3_console_init();
+
+	/*
+	 * In debug builds, a special value is passed in 'arg1' to verify
+	 * platform parameters from BL2 to BL31. Not used in release builds.
+	 */
+	assert(arg1 == RPI3_BL31_PLAT_PARAM_VAL);
+
+	/* Check that params passed from BL2 are not NULL. */
+	bl_params_t *params_from_bl2 = (bl_params_t *) arg0;
+
+	assert(params_from_bl2 != NULL);
+	assert(params_from_bl2->h.type == PARAM_BL_PARAMS);
+	assert(params_from_bl2->h.version >= VERSION_2);
+
+	bl_params_node_t *bl_params = params_from_bl2->head;
+
+	/*
+	 * Copy BL33 and BL32 (if present), entry point information.
+	 * They are stored in Secure RAM, in BL2's address space.
+	 */
+	while (bl_params) {
+		if (bl_params->image_id == BL32_IMAGE_ID) {
+			bl32_image_ep_info = *bl_params->ep_info;
+		}
+
+		if (bl_params->image_id == BL33_IMAGE_ID) {
+			bl33_image_ep_info = *bl_params->ep_info;
+		}
+
+		bl_params = bl_params->next_params_info;
+	}
+
+	if (bl33_image_ep_info.pc == 0) {
+		panic();
+	}
+
+#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("rpi3: 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 = (u_register_t) RPI3_PRELOADED_DTB_BASE;
+# 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("rpi3: Preparing to boot 64-bit Linux kernel\n");
+	bl33_image_ep_info.args.arg0 = (u_register_t) RPI3_PRELOADED_DTB_BASE;
+	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)
+{
+	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);
+}
+
+#ifdef RPI3_PRELOADED_DTB_BASE
+/*
+ * Add information to the device tree (if any) about the reserved DRAM used by
+ * the Trusted Firmware.
+ */
+static void rpi3_dtb_add_mem_rsv(void)
+{
+	int i, regions, rc;
+	uint64_t addr, size;
+	void *dtb = (void *)RPI3_PRELOADED_DTB_BASE;
+
+	INFO("rpi3: Checking DTB...\n");
+
+	/* Return if no device tree is detected */
+	if (fdt_check_header(dtb) != 0)
+		return;
+
+	regions = fdt_num_mem_rsv(dtb);
+
+	VERBOSE("rpi3: Found %d mem reserve region(s)\n", regions);
+
+	/* We expect to find one reserved region that we can modify */
+	if (regions < 1)
+		return;
+
+	/*
+	 * Look for the region that corresponds to the default boot firmware. It
+	 * starts at address 0, and it is not needed when the default firmware
+	 * is replaced by this port of the Trusted Firmware.
+	 */
+	for (i = 0; i < regions; i++) {
+		if (fdt_get_mem_rsv(dtb, i, &addr, &size) != 0)
+			continue;
+
+		if (addr != 0x0)
+			continue;
+
+		VERBOSE("rpi3: Firmware mem reserve region found\n");
+
+		rc = fdt_del_mem_rsv(dtb, i);
+		if (rc != 0) {
+			INFO("rpi3: Can't remove mem reserve region (%d)\n", rc);
+		}
+
+		break;
+	}
+
+	if (i == regions) {
+		VERBOSE("rpi3: Firmware mem reserve region not found\n");
+	}
+
+	/*
+	 * Reserve all SRAM. As said in the documentation, this isn't actually
+	 * secure memory, so it is needed to tell BL33 that this is a reserved
+	 * memory region. It doesn't guarantee it won't use it, though.
+	 */
+	rc = fdt_add_mem_rsv(dtb, SEC_SRAM_BASE, SEC_SRAM_SIZE);
+	if (rc != 0) {
+		WARN("rpi3: Can't add mem reserve region (%d)\n", rc);
+	}
+
+	INFO("rpi3: Reserved 0x%llx - 0x%llx in DTB\n", SEC_SRAM_BASE,
+	     SEC_SRAM_BASE + SEC_SRAM_SIZE);
+}
+#endif
+
+void bl31_platform_setup(void)
+{
+#ifdef RPI3_PRELOADED_DTB_BASE
+	/* Only modify a DTB if we know where to look for it */
+	rpi3_dtb_add_mem_rsv();
+#endif
+}
diff --git a/plat/rpi/rpi3/rpi3_common.c b/plat/rpi/rpi3/rpi3_common.c
new file mode 100644
index 0000000..9b10974
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_common.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <bl31/interrupt_mgmt.h>
+#include <drivers/console.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include "rpi3_hw.h"
+#include "rpi3_private.h"
+
+#define MAP_DEVICE0	MAP_REGION_FLAT(DEVICE0_BASE,			\
+					DEVICE0_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#define MAP_SHARED_RAM	MAP_REGION_FLAT(SHARED_RAM_BASE,		\
+					SHARED_RAM_SIZE,		\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+#ifdef RPI3_PRELOADED_DTB_BASE
+#define MAP_NS_DTB	MAP_REGION_FLAT(RPI3_PRELOADED_DTB_BASE, 0x10000, \
+					MT_MEMORY | MT_RW | MT_NS)
+#endif
+
+#define MAP_NS_DRAM0	MAP_REGION_FLAT(NS_DRAM0_BASE, NS_DRAM0_SIZE,	\
+					MT_MEMORY | MT_RW | MT_NS)
+
+#define MAP_FIP		MAP_REGION_FLAT(PLAT_RPI3_FIP_BASE,		\
+					PLAT_RPI3_FIP_MAX_SIZE,		\
+					MT_MEMORY | MT_RO | MT_NS)
+
+#define MAP_BL32_MEM	MAP_REGION_FLAT(BL32_MEM_BASE, BL32_MEM_SIZE,	\
+					MT_MEMORY | MT_RW | MT_SECURE)
+
+#ifdef SPD_opteed
+#define MAP_OPTEE_PAGEABLE	MAP_REGION_FLAT(		\
+				RPI3_OPTEE_PAGEABLE_LOAD_BASE,	\
+				RPI3_OPTEE_PAGEABLE_LOAD_SIZE,	\
+				MT_MEMORY | MT_RW | MT_SECURE)
+#endif
+
+/*
+ * Table of regions for various BL stages to map using the MMU.
+ */
+#ifdef IMAGE_BL1
+static const mmap_region_t plat_rpi3_mmap[] = {
+	MAP_SHARED_RAM,
+	MAP_DEVICE0,
+	MAP_FIP,
+#ifdef SPD_opteed
+	MAP_OPTEE_PAGEABLE,
+#endif
+	{0}
+};
+#endif
+
+#ifdef IMAGE_BL2
+static const mmap_region_t plat_rpi3_mmap[] = {
+	MAP_SHARED_RAM,
+	MAP_DEVICE0,
+	MAP_FIP,
+	MAP_NS_DRAM0,
+#ifdef BL32_BASE
+	MAP_BL32_MEM,
+#endif
+	{0}
+};
+#endif
+
+#ifdef IMAGE_BL31
+static const mmap_region_t plat_rpi3_mmap[] = {
+	MAP_SHARED_RAM,
+	MAP_DEVICE0,
+#ifdef RPI3_PRELOADED_DTB_BASE
+	MAP_NS_DTB,
+#endif
+#ifdef BL32_BASE
+	MAP_BL32_MEM,
+#endif
+	{0}
+};
+#endif
+
+/*******************************************************************************
+ * Function that sets up the console
+ ******************************************************************************/
+static console_16550_t rpi3_console;
+
+void rpi3_console_init(void)
+{
+	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,
+					PLAT_RPI3_UART_BAUDRATE,
+					&rpi3_console);
+	if (rc == 0) {
+		/*
+		 * The crash console doesn't use the multi console API, it uses
+		 * the core console functions directly. It is safe to call panic
+		 * and let it print debug information.
+		 */
+		panic();
+	}
+
+	console_set_scope(&rpi3_console.console, console_scope);
+}
+
+/*******************************************************************************
+ * Function that sets up the translation tables.
+ ******************************************************************************/
+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
+#if USE_COHERENT_MEM
+			    , uintptr_t coh_start, uintptr_t coh_limit
+#endif
+			    )
+{
+	/*
+	 * Map the Trusted SRAM with appropriate memory attributes.
+	 * Subsequent mappings will adjust the attributes for specific regions.
+	 */
+	VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n",
+		(void *) total_base, (void *) (total_base + total_size));
+	mmap_add_region(total_base, total_base,
+			total_size,
+			MT_MEMORY | MT_RW | MT_SECURE);
+
+	/* Re-map the code section */
+	VERBOSE("Code region: %p - %p\n",
+		(void *) code_start, (void *) code_limit);
+	mmap_add_region(code_start, code_start,
+			code_limit - code_start,
+			MT_CODE | MT_SECURE);
+
+	/* Re-map the read-only data section */
+	VERBOSE("Read-only data region: %p - %p\n",
+		(void *) rodata_start, (void *) rodata_limit);
+	mmap_add_region(rodata_start, rodata_start,
+			rodata_limit - rodata_start,
+			MT_RO_DATA | MT_SECURE);
+
+#if USE_COHERENT_MEM
+	/* Re-map the coherent memory region */
+	VERBOSE("Coherent region: %p - %p\n",
+		(void *) coh_start, (void *) coh_limit);
+	mmap_add_region(coh_start, coh_start,
+			coh_limit - coh_start,
+			MT_DEVICE | MT_RW | MT_SECURE);
+#endif
+
+	mmap_add(plat_rpi3_mmap);
+
+	init_xlat_tables();
+}
+
+/*******************************************************************************
+ * 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)
+{
+	/*
+	 * The Secure Payload Dispatcher service is responsible for
+	 * setting the SPSR prior to entry into the BL32 image.
+	 */
+	return 0;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+uint32_t rpi3_get_spsr_for_bl33_entry(void)
+{
+#if RPI3_BL33_IN_AARCH32
+	INFO("BL33 will boot in Non-secure AArch32 Hypervisor mode\n");
+	return SPSR_MODE32(MODE32_hyp, SPSR_T_ARM, SPSR_E_LITTLE,
+			   DISABLE_ALL_EXCEPTIONS);
+#else
+	return SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+#endif
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
+
+uint32_t plat_ic_get_pending_interrupt_type(void)
+{
+	ERROR("rpi3: Interrupt routed to EL3.\n");
+	return INTR_TYPE_INVAL;
+}
+
+uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state)
+{
+	assert((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_EL3) ||
+	       (type == INTR_TYPE_NS));
+
+	assert(sec_state_is_valid(security_state));
+
+	/* Non-secure interrupts are signalled on the IRQ line always. */
+	if (type == INTR_TYPE_NS)
+		return __builtin_ctz(SCR_IRQ_BIT);
+
+	/* Secure interrupts are signalled on the FIQ line always. */
+	return  __builtin_ctz(SCR_FIQ_BIT);
+}
diff --git a/plat/rpi/rpi3/rpi3_hw.h b/plat/rpi/rpi3/rpi3_hw.h
new file mode 100644
index 0000000..1a86835
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_hw.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI3_HW_H
+#define RPI3_HW_H
+
+#include <lib/utils_def.h>
+
+/*
+ * Peripherals
+ */
+
+#define RPI3_IO_BASE			ULL(0x3F000000)
+#define RPI3_IO_SIZE			ULL(0x01000000)
+
+/*
+ * ARM <-> VideoCore mailboxes
+ */
+#define RPI3_MBOX_OFFSET		ULL(0x0000B880)
+#define RPI3_MBOX_BASE			(RPI3_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			(RPI3_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)
+
+/*
+ * Hardware random number generator.
+ */
+#define RPI3_IO_RNG_OFFSET		ULL(0x00104000)
+#define RPI3_RNG_BASE			(RPI3_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 BCM docucmentation).
+ */
+#define RPI3_IO_MINI_UART_OFFSET	ULL(0x00215040)
+#define RPI3_MINI_UART_BASE		(RPI3_IO_BASE + RPI3_IO_MINI_UART_OFFSET)
+#define RPI3_MINI_UART_CLK_IN_HZ	ULL(500000000)
+
+/*
+ * GPIO controller
+ */
+#define RPI3_IO_GPIO_OFFSET		ULL(0x00200000)
+#define RPI3_GPIO_BASE			(RPI3_IO_BASE + RPI3_IO_GPIO_OFFSET)
+
+/*
+ * SDHost controller
+ */
+#define RPI3_IO_SDHOST_OFFSET           ULL(0x00202000)
+#define RPI3_SDHOST_BASE                (RPI3_IO_BASE + RPI3_IO_SDHOST_OFFSET)
+
+/*
+ * Local interrupt controller
+ */
+#define RPI3_INTC_BASE_ADDRESS			ULL(0x40000000)
+/* Registers on top of RPI3_INTC_BASE_ADDRESS */
+#define RPI3_INTC_CONTROL_OFFSET		ULL(0x00000000)
+#define RPI3_INTC_PRESCALER_OFFSET		ULL(0x00000008)
+#define RPI3_INTC_MBOX_CONTROL_OFFSET		ULL(0x00000050)
+#define RPI3_INTC_MBOX_CONTROL_SLOT3_FIQ	ULL(0x00000080)
+#define RPI3_INTC_PENDING_FIQ_OFFSET		ULL(0x00000070)
+#define RPI3_INTC_PENDING_FIQ_MBOX3		ULL(0x00000080)
+
+#endif /* RPI3_HW_H */
diff --git a/plat/rpi/rpi3/rpi3_image_load.c b/plat/rpi/rpi3/rpi3_image_load.c
new file mode 100644
index 0000000..5394c6f
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_image_load.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/desc_image_load.h>
+#include <plat/common/platform.h>
+
+/*******************************************************************************
+ * This function flushes the data structures so that they are visible
+ * in memory for the next BL image.
+ ******************************************************************************/
+void plat_flush_next_bl_params(void)
+{
+	flush_bl_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of loadable images.
+ ******************************************************************************/
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+/*******************************************************************************
+ * This function returns the list of executable images.
+ ******************************************************************************/
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
diff --git a/plat/rpi/rpi3/rpi3_io_storage.c b/plat/rpi/rpi3/rpi3_io_storage.c
new file mode 100644
index 0000000..49c6a76
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_io_storage.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <tools_share/firmware_image_package.h>
+
+/* Semihosting filenames */
+#define BL2_IMAGE_NAME			"bl2.bin"
+#define BL31_IMAGE_NAME			"bl31.bin"
+#define BL32_IMAGE_NAME			"bl32.bin"
+#define BL33_IMAGE_NAME			"bl33.bin"
+
+#if TRUSTED_BOARD_BOOT
+#define TRUSTED_BOOT_FW_CERT_NAME	"tb_fw.crt"
+#define TRUSTED_KEY_CERT_NAME		"trusted_key.crt"
+#define SOC_FW_KEY_CERT_NAME		"soc_fw_key.crt"
+#define TOS_FW_KEY_CERT_NAME		"tos_fw_key.crt"
+#define NT_FW_KEY_CERT_NAME		"nt_fw_key.crt"
+#define SOC_FW_CONTENT_CERT_NAME	"soc_fw_content.crt"
+#define TOS_FW_CONTENT_CERT_NAME	"tos_fw_content.crt"
+#define NT_FW_CONTENT_CERT_NAME		"nt_fw_content.crt"
+#endif /* TRUSTED_BOARD_BOOT */
+
+/* IO devices */
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+static const io_dev_connector_t *memmap_dev_con;
+static uintptr_t memmap_dev_handle;
+
+static const io_block_spec_t fip_block_spec = {
+	.offset = PLAT_RPI3_FIP_BASE,
+	.length = PLAT_RPI3_FIP_MAX_SIZE
+};
+
+static const io_uuid_spec_t bl2_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t bl31_uuid_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t bl32_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t bl32_extra1_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1,
+};
+
+static const io_uuid_spec_t bl32_extra2_uuid_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2,
+};
+
+static const io_uuid_spec_t bl33_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t tb_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FW_CERT,
+};
+
+static const io_uuid_spec_t trusted_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+static int open_fip(const uintptr_t spec);
+static int open_memmap(const uintptr_t spec);
+
+struct plat_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	int (*check)(const uintptr_t spec);
+};
+
+/* By default, load images from the FIP */
+static const struct plat_io_policy policies[] = {
+	[FIP_IMAGE_ID] = {
+		&memmap_dev_handle,
+		(uintptr_t)&fip_block_spec,
+		open_memmap
+	},
+	[BL2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl2_uuid_spec,
+		open_fip
+	},
+	[BL31_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		open_fip
+	},
+	[BL32_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_uuid_spec,
+		open_fip
+	},
+	[BL32_EXTRA1_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra1_uuid_spec,
+		open_fip
+	},
+	[BL32_EXTRA2_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl32_extra2_uuid_spec,
+		open_fip
+	},
+	[BL33_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&bl33_uuid_spec,
+		open_fip
+	},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_BOOT_FW_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tb_fw_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&trusted_key_cert_uuid_spec,
+		open_fip
+	},
+	[SOC_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_key_cert_uuid_spec,
+		open_fip
+	},
+	[SOC_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_cert_uuid_spec,
+		open_fip
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_cert_uuid_spec,
+		open_fip
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_cert_uuid_spec,
+		open_fip
+	},
+#endif /* TRUSTED_BOARD_BOOT */
+};
+
+static int open_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if a Firmware Image Package is available */
+	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(fip_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using FIP\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+static int open_memmap(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(memmap_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using Memmap\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+
+void plat_rpi3_io_setup(void)
+{
+	int io_result;
+
+	io_result = register_io_dev_fip(&fip_dev_con);
+	assert(io_result == 0);
+
+	io_result = register_io_dev_memmap(&memmap_dev_con);
+	assert(io_result == 0);
+
+	/* Open connections to devices and cache the handles */
+	io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+				&fip_dev_handle);
+	assert(io_result == 0);
+
+	io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL,
+				&memmap_dev_handle);
+	assert(io_result == 0);
+
+	/* Ignore improbable errors in release builds */
+	(void)io_result;
+}
+
+/*
+ * Return an IO device handle and specification which can be used to access
+ * an image. Use this to enforce platform load policy
+ */
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	int result;
+	const struct plat_io_policy *policy;
+
+	assert(image_id < ARRAY_SIZE(policies));
+
+	policy = &policies[image_id];
+	result = policy->check(policy->image_spec);
+	if (result == 0) {
+		*image_spec = policy->image_spec;
+		*dev_handle = *(policy->dev_handle);
+	}
+
+	return result;
+}
diff --git a/plat/rpi/rpi3/rpi3_mbox.c b/plat/rpi/rpi3/rpi3_mbox.c
new file mode 100644
index 0000000..2db605e
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_mbox.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+
+#include "rpi3_hw.h"
+
+/* This struct must be aligned to 16 bytes */
+typedef struct __packed __aligned(16) rpi3_mbox_request {
+	uint32_t	size; /* Buffer size in bytes */
+	uint32_t	code; /* Request/response code */
+	uint32_t	tags[0];
+} rpi3_mbox_request_t;
+
+#define RPI3_MBOX_BUFFER_SIZE		U(256)
+static uint8_t __aligned(16) rpi3_mbox_buffer[RPI3_MBOX_BUFFER_SIZE];
+
+/* Constants to perform a request/check the status of a request. */
+#define RPI3_MBOX_PROCESS_REQUEST	U(0x00000000)
+#define RPI3_MBOX_REQUEST_SUCCESSFUL	U(0x80000000)
+#define RPI3_MBOX_REQUEST_ERROR		U(0x80000001)
+
+/* Command constants */
+#define RPI3_TAG_HARDWARE_GET_BOARD_REVISION	U(0x00010002)
+#define RPI3_TAG_END				U(0x00000000)
+
+#define RPI3_TAG_REQUEST		U(0x00000000)
+#define RPI3_TAG_IS_RESPONSE		U(0x80000000) /* Set if response */
+#define RPI3_TAG_RESPONSE_LENGTH_MASK	U(0x7FFFFFFF)
+
+#define RPI3_CHANNEL_ARM_TO_VC		U(0x8)
+#define RPI3_CHANNEL_MASK		U(0xF)
+
+#define RPI3_MAILBOX_MAX_RETRIES	U(1000000)
+
+/*******************************************************************************
+ * Helpers to send requests to the VideoCore using the mailboxes.
+ ******************************************************************************/
+static void rpi3_vc_mailbox_request_send(void)
+{
+	uint32_t st, data;
+	uintptr_t resp_addr, addr;
+	unsigned int retries;
+
+	/* This is the location of the request buffer */
+	addr = (uintptr_t) &rpi3_mbox_buffer;
+
+	/* Make sure that the changes are seen by the VideoCore */
+	flush_dcache_range(addr, RPI3_MBOX_BUFFER_SIZE);
+
+	/* Wait until the outbound mailbox is empty */
+	retries = 0U;
+
+	do {
+		st = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX1_STATUS_OFFSET);
+
+		retries++;
+		if (retries == RPI3_MAILBOX_MAX_RETRIES) {
+			ERROR("rpi3: mbox: Send request timeout\n");
+			return;
+		}
+
+	} while ((st & RPI3_MBOX_STATUS_EMPTY_MASK) == 0U);
+
+	/* Send base address of this message to start request */
+	mmio_write_32(RPI3_MBOX_BASE + RPI3_MBOX1_WRITE_OFFSET,
+		      RPI3_CHANNEL_ARM_TO_VC | (uint32_t) addr);
+
+	/* Wait until the inbound mailbox isn't empty */
+	retries = 0U;
+
+	do {
+		st = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX0_STATUS_OFFSET);
+
+		retries++;
+		if (retries == RPI3_MAILBOX_MAX_RETRIES) {
+			ERROR("rpi3: mbox: Receive response timeout\n");
+			return;
+		}
+
+	} while ((st & RPI3_MBOX_STATUS_EMPTY_MASK) != 0U);
+
+	/* Get location and channel */
+	data = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX0_READ_OFFSET);
+
+	if ((data & RPI3_CHANNEL_MASK) != RPI3_CHANNEL_ARM_TO_VC) {
+		ERROR("rpi3: mbox: Wrong channel: 0x%08x\n", data);
+		panic();
+	}
+
+	resp_addr = (uintptr_t)(data & ~RPI3_CHANNEL_MASK);
+	if (addr != resp_addr) {
+		ERROR("rpi3: mbox: Unexpected address: 0x%08x\n", data);
+		panic();
+	}
+
+	/* Make sure that the data seen by the CPU is up to date */
+	inv_dcache_range(addr, RPI3_MBOX_BUFFER_SIZE);
+}
+
+/*******************************************************************************
+ * Request board revision. Returns the revision and 0 on success, -1 on error.
+ ******************************************************************************/
+int rpi3_vc_hardware_get_board_revision(uint32_t *revision)
+{
+	uint32_t tag_request_size = sizeof(uint32_t);
+	rpi3_mbox_request_t *req = (rpi3_mbox_request_t *) rpi3_mbox_buffer;
+
+	assert(revision != NULL);
+
+	VERBOSE("rpi3: mbox: Sending request at %p\n", (void *)req);
+
+	req->size = sizeof(rpi3_mbox_buffer);
+	req->code = RPI3_MBOX_PROCESS_REQUEST;
+
+	req->tags[0] = RPI3_TAG_HARDWARE_GET_BOARD_REVISION;
+	req->tags[1] = tag_request_size; /* Space available for the response */
+	req->tags[2] = RPI3_TAG_REQUEST;
+	req->tags[3] = 0; /* Placeholder for the response */
+
+	req->tags[4] = RPI3_TAG_END;
+
+	rpi3_vc_mailbox_request_send();
+
+	if (req->code != RPI3_MBOX_REQUEST_SUCCESSFUL) {
+		ERROR("rpi3: mbox: Code = 0x%08x\n", req->code);
+		return -1;
+	}
+
+	if (req->tags[2] != (RPI3_TAG_IS_RESPONSE | tag_request_size)) {
+		ERROR("rpi3: mbox: get board revision failed (0x%08x)\n",
+		      req->tags[2]);
+		return -1;
+	}
+
+	*revision = req->tags[3];
+
+	return 0;
+}
diff --git a/plat/rpi/rpi3/rpi3_pm.c b/plat/rpi/rpi3/rpi3_pm.c
new file mode 100644
index 0000000..4f586b5
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_pm.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+#include "rpi3_hw.h"
+
+/* Make composite power state parameter till power level 0 */
+#if PSCI_EXTENDED_STATE_ID
+
+#define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
+		(((lvl0_state) << PSTATE_ID_SHIFT) | \
+		 ((type) << PSTATE_TYPE_SHIFT))
+
+#else
+
+#define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \
+		(((lvl0_state) << PSTATE_ID_SHIFT) | \
+		 ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \
+		 ((type) << PSTATE_TYPE_SHIFT))
+
+#endif /* PSCI_EXTENDED_STATE_ID */
+
+#define rpi3_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \
+		(((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \
+		 rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type))
+
+/*
+ *  The table storing the valid idle power states. Ensure that the
+ *  array entries are populated in ascending order of state-id to
+ *  enable us to use binary search during power state validation.
+ *  The table must be terminated by a NULL entry.
+ */
+static const unsigned int rpi3_pm_idle_states[] = {
+	/* State-id - 0x01 */
+	rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET,
+				MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY),
+	/* State-id - 0x02 */
+	rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF,
+				MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN),
+	/* State-id - 0x22 */
+	rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_OFF, PLAT_LOCAL_STATE_OFF,
+				MPIDR_AFFLVL1, PSTATE_TYPE_POWERDOWN),
+	0,
+};
+
+/*******************************************************************************
+ * Platform handler called to check the validity of the power state
+ * parameter. The power state parameter has to be a composite power state.
+ ******************************************************************************/
+static int rpi3_validate_power_state(unsigned int power_state,
+				     psci_power_state_t *req_state)
+{
+	unsigned int state_id;
+	int i;
+
+	assert(req_state != 0);
+
+	/*
+	 *  Currently we are using a linear search for finding the matching
+	 *  entry in the idle power state array. This can be made a binary
+	 *  search if the number of entries justify the additional complexity.
+	 */
+	for (i = 0; rpi3_pm_idle_states[i] != 0; i++) {
+		if (power_state == rpi3_pm_idle_states[i]) {
+			break;
+		}
+	}
+
+	/* Return error if entry not found in the idle state array */
+	if (!rpi3_pm_idle_states[i]) {
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	i = 0;
+	state_id = psci_get_pstate_id(power_state);
+
+	/* Parse the State ID and populate the state info parameter */
+	while (state_id) {
+		req_state->pwr_domain_state[i++] = state_id &
+						PLAT_LOCAL_PSTATE_MASK;
+		state_id >>= PLAT_LOCAL_PSTATE_WIDTH;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+/*******************************************************************************
+ * Platform handler called when a CPU is about to enter standby.
+ ******************************************************************************/
+static void rpi3_cpu_standby(plat_local_state_t cpu_state)
+{
+	assert(cpu_state == PLAT_LOCAL_STATE_RET);
+
+	/*
+	 * Enter standby state.
+	 * dsb is good practice before using wfi to enter low power states
+	 */
+	dsb();
+	wfi();
+}
+
+/*******************************************************************************
+ * Platform handler called when a power domain is about to be turned on. The
+ * mpidr determines the CPU to be turned on.
+ ******************************************************************************/
+static int rpi3_pwr_domain_on(u_register_t mpidr)
+{
+	int rc = PSCI_E_SUCCESS;
+	unsigned int pos = plat_core_pos_by_mpidr(mpidr);
+	uint64_t *hold_base = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE;
+
+	assert(pos < PLATFORM_CORE_COUNT);
+
+	hold_base[pos] = PLAT_RPI3_TM_HOLD_STATE_GO;
+
+	/* Make sure that the write has completed */
+	dsb();
+	isb();
+
+	sev();
+
+	return rc;
+}
+
+/*******************************************************************************
+ * 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.
+ ******************************************************************************/
+static void rpi3_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
+					PLAT_LOCAL_STATE_OFF);
+}
+
+/*******************************************************************************
+ * Platform handlers for system reset and system off.
+ ******************************************************************************/
+
+/* 10 ticks (Watchdog timer = Timer clock / 16) */
+#define RESET_TIMEOUT	U(10)
+
+static void __dead2 rpi3_watchdog_reset(void)
+{
+	uint32_t rstc;
+
+	console_flush();
+
+	dsbsy();
+	isb();
+
+	mmio_write_32(RPI3_PM_BASE + RPI3_PM_WDOG_OFFSET,
+		      RPI3_PM_PASSWORD | RESET_TIMEOUT);
+
+	rstc = mmio_read_32(RPI3_PM_BASE + RPI3_PM_RSTC_OFFSET);
+	rstc &= ~RPI3_PM_RSTC_WRCFG_MASK;
+	rstc |= RPI3_PM_PASSWORD | RPI3_PM_RSTC_WRCFG_FULL_RESET;
+	mmio_write_32(RPI3_PM_BASE + RPI3_PM_RSTC_OFFSET, rstc);
+
+	for (;;) {
+		wfi();
+	}
+}
+
+static void __dead2 rpi3_system_reset(void)
+{
+	INFO("rpi3: PSCI_SYSTEM_RESET: Invoking watchdog reset\n");
+
+	rpi3_watchdog_reset();
+}
+
+static void __dead2 rpi3_system_off(void)
+{
+	uint32_t rsts;
+
+	INFO("rpi3: PSCI_SYSTEM_OFF: Invoking watchdog reset\n");
+
+	/*
+	 * This function doesn't actually make the Raspberry Pi turn itself off,
+	 * the hardware doesn't allow it. It simply reboots it and the RSTS
+	 * value tells the bootcode.bin firmware not to continue the regular
+	 * bootflow and to stay in a low power mode.
+	 */
+
+	rsts = mmio_read_32(RPI3_PM_BASE + RPI3_PM_RSTS_OFFSET);
+	rsts |= RPI3_PM_PASSWORD | RPI3_PM_RSTS_WRCFG_HALT;
+	mmio_write_32(RPI3_PM_BASE + RPI3_PM_RSTS_OFFSET, rsts);
+
+	rpi3_watchdog_reset();
+}
+
+/*******************************************************************************
+ * Platform handlers and setup function.
+ ******************************************************************************/
+static const plat_psci_ops_t plat_rpi3_psci_pm_ops = {
+	.cpu_standby = rpi3_cpu_standby,
+	.pwr_domain_on = rpi3_pwr_domain_on,
+	.pwr_domain_on_finish = rpi3_pwr_domain_on_finish,
+	.system_off = rpi3_system_off,
+	.system_reset = rpi3_system_reset,
+	.validate_power_state = rpi3_validate_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	uintptr_t *entrypoint = (void *) PLAT_RPI3_TM_ENTRYPOINT;
+
+	*entrypoint = sec_entrypoint;
+	*psci_ops = &plat_rpi3_psci_pm_ops;
+
+	return 0;
+}
diff --git a/plat/rpi/rpi3/rpi3_private.h b/plat/rpi/rpi3/rpi3_private.h
new file mode 100644
index 0000000..53078f8
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_private.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI3_PRIVATE_H
+#define RPI3_PRIVATE_H
+
+#include <stdint.h>
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+
+/* Utility functions */
+void rpi3_console_init(void);
+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
+#if USE_COHERENT_MEM
+			    , uintptr_t coh_start, uintptr_t coh_limit
+#endif
+			    );
+
+/* Optional functions required in the Raspberry Pi 3 port */
+unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr);
+
+/* BL2 utility functions */
+uint32_t rpi3_get_spsr_for_bl32_entry(void);
+uint32_t rpi3_get_spsr_for_bl33_entry(void);
+
+/* IO storage utility functions */
+void plat_rpi3_io_setup(void);
+
+/* Hardware RNG functions */
+void rpi3_rng_read(void *buf, size_t len);
+
+/* VideoCore firmware commands */
+int rpi3_vc_hardware_get_board_revision(uint32_t *revision);
+
+#endif /* RPI3_PRIVATE_H */
diff --git a/plat/rpi/rpi3/rpi3_rng.c b/plat/rpi/rpi3/rpi3_rng.c
new file mode 100644
index 0000000..fd69adb
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_rng.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <lib/mmio.h>
+
+#include "rpi3_hw.h"
+
+/* Initial amount of values to discard */
+#define RNG_WARMUP_COUNT	U(0x40000)
+
+static void rpi3_rng_initialize(void)
+{
+	uint32_t int_mask, ctrl;
+
+	/* Return if it is already enabled */
+	ctrl = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET);
+	if ((ctrl & RPI3_RNG_CTRL_ENABLE) != 0U) {
+		return;
+	}
+
+	/* Mask interrupts */
+	int_mask = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET);
+	int_mask |= RPI3_RNG_INT_MASK_DISABLE;
+	mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET, int_mask);
+
+	/* Discard several values when initializing to give it time to warmup */
+	mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET, RNG_WARMUP_COUNT);
+
+	mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET,
+		      RPI3_RNG_CTRL_ENABLE);
+}
+
+static uint32_t rpi3_rng_get_word(void)
+{
+	size_t nwords;
+
+	do {
+		/* Get number of available words to read */
+		nwords = (mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET)
+				       >> RPI3_RNG_STATUS_NUM_WORDS_SHIFT)
+				       & RPI3_RNG_STATUS_NUM_WORDS_MASK;
+	} while (nwords == 0U);
+
+	return mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_DATA_OFFSET);
+}
+
+void rpi3_rng_read(void *buf, size_t len)
+{
+	uint32_t data;
+	size_t left = len;
+	uint32_t *dst = buf;
+
+	assert(buf != NULL);
+	assert(len != 0U);
+	assert(check_uptr_overflow((uintptr_t) buf, (uintptr_t) len) == 0);
+
+	rpi3_rng_initialize();
+
+	while (left >= sizeof(uint32_t)) {
+		data = rpi3_rng_get_word();
+		*dst++ = data;
+		left -= sizeof(uint32_t);
+	}
+
+	if (left > 0U) {
+		data = rpi3_rng_get_word();
+		memcpy(dst, &data, left);
+	}
+}
diff --git a/plat/rpi/rpi3/rpi3_rotpk.S b/plat/rpi/rpi3/rpi3_rotpk.S
new file mode 100644
index 0000000..1c17b21
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_rotpk.S
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+	.global rpi3_rotpk_hash
+	.global rpi3_rotpk_hash_end
+rpi3_rotpk_hash:
+	/* DER header */
+	.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+	.byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+	/* SHA256 */
+	.incbin ROTPK_HASH
+rpi3_rotpk_hash_end:
diff --git a/plat/rpi/rpi3/rpi3_stack_protector.c b/plat/rpi/rpi3/rpi3_stack_protector.c
new file mode 100644
index 0000000..6f49f61
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_stack_protector.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <lib/utils.h>
+#include <lib/utils_def.h>
+
+#include "rpi3_private.h"
+
+/* Get 128 bits of entropy and fuse the values together to form the canary. */
+#define TRNG_NBYTES	16U
+
+u_register_t plat_get_stack_protector_canary(void)
+{
+	size_t i;
+	u_register_t buf[TRNG_NBYTES / sizeof(u_register_t)];
+	u_register_t ret = 0U;
+
+	rpi3_rng_read(buf, sizeof(buf));
+
+	for (i = 0U; i < ARRAY_SIZE(buf); i++)
+		ret ^= buf[i];
+
+	return ret;
+}
diff --git a/plat/rpi/rpi3/rpi3_topology.c b/plat/rpi/rpi3/rpi3_topology.c
new file mode 100644
index 0000000..200d41d
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_topology.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+
+#include "rpi3_private.h"
+
+/* The power domain tree descriptor */
+static unsigned char power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+/*******************************************************************************
+ * This function returns the ARM default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) {
+		return -1;
+	}
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT) {
+		return -1;
+	}
+
+	if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) {
+		return -1;
+	}
+
+	return plat_rpi3_calc_core_pos(mpidr);
+}
diff --git a/plat/rpi/rpi3/rpi3_trusted_boot.c b/plat/rpi/rpi3/rpi3_trusted_boot.c
new file mode 100644
index 0000000..f6c669f
--- /dev/null
+++ b/plat/rpi/rpi3/rpi3_trusted_boot.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+extern char rpi3_rotpk_hash[], rpi3_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+			unsigned int *flags)
+{
+	*key_ptr = rpi3_rotpk_hash;
+	*key_len = rpi3_rotpk_hash_end - rpi3_rotpk_hash;
+	*flags = ROTPK_IS_HASH;
+
+	return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+	*nv_ctr = 0;
+
+	return 0;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+	return 1;
+}
+
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+	return get_mbedtls_heap_helper(heap_addr, heap_size);
+}