uniphier: support Socionext UniPhier platform

Initial commit for Socionext UniPhier SoC support.  BL1, Bl2, and
BL31 are supported.  Refer to docs/plat/socionext-uniphier.md for
more detais.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
diff --git a/plat/socionext/uniphier/include/plat_macros.S b/plat/socionext/uniphier/include/plat_macros.S
new file mode 100644
index 0000000..6de4dde
--- /dev/null
+++ b/plat/socionext/uniphier/include/plat_macros.S
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_MACROS_S__
+#define __PLAT_MACROS_S__
+
+	.macro plat_crash_print_regs
+	.endm
+
+#endif /* __PLAT_MACROS_S__ */
diff --git a/plat/socionext/uniphier/include/platform_def.h b/plat/socionext/uniphier/include/platform_def.h
new file mode 100644
index 0000000..7e603a3
--- /dev/null
+++ b/plat/socionext/uniphier/include/platform_def.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLATFORM_DEF_H__
+#define __PLATFORM_DEF_H__
+
+#include <common_def.h>
+#include <tbbr/tbbr_img_def.h>
+
+#define PLATFORM_STACK_SIZE		0x1000
+
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(1 << (CACHE_WRITEBACK_SHIFT))
+
+/* topology */
+#define UNIPHIER_MAX_CPUS_PER_CLUSTER	4
+#define UNIPHIER_CLUSTER_COUNT		2
+
+#define PLATFORM_CORE_COUNT		\
+	((UNIPHIER_MAX_CPUS_PER_CLUSTER) * (UNIPHIER_CLUSTER_COUNT))
+
+#define PLAT_MAX_PWR_LVL		1
+
+#define PLAT_MAX_OFF_STATE		2
+#define PLAT_MAX_RET_STATE		1
+
+#define UNIPHIER_SEC_DRAM_BASE		0x81000000
+#define UNIPHIER_SEC_DRAM_LIMIT		0x82000000
+#define UNIPHIER_SEC_DRAM_SIZE		((UNIPHIER_SEC_DRAM_LIMIT) - \
+					 (UNIPHIER_SEC_DRAM_BASE))
+
+#define BL1_RO_BASE			0x80000000
+#define BL1_RO_LIMIT			0x80018000
+#define BL1_RW_LIMIT			(UNIPHIER_SEC_DRAM_LIMIT)
+#define BL1_RW_BASE			((BL1_RW_LIMIT) - 0x00040000)
+
+#define BL2_LIMIT			(BL1_RW_BASE)
+#define BL2_BASE			((BL2_LIMIT) - 0x00040000)
+
+#define BL31_BASE			(UNIPHIER_SEC_DRAM_BASE)
+#define BL31_LIMIT			((BL31_BASE) + 0x00080000)
+
+#define BL32_BASE			(BL31_LIMIT)
+#define BL32_LIMIT			(UNIPHIER_SEC_DRAM_LIMIT)
+
+#define UNIPHIER_BLOCK_BUF_SIZE		0x00400000
+#define UNIPHIER_BLOCK_BUF_BASE		((BL2_LIMIT) - \
+					 (UNIPHIER_BLOCK_BUF_SIZE))
+
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+
+#define PLAT_XLAT_TABLES_DYNAMIC	1
+#define MAX_XLAT_TABLES			7
+#define MAX_MMAP_REGIONS		6
+
+#define MAX_IO_HANDLES			2
+#define MAX_IO_DEVICES			2
+#define MAX_IO_BLOCK_DEVICES		1
+
+#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/socionext/uniphier/platform.mk b/plat/socionext/uniphier/platform.mk
new file mode 100644
index 0000000..af8e3ac
--- /dev/null
+++ b/plat/socionext/uniphier/platform.mk
@@ -0,0 +1,100 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+override COLD_BOOT_SINGLE_CPU	:= 1
+override ENABLE_PLAT_COMPAT	:= 0
+override ERROR_DEPRECATED	:= 1
+override LOAD_IMAGE_V2		:= 1
+override USE_COHERENT_MEM	:= 1
+override USE_TBBR_DEFS		:= 1
+
+# Cortex-A53 revision r0p4-51rel0
+# needed for LD20, unneeded for LD11, PXs3 (no ACE)
+ERRATA_A53_855873		:= 1
+
+FIP_ALIGN			:= 512
+
+ifeq ($(NEED_BL32),yes)
+$(eval $(call add_define,UNIPHIER_LOAD_BL32))
+endif
+
+PLAT_PATH		:=	plat/socionext/uniphier
+PLAT_INCLUDES		:=	-I$(PLAT_PATH)/include
+
+# IO sources for BL1, BL2
+IO_SOURCES		:=	drivers/io/io_block.c			\
+				drivers/io/io_fip.c			\
+				drivers/io/io_memmap.c			\
+				drivers/io/io_storage.c			\
+				$(PLAT_PATH)/uniphier_boot_device.c	\
+				$(PLAT_PATH)/uniphier_emmc.c		\
+				$(PLAT_PATH)/uniphier_io_storage.c	\
+				$(PLAT_PATH)/uniphier_nand.c		\
+				$(PLAT_PATH)/uniphier_usb.c
+
+# common sources for BL1, BL2, BL31
+PLAT_BL_COMMON_SOURCES	+=	drivers/console/aarch64/console.S	\
+				lib/xlat_tables_v2/aarch64/xlat_tables_arch.c \
+				lib/xlat_tables_v2/xlat_tables_common.c	\
+				lib/xlat_tables_v2/xlat_tables_internal.c \
+				$(PLAT_PATH)/uniphier_console.S		\
+				$(PLAT_PATH)/uniphier_helpers.S		\
+				$(PLAT_PATH)/uniphier_soc_info.c	\
+				$(PLAT_PATH)/uniphier_xlat_setup.c
+
+BL1_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
+				lib/cpus/aarch64/cortex_a72.S		\
+				$(PLAT_PATH)/uniphier_bl1_helpers.S	\
+				$(PLAT_PATH)/uniphier_bl1_setup.c	\
+				$(IO_SOURCES)
+
+BL2_SOURCES		+=	common/desc_image_load.c		\
+				$(PLAT_PATH)/uniphier_bl2_setup.c	\
+				$(PLAT_PATH)/uniphier_image_desc.c	\
+				$(PLAT_PATH)/uniphier_scp.c		\
+				$(IO_SOURCES)
+
+BL31_SOURCES		+=	drivers/arm/cci/cci.c			\
+				drivers/arm/gic/common/gic_common.c	\
+				drivers/arm/gic/v3/gicv3_helpers.c	\
+				drivers/arm/gic/v3/gicv3_main.c		\
+				lib/cpus/aarch64/cortex_a53.S		\
+				lib/cpus/aarch64/cortex_a72.S		\
+				plat/common/plat_gicv3.c		\
+				plat/common/plat_psci_common.c		\
+				$(PLAT_PATH)/uniphier_bl31_setup.c	\
+				$(PLAT_PATH)/uniphier_cci.c		\
+				$(PLAT_PATH)/uniphier_gicv3.c		\
+				$(PLAT_PATH)/uniphier_psci.c		\
+				$(PLAT_PATH)/uniphier_scp.c		\
+				$(PLAT_PATH)/uniphier_smp.S		\
+				$(PLAT_PATH)/uniphier_syscnt.c		\
+				$(PLAT_PATH)/uniphier_topology.c
+
+ifeq (${TRUSTED_BOARD_BOOT},1)
+
+include drivers/auth/mbedtls/mbedtls_crypto.mk
+include drivers/auth/mbedtls/mbedtls_x509.mk
+
+PLAT_INCLUDES		+=	-Iinclude/common/tbbr
+
+TBB_SOURCES		:=	drivers/auth/auth_mod.c			\
+				drivers/auth/crypto_mod.c		\
+				drivers/auth/img_parser_mod.c		\
+				drivers/auth/tbbr/tbbr_cot.c		\
+				plat/common/tbbr/plat_tbbr.c		\
+				$(PLAT_PATH)/uniphier_tbbr.c
+
+BL1_SOURCES		+=	$(TBB_SOURCES)
+BL2_SOURCES		+=	$(TBB_SOURCES)
+
+endif
+
+.PHONY: bl1_gzip
+bl1_gzip: $(BUILD_PLAT)/bl1.bin.gzip
+%.gzip: %
+	@echo " GZIP     $@"
+	$(Q)(cat $< | gzip -n -f -9 > $@) || (rm -f $@ || false)
diff --git a/plat/socionext/uniphier/uniphier.h b/plat/socionext/uniphier/uniphier.h
new file mode 100644
index 0000000..95b29b8
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __UNIPHIER_H__
+#define __UNIPHIER_H__
+
+#include <stdint.h>
+#include <types.h>
+
+unsigned int uniphier_get_soc_type(void);
+unsigned int uniphier_get_soc_model(void);
+unsigned int uniphier_get_soc_revision(void);
+unsigned int uniphier_get_soc_id(void);
+
+#define UNIPHIER_SOC_LD11		0
+#define UNIPHIER_SOC_LD20		1
+#define UNIPHIER_SOC_PXS3		2
+#define UNIPHIER_SOC_UNKNOWN		0xffffffff
+
+unsigned int uniphier_get_boot_device(unsigned int soc);
+
+#define UNIPHIER_BOOT_DEVICE_EMMC	0
+#define UNIPHIER_BOOT_DEVICE_NAND	1
+#define UNIPHIER_BOOT_DEVICE_NOR	2
+#define UNIPHIER_BOOT_DEVICE_USB	3
+#define UNIPHIER_BOOT_DEVICE_RSV	0xffffffff
+
+unsigned int uniphier_get_boot_master(unsigned int soc);
+
+#define UNIPHIER_BOOT_MASTER_THIS	0
+#define UNIPHIER_BOOT_MASTER_SCP	1
+#define UNIPHIER_BOOT_MASTER_EXT	2
+
+void uniphier_console_setup(void);
+
+int uniphier_emmc_init(uintptr_t *block_dev_spec);
+int uniphier_nand_init(uintptr_t *block_dev_spec);
+int uniphier_usb_init(unsigned int soc, uintptr_t *block_dev_spec);
+
+int uniphier_io_setup(unsigned int soc);
+int uniphier_check_image(unsigned int image_id);
+void uniphier_image_descs_fixup(void);
+
+int uniphier_scp_is_running(void);
+void uniphier_scp_start(void);
+void uniphier_scp_open_com(void);
+void uniphier_scp_system_off(void);
+void uniphier_scp_system_reset(void);
+
+struct mmap_region;
+void uniphier_mmap_setup(uintptr_t total_base, size_t total_size,
+			 const struct mmap_region *mmap);
+
+void uniphier_cci_init(unsigned int soc);
+void uniphier_cci_enable(void);
+void uniphier_cci_disable(void);
+
+void uniphier_gic_driver_init(unsigned int soc);
+void uniphier_gic_init(void);
+void uniphier_gic_cpuif_enable(void);
+void uniphier_gic_cpuif_disable(void);
+void uniphier_gic_pcpu_init(void);
+
+unsigned int uniphier_calc_core_pos(u_register_t mpidr);
+
+#define UNIPHIER_NS_DRAM_BASE		0x84000000
+#define UNIPHIER_NS_DRAM_SIZE		0x01000000
+
+#define UNIPHIER_BL33_BASE		(UNIPHIER_NS_DRAM_BASE)
+#define UNIPHIER_BL33_MAX_SIZE		0x00100000
+
+#define UNIPHIER_SCP_BASE		((UNIPHIER_BL33_BASE) + \
+					 (UNIPHIER_BL33_MAX_SIZE))
+#define UNIPHIER_SCP_MAX_SIZE		0x00020000
+
+#endif /* __UNIPHIER_H__ */
diff --git a/plat/socionext/uniphier/uniphier_bl1_helpers.S b/plat/socionext/uniphier/uniphier_bl1_helpers.S
new file mode 100644
index 0000000..5818565
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_bl1_helpers.S
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+	.globl	plat_get_my_entrypoint
+
+func plat_get_my_entrypoint
+	mov	x0, #0
+	ret
+endfunc plat_get_my_entrypoint
diff --git a/plat/socionext/uniphier/uniphier_bl1_setup.c b/plat/socionext/uniphier/uniphier_bl1_setup.c
new file mode 100644
index 0000000..da7740a
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_bl1_setup.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <bl_common.h>
+#include <console.h>
+#include <debug.h>
+#include <errno.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <xlat_mmu_helpers.h>
+
+#include "uniphier.h"
+
+void bl1_early_platform_setup(void)
+{
+	uniphier_console_setup();
+}
+
+void bl1_plat_arch_setup(void)
+{
+	uniphier_mmap_setup(UNIPHIER_SEC_DRAM_BASE, UNIPHIER_SEC_DRAM_SIZE,
+			    NULL);
+	enable_mmu_el3(0);
+}
+
+void bl1_platform_setup(void)
+{
+	unsigned int soc;
+	int ret;
+
+	soc = uniphier_get_soc_id();
+	if (soc == UNIPHIER_SOC_UNKNOWN) {
+		ERROR("unsupported SoC\n");
+		plat_error_handler(-ENOTSUP);
+	}
+
+	ret = uniphier_io_setup(soc);
+	if (ret) {
+		ERROR("failed to setup io devices\n");
+		plat_error_handler(ret);
+	}
+}
+
+static meminfo_t uniphier_tzram_layout = {
+	.total_base = UNIPHIER_SEC_DRAM_BASE,
+	.total_size = UNIPHIER_SEC_DRAM_SIZE,
+};
+
+meminfo_t *bl1_plat_sec_mem_layout(void)
+{
+	return &uniphier_tzram_layout;
+}
diff --git a/plat/socionext/uniphier/uniphier_bl2_setup.c b/plat/socionext/uniphier/uniphier_bl2_setup.c
new file mode 100644
index 0000000..b83e700
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_bl2_setup.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <bl_common.h>
+#include <debug.h>
+#include <desc_image_load.h>
+#include <errno.h>
+#include <io/io_storage.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <xlat_tables_v2.h>
+
+#include "uniphier.h"
+
+static meminfo_t uniphier_bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
+static int uniphier_bl2_kick_scp;
+
+void bl2_early_platform_setup(meminfo_t *mem_layout)
+{
+	uniphier_bl2_tzram_layout = *mem_layout;
+
+	uniphier_console_setup();
+}
+
+static const struct mmap_region uniphier_bl2_mmap[] = {
+	/* for SCP, BL33 */
+	MAP_REGION_FLAT(UNIPHIER_NS_DRAM_BASE, UNIPHIER_NS_DRAM_SIZE,
+			MT_MEMORY | MT_RW | MT_NS),
+	{ .size = 0 },
+};
+
+void bl2_plat_arch_setup(void)
+{
+	unsigned int soc;
+	int skip_scp = 0;
+	int ret;
+
+	uniphier_mmap_setup(UNIPHIER_SEC_DRAM_BASE, UNIPHIER_SEC_DRAM_SIZE,
+			    uniphier_bl2_mmap);
+	enable_mmu_el1(0);
+
+	soc = uniphier_get_soc_id();
+	if (soc == UNIPHIER_SOC_UNKNOWN) {
+		ERROR("unsupported SoC\n");
+		plat_error_handler(-ENOTSUP);
+	}
+
+	ret = uniphier_io_setup(soc);
+	if (ret) {
+		ERROR("failed to setup io devices\n");
+		plat_error_handler(ret);
+	}
+
+	switch (uniphier_get_boot_master(soc)) {
+	case UNIPHIER_BOOT_MASTER_THIS:
+		INFO("Booting from this SoC\n");
+		skip_scp = 1;
+		break;
+	case UNIPHIER_BOOT_MASTER_SCP:
+		INFO("Booting from on-chip SCP\n");
+		if (uniphier_scp_is_running()) {
+			INFO("SCP is already running. SCP_BL2 load will be skipped.\n");
+			skip_scp = 1;
+		}
+
+		/*
+		 * SCP must be kicked every time even if it is already running
+		 * because it polls this event after the reboot of the backend.
+		 */
+		uniphier_bl2_kick_scp = 1;
+		break;
+	case UNIPHIER_BOOT_MASTER_EXT:
+		INFO("Booting from external SCP\n");
+		skip_scp = 1;
+		break;
+	default:
+		plat_error_handler(-ENOTSUP);
+	}
+
+	if (!skip_scp) {
+		ret = uniphier_check_image(SCP_BL2_IMAGE_ID);
+		if (ret) {
+			WARN("SCP_BL2 image not found. SCP_BL2 load will be skipped.\n");
+			WARN("You must setup SCP by other means.\n");
+			skip_scp = 1;
+			uniphier_bl2_kick_scp = 0;
+		}
+	}
+
+	if (skip_scp)
+		uniphier_image_descs_fixup();
+}
+
+void bl2_platform_setup(void)
+{
+}
+
+void plat_flush_next_bl_params(void)
+{
+	flush_bl_params_desc();
+}
+
+bl_load_info_t *plat_get_bl_image_load_info(void)
+{
+	return get_bl_load_info_from_mem_params_desc();
+}
+
+bl_params_t *plat_get_next_bl_params(void)
+{
+	return get_next_bl_params_from_mem_params_desc();
+}
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+	if (image_id == SCP_BL2_IMAGE_ID && uniphier_bl2_kick_scp)
+		uniphier_scp_start();
+
+	return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_bl31_setup.c b/plat/socionext/uniphier/uniphier_bl31_setup.c
new file mode 100644
index 0000000..d9c87bd
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_bl31_setup.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <console.h>
+#include <debug.h>
+#include <errno.h>
+#include <mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <xlat_mmu_helpers.h>
+
+#include "uniphier.h"
+
+#define BL31_END		(unsigned long)(&__BL31_END__)
+#define BL31_SIZE		((BL31_END) - (BL31_BASE))
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	assert(sec_state_is_valid(type));
+	return type == NON_SECURE ? &bl33_image_ep_info : &bl32_image_ep_info;
+}
+
+void bl31_early_platform_setup(void *from_bl2, void *plat_params_from_bl2)
+{
+	bl_params_node_t *bl_params = ((bl_params_t *)from_bl2)->head;
+
+	uniphier_console_setup();
+
+	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();
+}
+
+#define UNIPHIER_SYS_CNTCTL_BASE	0x60E00000
+
+void bl31_platform_setup(void)
+{
+	unsigned int soc;
+
+	soc = uniphier_get_soc_id();
+	if (soc == UNIPHIER_SOC_UNKNOWN) {
+		ERROR("unsupported SoC\n");
+		plat_error_handler(-ENOTSUP);
+	}
+
+	uniphier_cci_init(soc);
+	uniphier_cci_enable();
+
+	/* Initialize the GIC driver, cpu and distributor interfaces */
+	uniphier_gic_driver_init(soc);
+	uniphier_gic_init();
+
+	/* Enable and initialize the System level generic timer */
+	mmio_write_32(UNIPHIER_SYS_CNTCTL_BASE + CNTCR_OFF,
+			CNTCR_FCREQ(0) | CNTCR_EN);
+}
+
+void bl31_plat_arch_setup(void)
+{
+	uniphier_mmap_setup(BL31_BASE, BL31_SIZE, NULL);
+	enable_mmu_el3(0);
+}
+
+void bl31_plat_runtime_setup(void)
+{
+	/* Suppress any runtime logs unless DEBUG is defined */
+#if !DEBUG
+	console_uninit();
+#endif
+}
diff --git a/plat/socionext/uniphier/uniphier_boot_device.c b/plat/socionext/uniphier/uniphier_boot_device.c
new file mode 100644
index 0000000..78ca8ef
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_boot_device.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <mmio.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_PINMON0		0x5f900100
+#define UNIPHIER_PINMON2		0x5f900108
+
+static int uniphier_ld11_is_usb_boot(uint32_t pinmon)
+{
+	return !!(~pinmon & 0x00000080);
+}
+
+static int uniphier_ld20_is_usb_boot(uint32_t pinmon)
+{
+	return !!(~pinmon & 0x00000780);
+}
+
+static int uniphier_pxs3_is_usb_boot(uint32_t pinmon)
+{
+	uint32_t pinmon2 = mmio_read_32(UNIPHIER_PINMON2);
+
+	return !!(pinmon2 & BIT(31));
+}
+
+static const unsigned int uniphier_ld11_boot_device_table[] = {
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_NOR,
+};
+
+static unsigned int uniphier_ld11_get_boot_device(uint32_t pinmon)
+{
+	unsigned int boot_sel = (pinmon >> 1) & 0x1f;
+
+	assert(boot_sel < ARRAY_SIZE(uniphier_ld11_boot_device_table));
+
+	return uniphier_ld11_boot_device_table[boot_sel];
+}
+
+static const unsigned int uniphier_pxs3_boot_device_table[] = {
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_EMMC,
+	UNIPHIER_BOOT_DEVICE_NAND,
+	UNIPHIER_BOOT_DEVICE_NAND,
+};
+
+static unsigned int uniphier_pxs3_get_boot_device(uint32_t pinmon)
+{
+	unsigned int boot_sel = (pinmon >> 1) & 0xf;
+
+	assert(boot_sel < ARRAY_SIZE(uniphier_pxs3_boot_device_table));
+
+	return uniphier_pxs3_boot_device_table[boot_sel];
+}
+
+struct uniphier_boot_device_info {
+	int (*is_usb_boot)(uint32_t pinmon);
+	unsigned int (*get_boot_device)(uint32_t pinmon);
+};
+
+static const struct uniphier_boot_device_info uniphier_boot_device_info[] = {
+	[UNIPHIER_SOC_LD11] = {
+		.is_usb_boot = uniphier_ld11_is_usb_boot,
+		.get_boot_device = uniphier_ld11_get_boot_device,
+	},
+	[UNIPHIER_SOC_LD20] = {
+		.is_usb_boot = uniphier_ld20_is_usb_boot,
+		.get_boot_device = uniphier_ld11_get_boot_device,
+	},
+	[UNIPHIER_SOC_PXS3] = {
+		.is_usb_boot = uniphier_pxs3_is_usb_boot,
+		.get_boot_device = uniphier_pxs3_get_boot_device,
+	},
+};
+
+unsigned int uniphier_get_boot_device(unsigned int soc)
+{
+	const struct uniphier_boot_device_info *info;
+	uint32_t pinmon;
+
+	assert(soc < ARRAY_SIZE(uniphier_boot_device_info));
+	info = &uniphier_boot_device_info[soc];
+
+	pinmon = mmio_read_32(UNIPHIER_PINMON0);
+
+	if (!(pinmon & BIT(29)))
+		return UNIPHIER_BOOT_DEVICE_NOR;
+
+	if (info->is_usb_boot(pinmon))
+		return UNIPHIER_BOOT_DEVICE_USB;
+
+	return info->get_boot_device(pinmon);
+}
+
+static const bool uniphier_have_onchip_scp[] = {
+	[UNIPHIER_SOC_LD11] = true,
+	[UNIPHIER_SOC_LD20] = true,
+	[UNIPHIER_SOC_PXS3] = false,
+};
+
+unsigned int uniphier_get_boot_master(unsigned int soc)
+{
+	assert(soc < ARRAY_SIZE(uniphier_have_onchip_scp));
+
+	if (uniphier_have_onchip_scp[soc]) {
+		if (mmio_read_32(UNIPHIER_PINMON0) & BIT(27))
+			return UNIPHIER_BOOT_MASTER_THIS;
+		else
+			return UNIPHIER_BOOT_MASTER_SCP;
+	} else {
+		return UNIPHIER_BOOT_MASTER_EXT;
+	}
+}
diff --git a/plat/socionext/uniphier/uniphier_cci.c b/plat/socionext/uniphier/uniphier_cci.c
new file mode 100644
index 0000000..30f4b47
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_cci.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <cci.h>
+#include <stddef.h>
+#include <utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_CCI500_BASE	0x5FD00000
+
+static const int uniphier_cci_map[] = {0, 1};
+
+static void __uniphier_cci_init(void)
+{
+	cci_init(UNIPHIER_CCI500_BASE, uniphier_cci_map,
+		 ARRAY_SIZE(uniphier_cci_map));
+}
+
+static void __uniphier_cci_enable(void)
+{
+	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+static void __uniphier_cci_disable(void)
+{
+	cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+struct uniphier_cci_ops {
+	void (*init)(void);
+	void (*enable)(void);
+	void (*disable)(void);
+};
+
+static const struct uniphier_cci_ops uniphier_cci_ops_table[] = {
+	[UNIPHIER_SOC_LD11] = {
+		.init = NULL,
+		.enable = NULL,
+		.disable = NULL,
+	},
+	[UNIPHIER_SOC_LD20] = {
+		.init = __uniphier_cci_init,
+		.enable = __uniphier_cci_enable,
+		.disable = __uniphier_cci_disable,
+	},
+	[UNIPHIER_SOC_PXS3] = {
+		.init = NULL,
+		.enable = NULL,
+		.disable = NULL,
+	},
+};
+
+static struct uniphier_cci_ops uniphier_cci_ops;
+
+void uniphier_cci_init(unsigned int soc)
+{
+	uniphier_cci_ops = uniphier_cci_ops_table[soc];
+	flush_dcache_range((uint64_t)&uniphier_cci_ops,
+			   sizeof(uniphier_cci_ops));
+
+	if (uniphier_cci_ops.init)
+		uniphier_cci_ops.init();
+}
+
+void uniphier_cci_enable(void)
+{
+	if (uniphier_cci_ops.enable)
+		uniphier_cci_ops.enable();
+}
+
+void uniphier_cci_disable(void)
+{
+	if (uniphier_cci_ops.disable)
+		uniphier_cci_ops.disable();
+}
diff --git a/plat/socionext/uniphier/uniphier_console.S b/plat/socionext/uniphier/uniphier_console.S
new file mode 100644
index 0000000..03aff48
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_console.S
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+#define UNIPHIER_UART_BASE	0x54006800
+#define UNIPHIER_UART_END	0x54006c00
+#define UNIPHIER_UART_OFFSET	0x100
+
+#define UNIPHIER_UART_RX	0x00	/* In:  Receive buffer */
+#define UNIPHIER_UART_TX	0x00	/* Out: Transmit buffer */
+
+#define UNIPHIER_UART_FCR	0x0c	/* Char/FIFO Control Register */
+#define   UNIPHIER_UART_FCR_ENABLE_FIFO	0x01	/* Enable the FIFO */
+
+#define UNIPHIER_UART_LCR_MCR	0x10	/* Line/Modem Control Register */
+#define   UNIPHIER_UART_LCR_WLEN8	0x03	/* Wordlength: 8 bits */
+#define UNIPHIER_UART_LSR	0x14	/* Line Status Register */
+#define   UNIPHIER_UART_LSR_TEMT_BIT	6	/* Transmitter empty */
+#define   UNIPHIER_UART_LSR_THRE_BIT	5	/* Transmit-hold-register empty */
+#define   UNIPHIER_UART_LSR_DR_BIT	0	/* Receiver data ready */
+#define UNIPHIER_UART_DLR	0x24	/* Divisor Latch Register */
+
+/*
+ * Uncomment for debug
+ */
+/* #define UNIPHIER_UART_INIT_DIVISOR */
+#define UNIPHIER_UART_DEFAULT_BASE	(UNIPHIER_UART_BASE)
+#define UNIPHIER_UART_CLK_RATE		58820000
+#define UNIPHIER_UART_DEFAULT_BAUDRATE	115200
+
+/*
+ * In: x0 - console base address
+ *     w1 - uart clock in Hz
+ *     w2 - baud rate
+ * Out: return 1 on success, or 0 on error
+ */
+	.globl	console_core_init
+func console_core_init
+	cbz	x0, 1f
+#ifdef UNIPHIER_UART_INIT_DIVISOR
+	cbz	w1, 1f
+	cbz	w2, 1f
+	/* divisor = uart_clock / (16 * baud_rate) */
+	udiv	w2, w1, w2
+	lsr	w2, w2, #4
+#endif
+	/* Make sure the transmitter is empty before the divisor set/change */
+0:	ldr	w1, [x0, #UNIPHIER_UART_LSR]
+	tbz	w1, #UNIPHIER_UART_LSR_TEMT_BIT, 0b
+#ifdef UNIPHIER_UART_INIT_DIVISOR
+	str	w2, [x0, #UNIPHIER_UART_DLR]
+#endif
+	mov	w2, #UNIPHIER_UART_FCR_ENABLE_FIFO
+	str	w2, [x0, #UNIPHIER_UART_FCR]
+
+	mov	w2, #(UNIPHIER_UART_LCR_WLEN8 << 8)
+	str	w2, [x0, #UNIPHIER_UART_LCR_MCR]
+
+	mov	w0, #1
+	ret
+1:	mov	w0, #0
+	ret
+endfunc console_core_init
+
+/*
+ * In: w0 - character to be printed
+ *     x1 - console base address
+ * Out: return the character written, or -1 on error
+ * Clobber: x2
+ */
+	.globl	console_core_putc
+func console_core_putc
+	/* Error out if the console is not initialized */
+	cbz	x1, 2f
+
+	/* Wait until the transmitter FIFO gets empty */
+0:	ldr	w2, [x1, #UNIPHIER_UART_LSR]
+	tbz	w2, #UNIPHIER_UART_LSR_THRE_BIT, 0b
+
+	mov	w2, w0
+
+1:	str	w2, [x1, #UNIPHIER_UART_TX]
+
+	cmp	w2, #'\n'
+	b.ne	3f
+	mov	w2, #'\r'	/* Append '\r' to '\n' */
+	b	1b
+2:	mov	w0, #-1
+3:	ret
+endfunc console_core_putc
+
+/*
+ * In: x0 - console base address
+ * Out: return the character read
+ * Clobber: x1
+ */
+	.globl	console_core_getc
+func console_core_getc
+	/* Error out if the console is not initialized */
+	cbz	x0, 1f
+
+	/* Wait while the receiver FIFO is empty */
+0:	ldr	w1, [x0, #UNIPHIER_UART_LSR]
+	tbz	w1, #UNIPHIER_UART_LSR_DR_BIT, 0b
+
+	ldr	w0, [x0, #UNIPHIER_UART_RX]
+
+	ret
+1:	mov	w0, #-1
+	ret
+endfunc console_core_getc
+
+/*
+ * In:  x0 - console base address
+ * Out: return 0, or -1 on error
+ * Clobber: x1
+ */
+	.global console_core_flush
+func console_core_flush
+	/* Error out if the console is not initialized */
+	cbz	x0, 1f
+
+	/* wait until the transmitter gets empty */
+0:	ldr	w1, [x0, #UNIPHIER_UART_LSR]
+	tbz	w1, #UNIPHIER_UART_LSR_TEMT_BIT, 0b
+
+	mov	w0, #0
+	ret
+1:	mov	w0, #-1
+	ret
+endfunc console_core_flush
+
+/* find initialized UART port */
+.macro uniphier_console_get_base base, tmpx, tmpw
+	ldr	\base, =UNIPHIER_UART_BASE
+0000:	ldr	\tmpw, [\base, #UNIPHIER_UART_DLR]
+	mvn	\tmpw, \tmpw
+	uxth	\tmpw, \tmpw
+	cbnz	\tmpw, 0001f
+	add	\base, \base, #UNIPHIER_UART_OFFSET
+	ldr	\tmpx, =UNIPHIER_UART_END
+	cmp	\base, \tmpx
+	b.lo	0000b
+	mov	\base, #0
+0001:
+.endm
+
+/*
+ * int plat_crash_console_init(void)
+ * Clobber: x0-x2
+ */
+	.globl	plat_crash_console_init
+func plat_crash_console_init
+#ifdef UNIPHIER_UART_INIT_DIVISOR
+	ldr	x0, =UNIPHIER_UART_DEFAULT_BASE
+	ldr	x1, =UNIPHIER_UART_CLK_RATE
+	ldr	x2, =UNIPHIER_UART_DEFAULT_BAUDRATE
+	b	console_core_init
+#else
+	ret
+#endif
+endfunc plat_crash_console_init
+
+/*
+ * int plat_crash_console_putc(int c)
+ * Clobber: x1, x2
+ */
+	.globl	plat_crash_console_putc
+func plat_crash_console_putc
+#ifdef UNIPHIER_UART_INIT_DIVISOR
+	ldr	x1, =UNIPHIER_UART_DEFAULT_BASE
+#else
+	uniphier_console_get_base x1, x2, w2
+#endif
+	b	console_core_putc
+endfunc plat_crash_console_putc
+
+/*
+ * int plat_crash_console_flush(void)
+ * Clobber: x0, x1
+ */
+	.global plat_crash_console_flush
+func plat_crash_console_flush
+#ifdef UNIPHIER_UART_INIT_DIVISOR
+	ldr	x0, =UNIPHIER_UART_DEFAULT_BASE
+#else
+	uniphier_console_get_base x0, x1, w1
+#endif
+	b	console_core_flush
+endfunc plat_crash_console_flush
+
+/*
+ * void uniphier_console_setup(void)
+ * Clobber: x0-x2
+ */
+	.globl	uniphier_console_setup
+func uniphier_console_setup
+#ifdef UNIPHIER_UART_INIT_DIVISOR
+	ldr	x0, =UNIPHIER_UART_DEFAULT_BASE
+	ldr	w1, =UNIPHIER_UART_CLK_RATE
+	ldr	w2, =UNIPHIER_UART_DEFAULT_BAUDRATE
+#else
+	uniphier_console_get_base x0, x1, w1
+	mov	w1, #0
+	mov	w2, #0
+#endif
+	b	console_init
+endfunc uniphier_console_setup
diff --git a/plat/socionext/uniphier/uniphier_emmc.c b/plat/socionext/uniphier/uniphier_emmc.c
new file mode 100644
index 0000000..fcd4cb4
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_emmc.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <io/io_block.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <sys/types.h>
+#include <utils_def.h>
+
+#include "uniphier.h"
+
+#define MMC_CMD_SWITCH			6
+#define MMC_CMD_SELECT_CARD		7
+#define MMC_CMD_SEND_CSD		9
+#define MMC_CMD_READ_MULTIPLE_BLOCK	18
+
+#define EXT_CSD_PART_CONF		179	/* R/W */
+
+#define MMC_RSP_PRESENT BIT(0)
+#define MMC_RSP_136	BIT(1)		/* 136 bit response */
+#define MMC_RSP_CRC	BIT(2)		/* expect valid crc */
+#define MMC_RSP_BUSY	BIT(3)		/* card may send busy */
+#define MMC_RSP_OPCODE	BIT(4)		/* response contains opcode */
+
+#define MMC_RSP_NONE	(0)
+#define MMC_RSP_R1	(MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_R1b	(MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | \
+			MMC_RSP_BUSY)
+#define MMC_RSP_R2	(MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC)
+#define MMC_RSP_R3	(MMC_RSP_PRESENT)
+#define MMC_RSP_R4	(MMC_RSP_PRESENT)
+#define MMC_RSP_R5	(MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_R6	(MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_R7	(MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+
+#define SDHCI_DMA_ADDRESS	0x00
+#define SDHCI_BLOCK_SIZE	0x04
+#define  SDHCI_MAKE_BLKSZ(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF))
+#define SDHCI_BLOCK_COUNT	0x06
+#define SDHCI_ARGUMENT		0x08
+#define SDHCI_TRANSFER_MODE	0x0C
+#define  SDHCI_TRNS_DMA		BIT(0)
+#define  SDHCI_TRNS_BLK_CNT_EN	BIT(1)
+#define  SDHCI_TRNS_ACMD12	BIT(2)
+#define  SDHCI_TRNS_READ	BIT(4)
+#define  SDHCI_TRNS_MULTI	BIT(5)
+#define SDHCI_COMMAND		0x0E
+#define  SDHCI_CMD_RESP_MASK	0x03
+#define  SDHCI_CMD_CRC		0x08
+#define  SDHCI_CMD_INDEX	0x10
+#define  SDHCI_CMD_DATA		0x20
+#define  SDHCI_CMD_ABORTCMD	0xC0
+#define  SDHCI_CMD_RESP_NONE	0x00
+#define  SDHCI_CMD_RESP_LONG	0x01
+#define  SDHCI_CMD_RESP_SHORT	0x02
+#define  SDHCI_CMD_RESP_SHORT_BUSY 0x03
+#define  SDHCI_MAKE_CMD(c, f) ((((c) & 0xff) << 8) | ((f) & 0xff))
+#define SDHCI_RESPONSE		0x10
+#define SDHCI_HOST_CONTROL	0x28
+#define  SDHCI_CTRL_DMA_MASK	0x18
+#define   SDHCI_CTRL_SDMA	0x00
+#define SDHCI_BLOCK_GAP_CONTROL	0x2A
+#define SDHCI_SOFTWARE_RESET	0x2F
+#define  SDHCI_RESET_CMD	0x02
+#define  SDHCI_RESET_DATA	0x04
+#define SDHCI_INT_STATUS	0x30
+#define  SDHCI_INT_RESPONSE	BIT(0)
+#define  SDHCI_INT_DATA_END	BIT(1)
+#define  SDHCI_INT_DMA_END	BIT(3)
+#define  SDHCI_INT_ERROR	BIT(15)
+#define SDHCI_SIGNAL_ENABLE	0x38
+
+/* RCA assigned by Boot ROM */
+#define UNIPHIER_EMMC_RCA	0x1000
+
+struct uniphier_mmc_cmd {
+	unsigned int cmdidx;
+	unsigned int resp_type;
+	unsigned int cmdarg;
+	unsigned int is_data;
+};
+
+static int uniphier_emmc_block_addressing;
+
+static int uniphier_emmc_send_cmd(uintptr_t host_base,
+				  struct uniphier_mmc_cmd *cmd)
+{
+	uint32_t mode = 0;
+	uint32_t end_bit;
+	uint32_t stat, flags, dma_addr;
+
+	mmio_write_32(host_base + SDHCI_INT_STATUS, -1);
+	mmio_write_32(host_base + SDHCI_SIGNAL_ENABLE, 0);
+	mmio_write_32(host_base + SDHCI_ARGUMENT, cmd->cmdarg);
+
+	if (cmd->is_data)
+		mode = SDHCI_TRNS_DMA | SDHCI_TRNS_BLK_CNT_EN |
+			SDHCI_TRNS_ACMD12 | SDHCI_TRNS_READ |
+			SDHCI_TRNS_MULTI;
+
+	mmio_write_16(host_base + SDHCI_TRANSFER_MODE, mode);
+
+	if (!(cmd->resp_type & MMC_RSP_PRESENT))
+		flags = SDHCI_CMD_RESP_NONE;
+	else if (cmd->resp_type & MMC_RSP_136)
+		flags = SDHCI_CMD_RESP_LONG;
+	else if (cmd->resp_type & MMC_RSP_BUSY)
+		flags = SDHCI_CMD_RESP_SHORT_BUSY;
+	else
+		flags = SDHCI_CMD_RESP_SHORT;
+
+	if (cmd->resp_type & MMC_RSP_CRC)
+		flags |= SDHCI_CMD_CRC;
+	if (cmd->resp_type & MMC_RSP_OPCODE)
+		flags |= SDHCI_CMD_INDEX;
+	if (cmd->is_data)
+		flags |= SDHCI_CMD_DATA;
+
+	if (cmd->resp_type & MMC_RSP_BUSY || cmd->is_data)
+		end_bit = SDHCI_INT_DATA_END;
+	else
+		end_bit = SDHCI_INT_RESPONSE;
+
+	mmio_write_16(host_base + SDHCI_COMMAND,
+		      SDHCI_MAKE_CMD(cmd->cmdidx, flags));
+
+	do {
+		stat = mmio_read_32(host_base + SDHCI_INT_STATUS);
+		if (stat & SDHCI_INT_ERROR)
+			return -EIO;
+
+		if (stat & SDHCI_INT_DMA_END) {
+			mmio_write_32(host_base + SDHCI_INT_STATUS, stat);
+			dma_addr = mmio_read_32(host_base + SDHCI_DMA_ADDRESS);
+			mmio_write_32(host_base + SDHCI_DMA_ADDRESS, dma_addr);
+		}
+	} while (!(stat & end_bit));
+
+	return 0;
+}
+
+static int uniphier_emmc_switch_part(uintptr_t host_base, int part_num)
+{
+	struct uniphier_mmc_cmd cmd = {0};
+
+	cmd.cmdidx = MMC_CMD_SWITCH;
+	cmd.resp_type = MMC_RSP_R1b;
+	cmd.cmdarg = (EXT_CSD_PART_CONF << 16) | (part_num << 8) | (3 << 24);
+
+	return uniphier_emmc_send_cmd(host_base, &cmd);
+}
+
+static int uniphier_emmc_is_over_2gb(uintptr_t host_base)
+{
+	struct uniphier_mmc_cmd cmd = {0};
+	uint32_t csd40, csd72;	/* CSD[71:40], CSD[103:72] */
+	int ret;
+
+	cmd.cmdidx = MMC_CMD_SEND_CSD;
+	cmd.resp_type = MMC_RSP_R2;
+	cmd.cmdarg = UNIPHIER_EMMC_RCA << 16;
+
+	ret = uniphier_emmc_send_cmd(host_base, &cmd);
+	if (ret)
+		return ret;
+
+	csd40 = mmio_read_32(host_base + SDHCI_RESPONSE + 4);
+	csd72 = mmio_read_32(host_base + SDHCI_RESPONSE + 8);
+
+	return !(~csd40 & 0xffc00380) && !(~csd72 & 0x3);
+}
+
+static int uniphier_emmc_load_image(uintptr_t host_base,
+				    uint32_t dev_addr,
+				    unsigned long load_addr,
+				    uint32_t block_cnt)
+{
+	struct uniphier_mmc_cmd cmd = {0};
+	uint8_t tmp;
+
+	assert((load_addr >> 32) == 0);
+
+	mmio_write_32(host_base + SDHCI_DMA_ADDRESS, load_addr);
+	mmio_write_16(host_base + SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(7, 512));
+	mmio_write_16(host_base + SDHCI_BLOCK_COUNT, block_cnt);
+
+	tmp = mmio_read_8(host_base + SDHCI_HOST_CONTROL);
+	tmp &= ~SDHCI_CTRL_DMA_MASK;
+	tmp |= SDHCI_CTRL_SDMA;
+	mmio_write_8(host_base + SDHCI_HOST_CONTROL, tmp);
+
+	tmp = mmio_read_8(host_base + SDHCI_BLOCK_GAP_CONTROL);
+	tmp &= ~1;		/* clear Stop At Block Gap Request */
+	mmio_write_8(host_base + SDHCI_BLOCK_GAP_CONTROL, tmp);
+
+	cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
+	cmd.resp_type = MMC_RSP_R1;
+	cmd.cmdarg = dev_addr;
+	cmd.is_data = 1;
+
+	return uniphier_emmc_send_cmd(host_base, &cmd);
+}
+
+static size_t uniphier_emmc_read(int lba, uintptr_t buf, size_t size)
+{
+	uintptr_t host_base = 0x5a000200;
+	int ret;
+
+	inv_dcache_range(buf, size);
+
+	if (!uniphier_emmc_block_addressing)
+		lba *= 512;
+
+	ret = uniphier_emmc_load_image(host_base, lba, buf, size / 512);
+
+	inv_dcache_range(buf, size);
+
+	return ret ? 0 : size;
+}
+
+static const struct io_block_dev_spec uniphier_emmc_dev_spec = {
+	.buffer = {
+		.offset = UNIPHIER_BLOCK_BUF_BASE,
+		.length = UNIPHIER_BLOCK_BUF_SIZE,
+	},
+	.ops = {
+		.read = uniphier_emmc_read,
+	},
+	.block_size = 512,
+};
+
+static int uniphier_emmc_hw_init(void)
+{
+	uintptr_t host_base = 0x5a000200;
+	struct uniphier_mmc_cmd cmd = {0};
+	int ret;
+
+	/*
+	 * deselect card before SEND_CSD command.
+	 * Do not check the return code.  It fails, but it is OK.
+	 */
+	cmd.cmdidx = MMC_CMD_SELECT_CARD;
+	cmd.resp_type = MMC_RSP_R1;
+
+	uniphier_emmc_send_cmd(host_base, &cmd); /* CMD7 (arg=0) */
+
+	/* reset CMD Line */
+	mmio_write_8(host_base + SDHCI_SOFTWARE_RESET,
+		     SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+	while (mmio_read_8(host_base + SDHCI_SOFTWARE_RESET))
+		;
+
+	ret = uniphier_emmc_is_over_2gb(host_base);
+	if (ret < 0)
+		return ret;
+
+	uniphier_emmc_block_addressing = ret;
+
+	cmd.cmdarg = UNIPHIER_EMMC_RCA << 16;
+
+	/* select card again */
+	ret = uniphier_emmc_send_cmd(host_base, &cmd);
+	if (ret)
+		return ret;
+
+	/* switch to Boot Partition 1 */
+	ret = uniphier_emmc_switch_part(host_base, 1);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int uniphier_emmc_init(uintptr_t *block_dev_spec)
+{
+	int ret;
+
+	ret = uniphier_emmc_hw_init();
+	if (ret)
+		return ret;
+
+	*block_dev_spec = (uintptr_t)&uniphier_emmc_dev_spec;
+
+	return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_gicv3.c b/plat/socionext/uniphier/uniphier_gicv3.c
new file mode 100644
index 0000000..05a4e35
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_gicv3.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <gicv3.h>
+#include <platform.h>
+#include <platform_def.h>
+
+#include "uniphier.h"
+
+static uintptr_t uniphier_rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const unsigned int g0_interrupt_array[] = {
+	8,	/* SGI0 */
+	14,	/* SGI6 */
+};
+
+static const unsigned int g1s_interrupt_array[] = {
+	29,	/* Timer */
+	9,	/* SGI1 */
+	10,	/* SGI2 */
+	11,	/* SGI3 */
+	12,	/* SGI4 */
+	13,	/* SGI5 */
+	15,	/* SGI7 */
+};
+
+static unsigned int uniphier_mpidr_to_core_pos(u_register_t mpidr)
+{
+	return plat_core_pos_by_mpidr(mpidr);
+}
+
+static const struct gicv3_driver_data uniphier_gic_driver_data[] = {
+	[UNIPHIER_SOC_LD11] = {
+		.gicd_base = 0x5fe00000,
+		.gicr_base = 0x5fe40000,
+		.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
+		.g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array),
+		.g0_interrupt_array = g0_interrupt_array,
+		.g1s_interrupt_array = g1s_interrupt_array,
+		.rdistif_num = PLATFORM_CORE_COUNT,
+		.rdistif_base_addrs = uniphier_rdistif_base_addrs,
+		.mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
+	},
+	[UNIPHIER_SOC_LD20] = {
+		.gicd_base = 0x5fe00000,
+		.gicr_base = 0x5fe80000,
+		.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
+		.g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array),
+		.g0_interrupt_array = g0_interrupt_array,
+		.g1s_interrupt_array = g1s_interrupt_array,
+		.rdistif_num = PLATFORM_CORE_COUNT,
+		.rdistif_base_addrs = uniphier_rdistif_base_addrs,
+		.mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
+	},
+	[UNIPHIER_SOC_PXS3] = {
+		.gicd_base = 0x5fe00000,
+		.gicr_base = 0x5fe80000,
+		.g0_interrupt_num = ARRAY_SIZE(g0_interrupt_array),
+		.g1s_interrupt_num = ARRAY_SIZE(g1s_interrupt_array),
+		.g0_interrupt_array = g0_interrupt_array,
+		.g1s_interrupt_array = g1s_interrupt_array,
+		.rdistif_num = PLATFORM_CORE_COUNT,
+		.rdistif_base_addrs = uniphier_rdistif_base_addrs,
+		.mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
+	},
+};
+
+void uniphier_gic_driver_init(unsigned int soc)
+{
+	assert(soc < ARRAY_SIZE(uniphier_gic_driver_data));
+
+	gicv3_driver_init(&uniphier_gic_driver_data[soc]);
+}
+
+void uniphier_gic_init(void)
+{
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void uniphier_gic_cpuif_enable(void)
+{
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void uniphier_gic_cpuif_disable(void)
+{
+	gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+void uniphier_gic_pcpu_init(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+}
diff --git a/plat/socionext/uniphier/uniphier_helpers.S b/plat/socionext/uniphier/uniphier_helpers.S
new file mode 100644
index 0000000..105cf9e
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_helpers.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.global	uniphier_calc_core_pos
+	.global	plat_my_core_pos
+	.globl	platform_mem_init
+
+/*
+ * unsigned int uniphier_calc_core_pos(u_register_t mpidr)
+ * core_pos = (cluster_id * max_cpus_per_cluster) + core_id
+ */
+func uniphier_calc_core_pos
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	lsr	x0, x0, #MPIDR_AFFINITY_BITS
+	mov	x2, #UNIPHIER_MAX_CPUS_PER_CLUSTER
+	madd	x0, x0, x2, x1
+	ret
+endfunc uniphier_calc_core_pos
+
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	uniphier_calc_core_pos
+endfunc plat_my_core_pos
+
+func platform_mem_init
+	ret
+endfunc platform_mem_init
diff --git a/plat/socionext/uniphier/uniphier_image_desc.c b/plat/socionext/uniphier/uniphier_image_desc.c
new file mode 100644
index 0000000..1e474c5
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_image_desc.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <assert.h>
+#include <desc_image_load.h>
+#include <platform_def.h>
+
+#include "uniphier.h"
+
+static struct bl_mem_params_node uniphier_image_descs[] = {
+	{
+		.image_id = SCP_BL2_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t, 0),
+		.image_info.image_base = UNIPHIER_SCP_BASE,
+		.image_info.image_max_size = UNIPHIER_SCP_MAX_SIZE,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      NON_SECURE | NON_EXECUTABLE),
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+	{
+		.image_id = BL31_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t, 0),
+		.image_info.image_base = BL31_BASE,
+		.image_info.image_max_size = BL31_LIMIT - BL31_BASE,
+
+		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),
+
+#ifdef UNIPHIER_LOAD_BL32
+		.next_handoff_image_id = BL32_IMAGE_ID,
+#else
+		.next_handoff_image_id = BL33_IMAGE_ID,
+#endif
+	},
+#ifdef UNIPHIER_LOAD_BL32
+	{
+		.image_id = BL32_IMAGE_ID,
+
+		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,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      SECURE | EXECUTABLE),
+		.ep_info.pc = BL32_BASE,
+		.ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX,
+					DISABLE_ALL_EXCEPTIONS),
+
+		.next_handoff_image_id = BL33_IMAGE_ID,
+	},
+#endif
+	{
+		.image_id = BL33_IMAGE_ID,
+
+		SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+				      VERSION_2, image_info_t, 0),
+		.image_info.image_base = UNIPHIER_BL33_BASE,
+		.image_info.image_max_size = UNIPHIER_BL33_MAX_SIZE,
+
+		SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+				      VERSION_2, entry_point_info_t,
+				      NON_SECURE | EXECUTABLE),
+		.ep_info.pc = UNIPHIER_BL33_BASE,
+		.ep_info.spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+					DISABLE_ALL_EXCEPTIONS),
+
+		.next_handoff_image_id = INVALID_IMAGE_ID,
+	},
+};
+REGISTER_BL_IMAGE_DESCS(uniphier_image_descs)
+
+/* SCP is optional.  Allow run-time fixup of the descriptor array. */
+void uniphier_image_descs_fixup(void)
+{
+	struct bl_mem_params_node *desc;
+
+	desc = get_bl_mem_params_node(SCP_BL2_IMAGE_ID);
+	assert(desc != NULL);
+	desc->image_info.h.attr |= IMAGE_ATTRIB_SKIP_LOADING;
+}
diff --git a/plat/socionext/uniphier/uniphier_io_storage.c b/plat/socionext/uniphier/uniphier_io_storage.c
new file mode 100644
index 0000000..bc31350
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_io_storage.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <firmware_image_package.h>
+#include <io/io_block.h>
+#include <io/io_driver.h>
+#include <io/io_fip.h>
+#include <io/io_memmap.h>
+#include <platform_def.h>
+#include <types.h>
+#include <utils_def.h>
+#include <xlat_tables_v2.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_ROM_REGION_BASE	0x00000000
+#define UNIPHIER_ROM_REGION_SIZE	0x10000000
+
+static const io_dev_connector_t *uniphier_fip_dev_con;
+static uintptr_t uniphier_fip_dev_handle;
+
+static const io_dev_connector_t *uniphier_backend_dev_con;
+static uintptr_t uniphier_backend_dev_handle;
+
+static io_block_spec_t uniphier_fip_spec = {
+	/* .offset will be set by the io_setup func */
+	.length = 0x00200000,
+};
+
+static const io_uuid_spec_t uniphier_bl2_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t uniphier_scp_spec = {
+	.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
+};
+
+static const io_uuid_spec_t uniphier_bl31_spec = {
+	.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t uniphier_bl32_spec = {
+	.uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t uniphier_bl33_spec = {
+	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t uniphier_tb_fw_cert_spec = {
+	.uuid = UUID_TRUSTED_BOOT_FW_CERT,
+};
+
+static const io_uuid_spec_t uniphier_trusted_key_cert_spec = {
+	.uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t uniphier_scp_fw_key_cert_spec = {
+	.uuid = UUID_SCP_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t uniphier_soc_fw_key_cert_spec = {
+	.uuid = UUID_SOC_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t uniphier_tos_fw_key_cert_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t uniphier_nt_fw_key_cert_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t uniphier_scp_fw_cert_spec = {
+	.uuid = UUID_SCP_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t uniphier_soc_fw_cert_spec = {
+	.uuid = UUID_SOC_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t uniphier_tos_fw_cert_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t uniphier_nt_fw_cert_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+struct uniphier_io_policy {
+	uintptr_t *dev_handle;
+	uintptr_t image_spec;
+	uintptr_t init_params;
+};
+
+static const struct uniphier_io_policy uniphier_io_policies[] = {
+	[FIP_IMAGE_ID] = {
+		.dev_handle = &uniphier_backend_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_fip_spec,
+	},
+	[BL2_IMAGE_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_bl2_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[SCP_BL2_IMAGE_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_scp_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[BL31_IMAGE_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_bl31_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[BL32_IMAGE_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_bl32_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[BL33_IMAGE_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_bl33_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_BOOT_FW_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_tb_fw_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[TRUSTED_KEY_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_trusted_key_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[SCP_FW_KEY_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_scp_fw_key_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[SOC_FW_KEY_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_soc_fw_key_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_tos_fw_key_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_nt_fw_key_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[SCP_FW_CONTENT_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_scp_fw_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[SOC_FW_CONTENT_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_soc_fw_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_tos_fw_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+		.dev_handle = &uniphier_fip_dev_handle,
+		.image_spec = (uintptr_t)&uniphier_nt_fw_cert_spec,
+		.init_params = FIP_IMAGE_ID,
+	},
+#endif
+};
+
+static int uniphier_io_block_setup(size_t fip_offset, uintptr_t block_dev_spec)
+{
+	int ret;
+
+	uniphier_fip_spec.offset = fip_offset;
+
+	ret = register_io_dev_block(&uniphier_backend_dev_con);
+	if (ret)
+		return ret;
+
+	return io_dev_open(uniphier_backend_dev_con, block_dev_spec,
+			   &uniphier_backend_dev_handle);
+}
+
+static int uniphier_io_memmap_setup(size_t fip_offset)
+{
+	int ret;
+
+	uniphier_fip_spec.offset = fip_offset;
+
+	ret = mmap_add_dynamic_region(fip_offset, fip_offset,
+				      uniphier_fip_spec.length,
+				      MT_RO_DATA | MT_SECURE);
+	if (ret)
+		return ret;
+
+	ret = register_io_dev_memmap(&uniphier_backend_dev_con);
+	if (ret)
+		return ret;
+
+	return io_dev_open(uniphier_backend_dev_con, 0,
+			   &uniphier_backend_dev_handle);
+}
+
+static int uniphier_io_fip_setup(void)
+{
+	int ret;
+
+	ret = register_io_dev_fip(&uniphier_fip_dev_con);
+	if (ret)
+		return ret;
+
+	return io_dev_open(uniphier_fip_dev_con, 0, &uniphier_fip_dev_handle);
+}
+
+static int uniphier_io_emmc_setup(unsigned int soc_id)
+{
+	uintptr_t block_dev_spec;
+	int ret;
+
+	ret = uniphier_emmc_init(&block_dev_spec);
+	if (ret)
+		return ret;
+
+	return uniphier_io_block_setup(0x20000, block_dev_spec);
+}
+
+static int uniphier_io_nand_setup(unsigned int soc_id)
+{
+	uintptr_t block_dev_spec;
+	int ret;
+
+	ret = uniphier_nand_init(&block_dev_spec);
+	if (ret)
+		return ret;
+
+	return uniphier_io_block_setup(0x20000, block_dev_spec);
+}
+
+static int uniphier_io_nor_setup(unsigned int soc_id)
+{
+	return uniphier_io_memmap_setup(0x70000);
+}
+
+static int uniphier_io_usb_setup(unsigned int soc_id)
+{
+	uintptr_t block_dev_spec;
+	int ret;
+
+	/* use ROM API for loading images from USB storage */
+	ret = mmap_add_dynamic_region(UNIPHIER_ROM_REGION_BASE,
+				      UNIPHIER_ROM_REGION_BASE,
+				      UNIPHIER_ROM_REGION_SIZE,
+				      MT_CODE | MT_SECURE);
+	if (ret)
+		return ret;
+
+	ret = uniphier_usb_init(soc_id, &block_dev_spec);
+	if (ret)
+		return ret;
+
+	return uniphier_io_block_setup(0x20000, block_dev_spec);
+}
+
+static int (* const uniphier_io_setup_table[])(unsigned int) = {
+	[UNIPHIER_BOOT_DEVICE_EMMC] = uniphier_io_emmc_setup,
+	[UNIPHIER_BOOT_DEVICE_NAND] = uniphier_io_nand_setup,
+	[UNIPHIER_BOOT_DEVICE_NOR] = uniphier_io_nor_setup,
+	[UNIPHIER_BOOT_DEVICE_USB] = uniphier_io_usb_setup,
+};
+
+int uniphier_io_setup(unsigned int soc_id)
+{
+	int (*io_setup)(unsigned int soc_id);
+	unsigned int boot_dev;
+	int ret;
+
+	boot_dev = uniphier_get_boot_device(soc_id);
+	if (boot_dev == UNIPHIER_BOOT_DEVICE_RSV)
+		return -EINVAL;
+
+	io_setup = uniphier_io_setup_table[boot_dev];
+	ret = io_setup(soc_id);
+	if (ret)
+		return ret;
+
+	ret = uniphier_io_fip_setup();
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
+			  uintptr_t *image_spec)
+{
+	uintptr_t init_params;
+
+	assert(image_id < ARRAY_SIZE(uniphier_io_policies));
+
+	*dev_handle = *(uniphier_io_policies[image_id].dev_handle);
+	*image_spec = uniphier_io_policies[image_id].image_spec;
+	init_params = uniphier_io_policies[image_id].init_params;
+
+	return io_dev_init(*dev_handle, init_params);
+}
+
+int uniphier_check_image(unsigned int image_id)
+{
+	uintptr_t dev_handle, image_spec, image_handle;
+	int ret;
+
+	ret = plat_get_image_source(image_id, &dev_handle, &image_spec);
+	if (ret)
+		return ret;
+
+	ret = io_open(dev_handle, image_spec, &image_handle);
+	if (ret)
+		return ret;
+
+	io_close(image_handle);
+
+	return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_nand.c b/plat/socionext/uniphier/uniphier_nand.c
new file mode 100644
index 0000000..acf6a74
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_nand.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <io/io_block.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <sys/types.h>
+#include <utils_def.h>
+
+#include "uniphier.h"
+
+#define DIV_ROUND_UP(n, d)	(((n) + (d) - 1) / (d))
+
+#define NAND_CMD_READ0		0
+#define NAND_CMD_READSTART	0x30
+
+#define DENALI_ECC_ENABLE			0x0e0
+#define DENALI_PAGES_PER_BLOCK			0x150
+#define DENALI_DEVICE_MAIN_AREA_SIZE		0x170
+#define DENALI_DEVICE_SPARE_AREA_SIZE		0x180
+#define DENALI_TWO_ROW_ADDR_CYCLES		0x190
+#define DENALI_INTR_STATUS0			0x410
+#define   DENALI_INTR_ECC_UNCOR_ERR			BIT(1)
+#define   DENALI_INTR_DMA_CMD_COMP			BIT(2)
+#define   DENALI_INTR_INT_ACT				BIT(12)
+
+#define DENALI_DMA_ENABLE			0x700
+
+#define DENALI_HOST_ADDR			0x00
+#define DENALI_HOST_DATA			0x10
+
+#define DENALI_MAP01				(1 << 26)
+#define DENALI_MAP10				(2 << 26)
+#define DENALI_MAP11				(3 << 26)
+
+#define DENALI_MAP11_CMD			((DENALI_MAP11) | 0)
+#define DENALI_MAP11_ADDR			((DENALI_MAP11) | 1)
+#define DENALI_MAP11_DATA			((DENALI_MAP11) | 2)
+
+#define DENALI_ACCESS_DEFAULT_AREA		0x42
+
+#define UNIPHIER_NAND_BBT_UNKNOWN		0xff
+
+struct uniphier_nand {
+	uintptr_t host_base;
+	uintptr_t reg_base;
+	int pages_per_block;
+	int page_size;
+	int two_row_addr_cycles;
+	uint8_t bbt[16];
+};
+
+struct uniphier_nand uniphier_nand;
+
+static void uniphier_nand_host_write(struct uniphier_nand *nand,
+				     uint32_t addr, uint32_t data)
+{
+	mmio_write_32(nand->host_base + DENALI_HOST_ADDR, addr);
+	mmio_write_32(nand->host_base + DENALI_HOST_DATA, data);
+}
+
+static uint32_t uniphier_nand_host_read(struct uniphier_nand *nand,
+					uint32_t addr)
+{
+	mmio_write_32(nand->host_base + DENALI_HOST_ADDR, addr);
+	return mmio_read_32(nand->host_base + DENALI_HOST_DATA);
+}
+
+static int uniphier_nand_block_isbad(struct uniphier_nand *nand, int block)
+{
+	int page = nand->pages_per_block * block;
+	int column = nand->page_size;
+	uint8_t bbm;
+	uint32_t status;
+	int is_bad;
+
+	/* use cache if available */
+	if (block < ARRAY_SIZE(nand->bbt) &&
+	    nand->bbt[block] != UNIPHIER_NAND_BBT_UNKNOWN)
+		return nand->bbt[block];
+
+	mmio_write_32(nand->reg_base + DENALI_ECC_ENABLE, 0);
+
+	mmio_write_32(nand->reg_base + DENALI_INTR_STATUS0, -1);
+
+	uniphier_nand_host_write(nand, DENALI_MAP11_CMD, NAND_CMD_READ0);
+	uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, column & 0xff);
+	uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, (column >> 8) & 0xff);
+	uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, page & 0xff);
+	uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, (page >> 8) & 0xff);
+	if (!nand->two_row_addr_cycles)
+		uniphier_nand_host_write(nand, DENALI_MAP11_ADDR,
+					 (page >> 16) & 0xff);
+	uniphier_nand_host_write(nand, DENALI_MAP11_CMD, NAND_CMD_READSTART);
+
+	do {
+		status = mmio_read_32(nand->reg_base + DENALI_INTR_STATUS0);
+	} while (!(status & DENALI_INTR_INT_ACT));
+
+	bbm = uniphier_nand_host_read(nand, DENALI_MAP11_DATA);
+
+	is_bad = bbm != 0xff;
+
+	/* save the result for future re-use */
+	nand->bbt[block] = is_bad;
+
+	if (is_bad)
+		WARN("found bad block at %d. skip.\n", block);
+
+	return is_bad;
+}
+
+static int uniphier_nand_read_pages(struct uniphier_nand *nand, uintptr_t buf,
+				    int page_start, int page_count)
+{
+	uint32_t status;
+
+	mmio_write_32(nand->reg_base + DENALI_ECC_ENABLE, 1);
+	mmio_write_32(nand->reg_base + DENALI_DMA_ENABLE, 1);
+
+	mmio_write_32(nand->reg_base + DENALI_INTR_STATUS0, -1);
+
+	/* use Data DMA (64bit) */
+	mmio_write_32(nand->host_base + DENALI_HOST_ADDR,
+		      DENALI_MAP10 | page_start);
+
+	/*
+	 * 1. setup transfer type, interrupt when complete,
+	 *    burst len = 64 bytes, the number of pages
+	 */
+	mmio_write_32(nand->host_base + DENALI_HOST_DATA,
+		      0x01002000 | (64 << 16) | page_count);
+
+	/* 2. set memory low address */
+	mmio_write_32(nand->host_base + DENALI_HOST_DATA, buf);
+
+	/* 3. set memory high address */
+	mmio_write_32(nand->host_base + DENALI_HOST_DATA, buf >> 32);
+
+	do {
+		status = mmio_read_32(nand->reg_base + DENALI_INTR_STATUS0);
+	} while (!(status & DENALI_INTR_DMA_CMD_COMP));
+
+	mmio_write_32(nand->reg_base + DENALI_DMA_ENABLE, 0);
+
+	if (status & DENALI_INTR_ECC_UNCOR_ERR) {
+		ERROR("uncorrectable error in page range %d-%d",
+		      page_start, page_start + page_count - 1);
+		return -EBADMSG;
+	}
+
+	return 0;
+}
+
+static size_t __uniphier_nand_read(struct uniphier_nand *nand, int lba,
+				   uintptr_t buf, size_t size)
+{
+	int pages_per_block = nand->pages_per_block;
+	int page_size = nand->page_size;
+	int blocks_to_skip = lba / pages_per_block;
+	int pages_to_read = DIV_ROUND_UP(size, page_size);
+	int page = lba % pages_per_block;
+	int block = 0;
+	uintptr_t p = buf;
+	int page_count, ret;
+
+	while (blocks_to_skip) {
+		ret = uniphier_nand_block_isbad(nand, block);
+		if (ret < 0)
+			goto out;
+
+		if (!ret)
+			blocks_to_skip--;
+
+		block++;
+	}
+
+	while (pages_to_read) {
+		ret = uniphier_nand_block_isbad(nand, block);
+		if (ret < 0)
+			goto out;
+
+		if (ret) {
+			block++;
+			continue;
+		}
+
+		page_count = MIN(pages_per_block - page, pages_to_read);
+
+		ret = uniphier_nand_read_pages(nand, p,
+					       block * pages_per_block + page,
+					       page_count);
+		if (ret)
+			goto out;
+
+		block++;
+		page = 0;
+		p += page_size * page_count;
+		pages_to_read -= page_count;
+	}
+
+out:
+	/* number of read bytes */
+	return MIN(size, p - buf);
+}
+
+static size_t uniphier_nand_read(int lba, uintptr_t buf, size_t size)
+{
+	size_t count;
+
+	inv_dcache_range(buf, size);
+
+	count = __uniphier_nand_read(&uniphier_nand, lba, buf, size);
+
+	inv_dcache_range(buf, size);
+
+	return count;
+}
+
+static struct io_block_dev_spec uniphier_nand_dev_spec = {
+	.buffer = {
+		.offset = UNIPHIER_BLOCK_BUF_BASE,
+		.length = UNIPHIER_BLOCK_BUF_SIZE,
+	},
+	.ops = {
+		.read = uniphier_nand_read,
+	},
+	/* fill .block_size at run-time */
+};
+
+static int uniphier_nand_hw_init(struct uniphier_nand *nand)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nand->bbt); i++)
+		nand->bbt[i] = UNIPHIER_NAND_BBT_UNKNOWN;
+
+	nand->host_base = 0x68000000;
+	nand->reg_base = 0x68100000;
+
+	nand->pages_per_block =
+			mmio_read_32(nand->reg_base + DENALI_PAGES_PER_BLOCK);
+
+	nand->page_size =
+		mmio_read_32(nand->reg_base + DENALI_DEVICE_MAIN_AREA_SIZE);
+
+	if (mmio_read_32(nand->reg_base + DENALI_TWO_ROW_ADDR_CYCLES) & BIT(0))
+		nand->two_row_addr_cycles = 1;
+
+	uniphier_nand_host_write(nand, DENALI_MAP10,
+				 DENALI_ACCESS_DEFAULT_AREA);
+
+	return 0;
+}
+
+int uniphier_nand_init(uintptr_t *block_dev_spec)
+{
+	int ret;
+
+	ret = uniphier_nand_hw_init(&uniphier_nand);
+	if (ret)
+		return ret;
+
+	uniphier_nand_dev_spec.block_size = uniphier_nand.page_size;
+
+	*block_dev_spec = (uintptr_t)&uniphier_nand_dev_spec;
+
+	return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_psci.c b/plat/socionext/uniphier/uniphier_psci.c
new file mode 100644
index 0000000..82081a0
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_psci.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <mmio.h>
+#include <psci.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_ROM_RSV0		0x59801200
+
+#define UNIPHIER_SLFRSTSEL		0x61843010
+#define   UNIPHIER_SLFRSTSEL_MASK		(0x3 << 0)
+#define UNIPHIER_SLFRSTCTL		0x61843014
+#define   UNIPHIER_SLFRSTCTL_RST		(1 << 0)
+
+#define MPIDR_AFFINITY_INVALID		((u_register_t)-1)
+
+uintptr_t uniphier_sec_entrypoint;
+
+void uniphier_warmboot_entrypoint(void);
+void __dead2 uniphier_fake_pwr_down(void);
+u_register_t uniphier_holding_pen_release;
+static int uniphier_psci_scp_mode;
+
+static int uniphier_psci_pwr_domain_on(u_register_t mpidr)
+{
+	uniphier_holding_pen_release = mpidr;
+	flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
+			   sizeof(uniphier_holding_pen_release));
+
+	mmio_write_64(UNIPHIER_ROM_RSV0,
+		      (uint64_t)&uniphier_warmboot_entrypoint);
+	sev();
+
+	return PSCI_E_SUCCESS;
+}
+
+static void uniphier_psci_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	uniphier_gic_cpuif_disable();
+}
+
+static void uniphier_psci_pwr_domain_on_finish(
+					const psci_power_state_t *target_state)
+{
+	uniphier_gic_pcpu_init();
+	uniphier_gic_cpuif_enable();
+
+	uniphier_cci_enable();
+}
+
+static void __dead2 uniphier_psci_pwr_domain_pwr_down_wfi(
+					const psci_power_state_t *target_state)
+{
+	/*
+	 * The Boot ROM cannot distinguish warn and cold resets.
+	 * Instead of the CPU reset, fake it.
+	 */
+	uniphier_holding_pen_release = MPIDR_AFFINITY_INVALID;
+	flush_dcache_range((uint64_t)&uniphier_holding_pen_release,
+			   sizeof(uniphier_holding_pen_release));
+
+	uniphier_fake_pwr_down();
+}
+
+static void uniphier_self_system_reset(void)
+{
+	mmio_clrbits_32(UNIPHIER_SLFRSTSEL, UNIPHIER_SLFRSTSEL_MASK);
+	mmio_setbits_32(UNIPHIER_SLFRSTCTL, UNIPHIER_SLFRSTCTL_RST);
+}
+
+static void __dead2 uniphier_psci_system_off(void)
+{
+	if (uniphier_psci_scp_mode) {
+		uniphier_scp_system_off();
+	} else {
+		NOTICE("SCP is disabled; can't shutdown the system.\n");
+		NOTICE("Resetting the system instead.\n");
+		uniphier_self_system_reset();
+	}
+
+	wfi();
+	ERROR("UniPhier System Off: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 uniphier_psci_system_reset(void)
+{
+	if (uniphier_psci_scp_mode)
+		uniphier_scp_system_reset();
+	else
+		uniphier_self_system_reset();
+
+	wfi();
+	ERROR("UniPhier System Reset: operation not handled.\n");
+	panic();
+}
+
+static const struct plat_psci_ops uniphier_psci_ops = {
+	.pwr_domain_on = uniphier_psci_pwr_domain_on,
+	.pwr_domain_off = uniphier_psci_pwr_domain_off,
+	.pwr_domain_on_finish = uniphier_psci_pwr_domain_on_finish,
+	.pwr_domain_pwr_down_wfi = uniphier_psci_pwr_domain_pwr_down_wfi,
+	.system_off = uniphier_psci_system_off,
+	.system_reset = uniphier_psci_system_reset,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const struct plat_psci_ops **psci_ops)
+{
+	uniphier_sec_entrypoint = sec_entrypoint;
+	flush_dcache_range((uint64_t)&uniphier_sec_entrypoint,
+			   sizeof(uniphier_sec_entrypoint));
+
+	uniphier_psci_scp_mode = uniphier_scp_is_running();
+	flush_dcache_range((uint64_t)&uniphier_psci_scp_mode,
+			   sizeof(uniphier_psci_scp_mode));
+
+	if (uniphier_psci_scp_mode)
+		uniphier_scp_open_com();
+
+	*psci_ops = &uniphier_psci_ops;
+
+	return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_scp.c b/plat/socionext/uniphier/uniphier_scp.c
new file mode 100644
index 0000000..9a921c4
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_scp.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mmio.h>
+#include <utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_ROM_RSV3		0x5980120c
+
+#define UNIPHIER_STMBE2COM		0x5f800030
+#define UNIPHIER_BETOSTMIRQ0PT		0x5f800070
+
+#define UNIPHIER_SCP_READY_MAGIC	0x0000b6a5
+
+#define UNIPHIER_SCP_PACKET_START	0xA0
+#define UNIPHIER_SCP_PACKET_END		0xA5
+#define UNIPHIER_SCP_PACKET_ESC		0xA6
+#define UNIPHIER_SCP_IS_CTRL_CODE(c)	(0xA0 <= (c) && (c) <= 0xA6)
+
+int uniphier_scp_is_running(void)
+{
+	return mmio_read_32(UNIPHIER_STMBE2COM) == UNIPHIER_SCP_READY_MAGIC;
+}
+
+void uniphier_scp_start(void)
+{
+	uint32_t tmp;
+
+	mmio_write_32(UNIPHIER_STMBE2COM + 4, UNIPHIER_SCP_BASE);
+	mmio_write_32(UNIPHIER_STMBE2COM, UNIPHIER_SCP_READY_MAGIC);
+
+	do {
+		tmp = mmio_read_32(UNIPHIER_ROM_RSV3);
+	} while (!(tmp & BIT(8)));
+
+	mmio_write_32(UNIPHIER_ROM_RSV3, tmp | BIT(9));
+}
+
+static void uniphier_scp_send_packet(const uint8_t *packet, int packet_len)
+{
+	uintptr_t reg = UNIPHIER_STMBE2COM;
+	uint32_t word;
+	int len, i;
+
+	while (packet_len) {
+		len = MIN(packet_len, 4);
+		word = 0;
+
+		for (i = 0; i < len; i++)
+			word |= *packet++ << (8 * i);
+
+		mmio_write_32(reg, word);
+		reg += 4;
+		packet_len -= len;
+	}
+
+	mmio_write_8(UNIPHIER_BETOSTMIRQ0PT, 0x55);
+}
+
+static void uniphier_scp_send_cmd(const uint8_t *cmd, int cmd_len)
+{
+	uint8_t packet[32];	/* long enough */
+	uint8_t *p = packet;
+	uint8_t c;
+	int i;
+
+	*p++ = UNIPHIER_SCP_PACKET_START;
+	*p++ = cmd_len;
+
+	for (i = 0; i < cmd_len; i++) {
+		c = *cmd++;
+		if (UNIPHIER_SCP_IS_CTRL_CODE(c)) {
+			*p++ = UNIPHIER_SCP_PACKET_ESC;
+			*p++ = c ^ BIT(7);
+		} else {
+			*p++ = c;
+		}
+	}
+
+	*p++ = UNIPHIER_SCP_PACKET_END;
+
+	uniphier_scp_send_packet(packet, p - packet);
+}
+
+#define UNIPHIER_SCP_CMD(name, ...)					\
+static const uint8_t __uniphier_scp_##name##_cmd[] = {			\
+	__VA_ARGS__							\
+};									\
+void uniphier_scp_##name(void)						\
+{									\
+	uniphier_scp_send_cmd(__uniphier_scp_##name##_cmd,		\
+			      ARRAY_SIZE(__uniphier_scp_##name##_cmd));	\
+}
+
+UNIPHIER_SCP_CMD(open_com, 0x00, 0x00, 0x05)
+UNIPHIER_SCP_CMD(system_off, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01)
+UNIPHIER_SCP_CMD(system_reset, 0x00, 0x02, 0x00)
diff --git a/plat/socionext/uniphier/uniphier_smp.S b/plat/socionext/uniphier/uniphier_smp.S
new file mode 100644
index 0000000..d6cb9ff
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_smp.S
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+	.globl	uniphier_warmboot_entrypoint
+	.globl	uniphier_fake_pwr_down
+
+func uniphier_warmboot_entrypoint
+	mrs	x0, mpidr_el1
+	mov_imm	x1, MPIDR_AFFINITY_MASK
+	and	x0, x0, x1
+	b	1f
+0:	wfe
+1:	ldr	x1, uniphier_holding_pen_release
+	cmp	x1, x0
+	b.ne	0b
+	ldr	x0, uniphier_sec_entrypoint
+	br	x0
+endfunc uniphier_warmboot_entrypoint
+
+func uniphier_fake_pwr_down
+	bl	disable_mmu_icache_el3
+	b	uniphier_warmboot_entrypoint
+endfunc uniphier_fake_pwr_down
diff --git a/plat/socionext/uniphier/uniphier_soc_info.c b/plat/socionext/uniphier/uniphier_soc_info.c
new file mode 100644
index 0000000..55688f3
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_soc_info.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mmio.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_REVISION		0x5f800000
+
+static unsigned int uniphier_get_revision_field(unsigned int mask,
+						unsigned int shift)
+{
+	uint32_t revision = mmio_read_32(UNIPHIER_REVISION);
+
+	return (revision >> shift) & mask;
+}
+
+unsigned int uniphier_get_soc_type(void)
+{
+	return uniphier_get_revision_field(0xff, 16);
+}
+
+unsigned int uniphier_get_soc_model(void)
+{
+	return uniphier_get_revision_field(0x07, 8);
+}
+
+unsigned int uniphier_get_soc_revision(void)
+{
+	return uniphier_get_revision_field(0x1f, 0);
+}
+
+unsigned int uniphier_get_soc_id(void)
+{
+	uint32_t type = uniphier_get_soc_type();
+
+	switch (type) {
+	case 0x31:
+		return UNIPHIER_SOC_LD11;
+	case 0x32:
+		return UNIPHIER_SOC_LD20;
+	case 0x35:
+		return UNIPHIER_SOC_PXS3;
+	default:
+		return UNIPHIER_SOC_UNKNOWN;
+	}
+}
diff --git a/plat/socionext/uniphier/uniphier_syscnt.c b/plat/socionext/uniphier/uniphier_syscnt.c
new file mode 100644
index 0000000..d7bcaf8
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_syscnt.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform.h>
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return 50000000;
+}
diff --git a/plat/socionext/uniphier/uniphier_tbbr.c b/plat/socionext/uniphier/uniphier_tbbr.c
new file mode 100644
index 0000000..cafe1a3
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_tbbr.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform.h>
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+			unsigned int *flags)
+{
+	*flags = ROTPK_NOT_DEPLOYED;
+
+	return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+	/*
+	 * No support for non-volatile counter.  Update the ROT key to protect
+	 * the system against rollback.
+	 */
+	*nv_ctr = 0;
+
+	return 0;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+	return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_topology.c b/plat/socionext/uniphier/uniphier_topology.c
new file mode 100644
index 0000000..1f96f58
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_topology.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <platform.h>
+
+#include "uniphier.h"
+
+static unsigned char uniphier_power_domain_tree_desc[UNIPHIER_CLUSTER_COUNT + 1];
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	int i;
+
+	uniphier_power_domain_tree_desc[0] = UNIPHIER_CLUSTER_COUNT;
+
+	for (i = 0; i < UNIPHIER_CLUSTER_COUNT; i++)
+		uniphier_power_domain_tree_desc[i + 1] =
+						UNIPHIER_MAX_CPUS_PER_CLUSTER;
+
+	return uniphier_power_domain_tree_desc;
+}
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	if (cluster_id >= UNIPHIER_CLUSTER_COUNT)
+		return -1;
+
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+	if (cpu_id >= UNIPHIER_MAX_CPUS_PER_CLUSTER)
+		return -1;
+
+	return uniphier_calc_core_pos(mpidr);
+}
diff --git a/plat/socionext/uniphier/uniphier_usb.c b/plat/socionext/uniphier/uniphier_usb.c
new file mode 100644
index 0000000..49ca8e5
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_usb.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <io/io_block.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <sys/types.h>
+#include <utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_LD11_USB_DESC_BASE	0x30010000
+#define UNIPHIER_LD20_USB_DESC_BASE	0x30014000
+
+#define UNIPHIER_SRB_OCM_CONT		0x61200000
+
+struct uniphier_ld11_trans_op {
+	uint8_t __pad[48];
+};
+
+struct uniphier_ld11_op {
+	uint8_t __pad[56];
+	struct uniphier_ld11_trans_op *trans_op;
+	void *__pad2;
+	void *dev_desc;
+};
+
+struct uniphier_ld20_trans_op {
+	uint8_t __pad[40];
+};
+
+struct uniphier_ld20_op {
+	uint8_t __pad[192];
+	struct uniphier_ld20_trans_op *trans_op;
+	void *__pad2;
+	void *dev_desc;
+};
+
+static int (*__uniphier_usb_read)(int lba, uintptr_t buf, size_t size);
+
+static void uniphier_ld11_usb_init(void)
+{
+	struct uniphier_ld11_op *op = (void *)UNIPHIER_LD11_USB_DESC_BASE;
+
+	op->trans_op = (void *)(op + 1);
+
+	op->dev_desc = op->trans_op + 1;
+}
+
+static int uniphier_ld11_usb_read(int lba, uintptr_t buf, size_t size)
+{
+	static int (*rom_usb_read)(uintptr_t desc, unsigned int lba,
+				   unsigned int size, uintptr_t buf);
+	uintptr_t func_addr;
+
+	func_addr = uniphier_get_soc_revision() == 1 ? 0x3880 : 0x3958;
+	rom_usb_read = (__typeof(rom_usb_read))func_addr;
+
+	return rom_usb_read(UNIPHIER_LD11_USB_DESC_BASE, lba, size, buf);
+}
+
+static void uniphier_ld20_usb_init(void)
+{
+	struct uniphier_ld20_op *op = (void *)UNIPHIER_LD20_USB_DESC_BASE;
+
+	op->trans_op = (void *)(op + 1);
+
+	op->dev_desc = op->trans_op + 1;
+}
+
+static int uniphier_ld20_usb_read(int lba, uintptr_t buf, size_t size)
+{
+	static int (*rom_usb_read)(uintptr_t desc, unsigned int lba,
+				   unsigned int size, uintptr_t buf);
+	int ret;
+
+	rom_usb_read = (__typeof(rom_usb_read))0x37f0;
+
+	mmio_write_32(UNIPHIER_SRB_OCM_CONT, 0x1ff);
+
+	/* ROM-API - return 1 on success, 0 on error */
+	ret = rom_usb_read(UNIPHIER_LD20_USB_DESC_BASE, lba, size, buf);
+
+	mmio_write_32(UNIPHIER_SRB_OCM_CONT, 0);
+
+	return ret ? 0 : -1;
+}
+
+static int uniphier_pxs3_usb_read(int lba, uintptr_t buf, size_t size)
+{
+	static int (*rom_usb_read)(unsigned int lba, unsigned int size,
+				   uintptr_t buf);
+
+	rom_usb_read = (__typeof(rom_usb_read))0x100c;
+
+	return rom_usb_read(lba, size, buf);
+}
+
+struct uniphier_usb_rom_param {
+	void (*init)(void);
+	int (*read)(int lba, uintptr_t buf, size_t size);
+};
+
+static const struct uniphier_usb_rom_param uniphier_usb_rom_params[] = {
+	[UNIPHIER_SOC_LD11] = {
+		.init = uniphier_ld11_usb_init,
+		.read = uniphier_ld11_usb_read,
+	},
+	[UNIPHIER_SOC_LD20] = {
+		.init = uniphier_ld20_usb_init,
+		.read = uniphier_ld20_usb_read,
+	},
+	[UNIPHIER_SOC_PXS3] = {
+		.read = uniphier_pxs3_usb_read,
+	},
+};
+
+static size_t uniphier_usb_read(int lba, uintptr_t buf, size_t size)
+{
+	int ret;
+
+	inv_dcache_range(buf, size);
+
+	ret = __uniphier_usb_read(lba, buf, size);
+
+	inv_dcache_range(buf, size);
+
+	return ret ? 0 : size;
+}
+
+static struct io_block_dev_spec uniphier_usb_dev_spec = {
+	.buffer = {
+		.offset = UNIPHIER_BLOCK_BUF_BASE,
+		.length = UNIPHIER_BLOCK_BUF_SIZE,
+	},
+	.ops = {
+		.read = uniphier_usb_read,
+	},
+	.block_size = 512,
+};
+
+int uniphier_usb_init(unsigned int soc, uintptr_t *block_dev_spec)
+{
+	const struct uniphier_usb_rom_param *param;
+
+	assert(soc < ARRAY_SIZE(uniphier_usb_rom_params));
+	param = &uniphier_usb_rom_params[soc];
+
+	if (param->init)
+		param->init();
+
+	__uniphier_usb_read = param->read;
+
+	*block_dev_spec = (uintptr_t)&uniphier_usb_dev_spec;
+
+	return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_xlat_setup.c b/plat/socionext/uniphier/uniphier_xlat_setup.c
new file mode 100644
index 0000000..6532c49
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_xlat_setup.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <platform_def.h>
+#include <xlat_tables_v2.h>
+
+#define UNIPHIER_OCM_REGION_BASE	0x30000000
+#define UNIPHIER_OCM_REGION_SIZE	0x00040000
+
+#define UNIPHIER_REG_REGION_BASE	0x50000000
+#define UNIPHIER_REG_REGION_SIZE	0x20000000
+
+void uniphier_mmap_setup(uintptr_t total_base, size_t total_size,
+			 const struct mmap_region *mmap)
+{
+	VERBOSE("Trusted RAM 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);
+
+	/* remap the code section */
+	VERBOSE("Code region: %p - %p\n",
+		(void *)BL_CODE_BASE, (void *)BL_CODE_END);
+	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
+			round_up(BL_CODE_END, PAGE_SIZE) - BL_CODE_BASE,
+			MT_CODE | MT_SECURE);
+
+	/* remap the coherent memory region */
+	VERBOSE("Coherent region: %p - %p\n",
+		(void *)BL_COHERENT_RAM_BASE, (void *)BL_COHERENT_RAM_END);
+	mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE,
+			BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+			MT_DEVICE | MT_RW | MT_SECURE);
+
+	/*
+	 * on-chip SRAM region: should be DEVICE attribute because the USB
+	 * load functions provided by the ROM use this memory region as a work
+	 * area, but do not cater to cache coherency.
+	 */
+	mmap_add_region(UNIPHIER_OCM_REGION_BASE, UNIPHIER_OCM_REGION_BASE,
+			UNIPHIER_OCM_REGION_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE);
+
+	/* register region */
+	mmap_add_region(UNIPHIER_REG_REGION_BASE, UNIPHIER_REG_REGION_BASE,
+			UNIPHIER_REG_REGION_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE);
+
+	/* additional regions if needed */
+	if (mmap)
+		mmap_add(mmap);
+
+	init_xlat_tables();
+}