uniphier: support Socionext UniPhier platform
authorMasahiro Yamada <yamada.masahiro@socionext.com>
Sat, 3 Sep 2016 02:37:40 +0000 (11:37 +0900)
committerMasahiro Yamada <yamada.masahiro@socionext.com>
Mon, 12 Jun 2017 15:32:57 +0000 (00:32 +0900)
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>
28 files changed:
acknowledgements.md
docs/plat/socionext-uniphier.md [new file with mode: 0644]
plat/socionext/uniphier/include/plat_macros.S [new file with mode: 0644]
plat/socionext/uniphier/include/platform_def.h [new file with mode: 0644]
plat/socionext/uniphier/platform.mk [new file with mode: 0644]
plat/socionext/uniphier/uniphier.h [new file with mode: 0644]
plat/socionext/uniphier/uniphier_bl1_helpers.S [new file with mode: 0644]
plat/socionext/uniphier/uniphier_bl1_setup.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_bl2_setup.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_bl31_setup.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_boot_device.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_cci.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_console.S [new file with mode: 0644]
plat/socionext/uniphier/uniphier_emmc.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_gicv3.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_helpers.S [new file with mode: 0644]
plat/socionext/uniphier/uniphier_image_desc.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_io_storage.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_nand.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_psci.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_scp.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_smp.S [new file with mode: 0644]
plat/socionext/uniphier/uniphier_soc_info.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_syscnt.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_tbbr.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_topology.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_usb.c [new file with mode: 0644]
plat/socionext/uniphier/uniphier_xlat_setup.c [new file with mode: 0644]

index 2f6309ea0bf41eb08a7ddb57b38db9d25ee685cb..028f321dba7a5e5b6657a73bff0d327aa10a3039 100644 (file)
@@ -7,6 +7,8 @@ Linaro Limited
 
 NVIDIA Corporation
 
+Socionext Inc.
+
 Xilinx, Inc.
 
 Individuals
diff --git a/docs/plat/socionext-uniphier.md b/docs/plat/socionext-uniphier.md
new file mode 100644 (file)
index 0000000..75e6545
--- /dev/null
@@ -0,0 +1,123 @@
+ARM Trusted Firmware for Socionext UniPhier SoCs
+================================================
+
+Socionext UniPhier ARMv8-A SoCs use ARM Trusted Firmware as the secure world
+firmware, supporting BL1, BL2, and BL31.
+
+UniPhier SoC family implements its internal boot ROM, so BL1 is used as pseudo
+ROM (i.e. runs in RAM).  The internal boot ROM loads 64KB [1] image from a
+non-volatile storage to the on-chip SRAM.  Unfortunately, BL1 does not fit in
+the 64KB limit if [Trusted Board Boot] (TBB) is enabled.  To solve this problem,
+Socionext provides a first stage loader called [UniPhier BL].  This loader runs
+in the on-chip SRAM, initializes the DRAM, expands BL1 there, and hands the
+control over to it.  Therefore, all images of ARM Trusted Firmware run in DRAM.
+
+The UniPhier platform works with/without TBB.  See below for the build process
+of each case.  The image authentication for the UniPhier platform fully
+complies with the Trusted Board Boot Requirements (TBBR) specification.
+
+The UniPhier BL does not implement the authentication functionality, that is,
+it can not verify the BL1 image by itself.  Instead, the UniPhier BL assures
+the BL1 validity in a different way; BL1 is GZIP-compressed and appended to
+the UniPhier BL.  The concatenation of the UniPhier BL and the compressed BL1
+fits in the 64KB limit.  The concatenated image is loaded by the boot ROM
+(and verified if the chip fuses are blown).
+
+[1]: Some SoCs can load 80KB, but the software implementation must be aligned
+     to the lowest common denominator.
+
+[Trusted Board Boot]: ../trusted-board-boot.md
+
+[UniPhier BL]: https://github.com/uniphier/uniphier-bl
+
+
+Boot Flow
+---------
+
+1. The Boot ROM
+
+  This is hard-wired ROM, so never corrupted.  It loads the UniPhier BL (with
+  compressed-BL1 appended) into the on-chip SRAM.  If the SoC fuses are blown,
+  the image is verified by the SoC's own method.
+
+2. UniPhier BL
+
+  This runs in the on-chip SRAM.  After the minimum SoC initialization and DRAM
+  setup, it decompresses the appended BL1 image into the DRAM, then jumps to
+  the BL1 entry.
+
+3. BL1
+
+  This runs in the DRAM.  It extracts BL2 from FIP (Firmware Image Package).
+  If TBB is enabled, the BL2 is authenticated by the standard mechanism of ARM
+  Trusted Firmware.
+
+4. BL2, BL31, and more
+
+  They all run in the DRAM, and are authenticated by the standard mechanism if
+  TBB is enabled.  See [Firmware Design] for details.
+
+[Firmware Design]: ../firmware-design.md
+
+
+Basic Build
+-----------
+
+BL1 must be compressed for the reason above.  The UniPhier's platform makefile
+provides a build target `bl1_gzip` for this.
+
+For a non-secure boot loader (aka BL33), U-Boot is well supported for UniPhier
+SoCs.  The U-Boot image (`u-boot.bin`) must be built in advance.  For the build
+procedure of U-Boot, refer to the document in the [U-Boot] project.
+
+[U-Boot]: https://www.denx.de/wiki/U-Boot
+
+To build minimum functionality for UniPhier (without TBB):
+
+```
+make CROSS_COMPILE=<gcc-prefix> PLAT=uniphier BL33=<path-to-BL33> bl1_gzip fip
+```
+
+Output images:
+
+- `bl1.bin.gzip`
+- `fip.bin`
+
+
+Optional features
+-----------------
+
+- Trusted Board Boot
+
+[mbed TLS] is needed as the cryptographic and image parser modules.
+Refer to the [User Guide] for the appropriate version of mbed TLS.
+
+To enable TBB, add the following options to the build command:
+
+```
+  TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 MBEDTLS_DIR=<path-to-mbedtls>
+```
+
+[mbed TLS]: https://tls.mbed.org/
+
+[User Guide]: ../user-guide.md
+
+- System Control Processor (SCP)
+
+If desired, FIP can include an SCP BL2 image.  If BL2 finds an SCP BL2 image
+in FIP, BL2 loads it into DRAM and kicks the SCP.  Most of UniPhier boards
+still work without SCP, but SCP provides better power management support.
+
+To include SCP_BL2, add the following option to the build command:
+
+```
+  SCP_BL2=<path-to-SCP>
+```
+
+- BL32 (Secure Payload)
+
+To enable BL32, add the following option to the build command:
+
+```
+  SPD=<spd> BL32=<path-to-BL32>
+```
diff --git a/plat/socionext/uniphier/include/plat_macros.S b/plat/socionext/uniphier/include/plat_macros.S
new file mode 100644 (file)
index 0000000..6de4dde
--- /dev/null
@@ -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 (file)
index 0000000..7e603a3
--- /dev/null
@@ -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 (file)
index 0000000..af8e3ac
--- /dev/null
@@ -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 (file)
index 0000000..95b29b8
--- /dev/null
@@ -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 (file)
index 0000000..5818565
--- /dev/null
@@ -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 (file)
index 0000000..da7740a
--- /dev/null
@@ -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 (file)
index 0000000..b83e700
--- /dev/null
@@ -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 (file)
index 0000000..d9c87bd
--- /dev/null
@@ -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 (file)
index 0000000..78ca8ef
--- /dev/null
@@ -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 (file)
index 0000000..30f4b47
--- /dev/null
@@ -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 (file)
index 0000000..03aff48
--- /dev/null
@@ -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 (file)
index 0000000..fcd4cb4
--- /dev/null
@@ -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 (file)
index 0000000..05a4e35
--- /dev/null
@@ -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 (file)
index 0000000..105cf9e
--- /dev/null
@@ -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 (file)
index 0000000..1e474c5
--- /dev/null
@@ -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 (file)
index 0000000..bc31350
--- /dev/null
@@ -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 (file)
index 0000000..acf6a74
--- /dev/null
@@ -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 (file)
index 0000000..82081a0
--- /dev/null
@@ -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 (file)
index 0000000..9a921c4
--- /dev/null
@@ -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 (file)
index 0000000..d6cb9ff
--- /dev/null
@@ -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 (file)
index 0000000..55688f3
--- /dev/null
@@ -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 (file)
index 0000000..d7bcaf8
--- /dev/null
@@ -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 (file)
index 0000000..cafe1a3
--- /dev/null
@@ -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 (file)
index 0000000..1f96f58
--- /dev/null
@@ -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 (file)
index 0000000..49ca8e5
--- /dev/null
@@ -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 (file)
index 0000000..6532c49
--- /dev/null
@@ -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();
+}