summaryrefslogtreecommitdiffstats
path: root/plat/socionext
diff options
context:
space:
mode:
Diffstat (limited to 'plat/socionext')
-rw-r--r--plat/socionext/synquacer/drivers/mhu/sq_mhu.c98
-rw-r--r--plat/socionext/synquacer/drivers/mhu/sq_mhu.h19
-rw-r--r--plat/socionext/synquacer/drivers/scp/sq_scmi.c244
-rw-r--r--plat/socionext/synquacer/drivers/scp/sq_scp.c21
-rw-r--r--plat/socionext/synquacer/drivers/scpi/sq_scpi.c219
-rw-r--r--plat/socionext/synquacer/drivers/scpi/sq_scpi.h83
-rw-r--r--plat/socionext/synquacer/include/plat.ld.S31
-rw-r--r--plat/socionext/synquacer/include/plat_macros.S16
-rw-r--r--plat/socionext/synquacer/include/platform_def.h207
-rw-r--r--plat/socionext/synquacer/include/sq_common.h56
-rw-r--r--plat/socionext/synquacer/platform.mk117
-rw-r--r--plat/socionext/synquacer/sq_bl2_setup.c84
-rw-r--r--plat/socionext/synquacer/sq_bl31_setup.c247
-rw-r--r--plat/socionext/synquacer/sq_ccn.c45
-rw-r--r--plat/socionext/synquacer/sq_gicv3.c94
-rw-r--r--plat/socionext/synquacer/sq_helpers.S115
-rw-r--r--plat/socionext/synquacer/sq_image_desc.c76
-rw-r--r--plat/socionext/synquacer/sq_io_storage.c246
-rw-r--r--plat/socionext/synquacer/sq_psci.c215
-rw-r--r--plat/socionext/synquacer/sq_rotpk.S16
-rw-r--r--plat/socionext/synquacer/sq_spm.c75
-rw-r--r--plat/socionext/synquacer/sq_tbbr.c40
-rw-r--r--plat/socionext/synquacer/sq_topology.c40
-rw-r--r--plat/socionext/synquacer/sq_xlat_setup.c56
-rw-r--r--plat/socionext/uniphier/include/plat_macros.S13
-rw-r--r--plat/socionext/uniphier/include/platform_def.h76
-rw-r--r--plat/socionext/uniphier/platform.mk140
-rw-r--r--plat/socionext/uniphier/tsp/tsp-uniphier.mk9
-rw-r--r--plat/socionext/uniphier/tsp/uniphier_tsp_setup.c34
-rw-r--r--plat/socionext/uniphier/uniphier.h76
-rw-r--r--plat/socionext/uniphier/uniphier_bl2_setup.c166
-rw-r--r--plat/socionext/uniphier/uniphier_bl31_setup.c89
-rw-r--r--plat/socionext/uniphier/uniphier_boot_device.c189
-rw-r--r--plat/socionext/uniphier/uniphier_cci.c81
-rw-r--r--plat/socionext/uniphier/uniphier_console.S65
-rw-r--r--plat/socionext/uniphier/uniphier_console.h25
-rw-r--r--plat/socionext/uniphier/uniphier_console_setup.c94
-rw-r--r--plat/socionext/uniphier/uniphier_emmc.c308
-rw-r--r--plat/socionext/uniphier/uniphier_gicv3.c116
-rw-r--r--plat/socionext/uniphier/uniphier_helpers.S34
-rw-r--r--plat/socionext/uniphier/uniphier_image_desc.c119
-rw-r--r--plat/socionext/uniphier/uniphier_io_storage.c373
-rw-r--r--plat/socionext/uniphier/uniphier_nand.c283
-rw-r--r--plat/socionext/uniphier/uniphier_psci.c167
-rw-r--r--plat/socionext/uniphier/uniphier_rotpk.S16
-rw-r--r--plat/socionext/uniphier/uniphier_scp.c107
-rw-r--r--plat/socionext/uniphier/uniphier_smp.S29
-rw-r--r--plat/socionext/uniphier/uniphier_soc_info.c57
-rw-r--r--plat/socionext/uniphier/uniphier_syscnt.c12
-rw-r--r--plat/socionext/uniphier/uniphier_tbbr.c40
-rw-r--r--plat/socionext/uniphier/uniphier_topology.c40
-rw-r--r--plat/socionext/uniphier/uniphier_usb.c183
-rw-r--r--plat/socionext/uniphier/uniphier_xlat_setup.c81
53 files changed, 5482 insertions, 0 deletions
diff --git a/plat/socionext/synquacer/drivers/mhu/sq_mhu.c b/plat/socionext/synquacer/drivers/mhu/sq_mhu.c
new file mode 100644
index 0000000..925ed97
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/mhu/sq_mhu.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <sq_common.h>
+#include "sq_mhu.h"
+
+/* SCP MHU secure channel registers */
+#define SCP_INTR_S_STAT 0x200
+#define SCP_INTR_S_SET 0x208
+#define SCP_INTR_S_CLEAR 0x210
+
+/* CPU MHU secure channel registers */
+#define CPU_INTR_S_STAT 0x300
+#define CPU_INTR_S_SET 0x308
+#define CPU_INTR_S_CLEAR 0x310
+
+DEFINE_BAKERY_LOCK(sq_lock);
+
+/*
+ * Slot 31 is reserved because the MHU hardware uses this register bit to
+ * indicate a non-secure access attempt. The total number of available slots is
+ * therefore 31 [30:0].
+ */
+#define MHU_MAX_SLOT_ID 30
+
+void mhu_secure_message_start(unsigned int slot_id)
+{
+ assert(slot_id <= MHU_MAX_SLOT_ID);
+
+ bakery_lock_get(&sq_lock);
+
+ /* Make sure any previous command has finished */
+ while (mmio_read_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_STAT) &
+ (1 << slot_id))
+ ;
+}
+
+void mhu_secure_message_send(unsigned int slot_id)
+{
+ assert(slot_id <= MHU_MAX_SLOT_ID);
+ assert(!(mmio_read_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_STAT) &
+ (1 << slot_id)));
+
+ /* Send command to SCP */
+ mmio_write_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_SET, 1 << slot_id);
+}
+
+uint32_t mhu_secure_message_wait(void)
+{
+ uint32_t response;
+
+ /* Wait for response from SCP */
+ while (!(response = mmio_read_32(PLAT_SQ_MHU_BASE + SCP_INTR_S_STAT)))
+ ;
+
+ return response;
+}
+
+void mhu_secure_message_end(unsigned int slot_id)
+{
+ assert(slot_id <= MHU_MAX_SLOT_ID);
+
+ /*
+ * Clear any response we got by writing one in the relevant slot bit to
+ * the CLEAR register
+ */
+ mmio_write_32(PLAT_SQ_MHU_BASE + SCP_INTR_S_CLEAR, 1 << slot_id);
+
+ bakery_lock_release(&sq_lock);
+}
+
+void mhu_secure_init(void)
+{
+ bakery_lock_init(&sq_lock);
+
+ /*
+ * The STAT register resets to zero. Ensure it is in the expected state,
+ * as a stale or garbage value would make us think it's a message we've
+ * already sent.
+ */
+ assert(mmio_read_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_STAT) == 0);
+}
+
+void plat_sq_pwrc_setup(void)
+{
+ mhu_secure_init();
+}
diff --git a/plat/socionext/synquacer/drivers/mhu/sq_mhu.h b/plat/socionext/synquacer/drivers/mhu/sq_mhu.h
new file mode 100644
index 0000000..f6b5cc3
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/mhu/sq_mhu.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SQ_MHU_H
+#define SQ_MHU_H
+
+#include <stdint.h>
+
+void mhu_secure_message_start(unsigned int slot_id);
+void mhu_secure_message_send(unsigned int slot_id);
+uint32_t mhu_secure_message_wait(void);
+void mhu_secure_message_end(unsigned int slot_id);
+
+void mhu_secure_init(void);
+
+#endif /* SQ_MHU_H */
diff --git a/plat/socionext/synquacer/drivers/scp/sq_scmi.c b/plat/socionext/synquacer/drivers/scp/sq_scmi.c
new file mode 100644
index 0000000..0e99256
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scp/sq_scmi.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/css/common/css_pm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include <scmi_sq.h>
+#include <sq_common.h>
+
+/*
+ * This file implements the SCP helper functions using SCMI protocol.
+ */
+
+DEFINE_BAKERY_LOCK(sq_scmi_lock);
+#define SQ_SCMI_LOCK_GET_INSTANCE (&sq_scmi_lock)
+
+#define SQ_SCMI_PAYLOAD_BASE PLAT_SQ_SCP_COM_SHARED_MEM_BASE
+#define MHU_CPU_INTR_S_SET_OFFSET 0x308
+
+const uint32_t sq_core_pos_to_scmi_dmn_id_map[PLATFORM_CORE_COUNT] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23
+};
+
+static scmi_channel_plat_info_t sq_scmi_plat_info = {
+ .scmi_mbx_mem = SQ_SCMI_PAYLOAD_BASE,
+ .db_reg_addr = PLAT_SQ_MHU_BASE + MHU_CPU_INTR_S_SET_OFFSET,
+ .db_preserve_mask = 0xfffffffe,
+ .db_modify_mask = 0x1,
+ .ring_doorbell = &mhu_ring_doorbell,
+};
+
+/*
+ * SCMI power state parameter bit field encoding for SynQuacer platform.
+ *
+ * 31 20 19 16 15 12 11 8 7 4 3 0
+ * +-------------------------------------------------------------+
+ * | SBZ | Max level | Level 3 | Level 2 | Level 1 | Level 0 |
+ * | | | state | state | state | state |
+ * +-------------------------------------------------------------+
+ *
+ * `Max level` encodes the highest level that has a valid power state
+ * encoded in the power state.
+ */
+#define SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT 16
+#define SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH 4
+#define SCMI_PWR_STATE_MAX_PWR_LVL_MASK \
+ ((1 << SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH) - 1)
+#define SCMI_SET_PWR_STATE_MAX_PWR_LVL(_power_state, _max_level) \
+ (_power_state) |= ((_max_level) & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)\
+ << SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT
+#define SCMI_GET_PWR_STATE_MAX_PWR_LVL(_power_state) \
+ (((_power_state) >> SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT) \
+ & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)
+
+#define SCMI_PWR_STATE_LVL_WIDTH 4
+#define SCMI_PWR_STATE_LVL_MASK \
+ ((1 << SCMI_PWR_STATE_LVL_WIDTH) - 1)
+#define SCMI_SET_PWR_STATE_LVL(_power_state, _level, _level_state) \
+ (_power_state) |= ((_level_state) & SCMI_PWR_STATE_LVL_MASK) \
+ << (SCMI_PWR_STATE_LVL_WIDTH * (_level))
+#define SCMI_GET_PWR_STATE_LVL(_power_state, _level) \
+ (((_power_state) >> (SCMI_PWR_STATE_LVL_WIDTH * (_level))) & \
+ SCMI_PWR_STATE_LVL_MASK)
+
+/*
+ * The SCMI power state enumeration for a power domain level
+ */
+typedef enum {
+ scmi_power_state_off = 0,
+ scmi_power_state_on = 1,
+ scmi_power_state_sleep = 2,
+} scmi_power_state_t;
+
+/*
+ * The global handle for invoking the SCMI driver APIs after the driver
+ * has been initialized.
+ */
+static void *sq_scmi_handle;
+
+/* The SCMI channel global object */
+static scmi_channel_t channel;
+
+/*
+ * Helper function to turn off a CPU power domain and
+ * its parent power domains if applicable.
+ */
+void sq_scmi_off(const struct psci_power_state *target_state)
+{
+ int lvl = 0, ret;
+ uint32_t scmi_pwr_state = 0;
+
+ /* At-least the CPU level should be specified to be OFF */
+ assert(target_state->pwr_domain_state[SQ_PWR_LVL0] ==
+ SQ_LOCAL_STATE_OFF);
+
+ for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+ if (target_state->pwr_domain_state[lvl] == SQ_LOCAL_STATE_RUN)
+ break;
+
+ assert(target_state->pwr_domain_state[lvl] ==
+ SQ_LOCAL_STATE_OFF);
+ SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+ scmi_power_state_off);
+ }
+
+ SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
+
+ ret = scmi_pwr_state_set(sq_scmi_handle,
+ sq_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()],
+ scmi_pwr_state);
+
+ if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) {
+ ERROR("SCMI set power state command return 0x%x unexpected\n",
+ ret);
+ panic();
+ }
+}
+
+/*
+ * Helper function to turn ON a CPU power domain and
+ *its parent power domains if applicable.
+ */
+void sq_scmi_on(u_register_t mpidr)
+{
+ int lvl = 0, ret, core_pos;
+ uint32_t scmi_pwr_state = 0;
+
+ for (; lvl <= PLAT_MAX_PWR_LVL; lvl++)
+ SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+ scmi_power_state_on);
+
+ SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
+
+ core_pos = plat_core_pos_by_mpidr(mpidr);
+ assert(core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT);
+
+ ret = scmi_pwr_state_set(sq_scmi_handle,
+ sq_core_pos_to_scmi_dmn_id_map[core_pos],
+ scmi_pwr_state);
+
+ if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) {
+ ERROR("SCMI set power state command return 0x%x unexpected\n",
+ ret);
+ panic();
+ }
+}
+
+void __dead2 sq_scmi_system_off(int state)
+{
+ int ret;
+
+ /*
+ * Disable GIC CPU interface to prevent pending interrupt from waking
+ * up the AP from WFI.
+ */
+ sq_gic_cpuif_disable();
+
+ /*
+ * Issue SCMI command. First issue a graceful
+ * request and if that fails force the request.
+ */
+ ret = scmi_sys_pwr_state_set(sq_scmi_handle,
+ SCMI_SYS_PWR_FORCEFUL_REQ,
+ state);
+
+ if (ret != SCMI_E_SUCCESS) {
+ ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n",
+ state, ret);
+ panic();
+ }
+ wfi();
+ ERROR("SCMI set power state: operation not handled.\n");
+ panic();
+}
+
+/*
+ * Helper function to reset the system via SCMI.
+ */
+void __dead2 sq_scmi_sys_shutdown(void)
+{
+ sq_scmi_system_off(SCMI_SYS_PWR_SHUTDOWN);
+}
+
+void __dead2 sq_scmi_sys_reboot(void)
+{
+ sq_scmi_system_off(SCMI_SYS_PWR_COLD_RESET);
+}
+
+static int scmi_ap_core_init(scmi_channel_t *ch)
+{
+#if PROGRAMMABLE_RESET_ADDRESS
+ uint32_t version;
+ int ret;
+
+ ret = scmi_proto_version(ch, SCMI_AP_CORE_PROTO_ID, &version);
+ if (ret != SCMI_E_SUCCESS) {
+ WARN("SCMI AP core protocol version message failed\n");
+ return -1;
+ }
+
+ if (!is_scmi_version_compatible(SCMI_AP_CORE_PROTO_VER, version)) {
+ WARN("SCMI AP core protocol version 0x%x incompatible with driver version 0x%x\n",
+ version, SCMI_AP_CORE_PROTO_VER);
+ return -1;
+ }
+ INFO("SCMI AP core protocol version 0x%x detected\n", version);
+#endif
+ return 0;
+}
+
+void __init plat_sq_pwrc_setup(void)
+{
+ channel.info = &sq_scmi_plat_info;
+ channel.lock = SQ_SCMI_LOCK_GET_INSTANCE;
+ sq_scmi_handle = scmi_init(&channel);
+ if (sq_scmi_handle == NULL) {
+ ERROR("SCMI Initialization failed\n");
+ panic();
+ }
+ if (scmi_ap_core_init(&channel) < 0) {
+ ERROR("SCMI AP core protocol initialization failed\n");
+ panic();
+ }
+}
+
+uint32_t sq_scmi_get_draminfo(struct draminfo *info)
+{
+ scmi_get_draminfo(sq_scmi_handle, info);
+
+ return 0;
+}
diff --git a/plat/socionext/synquacer/drivers/scp/sq_scp.c b/plat/socionext/synquacer/drivers/scp/sq_scp.c
new file mode 100644
index 0000000..e494022
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scp/sq_scp.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <sq_common.h>
+#include "sq_scpi.h"
+
+/*
+ * Helper function to get dram information from SCP.
+ */
+uint32_t sq_scp_get_draminfo(struct draminfo *info)
+{
+#if SQ_USE_SCMI_DRIVER
+ sq_scmi_get_draminfo(info);
+#else
+ scpi_get_draminfo(info);
+#endif
+ return 0;
+}
diff --git a/plat/socionext/synquacer/drivers/scpi/sq_scpi.c b/plat/socionext/synquacer/drivers/scpi/sq_scpi.c
new file mode 100644
index 0000000..0cb75a0
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scpi/sq_scpi.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <sq_common.h>
+
+#include "sq_mhu.h"
+#include "sq_scpi.h"
+
+#define SCPI_SHARED_MEM_SCP_TO_AP PLAT_SQ_SCP_COM_SHARED_MEM_BASE
+#define SCPI_SHARED_MEM_AP_TO_SCP (PLAT_SQ_SCP_COM_SHARED_MEM_BASE \
+ + 0x100)
+
+#define SCPI_CMD_HEADER_AP_TO_SCP \
+ ((scpi_cmd_t *) SCPI_SHARED_MEM_AP_TO_SCP)
+#define SCPI_CMD_PAYLOAD_AP_TO_SCP \
+ ((void *) (SCPI_SHARED_MEM_AP_TO_SCP + sizeof(scpi_cmd_t)))
+
+/* ID of the MHU slot used for the SCPI protocol */
+#define SCPI_MHU_SLOT_ID 0
+
+static void scpi_secure_message_start(void)
+{
+ mhu_secure_message_start(SCPI_MHU_SLOT_ID);
+}
+
+static void scpi_secure_message_send(size_t payload_size)
+{
+ /*
+ * Ensure that any write to the SCPI payload area is seen by SCP before
+ * we write to the MHU register. If these 2 writes were reordered by
+ * the CPU then SCP would read stale payload data
+ */
+ dmbst();
+
+ mhu_secure_message_send(SCPI_MHU_SLOT_ID);
+}
+
+static void scpi_secure_message_receive(scpi_cmd_t *cmd)
+{
+ uint32_t mhu_status;
+
+ assert(cmd != NULL);
+
+ mhu_status = mhu_secure_message_wait();
+
+ /* Expect an SCPI message, reject any other protocol */
+ if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) {
+ ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n",
+ mhu_status);
+ panic();
+ }
+
+ /*
+ * Ensure that any read to the SCPI payload area is done after reading
+ * the MHU register. If these 2 reads were reordered then the CPU would
+ * read invalid payload data
+ */
+ dmbld();
+
+ memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd));
+}
+
+static void scpi_secure_message_end(void)
+{
+ mhu_secure_message_end(SCPI_MHU_SLOT_ID);
+}
+
+int scpi_wait_ready(void)
+{
+ scpi_cmd_t scpi_cmd;
+ scpi_status_t status = SCP_OK;
+
+ VERBOSE("Waiting for SCP_READY command...\n");
+
+ /* Get a message from the SCP */
+ scpi_secure_message_start();
+ scpi_secure_message_receive(&scpi_cmd);
+ scpi_secure_message_end();
+
+ /* We are expecting 'SCP Ready', produce correct error if it's not */
+ if (scpi_cmd.id != SCPI_CMD_SCP_READY) {
+ ERROR("Unexpected SCP command: expected command #%u,"
+ "got command #%u\n", SCPI_CMD_SCP_READY, scpi_cmd.id);
+ status = SCP_E_SUPPORT;
+ } else if (scpi_cmd.size != 0) {
+ ERROR("SCP_READY command has incorrect size: expected 0,"
+ "got %u\n", scpi_cmd.size);
+ status = SCP_E_SIZE;
+ }
+
+ VERBOSE("Sending response for SCP_READY command\n");
+
+ /*
+ * Send our response back to SCP.
+ * We are using the same SCPI header, just update the status field.
+ */
+ scpi_cmd.status = status;
+ scpi_secure_message_start();
+ memcpy((void *) SCPI_SHARED_MEM_AP_TO_SCP, &scpi_cmd, sizeof(scpi_cmd));
+ scpi_secure_message_send(0);
+ scpi_secure_message_end();
+
+ return status == SCP_OK ? 0 : -1;
+}
+
+void scpi_set_sq_power_state(unsigned int mpidr, scpi_power_state_t cpu_state,
+ scpi_power_state_t cluster_state, scpi_power_state_t sq_state)
+{
+ scpi_cmd_t *cmd;
+ uint32_t state = 0;
+ uint32_t *payload_addr;
+
+ state |= mpidr & 0x0f; /* CPU ID */
+ state |= (mpidr & 0xf00) >> 4; /* Cluster ID */
+ state |= cpu_state << 8;
+ state |= cluster_state << 12;
+ state |= sq_state << 16;
+
+ scpi_secure_message_start();
+
+ /* Populate the command header */
+ cmd = SCPI_CMD_HEADER_AP_TO_SCP;
+ cmd->id = SCPI_CMD_SET_POWER_STATE;
+ cmd->set = SCPI_SET_NORMAL;
+ cmd->sender = 0;
+ cmd->size = sizeof(state);
+ /* Populate the command payload */
+ payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP;
+ *payload_addr = state;
+ scpi_secure_message_send(sizeof(state));
+
+ /*
+ * SCP does not reply to this command in order to avoid MHU interrupts
+ * from the sender, which could interfere with its power state request.
+ */
+ scpi_secure_message_end();
+}
+
+uint32_t scpi_sys_power_state(scpi_system_state_t system_state)
+{
+ scpi_cmd_t *cmd;
+ uint8_t *payload_addr;
+ scpi_cmd_t response;
+
+ scpi_secure_message_start();
+
+ /* Populate the command header */
+ cmd = SCPI_CMD_HEADER_AP_TO_SCP;
+ cmd->id = SCPI_CMD_SYS_POWER_STATE;
+ cmd->set = 0;
+ cmd->sender = 0;
+ cmd->size = sizeof(*payload_addr);
+ /* Populate the command payload */
+ payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP;
+ *payload_addr = system_state & 0xff;
+ scpi_secure_message_send(sizeof(*payload_addr));
+
+ scpi_secure_message_receive(&response);
+
+ scpi_secure_message_end();
+
+ return response.status;
+}
+
+uint32_t scpi_get_draminfo(struct draminfo *info)
+{
+ scpi_cmd_t *cmd;
+ struct {
+ scpi_cmd_t cmd;
+ struct draminfo info;
+ } response;
+ uint32_t mhu_status;
+
+ scpi_secure_message_start();
+
+ /* Populate the command header */
+ cmd = SCPI_CMD_HEADER_AP_TO_SCP;
+ cmd->id = SCPI_CMD_GET_DRAMINFO;
+ cmd->set = SCPI_SET_EXTENDED;
+ cmd->sender = 0;
+ cmd->size = 0;
+
+ scpi_secure_message_send(0);
+
+ mhu_status = mhu_secure_message_wait();
+
+ /* Expect an SCPI message, reject any other protocol */
+ if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) {
+ ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n",
+ mhu_status);
+ panic();
+ }
+
+ /*
+ * Ensure that any read to the SCPI payload area is done after reading
+ * the MHU register. If these 2 reads were reordered then the CPU would
+ * read invalid payload data
+ */
+ dmbld();
+
+ memcpy(&response, (void *)SCPI_SHARED_MEM_SCP_TO_AP, sizeof(response));
+
+ scpi_secure_message_end();
+
+ if (response.cmd.status == SCP_OK)
+ *info = response.info;
+
+ return response.cmd.status;
+}
diff --git a/plat/socionext/synquacer/drivers/scpi/sq_scpi.h b/plat/socionext/synquacer/drivers/scpi/sq_scpi.h
new file mode 100644
index 0000000..eb6ce5c
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scpi/sq_scpi.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SQ_SCPI_H
+#define SQ_SCPI_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * An SCPI command consists of a header and a payload.
+ * The following structure describes the header. It is 64-bit long.
+ */
+typedef struct {
+ /* Command ID */
+ uint32_t id : 7;
+ /* Set ID. Identifies whether this is a standard or extended command. */
+ uint32_t set : 1;
+ /* Sender ID to match a reply. The value is sender specific. */
+ uint32_t sender : 8;
+ /* Size of the payload in bytes (0 - 511) */
+ uint32_t size : 9;
+ uint32_t reserved : 7;
+ /*
+ * Status indicating the success of a command.
+ * See the enum below.
+ */
+ uint32_t status;
+} scpi_cmd_t;
+
+typedef enum {
+ SCPI_SET_NORMAL = 0, /* Normal SCPI commands */
+ SCPI_SET_EXTENDED /* Extended SCPI commands */
+} scpi_set_t;
+
+enum {
+ SCP_OK = 0, /* Success */
+ SCP_E_PARAM, /* Invalid parameter(s) */
+ SCP_E_ALIGN, /* Invalid alignment */
+ SCP_E_SIZE, /* Invalid size */
+ SCP_E_HANDLER, /* Invalid handler or callback */
+ SCP_E_ACCESS, /* Invalid access or permission denied */
+ SCP_E_RANGE, /* Value out of range */
+ SCP_E_TIMEOUT, /* Time out has ocurred */
+ SCP_E_NOMEM, /* Invalid memory area or pointer */
+ SCP_E_PWRSTATE, /* Invalid power state */
+ SCP_E_SUPPORT, /* Feature not supported or disabled */
+ SCPI_E_DEVICE, /* Device error */
+ SCPI_E_BUSY, /* Device is busy */
+};
+
+typedef uint32_t scpi_status_t;
+
+typedef enum {
+ SCPI_CMD_SCP_READY = 0x01,
+ SCPI_CMD_SET_POWER_STATE = 0x03,
+ SCPI_CMD_SYS_POWER_STATE = 0x05
+} scpi_command_t;
+
+typedef enum {
+ scpi_power_on = 0,
+ scpi_power_retention = 1,
+ scpi_power_off = 3,
+} scpi_power_state_t;
+
+typedef enum {
+ scpi_system_shutdown = 0,
+ scpi_system_reboot = 1,
+ scpi_system_reset = 2
+} scpi_system_state_t;
+
+extern int scpi_wait_ready(void);
+extern void scpi_set_sq_power_state(unsigned int mpidr,
+ scpi_power_state_t cpu_state,
+ scpi_power_state_t cluster_state,
+ scpi_power_state_t css_state);
+uint32_t scpi_sys_power_state(scpi_system_state_t system_state);
+uint32_t scpi_get_draminfo(struct draminfo *info);
+
+#endif /* SQ_SCPI_H */
diff --git a/plat/socionext/synquacer/include/plat.ld.S b/plat/socionext/synquacer/include/plat.ld.S
new file mode 100644
index 0000000..d02afa7
--- /dev/null
+++ b/plat/socionext/synquacer/include/plat.ld.S
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SYNQUACER_PLAT_LD_S__
+#define SYNQUACER_PLAT_LD_S__
+
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+#define SPM_SHIM_EXCEPTIONS_VMA SP_DRAM
+
+MEMORY {
+ SP_DRAM (rw): ORIGIN = PLAT_SQ_SP_PRIV_BASE, LENGTH = PLAT_SQ_SP_PRIV_SIZE
+}
+
+SECTIONS
+{
+ /*
+ * Put the page tables in secure DRAM so that the PTW can make cacheable
+ * accesses, as the core SPM code expects. (The SRAM on SynQuacer does
+ * not support inner shareable WBWA mappings so it is mapped normal
+ * non-cacheable)
+ */
+ .sp_xlat_table (NOLOAD) : ALIGN(PAGE_SIZE) {
+ *(.sp_xlat_table)
+ } >SP_DRAM
+}
+
+#endif /* SYNQUACER_PLAT_LD_S__ */
diff --git a/plat/socionext/synquacer/include/plat_macros.S b/plat/socionext/synquacer/include/plat_macros.S
new file mode 100644
index 0000000..932b21d
--- /dev/null
+++ b/plat/socionext/synquacer/include/plat_macros.S
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+/*
+ * Print CCN registers
+ */
+ .macro plat_crash_print_regs
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/socionext/synquacer/include/platform_def.h b/plat/socionext/synquacer/include/platform_def.h
new file mode 100644
index 0000000..acc74e2
--- /dev/null
+++ b/plat/socionext/synquacer/include/platform_def.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <lib/utils_def.h>
+#include <plat/common/common_def.h>
+
+/* CPU topology */
+#define PLAT_MAX_CORES_PER_CLUSTER U(2)
+#define PLAT_CLUSTER_COUNT U(12)
+#define PLATFORM_CORE_COUNT (PLAT_CLUSTER_COUNT * \
+ PLAT_MAX_CORES_PER_CLUSTER)
+
+/* Macros to read the SQ power domain state */
+#define SQ_PWR_LVL0 MPIDR_AFFLVL0
+#define SQ_PWR_LVL1 MPIDR_AFFLVL1
+#define SQ_PWR_LVL2 MPIDR_AFFLVL2
+
+#define SQ_CORE_PWR_STATE(state) (state)->pwr_domain_state[SQ_PWR_LVL0]
+#define SQ_CLUSTER_PWR_STATE(state) (state)->pwr_domain_state[SQ_PWR_LVL1]
+#define SQ_SYSTEM_PWR_STATE(state) ((PLAT_MAX_PWR_LVL > SQ_PWR_LVL1) ?\
+ (state)->pwr_domain_state[SQ_PWR_LVL2] : 0)
+
+#define PLAT_MAX_PWR_LVL U(1)
+#define PLAT_MAX_RET_STATE U(1)
+#define PLAT_MAX_OFF_STATE U(2)
+
+#define SQ_LOCAL_STATE_RUN 0
+#define SQ_LOCAL_STATE_RET 1
+#define SQ_LOCAL_STATE_OFF 2
+
+#define CACHE_WRITEBACK_SHIFT 6
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
+#define MAX_XLAT_TABLES 8
+#define MAX_MMAP_REGIONS 8
+
+#if TRUSTED_BOARD_BOOT
+#define PLATFORM_STACK_SIZE 0x1000
+#else
+#define PLATFORM_STACK_SIZE 0x400
+#endif
+
+#if !RESET_TO_BL31
+
+/* A mailbox page will be mapped from BL2 and BL31 */
+#define BL2_MAILBOX_BASE 0x0403f000
+#define BL2_MAILBOX_SIZE 0x1000
+
+#define PLAT_SQ_BOOTIDX_BASE 0x08510000
+#define PLAT_SQ_MAX_BOOT_INDEX 2
+
+#define MAX_IO_HANDLES 2
+#define MAX_IO_DEVICES 2
+#define MAX_IO_BLOCK_DEVICES U(1)
+
+#define BL2_BASE 0x04000000
+#define BL2_SIZE (256 * 1024)
+#define BL2_LIMIT (BL2_BASE + BL2_SIZE)
+
+/* If BL2 is enabled, the BL31 is loaded on secure DRAM */
+#define BL31_BASE 0xfbe00000
+#define BL31_SIZE 0x00100000
+#else
+
+#define BL31_BASE 0x04000000
+#define BL31_SIZE 0x00080000
+#endif
+
+#define BL31_LIMIT (BL31_BASE + BL31_SIZE)
+
+#define BL32_BASE 0xfc000000
+#define BL32_SIZE 0x03c00000
+#define BL32_LIMIT (BL32_BASE + BL32_SIZE)
+
+/* Alternative BL33 */
+#define PLAT_SQ_BL33_BASE 0xe0000000
+#define PLAT_SQ_BL33_SIZE 0x00200000
+
+/* FWU FIP IO base */
+#define PLAT_SQ_FIP_IOBASE 0x08600000
+#define PLAT_SQ_FIP_MAXSIZE 0x00400000
+
+#define PLAT_SQ_CCN_BASE 0x32000000
+#define PLAT_SQ_CLUSTER_TO_CCN_ID_MAP \
+ 0, /* Cluster 0 */ \
+ 18, /* Cluster 1 */ \
+ 11, /* Cluster 2 */ \
+ 29, /* Cluster 3 */ \
+ 35, /* Cluster 4 */ \
+ 17, /* Cluster 5 */ \
+ 12, /* Cluster 6 */ \
+ 30, /* Cluster 7 */ \
+ 14, /* Cluster 8 */ \
+ 32, /* Cluster 9 */ \
+ 15, /* Cluster 10 */ \
+ 33 /* Cluster 11 */
+
+/* UART related constants */
+#define PLAT_SQ_BOOT_UART_BASE 0x2A400000
+#define PLAT_SQ_BOOT_UART_CLK_IN_HZ 62500000
+#define SQ_CONSOLE_BAUDRATE 115200
+
+#define SQ_SYS_CNTCTL_BASE 0x2a430000
+
+#define SQ_SYS_TIMCTL_BASE 0x2a810000
+#define PLAT_SQ_NSTIMER_FRAME_ID 0
+#define SQ_SYS_CNT_BASE_NS 0x2a830000
+
+#define DRAMINFO_BASE 0x2E00FFC0
+
+#define PLAT_SQ_MHU_BASE 0x45000000
+
+#define PLAT_SQ_SCP_COM_SHARED_MEM_BASE 0x45400000
+#define SCPI_CMD_GET_DRAMINFO 0x1
+
+#define SQ_BOOT_CFG_ADDR 0x45410000
+#define PLAT_SQ_PRIMARY_CPU_SHIFT 8
+#define PLAT_SQ_PRIMARY_CPU_BIT_WIDTH 6
+
+#define PLAT_SQ_GICD_BASE 0x30000000
+#define PLAT_SQ_GICR_BASE 0x30400000
+
+#define PLAT_SQ_GPIO_BASE 0x51000000
+
+#define PLAT_SPM_BUF_BASE (BL32_LIMIT - 32 * PLAT_SPM_BUF_SIZE)
+#define PLAT_SPM_BUF_SIZE ULL(0x10000)
+#define PLAT_SPM_SPM_BUF_EL0_MMAP MAP_REGION2(PLAT_SPM_BUF_BASE, \
+ PLAT_SPM_BUF_BASE, \
+ PLAT_SPM_BUF_SIZE, \
+ MT_RO_DATA | MT_SECURE | \
+ MT_USER, PAGE_SIZE)
+
+#define PLAT_SP_IMAGE_NS_BUF_BASE BL32_LIMIT
+#define PLAT_SP_IMAGE_NS_BUF_SIZE ULL(0x200000)
+#define PLAT_SP_IMAGE_NS_BUF_MMAP MAP_REGION2(PLAT_SP_IMAGE_NS_BUF_BASE, \
+ PLAT_SP_IMAGE_NS_BUF_BASE, \
+ PLAT_SP_IMAGE_NS_BUF_SIZE, \
+ MT_RW_DATA | MT_NS | \
+ MT_USER, PAGE_SIZE)
+
+#define PLAT_SP_IMAGE_STACK_PCPU_SIZE ULL(0x10000)
+#define PLAT_SP_IMAGE_STACK_SIZE (32 * PLAT_SP_IMAGE_STACK_PCPU_SIZE)
+#define PLAT_SP_IMAGE_STACK_BASE (PLAT_SQ_SP_HEAP_BASE + PLAT_SQ_SP_HEAP_SIZE)
+
+#define PLAT_SQ_SP_IMAGE_SIZE ULL(0x200000)
+#define PLAT_SQ_SP_IMAGE_MMAP MAP_REGION2(BL32_BASE, BL32_BASE, \
+ PLAT_SQ_SP_IMAGE_SIZE, \
+ MT_CODE | MT_SECURE | \
+ MT_USER, PAGE_SIZE)
+
+#define PLAT_SQ_SP_HEAP_BASE (BL32_BASE + PLAT_SQ_SP_IMAGE_SIZE)
+#define PLAT_SQ_SP_HEAP_SIZE ULL(0x800000)
+
+#define PLAT_SQ_SP_IMAGE_RW_MMAP MAP_REGION2(PLAT_SQ_SP_HEAP_BASE, \
+ PLAT_SQ_SP_HEAP_BASE, \
+ (PLAT_SQ_SP_HEAP_SIZE + \
+ PLAT_SP_IMAGE_STACK_SIZE), \
+ MT_RW_DATA | MT_SECURE | \
+ MT_USER, PAGE_SIZE)
+
+#define PLAT_SQ_SP_PRIV_BASE (PLAT_SP_IMAGE_STACK_BASE + \
+ PLAT_SP_IMAGE_STACK_SIZE)
+#define PLAT_SQ_SP_PRIV_SIZE ULL(0x40000)
+
+#define PLAT_SP_PRI 0x20
+#define PLAT_PRI_BITS 2
+#define PLAT_SPM_COOKIE_0 ULL(0)
+#define PLAT_SPM_COOKIE_1 ULL(0)
+
+/* Total number of memory regions with distinct properties */
+#define PLAT_SP_IMAGE_NUM_MEM_REGIONS 6
+
+#define PLAT_SP_IMAGE_MMAP_REGIONS 30
+#define PLAT_SP_IMAGE_MAX_XLAT_TABLES 20
+#define PLAT_SP_IMAGE_XLAT_SECTION_NAME ".sp_xlat_table"
+#define PLAT_SP_IMAGE_BASE_XLAT_SECTION_NAME ".sp_xlat_table"
+
+#define PLAT_SQ_UART1_BASE PLAT_SQ_BOOT_UART_BASE
+#define PLAT_SQ_UART1_SIZE ULL(0x1000)
+#define PLAT_SQ_UART1_MMAP MAP_REGION_FLAT(PLAT_SQ_UART1_BASE, \
+ PLAT_SQ_UART1_SIZE, \
+ MT_DEVICE | MT_RW | \
+ MT_NS | MT_PRIVILEGED)
+
+#define PLAT_SQ_PERIPH_BASE 0x50000000
+#define PLAT_SQ_PERIPH_SIZE ULL(0x8000000)
+#define PLAT_SQ_PERIPH_MMAP MAP_REGION_FLAT(PLAT_SQ_PERIPH_BASE, \
+ PLAT_SQ_PERIPH_SIZE, \
+ MT_DEVICE | MT_RW | \
+ MT_NS | MT_USER)
+
+#define PLAT_SQ_FLASH_BASE 0x08000000
+#define PLAT_SQ_FLASH_SIZE ULL(0x8000000)
+#define PLAT_SQ_FLASH_MMAP MAP_REGION_FLAT(PLAT_SQ_FLASH_BASE, \
+ PLAT_SQ_FLASH_SIZE, \
+ MT_DEVICE | MT_RW | \
+ MT_NS | MT_USER)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/socionext/synquacer/include/sq_common.h b/plat/socionext/synquacer/include/sq_common.h
new file mode 100644
index 0000000..eef0e1f
--- /dev/null
+++ b/plat/socionext/synquacer/include/sq_common.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SQ_COMMON_H
+#define SQ_COMMON_H
+
+#include <stdint.h>
+
+#include <lib/psci/psci.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+struct draminfo {
+ uint32_t num_regions;
+ uint32_t reserved;
+ uint64_t base1;
+ uint64_t size1;
+ uint64_t base2;
+ uint64_t size2;
+ uint64_t base3;
+ uint64_t size3;
+};
+
+uint32_t sq_scp_get_draminfo(struct draminfo *info);
+
+void plat_sq_pwrc_setup(void);
+
+void plat_sq_interconnect_init(void);
+void plat_sq_interconnect_enter_coherency(void);
+void plat_sq_interconnect_exit_coherency(void);
+
+unsigned int sq_calc_core_pos(u_register_t mpidr);
+
+void sq_gic_driver_init(void);
+void sq_gic_init(void);
+void sq_gic_cpuif_enable(void);
+void sq_gic_cpuif_disable(void);
+void sq_gic_pcpu_init(void);
+
+int sq_io_setup(void);
+struct image_info *sq_get_image_info(unsigned int image_id);
+void sq_mmap_setup(uintptr_t total_base, size_t total_size,
+ const struct mmap_region *mmap);
+
+/* SCMI API for power management by SCP */
+void sq_scmi_off(const struct psci_power_state *target_state);
+void sq_scmi_on(u_register_t mpidr);
+void __dead2 sq_scmi_sys_shutdown(void);
+void __dead2 sq_scmi_sys_reboot(void);
+void __dead2 sq_scmi_system_off(int state);
+/* SCMI API for vendor specific protocol */
+uint32_t sq_scmi_get_draminfo(struct draminfo *info);
+
+#endif /* SQ_COMMON_H */
diff --git a/plat/socionext/synquacer/platform.mk b/plat/socionext/synquacer/platform.mk
new file mode 100644
index 0000000..a6d9bef
--- /dev/null
+++ b/plat/socionext/synquacer/platform.mk
@@ -0,0 +1,117 @@
+#
+# Copyright (c) 2018-2023, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+override PROGRAMMABLE_RESET_ADDRESS := 1
+override USE_COHERENT_MEM := 1
+override SEPARATE_CODE_AND_RODATA := 1
+override ENABLE_SVE_FOR_NS := 0
+# Enable workarounds for selected Cortex-A53 erratas.
+ERRATA_A53_855873 := 1
+
+ifeq (${RESET_TO_BL31}, 1)
+override RESET_TO_BL31 := 1
+override TRUSTED_BOARD_BOOT := 0
+SQ_USE_SCMI_DRIVER ?= 0
+else
+override RESET_TO_BL31 := 0
+override RESET_TO_BL2 := 1
+SQ_USE_SCMI_DRIVER := 1
+BL2_CPPFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
+endif
+
+# Libraries
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_PATH := plat/socionext/synquacer
+PLAT_INCLUDES := -I$(PLAT_PATH)/include \
+ -I$(PLAT_PATH)/drivers/scpi \
+ -I$(PLAT_PATH)/drivers/mhu \
+ -Idrivers/arm/css/scmi \
+ -Idrivers/arm/css/scmi/vendor
+
+PLAT_BL_COMMON_SOURCES += $(PLAT_PATH)/sq_helpers.S \
+ drivers/arm/pl011/aarch64/pl011_console.S \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ lib/cpus/aarch64/cortex_a53.S \
+ $(PLAT_PATH)/sq_xlat_setup.c \
+ ${XLAT_TABLES_LIB_SRCS}
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+ifneq (${RESET_TO_BL31}, 1)
+BL2_SOURCES += common/desc_image_load.c \
+ drivers/io/io_fip.c \
+ drivers/io/io_memmap.c \
+ drivers/io/io_storage.c \
+ $(PLAT_PATH)/sq_bl2_setup.c \
+ $(PLAT_PATH)/sq_image_desc.c \
+ $(PLAT_PATH)/sq_io_storage.c
+
+ifeq (${TRUSTED_BOARD_BOOT},1)
+include drivers/auth/mbedtls/mbedtls_crypto.mk
+include drivers/auth/mbedtls/mbedtls_x509.mk
+BL2_SOURCES += drivers/auth/auth_mod.c \
+ drivers/auth/crypto_mod.c \
+ drivers/auth/img_parser_mod.c \
+ drivers/auth/tbbr/tbbr_cot_common.c \
+ drivers/auth/tbbr/tbbr_cot_bl2.c \
+ plat/common/tbbr/plat_tbbr.c \
+ $(PLAT_PATH)/sq_rotpk.S \
+ $(PLAT_PATH)/sq_tbbr.c
+
+ROT_KEY = $(BUILD_PLAT)/rot_key.pem
+ROTPK_HASH = $(BUILD_PLAT)/rotpk_sha256.bin
+
+$(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
+$(BUILD_PLAT)/bl2/sq_rotpk.o: $(ROTPK_HASH)
+
+certificates: $(ROT_KEY)
+$(ROT_KEY): | $(BUILD_PLAT)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl genrsa 2048 > $@ 2>/dev/null
+
+$(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ ${OPENSSL_BIN_PATH}/openssl dgst -sha256 -binary > $@ 2>/dev/null
+
+endif # TRUSTED_BOARD_BOOT
+endif
+
+BL31_SOURCES += drivers/arm/ccn/ccn.c \
+ ${GICV3_SOURCES} \
+ plat/common/plat_gicv3.c \
+ plat/common/plat_psci_common.c \
+ $(PLAT_PATH)/sq_bl31_setup.c \
+ $(PLAT_PATH)/sq_ccn.c \
+ $(PLAT_PATH)/sq_topology.c \
+ $(PLAT_PATH)/sq_psci.c \
+ $(PLAT_PATH)/sq_gicv3.c \
+ $(PLAT_PATH)/drivers/scp/sq_scp.c
+
+ifeq (${SQ_USE_SCMI_DRIVER},0)
+BL31_SOURCES += $(PLAT_PATH)/drivers/scpi/sq_scpi.c \
+ $(PLAT_PATH)/drivers/mhu/sq_mhu.c
+else
+BL31_SOURCES += $(PLAT_PATH)/drivers/scp/sq_scmi.c \
+ drivers/arm/css/scmi/scmi_common.c \
+ drivers/arm/css/scmi/scmi_pwr_dmn_proto.c \
+ drivers/arm/css/scmi/scmi_sys_pwr_proto.c \
+ drivers/arm/css/scmi/vendor/scmi_sq.c \
+ drivers/arm/css/mhu/css_mhu_doorbell.c
+endif
+
+ifeq (${SPM_MM},1)
+$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
+
+BL31_SOURCES += $(PLAT_PATH)/sq_spm.c
+endif
+
+ifeq (${SQ_USE_SCMI_DRIVER},1)
+$(eval $(call add_define,SQ_USE_SCMI_DRIVER))
+endif
diff --git a/plat/socionext/synquacer/sq_bl2_setup.c b/plat/socionext/synquacer/sq_bl2_setup.c
new file mode 100644
index 0000000..a98d912
--- /dev/null
+++ b/plat/socionext/synquacer/sq_bl2_setup.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2022, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/image_decompress.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/io/io_storage.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+#include <sq_common.h>
+
+static console_t console;
+
+void bl2_el3_early_platform_setup(u_register_t x0, u_register_t x1,
+ u_register_t x2, u_register_t x3)
+{
+ /* Initialize the console to provide early debug support */
+ (void)console_pl011_register(PLAT_SQ_BOOT_UART_BASE,
+ PLAT_SQ_BOOT_UART_CLK_IN_HZ,
+ SQ_CONSOLE_BAUDRATE, &console);
+ console_set_scope(&console, CONSOLE_FLAG_BOOT);
+}
+
+void bl2_el3_plat_arch_setup(void)
+{
+ int ret;
+
+ sq_mmap_setup(BL2_BASE, BL2_SIZE, NULL);
+
+ ret = sq_io_setup();
+ if (ret) {
+ ERROR("failed to setup io devices\n");
+ plat_error_handler(ret);
+ }
+}
+
+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();
+}
+
+void bl2_plat_preload_setup(void)
+{
+}
+
+int bl2_plat_handle_pre_image_load(unsigned int image_id)
+{
+ struct image_info *image_info;
+
+ image_info = sq_get_image_info(image_id);
+
+ return mmap_add_dynamic_region(image_info->image_base,
+ image_info->image_base,
+ image_info->image_max_size,
+ MT_MEMORY | MT_RW | MT_NS);
+}
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+ return 0;
+}
diff --git a/plat/socionext/synquacer/sq_bl31_setup.c b/plat/socionext/synquacer/sq_bl31_setup.c
new file mode 100644
index 0000000..967437b
--- /dev/null
+++ b/plat/socionext/synquacer/sq_bl31_setup.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <lib/mmio.h>
+#include <sq_common.h>
+
+static console_t console;
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_START__, SPM_SHIM_EXCEPTIONS_START);
+IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_END__, SPM_SHIM_EXCEPTIONS_END);
+IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_LMA__, SPM_SHIM_EXCEPTIONS_LMA);
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ unsigned int counter_base_frequency;
+
+ /* Read the frequency from Frequency modes table */
+ counter_base_frequency = mmio_read_32(SQ_SYS_CNTCTL_BASE + CNTFID_OFF);
+
+ /* The first entry of the frequency modes table must not be 0 */
+ if (counter_base_frequency == 0)
+ panic();
+
+ return counter_base_frequency;
+}
+
+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;
+}
+
+#if !RESET_TO_BL31
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ void *from_bl2 = (void *) arg0;
+ bl_params_node_t *bl_params = ((bl_params_t *) from_bl2)->head;
+
+ /* Initialize the console to provide early debug support */
+ (void)console_pl011_register(PLAT_SQ_BOOT_UART_BASE,
+ PLAT_SQ_BOOT_UART_CLK_IN_HZ,
+ SQ_CONSOLE_BAUDRATE, &console);
+
+ console_set_scope(&console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME);
+
+ /* Initialize power controller before setting up topology */
+ plat_sq_pwrc_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;
+ }
+}
+
+#else
+/*******************************************************************************
+ * Gets SPSR for BL32 entry
+ ******************************************************************************/
+uint32_t sq_get_spsr_for_bl32_entry(void)
+{
+ /*
+ * The Secure Payload Dispatcher service is responsible for
+ * setting the SPSR prior to entry into the BL32 image.
+ */
+ return 0;
+}
+
+/*******************************************************************************
+ * Gets SPSR for BL33 entry
+ ******************************************************************************/
+uint32_t sq_get_spsr_for_bl33_entry(void)
+{
+ unsigned long el_status;
+ unsigned int mode;
+ uint32_t spsr;
+
+ /* Figure out what mode we enter the non-secure world in */
+ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+ el_status &= ID_AA64PFR0_ELX_MASK;
+
+ mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+ return spsr;
+}
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ /* Initialize the console to provide early debug support */
+ (void)console_pl011_register(PLAT_SQ_BOOT_UART_BASE,
+ PLAT_SQ_BOOT_UART_CLK_IN_HZ,
+ SQ_CONSOLE_BAUDRATE, &console);
+
+ console_set_scope(&console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME);
+
+ /* There are no parameters from BL2 if BL31 is a reset vector */
+ assert(arg0 == 0U);
+ assert(arg1 == 0U);
+
+ /* Initialize power controller before setting up topology */
+ plat_sq_pwrc_setup();
+
+#ifdef SPD_opteed
+ struct draminfo di = {0};
+
+ sq_scp_get_draminfo(&di);
+
+ /*
+ * Check if OP-TEE has been loaded in Secure RAM allocated
+ * from DRAM1 region
+ */
+ if ((di.base1 + di.size1) <= BL32_BASE) {
+ NOTICE("OP-TEE has been loaded by SCP firmware\n");
+ /* Populate entry point information for BL32 */
+ SET_PARAM_HEAD(&bl32_image_ep_info,
+ PARAM_EP,
+ VERSION_1,
+ 0);
+ SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+ bl32_image_ep_info.pc = BL32_BASE;
+ bl32_image_ep_info.spsr = sq_get_spsr_for_bl32_entry();
+ } else {
+ NOTICE("OP-TEE has not been loaded by SCP firmware\n");
+ }
+#endif /* SPD_opteed */
+
+ /* Populate entry point information for BL33 */
+ SET_PARAM_HEAD(&bl33_image_ep_info,
+ PARAM_EP,
+ VERSION_1,
+ 0);
+ /*
+ * Tell BL31 where the non-trusted software image
+ * is located and the entry state information
+ */
+ bl33_image_ep_info.pc = PRELOADED_BL33_BASE;
+ bl33_image_ep_info.spsr = sq_get_spsr_for_bl33_entry();
+ SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+}
+#endif
+
+static void sq_configure_sys_timer(void)
+{
+ unsigned int reg_val;
+ unsigned int freq_val = plat_get_syscnt_freq2();
+
+ reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT);
+ reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT);
+ reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT);
+ mmio_write_32(SQ_SYS_TIMCTL_BASE +
+ CNTACR_BASE(PLAT_SQ_NSTIMER_FRAME_ID), reg_val);
+
+ reg_val = (1 << CNTNSAR_NS_SHIFT(PLAT_SQ_NSTIMER_FRAME_ID));
+ mmio_write_32(SQ_SYS_TIMCTL_BASE + CNTNSAR, reg_val);
+
+ /* Initialize CNTFRQ register in CNTCTLBase frame */
+ mmio_write_32(SQ_SYS_TIMCTL_BASE + CNTCTLBASE_CNTFRQ, freq_val);
+
+ /*
+ * Initialize CNTFRQ register in Non-secure CNTBase frame.
+ * This is required for SynQuacer, because it does not
+ * follow ARM ARM in that the value updated in CNTFRQ is not
+ * reflected in CNTBASEN_CNTFRQ. Hence update the value manually.
+ */
+ mmio_write_32(SQ_SYS_CNT_BASE_NS + CNTBASEN_CNTFRQ, freq_val);
+}
+
+void bl31_platform_setup(void)
+{
+ /* Initialize the CCN interconnect */
+ plat_sq_interconnect_init();
+ plat_sq_interconnect_enter_coherency();
+
+ /* Initialize the GIC driver, cpu and distributor interfaces */
+ sq_gic_driver_init();
+ sq_gic_init();
+
+ /* Enable and initialize the System level generic timer */
+ mmio_write_32(SQ_SYS_CNTCTL_BASE + CNTCR_OFF,
+ CNTCR_FCREQ(0U) | CNTCR_EN);
+
+ /* Allow access to the System counter timer module */
+ sq_configure_sys_timer();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+ struct draminfo *di = (struct draminfo *)(unsigned long)DRAMINFO_BASE;
+
+ sq_scp_get_draminfo(di);
+}
+
+void bl31_plat_arch_setup(void)
+{
+ static const mmap_region_t secure_partition_mmap[] = {
+#if SPM_MM
+ MAP_REGION_FLAT(PLAT_SPM_BUF_BASE,
+ PLAT_SPM_BUF_SIZE,
+ MT_RW_DATA | MT_SECURE),
+ MAP_REGION_FLAT(PLAT_SQ_SP_PRIV_BASE,
+ PLAT_SQ_SP_PRIV_SIZE,
+ MT_RW_DATA | MT_SECURE),
+#endif
+#if !RESET_TO_BL31
+ MAP_REGION_FLAT(BL2_MAILBOX_BASE,
+ BL2_MAILBOX_SIZE,
+ MT_RW | MT_SECURE),
+#endif
+ {0},
+ };
+
+ sq_mmap_setup(BL31_BASE, BL31_SIZE, secure_partition_mmap);
+ enable_mmu_el3(XLAT_TABLE_NC);
+
+#if SPM_MM
+ memcpy((void *)SPM_SHIM_EXCEPTIONS_START,
+ (void *)SPM_SHIM_EXCEPTIONS_LMA,
+ (uintptr_t)SPM_SHIM_EXCEPTIONS_END -
+ (uintptr_t)SPM_SHIM_EXCEPTIONS_START);
+#endif
+}
+
+void bl31_plat_enable_mmu(uint32_t flags)
+{
+ enable_mmu_el3(flags | XLAT_TABLE_NC);
+}
diff --git a/plat/socionext/synquacer/sq_ccn.c b/plat/socionext/synquacer/sq_ccn.c
new file mode 100644
index 0000000..fa6ea87
--- /dev/null
+++ b/plat/socionext/synquacer/sq_ccn.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <drivers/arm/ccn.h>
+
+static const unsigned char master_to_rn_id_map[] = {
+ PLAT_SQ_CLUSTER_TO_CCN_ID_MAP
+};
+
+static const ccn_desc_t sq_ccn_desc = {
+ .periphbase = PLAT_SQ_CCN_BASE,
+ .num_masters = ARRAY_SIZE(master_to_rn_id_map),
+ .master_to_rn_id_map = master_to_rn_id_map
+};
+
+/******************************************************************************
+ * Helper function to initialize SQ CCN driver.
+ *****************************************************************************/
+void plat_sq_interconnect_init(void)
+{
+ ccn_init(&sq_ccn_desc);
+}
+
+/******************************************************************************
+ * Helper function to place current master into coherency
+ *****************************************************************************/
+void plat_sq_interconnect_enter_coherency(void)
+{
+ ccn_enter_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+/******************************************************************************
+ * Helper function to remove current master from coherency
+ *****************************************************************************/
+void plat_sq_interconnect_exit_coherency(void)
+{
+ ccn_exit_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
diff --git a/plat/socionext/synquacer/sq_gicv3.c b/plat/socionext/synquacer/sq_gicv3.c
new file mode 100644
index 0000000..05318e3
--- /dev/null
+++ b/plat/socionext/synquacer/sq_gicv3.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <plat/common/platform.h>
+
+#include "sq_common.h"
+
+static uintptr_t sq_rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t sq_interrupt_props[] = {
+ /* G0 interrupts */
+
+ /* SGI0 */
+ INTR_PROP_DESC(8, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ /* SGI6 */
+ INTR_PROP_DESC(14, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+
+ /* G1S interrupts */
+
+ /* Timer */
+ INTR_PROP_DESC(29, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_LEVEL),
+ /* SGI1 */
+ INTR_PROP_DESC(9, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI2 */
+ INTR_PROP_DESC(10, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI3 */
+ INTR_PROP_DESC(11, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI4 */
+ INTR_PROP_DESC(12, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI5 */
+ INTR_PROP_DESC(13, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI7 */
+ INTR_PROP_DESC(15, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE)
+};
+
+static unsigned int sq_mpidr_to_core_pos(u_register_t mpidr)
+{
+ return plat_core_pos_by_mpidr(mpidr);
+}
+
+static const struct gicv3_driver_data sq_gic_driver_data = {
+ .gicd_base = PLAT_SQ_GICD_BASE,
+ .gicr_base = PLAT_SQ_GICR_BASE,
+ .interrupt_props = sq_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(sq_interrupt_props),
+ .rdistif_num = PLATFORM_CORE_COUNT,
+ .rdistif_base_addrs = sq_rdistif_base_addrs,
+ .mpidr_to_core_pos = sq_mpidr_to_core_pos,
+};
+
+void sq_gic_driver_init(void)
+{
+ gicv3_driver_init(&sq_gic_driver_data);
+}
+
+void sq_gic_init(void)
+{
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void sq_gic_cpuif_enable(void)
+{
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void sq_gic_cpuif_disable(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+void sq_gic_pcpu_init(void)
+{
+ gicv3_rdistif_init(plat_my_core_pos());
+}
diff --git a/plat/socionext/synquacer/sq_helpers.S b/plat/socionext/synquacer/sq_helpers.S
new file mode 100644
index 0000000..5f9eab4
--- /dev/null
+++ b/plat/socionext/synquacer/sq_helpers.S
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+ .global sq_calc_core_pos
+ .global plat_my_core_pos
+ .global platform_mem_init
+ .global plat_is_my_cpu_primary
+ .global plat_secondary_cold_boot_setup
+ .global plat_crash_console_init
+ .global plat_crash_console_putc
+ .global plat_crash_console_flush
+
+/*
+ * unsigned int sq_calc_core_pos(u_register_t mpidr)
+ * core_pos = (cluster_id * max_cpus_per_cluster) + core_id
+ */
+func sq_calc_core_pos
+ and x1, x0, #MPIDR_CPU_MASK
+ and x0, x0, #MPIDR_CLUSTER_MASK
+ add x0, x1, x0, lsr #7
+ ret
+endfunc sq_calc_core_pos
+
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b sq_calc_core_pos
+endfunc plat_my_core_pos
+
+func platform_mem_init
+ ret
+endfunc platform_mem_init
+
+/*
+ * Secondary CPUs are placed in a holding pen, waiting for their mailbox
+ * to be populated. Note that all CPUs share the same mailbox ; therefore,
+ * populating it will release all CPUs from their holding pen. If
+ * finer-grained control is needed then this should be handled in the
+ * code that secondary CPUs jump to.
+ */
+func plat_secondary_cold_boot_setup
+#if !RESET_TO_BL31
+ mov_imm x0, BL2_MAILBOX_BASE
+ ldr x0, [x0]
+#else
+ ldr x0, sq_sec_entrypoint
+#endif
+
+ /* Wait until the mailbox gets populated */
+poll_mailbox:
+ cbz x0, 1f
+ br x0
+1:
+ wfe
+ b poll_mailbox
+endfunc plat_secondary_cold_boot_setup
+
+/*
+ * Find out whether the current cpu is the primary
+ * cpu (applicable only after a cold boot)
+ */
+func plat_is_my_cpu_primary
+ mov x9, x30
+ bl plat_my_core_pos
+ ldr x1, =SQ_BOOT_CFG_ADDR
+ ldr x1, [x1]
+ ubfx x1, x1, #PLAT_SQ_PRIMARY_CPU_SHIFT, \
+ #PLAT_SQ_PRIMARY_CPU_BIT_WIDTH
+ cmp x0, x1
+ cset w0, eq
+ ret x9
+endfunc plat_is_my_cpu_primary
+
+/*
+ * int plat_crash_console_init(void)
+ * Function to initialize the crash console
+ * without a C Runtime to print crash report.
+ * Clobber list : x0, x1, x2
+ */
+func plat_crash_console_init
+ mov_imm x0, PLAT_SQ_BOOT_UART_BASE
+ mov_imm x1, PLAT_SQ_BOOT_UART_CLK_IN_HZ
+ mov_imm x2, SQ_CONSOLE_BAUDRATE
+ b console_pl011_core_init
+endfunc plat_crash_console_init
+
+/*
+ * int plat_crash_console_putc(int c)
+ * Function to print a character on the crash
+ * console without a C Runtime.
+ * Clobber list : x1, x2
+ */
+func plat_crash_console_putc
+ mov_imm x1, PLAT_SQ_BOOT_UART_BASE
+ b console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+/*
+ * void plat_crash_console_flush(int c)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * Clobber list : x0, x1
+ */
+func plat_crash_console_flush
+ mov_imm x0, PLAT_SQ_BOOT_UART_BASE
+ b console_pl011_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/socionext/synquacer/sq_image_desc.c b/plat/socionext/synquacer/sq_image_desc.c
new file mode 100644
index 0000000..5fe125b
--- /dev/null
+++ b/plat/socionext/synquacer/sq_image_desc.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2022, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch.h>
+#include <common/desc_image_load.h>
+
+#include <platform_def.h>
+
+static struct bl_mem_params_node sq_image_descs[] = {
+ {
+ .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_SIZE,
+
+ 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),
+
+ .next_handoff_image_id = BL32_IMAGE_ID,
+ },
+ {
+ .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_SIZE,
+
+ 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,
+ },
+ {
+ .image_id = BL33_IMAGE_ID,
+
+ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+ VERSION_2, image_info_t, 0),
+ .image_info.image_base = PLAT_SQ_BL33_BASE,
+ .image_info.image_max_size = PLAT_SQ_BL33_SIZE,
+
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+ VERSION_2, entry_point_info_t,
+ NON_SECURE | EXECUTABLE),
+ .ep_info.pc = PLAT_SQ_BL33_BASE,
+ .ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS),
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ },
+};
+REGISTER_BL_IMAGE_DESCS(sq_image_descs)
+
+struct image_info *sq_get_image_info(unsigned int image_id)
+{
+ struct bl_mem_params_node *desc;
+
+ desc = get_bl_mem_params_node(image_id);
+ assert(desc);
+ return &desc->image_info;
+}
diff --git a/plat/socionext/synquacer/sq_io_storage.c b/plat/socionext/synquacer/sq_io_storage.c
new file mode 100644
index 0000000..ea83dad
--- /dev/null
+++ b/plat/socionext/synquacer/sq_io_storage.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2022, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <tools_share/firmware_image_package.h>
+
+#include <platform_def.h>
+#include <sq_common.h>
+
+static const io_dev_connector_t *sq_fip_dev_con;
+static uintptr_t sq_fip_dev_handle;
+
+static const io_dev_connector_t *sq_backend_dev_con;
+static uintptr_t sq_backend_dev_handle;
+
+static io_block_spec_t sq_fip_spec = {
+ .offset = PLAT_SQ_FIP_IOBASE, /* FIP Image is at 5MB offset on memory-mapped NOR flash */
+ .length = PLAT_SQ_FIP_MAXSIZE, /* Expected maximum FIP image size */
+};
+
+static const io_uuid_spec_t sq_bl2_spec = {
+ .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
+};
+
+static const io_uuid_spec_t sq_bl31_spec = {
+ .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
+};
+
+static const io_uuid_spec_t sq_bl32_spec = {
+ .uuid = UUID_SECURE_PAYLOAD_BL32,
+};
+
+static const io_uuid_spec_t sq_bl33_spec = {
+ .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
+};
+
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t sq_tb_fw_cert_spec = {
+ .uuid = UUID_TRUSTED_BOOT_FW_CERT,
+};
+
+static const io_uuid_spec_t sq_trusted_key_cert_spec = {
+ .uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t sq_soc_fw_key_cert_spec = {
+ .uuid = UUID_SOC_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t sq_tos_fw_key_cert_spec = {
+ .uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t sq_nt_fw_key_cert_spec = {
+ .uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t sq_soc_fw_cert_spec = {
+ .uuid = UUID_SOC_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t sq_tos_fw_cert_spec = {
+ .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t sq_nt_fw_cert_spec = {
+ .uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
+struct sq_io_policy {
+ uintptr_t *dev_handle;
+ uintptr_t image_spec;
+ uintptr_t init_params;
+};
+
+static const struct sq_io_policy sq_io_policies[] = {
+ [FIP_IMAGE_ID] = {
+ .dev_handle = &sq_backend_dev_handle,
+ .image_spec = (uintptr_t)&sq_fip_spec,
+ },
+ [BL2_IMAGE_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_bl2_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [BL31_IMAGE_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_bl31_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [BL32_IMAGE_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_bl32_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [BL33_IMAGE_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_bl33_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+#if TRUSTED_BOARD_BOOT
+ [TRUSTED_BOOT_FW_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_tb_fw_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [TRUSTED_KEY_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_trusted_key_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [SOC_FW_KEY_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_soc_fw_key_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [TRUSTED_OS_FW_KEY_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_tos_fw_key_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [NON_TRUSTED_FW_KEY_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_nt_fw_key_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [SOC_FW_CONTENT_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_soc_fw_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_tos_fw_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+ [NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+ .dev_handle = &sq_fip_dev_handle,
+ .image_spec = (uintptr_t)&sq_nt_fw_cert_spec,
+ .init_params = FIP_IMAGE_ID,
+ },
+#endif
+};
+
+static int sq_update_fip_spec(void)
+{
+ uint32_t boot_index;
+ int ret;
+
+ ret = mmap_add_dynamic_region(PLAT_SQ_BOOTIDX_BASE, PLAT_SQ_BOOTIDX_BASE,
+ PAGE_SIZE, MT_RO_DATA | MT_SECURE);
+ if (ret) {
+ return ret;
+ }
+
+ boot_index = mmio_read_32(PLAT_SQ_BOOTIDX_BASE);
+ if (boot_index < PLAT_SQ_MAX_BOOT_INDEX) {
+ sq_fip_spec.offset += PLAT_SQ_FIP_MAXSIZE * boot_index;
+ INFO("FWU Enabled: boot_index %d\n", boot_index);
+ } else {
+ WARN("FWU Disabled: wrong boot_index value. Fallback to index 0.\n");
+ }
+
+ mmap_remove_dynamic_region(PLAT_SQ_BOOTIDX_BASE, PAGE_SIZE);
+ return 0;
+}
+
+static int sq_io_memmap_setup(void)
+{
+ int ret;
+
+ ret = sq_update_fip_spec();
+ if (ret) {
+ return ret;
+ }
+
+ ret = mmap_add_dynamic_region(sq_fip_spec.offset, sq_fip_spec.offset,
+ sq_fip_spec.length, MT_RO_DATA | MT_SECURE);
+ if (ret) {
+ return ret;
+ }
+
+ ret = register_io_dev_memmap(&sq_backend_dev_con);
+ if (ret) {
+ return ret;
+ }
+
+ return io_dev_open(sq_backend_dev_con, 0, &sq_backend_dev_handle);
+}
+
+static int sq_io_fip_setup(void)
+{
+ int ret;
+
+ ret = register_io_dev_fip(&sq_fip_dev_con);
+ if (ret) {
+ return ret;
+ }
+
+ return io_dev_open(sq_fip_dev_con, 0, &sq_fip_dev_handle);
+}
+
+int sq_io_setup(void)
+{
+ int ret;
+
+ ret = sq_io_memmap_setup();
+ if (ret) {
+ return ret;
+ }
+
+ ret = sq_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(sq_io_policies));
+
+ *dev_handle = *sq_io_policies[image_id].dev_handle;
+ *image_spec = sq_io_policies[image_id].image_spec;
+ init_params = sq_io_policies[image_id].init_params;
+
+ return io_dev_init(*dev_handle, init_params);
+}
diff --git a/plat/socionext/synquacer/sq_psci.c b/plat/socionext/synquacer/sq_psci.c
new file mode 100644
index 0000000..017516f
--- /dev/null
+++ b/plat/socionext/synquacer/sq_psci.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/cassert.h>
+#include <lib/psci/psci.h>
+
+#include <sq_common.h>
+#include "sq_scpi.h"
+
+uintptr_t sq_sec_entrypoint;
+
+int sq_pwr_domain_on(u_register_t mpidr)
+{
+#if SQ_USE_SCMI_DRIVER
+ sq_scmi_on(mpidr);
+#else
+ /*
+ * SCP takes care of powering up parent power domains so we
+ * only need to care about level 0
+ */
+ scpi_set_sq_power_state(mpidr, scpi_power_on, scpi_power_on,
+ scpi_power_on);
+#endif
+
+ return PSCI_E_SUCCESS;
+}
+
+static void sq_pwr_domain_on_finisher_common(
+ const psci_power_state_t *target_state)
+{
+ assert(SQ_CORE_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF);
+
+ /*
+ * Perform the common cluster specific operations i.e enable coherency
+ * if this cluster was off.
+ */
+ if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
+ plat_sq_interconnect_enter_coherency();
+}
+
+void sq_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ /* Assert that the system power domain need not be initialized */
+ assert(SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_RUN);
+
+ sq_pwr_domain_on_finisher_common(target_state);
+
+ /* Program the gic per-cpu distributor or re-distributor interface */
+ sq_gic_pcpu_init();
+
+ /* Enable the gic cpu interface */
+ sq_gic_cpuif_enable();
+}
+
+#if !SQ_USE_SCMI_DRIVER
+static void sq_power_down_common(const psci_power_state_t *target_state)
+{
+ uint32_t cluster_state = scpi_power_on;
+ uint32_t system_state = scpi_power_on;
+
+ /* Prevent interrupts from spuriously waking up this cpu */
+ sq_gic_cpuif_disable();
+
+ /* Check if power down at system power domain level is requested */
+ if (SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF)
+ system_state = scpi_power_retention;
+
+ /* Cluster is to be turned off, so disable coherency */
+ if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
+ plat_sq_interconnect_exit_coherency();
+ cluster_state = scpi_power_off;
+ }
+
+ /*
+ * Ask the SCP to power down the appropriate components depending upon
+ * their state.
+ */
+ scpi_set_sq_power_state(read_mpidr_el1(),
+ scpi_power_off,
+ cluster_state,
+ system_state);
+}
+#endif
+
+void sq_pwr_domain_off(const psci_power_state_t *target_state)
+{
+#if SQ_USE_SCMI_DRIVER
+ /* Prevent interrupts from spuriously waking up this cpu */
+ sq_gic_cpuif_disable();
+
+ /* Cluster is to be turned off, so disable coherency */
+ if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) {
+ plat_sq_interconnect_exit_coherency();
+ }
+
+ sq_scmi_off(target_state);
+#else
+ sq_power_down_common(target_state);
+#endif
+}
+
+void __dead2 sq_system_off(void)
+{
+#if SQ_USE_SCMI_DRIVER
+ sq_scmi_sys_shutdown();
+#else
+ volatile uint32_t *gpio = (uint32_t *)PLAT_SQ_GPIO_BASE;
+
+ /* set PD[9] high to power off the system */
+ gpio[5] |= 0x2; /* set output */
+ gpio[1] |= 0x2; /* set high */
+ dmbst();
+
+ generic_delay_timer_init();
+
+ mdelay(1);
+
+ while (1) {
+ gpio[1] &= ~0x2; /* set low */
+ dmbst();
+
+ mdelay(1);
+
+ gpio[1] |= 0x2; /* set high */
+ dmbst();
+
+ mdelay(100);
+ }
+
+ wfi();
+ ERROR("SQ System Off: operation not handled.\n");
+ panic();
+#endif
+}
+
+void __dead2 sq_system_reset(void)
+{
+#if SQ_USE_SCMI_DRIVER
+ sq_scmi_sys_reboot();
+#else
+ uint32_t response;
+
+ /* Send the system reset request to the SCP */
+ response = scpi_sys_power_state(scpi_system_reboot);
+
+ if (response != SCP_OK) {
+ ERROR("SQ System Reset: SCP error %u.\n", response);
+ panic();
+ }
+ wfi();
+ ERROR("SQ System Reset: operation not handled.\n");
+ panic();
+#endif
+}
+
+void sq_cpu_standby(plat_local_state_t cpu_state)
+{
+ u_register_t scr;
+
+ assert(cpu_state == SQ_LOCAL_STATE_RET);
+
+ scr = read_scr_el3();
+ /* Enable PhysicalIRQ bit for NS world to wake the CPU */
+ write_scr_el3(scr | SCR_IRQ_BIT);
+ isb();
+ dsb();
+ wfi();
+
+ /*
+ * Restore SCR to the original value, synchronisation of scr_el3 is
+ * done by eret while el3_exit to save some execution cycles.
+ */
+ write_scr_el3(scr);
+}
+
+const plat_psci_ops_t sq_psci_ops = {
+ .pwr_domain_on = sq_pwr_domain_on,
+ .pwr_domain_off = sq_pwr_domain_off,
+ .pwr_domain_on_finish = sq_pwr_domain_on_finish,
+ .cpu_standby = sq_cpu_standby,
+ .system_off = sq_system_off,
+ .system_reset = sq_system_reset,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const struct plat_psci_ops **psci_ops)
+{
+#if !RESET_TO_BL31
+ uintptr_t *sq_sec_ep = (uintptr_t *)BL2_MAILBOX_BASE;
+
+ *sq_sec_ep = sec_entrypoint;
+ flush_dcache_range((uint64_t)sq_sec_ep,
+ sizeof(*sq_sec_ep));
+#else
+ sq_sec_entrypoint = sec_entrypoint;
+ flush_dcache_range((uint64_t)&sq_sec_entrypoint,
+ sizeof(sq_sec_entrypoint));
+#endif
+
+ *psci_ops = &sq_psci_ops;
+
+ return 0;
+}
diff --git a/plat/socionext/synquacer/sq_rotpk.S b/plat/socionext/synquacer/sq_rotpk.S
new file mode 100644
index 0000000..61227ed
--- /dev/null
+++ b/plat/socionext/synquacer/sq_rotpk.S
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2022, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+ .global sq_rotpk_hash
+ .global sq_rotpk_hash_end
+ .section .rodata.sq_rotpk_hash, "a"
+sq_rotpk_hash:
+ /* DER header */
+ .byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+ .byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+ /* SHA256 */
+ .incbin ROTPK_HASH
+sq_rotpk_hash_end:
diff --git a/plat/socionext/synquacer/sq_spm.c b/plat/socionext/synquacer/sq_spm.c
new file mode 100644
index 0000000..7bea111
--- /dev/null
+++ b/plat/socionext/synquacer/sq_spm.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <bl31/ehf.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <services/spm_mm_partition.h>
+
+static const mmap_region_t plat_arm_secure_partition_mmap[] = {
+ PLAT_SQ_FLASH_MMAP,
+ PLAT_SQ_UART1_MMAP,
+ PLAT_SQ_PERIPH_MMAP,
+ PLAT_SQ_SP_IMAGE_MMAP,
+ PLAT_SP_IMAGE_NS_BUF_MMAP,
+ PLAT_SQ_SP_IMAGE_RW_MMAP,
+ PLAT_SPM_SPM_BUF_EL0_MMAP,
+ {0}
+};
+
+/*
+ * Boot information passed to a secure partition during initialisation. Linear
+ * indices in MP information will be filled at runtime.
+ */
+static spm_mm_mp_info_t sp_mp_info[] = {
+ {0x80000000, 0}, {0x80000001, 0}, {0x80000100, 0}, {0x80000101, 0},
+ {0x80000200, 0}, {0x80000201, 0}, {0x80000300, 0}, {0x80000301, 0},
+ {0x80000400, 0}, {0x80000401, 0}, {0x80000500, 0}, {0x80000501, 0},
+ {0x80000600, 0}, {0x80000601, 0}, {0x80000700, 0}, {0x80000701, 0},
+ {0x80000800, 0}, {0x80000801, 0}, {0x80000900, 0}, {0x80000901, 0},
+ {0x80000a00, 0}, {0x80000a01, 0}, {0x80000b00, 0}, {0x80000b01, 0},
+};
+
+const spm_mm_boot_info_t plat_arm_secure_partition_boot_info = {
+ .h.type = PARAM_SP_IMAGE_BOOT_INFO,
+ .h.version = VERSION_1,
+ .h.size = sizeof(spm_mm_boot_info_t),
+ .h.attr = 0,
+ .sp_mem_base = BL32_BASE,
+ .sp_mem_limit = BL32_LIMIT,
+ .sp_image_base = BL32_BASE,
+ .sp_stack_base = PLAT_SP_IMAGE_STACK_BASE,
+ .sp_heap_base = PLAT_SQ_SP_HEAP_BASE,
+ .sp_ns_comm_buf_base = PLAT_SP_IMAGE_NS_BUF_BASE,
+ .sp_shared_buf_base = PLAT_SPM_BUF_BASE,
+ .sp_image_size = PLAT_SQ_SP_IMAGE_SIZE,
+ .sp_pcpu_stack_size = PLAT_SP_IMAGE_STACK_PCPU_SIZE,
+ .sp_heap_size = PLAT_SQ_SP_HEAP_SIZE,
+ .sp_ns_comm_buf_size = PLAT_SP_IMAGE_NS_BUF_SIZE,
+ .sp_shared_buf_size = PLAT_SPM_BUF_SIZE,
+ .num_sp_mem_regions = PLAT_SP_IMAGE_NUM_MEM_REGIONS,
+ .num_cpus = PLATFORM_CORE_COUNT,
+ .mp_info = sp_mp_info,
+};
+
+const struct mmap_region *plat_get_secure_partition_mmap(void *cookie)
+{
+ return plat_arm_secure_partition_mmap;
+}
+
+const struct spm_mm_boot_info *plat_get_secure_partition_boot_info(
+ void *cookie)
+{
+ return &plat_arm_secure_partition_boot_info;
+}
+
+static ehf_pri_desc_t sq_exceptions[] = {
+ EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SP_PRI),
+};
+EHF_REGISTER_PRIORITIES(sq_exceptions, ARRAY_SIZE(sq_exceptions), PLAT_PRI_BITS);
diff --git a/plat/socionext/synquacer/sq_tbbr.c b/plat/socionext/synquacer/sq_tbbr.c
new file mode 100644
index 0000000..e9fa18c
--- /dev/null
+++ b/plat/socionext/synquacer/sq_tbbr.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+extern char sq_rotpk_hash[], sq_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ *key_ptr = sq_rotpk_hash;
+ *key_len = sq_rotpk_hash_end - sq_rotpk_hash;
+ *flags = ROTPK_IS_HASH;
+
+ 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;
+}
+
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+ return get_mbedtls_heap_helper(heap_addr, heap_size);
+}
diff --git a/plat/socionext/synquacer/sq_topology.c b/plat/socionext/synquacer/sq_topology.c
new file mode 100644
index 0000000..359997a
--- /dev/null
+++ b/plat/socionext/synquacer/sq_topology.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+
+#include <sq_common.h>
+
+unsigned char sq_pd_tree_desc[PLAT_CLUSTER_COUNT + 1];
+
+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 >= PLAT_CLUSTER_COUNT)
+ return -1;
+
+ cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+ if (cpu_id >= PLAT_MAX_CORES_PER_CLUSTER)
+ return -1;
+
+ return sq_calc_core_pos(mpidr);
+}
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ int i;
+
+ sq_pd_tree_desc[0] = PLAT_CLUSTER_COUNT;
+
+ for (i = 0; i < PLAT_CLUSTER_COUNT; i++)
+ sq_pd_tree_desc[i + 1] = PLAT_MAX_CORES_PER_CLUSTER;
+
+ return sq_pd_tree_desc;
+}
diff --git a/plat/socionext/synquacer/sq_xlat_setup.c b/plat/socionext/synquacer/sq_xlat_setup.c
new file mode 100644
index 0000000..5d1669d
--- /dev/null
+++ b/plat/socionext/synquacer/sq_xlat_setup.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#define SQ_REG_REGION_BASE 0x20000000ULL
+#define SQ_REG_REGION_SIZE 0x60000000ULL
+
+void sq_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_NON_CACHEABLE | 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_NON_CACHEABLE | MT_RO | MT_SECURE);
+
+ /* Re-map the read-only data section */
+ VERBOSE("Read-only data region: %p - %p\n",
+ (void *)BL_RO_DATA_BASE, (void *)BL_RO_DATA_END);
+ mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE,
+ round_up(BL_RO_DATA_END, PAGE_SIZE) - BL_RO_DATA_BASE,
+ (MT_NON_CACHEABLE | MT_RO | MT_EXECUTE_NEVER |
+ 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);
+
+ /* register region */
+ mmap_add_region(SQ_REG_REGION_BASE, SQ_REG_REGION_BASE,
+ SQ_REG_REGION_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE);
+
+ /* additional regions if needed */
+ if (mmap)
+ mmap_add(mmap);
+
+ init_xlat_tables();
+}
diff --git a/plat/socionext/uniphier/include/plat_macros.S b/plat/socionext/uniphier/include/plat_macros.S
new file mode 100644
index 0000000..d6d2579
--- /dev/null
+++ b/plat/socionext/uniphier/include/plat_macros.S
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+ .macro plat_crash_print_regs
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/socionext/uniphier/include/platform_def.h b/plat/socionext/uniphier/include/platform_def.h
new file mode 100644
index 0000000..b23386d
--- /dev/null
+++ b/plat/socionext/uniphier/include/platform_def.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
+#include <plat/common/common_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 U(4)
+#define UNIPHIER_CLUSTER_COUNT U(2)
+
+#define PLATFORM_CORE_COUNT \
+ ((UNIPHIER_MAX_CPUS_PER_CLUSTER) * (UNIPHIER_CLUSTER_COUNT))
+
+#define PLAT_MAX_PWR_LVL U(1)
+
+#define PLAT_MAX_OFF_STATE U(2)
+#define PLAT_MAX_RET_STATE U(1)
+
+#define UNIPHIER_BL2_OFFSET UL(0x00000000)
+#define UNIPHIER_BL2_MAX_SIZE UL(0x00080000)
+
+/* 0x00080000-0x01000000: reserved for DSP */
+
+#define UNIPHIER_BL31_OFFSET UL(0x01000000)
+#define UNIPHIER_BL31_MAX_SIZE UL(0x00080000)
+
+#define UNIPHIER_BL32_OFFSET UL(0x01080000)
+#define UNIPHIER_BL32_MAX_SIZE UL(0x00100000)
+
+/*
+ * The link addresses are determined by UNIPHIER_MEM_BASE + offset.
+ * When ENABLE_PIE is set, all the TF images can be loaded anywhere, so
+ * UNIPHIER_MEM_BASE is arbitrary.
+ *
+ * When ENABLE_PIE is unset, UNIPHIER_MEM_BASE should be chosen so that
+ * BL2_BASE matches to the physical address where BL2 is loaded, that is,
+ * UNIPHIER_MEM_BASE should be the base address of the DRAM region.
+ */
+#define UNIPHIER_MEM_BASE UL(0x00000000)
+
+#define BL2_BASE (UNIPHIER_MEM_BASE + UNIPHIER_BL2_OFFSET)
+#define BL2_LIMIT (BL2_BASE + UNIPHIER_BL2_MAX_SIZE)
+
+#define BL31_BASE (UNIPHIER_MEM_BASE + UNIPHIER_BL31_OFFSET)
+#define BL31_LIMIT (BL31_BASE + UNIPHIER_BL31_MAX_SIZE)
+
+#define BL32_BASE (UNIPHIER_MEM_BASE + UNIPHIER_BL32_OFFSET)
+#define BL32_LIMIT (BL32_BASE + UNIPHIER_BL32_MAX_SIZE)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
+
+#define MAX_XLAT_TABLES 9
+#define MAX_MMAP_REGIONS 13
+
+#define MAX_IO_HANDLES 2
+#define MAX_IO_DEVICES 2
+#define MAX_IO_BLOCK_DEVICES U(1)
+
+#define TSP_SEC_MEM_BASE (BL32_BASE)
+#define TSP_SEC_MEM_SIZE ((BL32_LIMIT) - (BL32_BASE))
+#define TSP_IRQ_SEC_PHY_TIMER 29
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/socionext/uniphier/platform.mk b/plat/socionext/uniphier/platform.mk
new file mode 100644
index 0000000..d466aa1
--- /dev/null
+++ b/plat/socionext/uniphier/platform.mk
@@ -0,0 +1,140 @@
+#
+# Copyright (c) 2017-2023, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+override RESET_TO_BL2 := 1
+override COLD_BOOT_SINGLE_CPU := 1
+override PROGRAMMABLE_RESET_ADDRESS := 1
+override USE_COHERENT_MEM := 1
+override ENABLE_SVE_FOR_NS := 0
+
+# Disabling ENABLE_PIE saves memory footprint a lot, but you need to adjust
+# UNIPHIER_MEM_BASE so that all TF images are loaded at their link addresses.
+override ENABLE_PIE := 1
+
+ALLOW_RO_XLAT_TABLES := 1
+
+ifeq ($(ALLOW_RO_XLAT_TABLES),1)
+BL31_CPPFLAGS += -DPLAT_RO_XLAT_TABLES
+BL32_CPPFLAGS += -DPLAT_RO_XLAT_TABLES
+endif
+
+# The dynamic xlat table is only used in BL2
+BL2_CPPFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC
+
+# 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
+
+# Libraries
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_PATH := plat/socionext/uniphier
+PLAT_INCLUDES := -I$(PLAT_PATH)/include
+
+# common sources for BL2, BL31 (and BL32 if SPD=tspd)
+PLAT_BL_COMMON_SOURCES += plat/common/aarch64/crash_console_helpers.S \
+ $(PLAT_PATH)/uniphier_console.S \
+ $(PLAT_PATH)/uniphier_console_setup.c \
+ $(PLAT_PATH)/uniphier_helpers.S \
+ $(PLAT_PATH)/uniphier_soc_info.c \
+ $(PLAT_PATH)/uniphier_xlat_setup.c \
+ ${XLAT_TABLES_LIB_SRCS}
+
+BL2_SOURCES += common/desc_image_load.c \
+ drivers/io/io_block.c \
+ drivers/io/io_fip.c \
+ drivers/io/io_memmap.c \
+ drivers/io/io_storage.c \
+ lib/cpus/aarch64/cortex_a53.S \
+ lib/cpus/aarch64/cortex_a72.S \
+ $(PLAT_PATH)/uniphier_bl2_setup.c \
+ $(PLAT_PATH)/uniphier_boot_device.c \
+ $(PLAT_PATH)/uniphier_emmc.c \
+ $(PLAT_PATH)/uniphier_image_desc.c \
+ $(PLAT_PATH)/uniphier_io_storage.c \
+ $(PLAT_PATH)/uniphier_nand.c \
+ $(PLAT_PATH)/uniphier_scp.c \
+ $(PLAT_PATH)/uniphier_usb.c
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+BL31_SOURCES += drivers/arm/cci/cci.c \
+ ${GICV3_SOURCES} \
+ 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_boot_device.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
+
+BL2_SOURCES += drivers/auth/auth_mod.c \
+ drivers/auth/crypto_mod.c \
+ drivers/auth/img_parser_mod.c \
+ drivers/auth/tbbr/tbbr_cot_common.c \
+ drivers/auth/tbbr/tbbr_cot_bl2.c \
+ plat/common/tbbr/plat_tbbr.c \
+ $(PLAT_PATH)/uniphier_rotpk.S \
+ $(PLAT_PATH)/uniphier_tbbr.c
+
+ROT_KEY = $(BUILD_PLAT)/rot_key.pem
+ROTPK_HASH = $(BUILD_PLAT)/rotpk_sha256.bin
+
+$(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
+$(BUILD_PLAT)/bl2/uniphier_rotpk.o: $(ROTPK_HASH)
+
+certificates: $(ROT_KEY)
+$(ROT_KEY): | $(BUILD_PLAT)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl genrsa 2048 > $@ 2>/dev/null
+
+$(ROTPK_HASH): $(ROT_KEY)
+ @echo " OPENSSL $@"
+ $(Q)${OPENSSL_BIN_PATH}/openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+ ${OPENSSL_BIN_PATH}/openssl dgst -sha256 -binary > $@ 2>/dev/null
+
+endif
+
+ifeq (${FIP_GZIP},1)
+
+include lib/zlib/zlib.mk
+
+BL2_SOURCES += common/image_decompress.c \
+ $(ZLIB_SOURCES)
+
+$(eval $(call add_define,UNIPHIER_DECOMPRESS_GZIP))
+
+# compress all images loaded by BL2
+SCP_BL2_PRE_TOOL_FILTER := GZIP
+BL31_PRE_TOOL_FILTER := GZIP
+BL32_PRE_TOOL_FILTER := GZIP
+BL33_PRE_TOOL_FILTER := GZIP
+
+endif
+
+.PHONY: bl2_gzip
+bl2_gzip: $(BUILD_PLAT)/bl2.bin.gz
+%.gz: %
+ @echo " GZIP $@"
+ $(Q)gzip -n -f -9 $< --stdout > $@
diff --git a/plat/socionext/uniphier/tsp/tsp-uniphier.mk b/plat/socionext/uniphier/tsp/tsp-uniphier.mk
new file mode 100644
index 0000000..54d4f51
--- /dev/null
+++ b/plat/socionext/uniphier/tsp/tsp-uniphier.mk
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL32_SOURCES += plat/common/plat_gicv3.c \
+ plat/common/aarch64/platform_mp_stack.S \
+ $(PLAT_PATH)/tsp/uniphier_tsp_setup.c
diff --git a/plat/socionext/uniphier/tsp/uniphier_tsp_setup.c b/plat/socionext/uniphier/tsp/uniphier_tsp_setup.c
new file mode 100644
index 0000000..4bbb259
--- /dev/null
+++ b/plat/socionext/uniphier/tsp/uniphier_tsp_setup.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <plat/common/platform.h>
+
+#include "../uniphier.h"
+
+static unsigned int uniphier_soc = UNIPHIER_SOC_UNKNOWN;
+
+void tsp_early_platform_setup(void)
+{
+ uniphier_soc = uniphier_get_soc_id();
+ if (uniphier_soc == UNIPHIER_SOC_UNKNOWN)
+ plat_error_handler(-ENOTSUP);
+
+ uniphier_console_setup(uniphier_soc);
+}
+
+void tsp_platform_setup(void)
+{
+}
+
+void tsp_plat_arch_setup(void)
+{
+ uniphier_mmap_setup(uniphier_soc);
+}
diff --git a/plat/socionext/uniphier/uniphier.h b/plat/socionext/uniphier/uniphier.h
new file mode 100644
index 0000000..ee520ad
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UNIPHIER_H
+#define UNIPHIER_H
+
+#include <stdint.h>
+#include <string.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_SD 3
+#define UNIPHIER_BOOT_DEVICE_USB 4
+#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(unsigned int soc);
+
+struct io_block_dev_spec;
+int uniphier_emmc_init(unsigned int soc,
+ struct io_block_dev_spec **block_dev_spec);
+int uniphier_nand_init(unsigned int soc,
+ struct io_block_dev_spec **block_dev_spec);
+int uniphier_usb_init(unsigned int soc,
+ struct io_block_dev_spec **block_dev_spec);
+
+int uniphier_io_setup(unsigned int soc, uintptr_t mem_base);
+
+void uniphier_init_image_descs(uintptr_t mem_base);
+struct image_info;
+struct image_info *uniphier_get_image_info(unsigned int image_id);
+
+int uniphier_scp_is_running(void);
+void uniphier_scp_start(uint32_t scp_base);
+void uniphier_scp_open_com(void);
+void uniphier_scp_system_off(void);
+void uniphier_scp_system_reset(void);
+
+void uniphier_mmap_setup(unsigned int soc);
+
+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);
+
+void uniphier_psci_init(unsigned int soc);
+
+unsigned int uniphier_calc_core_pos(u_register_t mpidr);
+
+#endif /* UNIPHIER_H */
diff --git a/plat/socionext/uniphier/uniphier_bl2_setup.c b/plat/socionext/uniphier/uniphier_bl2_setup.c
new file mode 100644
index 0000000..4524610
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_bl2_setup.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/image_decompress.h>
+#include <drivers/io/io_storage.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#ifdef UNIPHIER_DECOMPRESS_GZIP
+#include <tf_gunzip.h>
+#endif
+
+#include "uniphier.h"
+
+#define UNIPHIER_IMAGE_BUF_OFFSET 0x03800000UL
+#define UNIPHIER_IMAGE_BUF_SIZE 0x00800000UL
+
+static uintptr_t uniphier_mem_base = UNIPHIER_MEM_BASE;
+static unsigned int uniphier_soc = UNIPHIER_SOC_UNKNOWN;
+static int uniphier_bl2_kick_scp;
+
+void bl2_el3_early_platform_setup(u_register_t x0, u_register_t x1,
+ u_register_t x2, u_register_t x3)
+{
+ uniphier_soc = uniphier_get_soc_id();
+ if (uniphier_soc == UNIPHIER_SOC_UNKNOWN)
+ plat_error_handler(-ENOTSUP);
+
+ uniphier_console_setup(uniphier_soc);
+}
+
+void bl2_el3_plat_arch_setup(void)
+{
+ int skip_scp = 0;
+ int ret;
+
+ uniphier_mmap_setup(uniphier_soc);
+
+ /* add relocation offset (run-time-address - link-address) */
+ uniphier_mem_base += BL_CODE_BASE - BL2_BASE;
+
+ ret = uniphier_io_setup(uniphier_soc, uniphier_mem_base);
+ if (ret) {
+ ERROR("failed to setup io devices\n");
+ plat_error_handler(ret);
+ }
+
+ switch (uniphier_get_boot_master(uniphier_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);
+ break;
+ }
+
+ if (skip_scp) {
+ struct image_info *image_info;
+
+ image_info = uniphier_get_image_info(SCP_BL2_IMAGE_ID);
+ image_info->h.attr |= IMAGE_ATTRIB_SKIP_LOADING;
+ }
+}
+
+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();
+}
+
+void bl2_plat_preload_setup(void)
+{
+#ifdef UNIPHIER_DECOMPRESS_GZIP
+ uintptr_t buf_base = uniphier_mem_base + UNIPHIER_IMAGE_BUF_OFFSET;
+ int ret;
+
+ ret = mmap_add_dynamic_region(buf_base, buf_base,
+ UNIPHIER_IMAGE_BUF_SIZE,
+ MT_MEMORY | MT_RW | MT_NS);
+ if (ret)
+ plat_error_handler(ret);
+
+ image_decompress_init(buf_base, UNIPHIER_IMAGE_BUF_SIZE, gunzip);
+#endif
+
+ uniphier_init_image_descs(uniphier_mem_base);
+}
+
+int bl2_plat_handle_pre_image_load(unsigned int image_id)
+{
+ struct image_info *image_info;
+ int ret;
+
+ image_info = uniphier_get_image_info(image_id);
+
+ ret = mmap_add_dynamic_region(image_info->image_base,
+ image_info->image_base,
+ image_info->image_max_size,
+ MT_MEMORY | MT_RW | MT_NS);
+ if (ret)
+ return ret;
+
+#ifdef UNIPHIER_DECOMPRESS_GZIP
+ image_decompress_prepare(image_info);
+#endif
+ return 0;
+}
+
+int bl2_plat_handle_post_image_load(unsigned int image_id)
+{
+ struct image_info *image_info = uniphier_get_image_info(image_id);
+#ifdef UNIPHIER_DECOMPRESS_GZIP
+ int ret;
+
+ if (!(image_info->h.attr & IMAGE_ATTRIB_SKIP_LOADING)) {
+ ret = image_decompress(uniphier_get_image_info(image_id));
+ if (ret)
+ return ret;
+ }
+#endif
+
+ if (image_id == SCP_BL2_IMAGE_ID && uniphier_bl2_kick_scp)
+ uniphier_scp_start(image_info->image_base);
+
+ return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_bl31_setup.c b/plat/socionext/uniphier/uniphier_bl31_setup.c
new file mode 100644
index 0000000..c2baebd
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_bl31_setup.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "uniphier.h"
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+static unsigned int uniphier_soc = UNIPHIER_SOC_UNKNOWN;
+
+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_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ void *from_bl2;
+
+ from_bl2 = (void *)arg0;
+
+ bl_params_node_t *bl_params = ((bl_params_t *)from_bl2)->head;
+
+ uniphier_soc = uniphier_get_soc_id();
+ if (uniphier_soc == UNIPHIER_SOC_UNKNOWN)
+ plat_error_handler(-ENOTSUP);
+
+ uniphier_console_setup(uniphier_soc);
+
+ 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();
+}
+
+static const uintptr_t uniphier_cntctl_base[] = {
+ [UNIPHIER_SOC_LD11] = 0x60e00000,
+ [UNIPHIER_SOC_LD20] = 0x60e00000,
+ [UNIPHIER_SOC_PXS3] = 0x60e00000,
+};
+
+void bl31_platform_setup(void)
+{
+ uintptr_t cntctl_base;
+
+ uniphier_cci_init(uniphier_soc);
+ uniphier_cci_enable();
+
+ /* Initialize the GIC driver, cpu and distributor interfaces */
+ uniphier_gic_driver_init(uniphier_soc);
+ uniphier_gic_init();
+
+ assert(uniphier_soc < ARRAY_SIZE(uniphier_cntctl_base));
+ cntctl_base = uniphier_cntctl_base[uniphier_soc];
+
+ /* Enable and initialize the System level generic timer */
+ mmio_write_32(cntctl_base + CNTCR_OFF, CNTCR_FCREQ(0U) | CNTCR_EN);
+
+ uniphier_psci_init(uniphier_soc);
+}
+
+void bl31_plat_arch_setup(void)
+{
+ uniphier_mmap_setup(uniphier_soc);
+}
diff --git a/plat/socionext/uniphier/uniphier_boot_device.c b/plat/socionext/uniphier/uniphier_boot_device.c
new file mode 100644
index 0000000..36a9908
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_boot_device.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_PINMON0 0x0
+#define UNIPHIER_PINMON2 0x8
+
+static const uintptr_t uniphier_pinmon_base[] = {
+ [UNIPHIER_SOC_LD11] = 0x5f900100,
+ [UNIPHIER_SOC_LD20] = 0x5f900100,
+ [UNIPHIER_SOC_PXS3] = 0x5f900100,
+};
+
+static bool uniphier_ld11_is_usb_boot(uint32_t pinmon)
+{
+ return !!(~pinmon & 0x00000080);
+}
+
+static bool uniphier_ld20_is_usb_boot(uint32_t pinmon)
+{
+ return !!(~pinmon & 0x00000780);
+}
+
+static bool uniphier_pxs3_is_usb_boot(uint32_t pinmon)
+{
+ uintptr_t pinmon_base = uniphier_pinmon_base[UNIPHIER_SOC_PXS3];
+ uint32_t pinmon2 = mmio_read_32(pinmon_base + 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 {
+ bool have_boot_swap;
+ bool (*is_sd_boot)(uint32_t pinmon);
+ bool (*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] = {
+ .have_boot_swap = true,
+ .is_usb_boot = uniphier_ld11_is_usb_boot,
+ .get_boot_device = uniphier_ld11_get_boot_device,
+ },
+ [UNIPHIER_SOC_LD20] = {
+ .have_boot_swap = true,
+ .is_usb_boot = uniphier_ld20_is_usb_boot,
+ .get_boot_device = uniphier_ld11_get_boot_device,
+ },
+ [UNIPHIER_SOC_PXS3] = {
+ .have_boot_swap = true,
+ .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;
+ uintptr_t pinmon_base;
+ uint32_t pinmon;
+
+ assert(soc < ARRAY_SIZE(uniphier_boot_device_info));
+ info = &uniphier_boot_device_info[soc];
+
+ assert(soc < ARRAY_SIZE(uniphier_boot_device_info));
+ pinmon_base = uniphier_pinmon_base[soc];
+
+ pinmon = mmio_read_32(pinmon_base + UNIPHIER_PINMON0);
+
+ if (info->have_boot_swap && !(pinmon & BIT(29)))
+ return UNIPHIER_BOOT_DEVICE_NOR;
+
+ if (info->is_sd_boot && info->is_sd_boot(pinmon))
+ return UNIPHIER_BOOT_DEVICE_SD;
+
+ if (info->is_usb_boot && 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]) {
+ uintptr_t pinmon_base;
+
+ assert(soc < ARRAY_SIZE(uniphier_boot_device_info));
+ pinmon_base = uniphier_pinmon_base[soc];
+
+ if (mmio_read_32(pinmon_base + UNIPHIER_PINMON0) & BIT(27))
+ return UNIPHIER_BOOT_MASTER_THIS;
+ else
+ return UNIPHIER_BOOT_MASTER_SCP;
+ } else {
+ return UNIPHIER_BOOT_MASTER_EXT;
+ }
+}
diff --git a/plat/socionext/uniphier/uniphier_cci.c b/plat/socionext/uniphier/uniphier_cci.c
new file mode 100644
index 0000000..3ca1768
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_cci.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/cci.h>
+#include <lib/utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_CCI500_BASE 0x5FD00000
+
+static const int uniphier_cci_map[] = {1, 0};
+
+static void __uniphier_cci_init(void)
+{
+ cci_init(UNIPHIER_CCI500_BASE, uniphier_cci_map,
+ ARRAY_SIZE(uniphier_cci_map));
+}
+
+static void __uniphier_cci_enable(void)
+{
+ cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+static void __uniphier_cci_disable(void)
+{
+ cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
+
+struct uniphier_cci_ops {
+ void (*init)(void);
+ void (*enable)(void);
+ void (*disable)(void);
+};
+
+static const struct uniphier_cci_ops uniphier_cci_ops_table[] = {
+ [UNIPHIER_SOC_LD11] = {
+ .init = NULL,
+ .enable = NULL,
+ .disable = NULL,
+ },
+ [UNIPHIER_SOC_LD20] = {
+ .init = __uniphier_cci_init,
+ .enable = __uniphier_cci_enable,
+ .disable = __uniphier_cci_disable,
+ },
+ [UNIPHIER_SOC_PXS3] = {
+ .init = NULL,
+ .enable = NULL,
+ .disable = NULL,
+ },
+};
+
+static struct uniphier_cci_ops uniphier_cci_ops;
+
+void uniphier_cci_init(unsigned int soc)
+{
+ uniphier_cci_ops = uniphier_cci_ops_table[soc];
+ flush_dcache_range((uint64_t)&uniphier_cci_ops,
+ sizeof(uniphier_cci_ops));
+
+ if (uniphier_cci_ops.init)
+ uniphier_cci_ops.init();
+}
+
+void uniphier_cci_enable(void)
+{
+ if (uniphier_cci_ops.enable)
+ uniphier_cci_ops.enable();
+}
+
+void uniphier_cci_disable(void)
+{
+ if (uniphier_cci_ops.disable)
+ uniphier_cci_ops.disable();
+}
diff --git a/plat/socionext/uniphier/uniphier_console.S b/plat/socionext/uniphier/uniphier_console.S
new file mode 100644
index 0000000..48927f4
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_console.S
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <drivers/console.h>
+
+#include "uniphier_console.h"
+
+/*
+ * In: w0 - character to be printed
+ * x1 - pointer to console structure
+ * Out: return the character written (always succeeds)
+ * Clobber: x2
+ */
+ .globl uniphier_console_putc
+func uniphier_console_putc
+ ldr x1, [x1, #CONSOLE_T_BASE]
+
+ /* Wait until the transmitter FIFO gets empty */
+0: ldr w2, [x1, #UNIPHIER_UART_LSR]
+ tbz w2, #UNIPHIER_UART_LSR_THRE_BIT, 0b
+
+ str w0, [x1, #UNIPHIER_UART_TX]
+
+ ret
+endfunc uniphier_console_putc
+
+/*
+ * In: x0 - pointer to console structure
+ * Out: return the character read, or ERROR_NO_PENDING_CHAR if no character
+ is available
+ * Clobber: x1
+ */
+ .globl uniphier_console_getc
+func uniphier_console_getc
+ ldr x0, [x0, #CONSOLE_T_BASE]
+
+ ldr w1, [x0, #UNIPHIER_UART_LSR]
+ tbz w1, #UNIPHIER_UART_LSR_DR_BIT, 0f
+
+ ldr w0, [x0, #UNIPHIER_UART_RX]
+ ret
+
+0: mov w0, #ERROR_NO_PENDING_CHAR
+ ret
+endfunc uniphier_console_getc
+
+/*
+ * In: x0 - pointer to console structure
+ * Out: return 0 (always succeeds)
+ * Clobber: x1
+ */
+ .global uniphier_console_flush
+func uniphier_console_flush
+ ldr x0, [x0, #CONSOLE_T_BASE]
+
+ /* wait until the transmitter gets empty */
+0: ldr w1, [x0, #UNIPHIER_UART_LSR]
+ tbz w1, #UNIPHIER_UART_LSR_TEMT_BIT, 0b
+
+ ret
+endfunc uniphier_console_flush
diff --git a/plat/socionext/uniphier/uniphier_console.h b/plat/socionext/uniphier/uniphier_console.h
new file mode 100644
index 0000000..e35fc88
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_console.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UNIPHIER_CONSOLE_H
+#define UNIPHIER_CONSOLE_H
+
+#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 0x40 /* Transmitter empty */
+#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 */
+
+#endif /* UNIPHIER_CONSOLE_H */
diff --git a/plat/socionext/uniphier/uniphier_console_setup.c b/plat/socionext/uniphier/uniphier_console_setup.c
new file mode 100644
index 0000000..9268f5d
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_console_setup.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2019-2020, Socionext Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <drivers/console.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "uniphier.h"
+#include "uniphier_console.h"
+
+#define UNIPHIER_UART_OFFSET 0x100
+#define UNIPHIER_UART_NR_PORTS 4
+
+/* These callbacks are implemented in assembly to use crash_console_helpers.S */
+int uniphier_console_putc(int character, struct console *console);
+int uniphier_console_getc(struct console *console);
+void uniphier_console_flush(struct console *console);
+
+static console_t uniphier_console = {
+ .flags = CONSOLE_FLAG_BOOT |
+#if DEBUG
+ CONSOLE_FLAG_RUNTIME |
+#endif
+ CONSOLE_FLAG_CRASH |
+ CONSOLE_FLAG_TRANSLATE_CRLF,
+ .putc = uniphier_console_putc,
+#if ENABLE_CONSOLE_GETC
+ .getc = uniphier_console_getc,
+#endif
+ .flush = uniphier_console_flush,
+};
+
+static const uintptr_t uniphier_uart_base[] = {
+ [UNIPHIER_SOC_LD11] = 0x54006800,
+ [UNIPHIER_SOC_LD20] = 0x54006800,
+ [UNIPHIER_SOC_PXS3] = 0x54006800,
+};
+
+/*
+ * There are 4 UART ports available on this platform. By default, we want to
+ * use the same one as used in the previous firmware stage.
+ */
+static uintptr_t uniphier_console_get_base(unsigned int soc)
+{
+ uintptr_t base, end;
+ uint32_t div;
+
+ assert(soc < ARRAY_SIZE(uniphier_uart_base));
+ base = uniphier_uart_base[soc];
+ end = base + UNIPHIER_UART_OFFSET * UNIPHIER_UART_NR_PORTS;
+
+ while (base < end) {
+ div = mmio_read_32(base + UNIPHIER_UART_DLR);
+ if (div)
+ return base;
+ base += UNIPHIER_UART_OFFSET;
+ }
+
+ return 0;
+}
+
+static void uniphier_console_init(uintptr_t base)
+{
+ mmio_write_32(base + UNIPHIER_UART_FCR, UNIPHIER_UART_FCR_ENABLE_FIFO);
+ mmio_write_32(base + UNIPHIER_UART_LCR_MCR,
+ UNIPHIER_UART_LCR_WLEN8 << 8);
+}
+
+void uniphier_console_setup(unsigned int soc)
+{
+ uintptr_t base;
+
+ base = uniphier_console_get_base(soc);
+ if (!base)
+ plat_error_handler(-EINVAL);
+
+ uniphier_console.base = base;
+ console_register(&uniphier_console);
+
+ /*
+ * The hardware might be still printing characters queued up in the
+ * previous firmware stage. Make sure the transmitter is empty before
+ * any initialization. Otherwise, the console might get corrupted.
+ */
+ console_flush();
+
+ uniphier_console_init(base);
+}
diff --git a/plat/socionext/uniphier/uniphier_emmc.c b/plat/socionext/uniphier/uniphier_emmc.c
new file mode 100644
index 0000000..b3d23cb
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_emmc.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/io/io_block.h>
+#include <lib/mmio.h>
+#include <lib/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;
+};
+
+struct uniphier_emmc_host {
+ uintptr_t base;
+ bool is_block_addressing;
+};
+
+static struct uniphier_emmc_host uniphier_emmc_host;
+
+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_check_device_size(uintptr_t host_base,
+ bool *is_block_addressing)
+{
+ 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);
+
+ /* C_SIZE == 0xfff && C_SIZE_MULT == 0x7 ? */
+ *is_block_addressing = !(~csd40 & 0xffc00380) && !(~csd72 & 0x3);
+
+ return 0;
+}
+
+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)
+{
+ int ret;
+
+ inv_dcache_range(buf, size);
+
+ if (!uniphier_emmc_host.is_block_addressing)
+ lba *= 512;
+
+ ret = uniphier_emmc_load_image(uniphier_emmc_host.base,
+ lba, buf, size / 512);
+
+ inv_dcache_range(buf, size);
+
+ return ret ? 0 : size;
+}
+
+static struct io_block_dev_spec uniphier_emmc_dev_spec = {
+ .ops = {
+ .read = uniphier_emmc_read,
+ },
+ .block_size = 512,
+};
+
+static int uniphier_emmc_hw_init(struct uniphier_emmc_host *host)
+{
+ struct uniphier_mmc_cmd cmd = {0};
+ uintptr_t host_base = uniphier_emmc_host.base;
+ 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_check_device_size(host_base,
+ &uniphier_emmc_host.is_block_addressing);
+ if (ret)
+ return 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;
+}
+
+static const uintptr_t uniphier_emmc_base[] = {
+ [UNIPHIER_SOC_LD11] = 0x5a000200,
+ [UNIPHIER_SOC_LD20] = 0x5a000200,
+ [UNIPHIER_SOC_PXS3] = 0x5a000200,
+};
+
+int uniphier_emmc_init(unsigned int soc,
+ struct io_block_dev_spec **block_dev_spec)
+{
+ int ret;
+
+ assert(soc < ARRAY_SIZE(uniphier_emmc_base));
+ uniphier_emmc_host.base = uniphier_emmc_base[soc];
+ if (uniphier_emmc_host.base == 0UL)
+ return -ENOTSUP;
+
+ ret = uniphier_emmc_hw_init(&uniphier_emmc_host);
+ if (ret)
+ return ret;
+
+ *block_dev_spec = &uniphier_emmc_dev_spec;
+
+ return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_gicv3.c b/plat/socionext/uniphier/uniphier_gicv3.c
new file mode 100644
index 0000000..266efe7
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_gicv3.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <drivers/arm/gicv3.h>
+#include <common/interrupt_props.h>
+#include <plat/common/platform.h>
+
+#include "uniphier.h"
+
+static uintptr_t uniphier_rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t uniphier_interrupt_props[] = {
+ /* G0 interrupts */
+
+ /* SGI0 */
+ INTR_PROP_DESC(8, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+ /* SGI6 */
+ INTR_PROP_DESC(14, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
+ GIC_INTR_CFG_EDGE),
+
+ /* G1S interrupts */
+
+ /* Timer */
+ INTR_PROP_DESC(29, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_LEVEL),
+ /* SGI1 */
+ INTR_PROP_DESC(9, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI2 */
+ INTR_PROP_DESC(10, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI3 */
+ INTR_PROP_DESC(11, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI4 */
+ INTR_PROP_DESC(12, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI5 */
+ INTR_PROP_DESC(13, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE),
+ /* SGI7 */
+ INTR_PROP_DESC(15, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S,
+ GIC_INTR_CFG_EDGE)
+};
+
+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,
+ .interrupt_props = uniphier_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(uniphier_interrupt_props),
+ .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,
+ .interrupt_props = uniphier_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(uniphier_interrupt_props),
+ .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,
+ .interrupt_props = uniphier_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(uniphier_interrupt_props),
+ .rdistif_num = PLATFORM_CORE_COUNT,
+ .rdistif_base_addrs = uniphier_rdistif_base_addrs,
+ .mpidr_to_core_pos = uniphier_mpidr_to_core_pos,
+ },
+};
+
+void uniphier_gic_driver_init(unsigned int soc)
+{
+ assert(soc < ARRAY_SIZE(uniphier_gic_driver_data));
+
+ gicv3_driver_init(&uniphier_gic_driver_data[soc]);
+}
+
+void uniphier_gic_init(void)
+{
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void uniphier_gic_cpuif_enable(void)
+{
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+void uniphier_gic_cpuif_disable(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+void uniphier_gic_pcpu_init(void)
+{
+ gicv3_rdistif_init(plat_my_core_pos());
+}
diff --git a/plat/socionext/uniphier/uniphier_helpers.S b/plat/socionext/uniphier/uniphier_helpers.S
new file mode 100644
index 0000000..105cf9e
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_helpers.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <platform_def.h>
+
+ .global uniphier_calc_core_pos
+ .global plat_my_core_pos
+ .globl platform_mem_init
+
+/*
+ * unsigned int uniphier_calc_core_pos(u_register_t mpidr)
+ * core_pos = (cluster_id * max_cpus_per_cluster) + core_id
+ */
+func uniphier_calc_core_pos
+ and x1, x0, #MPIDR_CPU_MASK
+ and x0, x0, #MPIDR_CLUSTER_MASK
+ lsr x0, x0, #MPIDR_AFFINITY_BITS
+ mov x2, #UNIPHIER_MAX_CPUS_PER_CLUSTER
+ madd x0, x0, x2, x1
+ ret
+endfunc uniphier_calc_core_pos
+
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b uniphier_calc_core_pos
+endfunc plat_my_core_pos
+
+func platform_mem_init
+ ret
+endfunc platform_mem_init
diff --git a/plat/socionext/uniphier/uniphier_image_desc.c b/plat/socionext/uniphier/uniphier_image_desc.c
new file mode 100644
index 0000000..dd62d1e
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_image_desc.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <common/desc_image_load.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_BL33_OFFSET 0x04000000UL
+#define UNIPHIER_BL33_MAX_SIZE 0x00800000UL
+
+#define UNIPHIER_SCP_OFFSET 0x04800000UL
+#define UNIPHIER_SCP_MAX_SIZE 0x00020000UL
+
+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_OFFSET,
+ .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 = UNIPHIER_BL31_OFFSET,
+ .image_info.image_max_size = UNIPHIER_BL31_MAX_SIZE,
+
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+ VERSION_2, entry_point_info_t,
+ SECURE | EXECUTABLE | EP_FIRST_EXE),
+ .ep_info.pc = UNIPHIER_BL31_OFFSET,
+ .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 = UNIPHIER_BL32_OFFSET,
+ .image_info.image_max_size = UNIPHIER_BL32_MAX_SIZE,
+
+ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+ VERSION_2, entry_point_info_t,
+ SECURE | EXECUTABLE),
+ .ep_info.pc = UNIPHIER_BL32_OFFSET,
+ .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_OFFSET,
+ .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_OFFSET,
+ .ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS),
+
+ .next_handoff_image_id = INVALID_IMAGE_ID,
+ },
+};
+REGISTER_BL_IMAGE_DESCS(uniphier_image_descs)
+
+/*
+ * image_info.image_base and ep_info.pc are the offset from the memory base.
+ * When ENABLE_PIE is set, we never know the real memory base at link-time.
+ * Fix-up the addresses by adding the run-time detected base.
+ */
+void uniphier_init_image_descs(uintptr_t mem_base)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(uniphier_image_descs); i++) {
+ uniphier_image_descs[i].image_info.image_base += mem_base;
+ uniphier_image_descs[i].ep_info.pc += mem_base;
+ }
+}
+
+struct image_info *uniphier_get_image_info(unsigned int image_id)
+{
+ struct bl_mem_params_node *desc;
+
+ desc = get_bl_mem_params_node(image_id);
+ assert(desc);
+ return &desc->image_info;
+}
diff --git a/plat/socionext/uniphier/uniphier_io_storage.c b/plat/socionext/uniphier/uniphier_io_storage.c
new file mode 100644
index 0000000..92e15b0
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_io_storage.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <drivers/io/io_block.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_fip.h>
+#include <drivers/io/io_memmap.h>
+#include <lib/utils_def.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_ROM_REGION_BASE 0x00000000ULL
+#define UNIPHIER_ROM_REGION_SIZE 0x04000000ULL
+
+#define UNIPHIER_OCM_REGION_SIZE 0x00040000ULL
+
+#define UNIPHIER_BLOCK_BUF_OFFSET 0x03000000UL
+#define UNIPHIER_BLOCK_BUF_SIZE 0x00800000UL
+
+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,
+ struct io_block_dev_spec *block_dev_spec,
+ size_t buffer_offset)
+{
+ int ret;
+
+ uniphier_fip_spec.offset = fip_offset;
+
+ block_dev_spec->buffer.offset = buffer_offset;
+ block_dev_spec->buffer.length = UNIPHIER_BLOCK_BUF_SIZE;
+
+ ret = mmap_add_dynamic_region(block_dev_spec->buffer.offset,
+ block_dev_spec->buffer.offset,
+ block_dev_spec->buffer.length,
+ MT_MEMORY | MT_RW | MT_NS);
+ if (ret)
+ return ret;
+
+ ret = register_io_dev_block(&uniphier_backend_dev_con);
+ if (ret)
+ return ret;
+
+ return io_dev_open(uniphier_backend_dev_con, (uintptr_t)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, size_t buffer_offset)
+{
+ struct io_block_dev_spec *block_dev_spec;
+ int ret;
+
+ ret = uniphier_emmc_init(soc, &block_dev_spec);
+ if (ret)
+ return ret;
+
+ return uniphier_io_block_setup(0x20000, block_dev_spec, buffer_offset);
+}
+
+static int uniphier_io_nand_setup(unsigned int soc, size_t buffer_offset)
+{
+ struct io_block_dev_spec *block_dev_spec;
+ int ret;
+
+ ret = uniphier_nand_init(soc, &block_dev_spec);
+ if (ret)
+ return ret;
+
+ return uniphier_io_block_setup(0x20000, block_dev_spec, buffer_offset);
+}
+
+static int uniphier_io_nor_setup(unsigned int soc_id, size_t buffer_offset)
+{
+ return uniphier_io_memmap_setup(0x70000);
+}
+
+static const uintptr_t uniphier_ocm_base[] = {
+ [UNIPHIER_SOC_LD11] = 0x30000000,
+ [UNIPHIER_SOC_LD20] = 0x30000000,
+ [UNIPHIER_SOC_PXS3] = 0x30000000,
+};
+
+static int uniphier_io_rom_api_setup(unsigned int soc)
+{
+ uintptr_t ocm_base;
+ int ret;
+
+ assert(soc < ARRAY_SIZE(uniphier_ocm_base));
+ ocm_base = uniphier_ocm_base[soc];
+
+ 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;
+
+ /*
+ * 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.
+ */
+ ret = mmap_add_dynamic_region(ocm_base, ocm_base,
+ UNIPHIER_OCM_REGION_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int uniphier_io_usb_setup(unsigned int soc, size_t buffer_offset)
+{
+ struct io_block_dev_spec *block_dev_spec;
+ int ret;
+
+ /* use ROM API for loading images from USB storage */
+ ret = uniphier_io_rom_api_setup(soc);
+ if (ret)
+ return ret;
+
+ ret = uniphier_usb_init(soc, &block_dev_spec);
+ if (ret)
+ return ret;
+
+ return uniphier_io_block_setup(0x20000, block_dev_spec, buffer_offset);
+}
+
+static int (* const uniphier_io_setup_table[])(unsigned int, size_t) = {
+ [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, uintptr_t mem_base)
+{
+ int (*io_setup)(unsigned int soc_id, size_t buffer_offset);
+ 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, mem_base + UNIPHIER_BLOCK_BUF_OFFSET);
+ 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);
+}
diff --git a/plat/socionext/uniphier/uniphier_nand.c b/plat/socionext/uniphier/uniphier_nand.c
new file mode 100644
index 0000000..71cb96c
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_nand.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/io/io_block.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "uniphier.h"
+
+#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;
+
+ /* if possible, save the result for future re-use */
+ if (block < ARRAY_SIZE(nand->bbt))
+ 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 = {
+ .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->reg_base = nand->host_base + 0x100000;
+
+ 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;
+}
+
+static const uintptr_t uniphier_nand_base[] = {
+ [UNIPHIER_SOC_LD11] = 0x68000000,
+ [UNIPHIER_SOC_LD20] = 0x68000000,
+ [UNIPHIER_SOC_PXS3] = 0x68000000,
+};
+
+int uniphier_nand_init(unsigned int soc,
+ struct io_block_dev_spec **block_dev_spec)
+{
+ int ret;
+
+ assert(soc < ARRAY_SIZE(uniphier_nand_base));
+ uniphier_nand.host_base = uniphier_nand_base[soc];
+ if (!uniphier_nand.host_base)
+ return -ENOTSUP;
+
+ ret = uniphier_nand_hw_init(&uniphier_nand);
+ if (ret)
+ return ret;
+
+ uniphier_nand_dev_spec.block_size = uniphier_nand.page_size;
+
+ *block_dev_spec = &uniphier_nand_dev_spec;
+
+ return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_psci.c b/plat/socionext/uniphier/uniphier_psci.c
new file mode 100644
index 0000000..a371705
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_psci.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <errno.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_ROM_RSV0 0x0
+
+#define UNIPHIER_SLFRSTSEL 0x10
+#define UNIPHIER_SLFRSTSEL_MASK GENMASK(1, 0)
+#define UNIPHIER_SLFRSTCTL 0x14
+#define UNIPHIER_SLFRSTCTL_RST BIT(0)
+
+#define MPIDR_AFFINITY_INVALID ((u_register_t)-1)
+
+static uintptr_t uniphier_rom_rsv_base;
+static uintptr_t uniphier_slfrst_base;
+
+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_rsv_base + 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 warm 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_slfrst_base + UNIPHIER_SLFRSTSEL,
+ UNIPHIER_SLFRSTSEL_MASK);
+ mmio_setbits_32(uniphier_slfrst_base + 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));
+
+ *psci_ops = &uniphier_psci_ops;
+
+ return 0;
+}
+
+struct uniphier_psci_ctrl_base {
+ uintptr_t rom_rsv_base;
+ uintptr_t slfrst_base;
+};
+
+static const struct uniphier_psci_ctrl_base uniphier_psci_ctrl_base[] = {
+ [UNIPHIER_SOC_LD11] = {
+ .rom_rsv_base = 0x59801200,
+ .slfrst_base = 0x61843000,
+ },
+ [UNIPHIER_SOC_LD20] = {
+ .rom_rsv_base = 0x59801200,
+ .slfrst_base = 0x61843000,
+ },
+ [UNIPHIER_SOC_PXS3] = {
+ .rom_rsv_base = 0x59801200,
+ .slfrst_base = 0x61843000,
+ },
+};
+
+void uniphier_psci_init(unsigned int soc)
+{
+ assert(soc < ARRAY_SIZE(uniphier_psci_ctrl_base));
+ uniphier_rom_rsv_base = uniphier_psci_ctrl_base[soc].rom_rsv_base;
+ uniphier_slfrst_base = uniphier_psci_ctrl_base[soc].slfrst_base;
+
+ if (uniphier_get_boot_master(soc) == UNIPHIER_BOOT_MASTER_SCP) {
+ 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();
+ }
+}
diff --git a/plat/socionext/uniphier/uniphier_rotpk.S b/plat/socionext/uniphier/uniphier_rotpk.S
new file mode 100644
index 0000000..21c44b6
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_rotpk.S
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+ .global uniphier_rotpk_hash
+ .global uniphier_rotpk_hash_end
+ .section .rodata.uniphier_rotpk_hash, "a"
+uniphier_rotpk_hash:
+ /* DER header */
+ .byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+ .byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+ /* SHA256 */
+ .incbin ROTPK_HASH
+uniphier_rotpk_hash_end:
diff --git a/plat/socionext/uniphier/uniphier_scp.c b/plat/socionext/uniphier/uniphier_scp.c
new file mode 100644
index 0000000..8a12d5d
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_scp.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_ROM_RSV3 0x5980120c
+
+#define UNIPHIER_STMBE2COM 0x5f800030
+#define UNIPHIER_STMTOBEIRQ 0x5f800060
+#define UNIPHIER_BETOSTMIRQ0PT 0x5f800070
+#define UNIPHIER_BEIRQCLRPT 0x5f800072
+
+#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(uint32_t scp_base)
+{
+ uint32_t tmp;
+
+ mmio_write_32(UNIPHIER_STMBE2COM + 4, 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);
+
+ while (!(mmio_read_32(UNIPHIER_STMTOBEIRQ) & BIT(1)))
+ ;
+ mmio_write_8(UNIPHIER_BEIRQCLRPT, BIT(1) | BIT(0));
+}
+
+static void uniphier_scp_send_cmd(const uint8_t *cmd, int cmd_len)
+{
+ uint8_t packet[32]; /* long enough */
+ uint8_t *p = packet;
+ uint8_t c;
+ int i;
+
+ *p++ = UNIPHIER_SCP_PACKET_START;
+ *p++ = cmd_len;
+
+ for (i = 0; i < cmd_len; i++) {
+ c = *cmd++;
+ if (UNIPHIER_SCP_IS_CTRL_CODE(c)) {
+ *p++ = UNIPHIER_SCP_PACKET_ESC;
+ *p++ = c ^ BIT(7);
+ } else {
+ *p++ = c;
+ }
+ }
+
+ *p++ = UNIPHIER_SCP_PACKET_END;
+
+ uniphier_scp_send_packet(packet, p - packet);
+}
+
+#define UNIPHIER_SCP_CMD(name, ...) \
+static const uint8_t __uniphier_scp_##name##_cmd[] = { \
+ __VA_ARGS__ \
+}; \
+void uniphier_scp_##name(void) \
+{ \
+ uniphier_scp_send_cmd(__uniphier_scp_##name##_cmd, \
+ ARRAY_SIZE(__uniphier_scp_##name##_cmd)); \
+}
+
+UNIPHIER_SCP_CMD(open_com, 0x00, 0x00, 0x05)
+UNIPHIER_SCP_CMD(system_off, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01)
+UNIPHIER_SCP_CMD(system_reset, 0x00, 0x02, 0x00)
diff --git a/plat/socionext/uniphier/uniphier_smp.S b/plat/socionext/uniphier/uniphier_smp.S
new file mode 100644
index 0000000..d6cb9ff
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_smp.S
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+ .globl uniphier_warmboot_entrypoint
+ .globl uniphier_fake_pwr_down
+
+func uniphier_warmboot_entrypoint
+ mrs x0, mpidr_el1
+ mov_imm x1, MPIDR_AFFINITY_MASK
+ and x0, x0, x1
+ b 1f
+0: wfe
+1: ldr x1, uniphier_holding_pen_release
+ cmp x1, x0
+ b.ne 0b
+ ldr x0, uniphier_sec_entrypoint
+ br x0
+endfunc uniphier_warmboot_entrypoint
+
+func uniphier_fake_pwr_down
+ bl disable_mmu_icache_el3
+ b uniphier_warmboot_entrypoint
+endfunc uniphier_fake_pwr_down
diff --git a/plat/socionext/uniphier/uniphier_soc_info.c b/plat/socionext/uniphier/uniphier_soc_info.c
new file mode 100644
index 0000000..0e7a2d1
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_soc_info.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <lib/mmio.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_REVISION 0x5f800000UL
+#define UNIPHIER_REVISION_NEW 0x1f800000UL
+
+static unsigned int uniphier_get_revision_field(unsigned int mask,
+ unsigned int shift)
+{
+ uintptr_t reg;
+
+ if (BL_CODE_BASE >= 0x80000000UL)
+ reg = UNIPHIER_REVISION;
+ else
+ reg = UNIPHIER_REVISION_NEW;
+
+ return (mmio_read_32(reg) >> shift) & mask;
+}
+
+unsigned int uniphier_get_soc_type(void)
+{
+ return uniphier_get_revision_field(0xff, 16);
+}
+
+unsigned int uniphier_get_soc_model(void)
+{
+ return uniphier_get_revision_field(0x07, 8);
+}
+
+unsigned int uniphier_get_soc_revision(void)
+{
+ return uniphier_get_revision_field(0x1f, 0);
+}
+
+unsigned int uniphier_get_soc_id(void)
+{
+ uint32_t type = uniphier_get_soc_type();
+
+ switch (type) {
+ case 0x31:
+ return UNIPHIER_SOC_LD11;
+ case 0x32:
+ return UNIPHIER_SOC_LD20;
+ case 0x35:
+ return UNIPHIER_SOC_PXS3;
+ default:
+ return UNIPHIER_SOC_UNKNOWN;
+ }
+}
diff --git a/plat/socionext/uniphier/uniphier_syscnt.c b/plat/socionext/uniphier/uniphier_syscnt.c
new file mode 100644
index 0000000..1937843
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_syscnt.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+ return 50000000;
+}
diff --git a/plat/socionext/uniphier/uniphier_tbbr.c b/plat/socionext/uniphier/uniphier_tbbr.c
new file mode 100644
index 0000000..e31ca03
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_tbbr.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat/common/platform.h>
+
+extern char uniphier_rotpk_hash[], uniphier_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+ unsigned int *flags)
+{
+ *key_ptr = uniphier_rotpk_hash;
+ *key_len = uniphier_rotpk_hash_end - uniphier_rotpk_hash;
+ *flags = ROTPK_IS_HASH;
+
+ 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;
+}
+
+int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
+{
+ return get_mbedtls_heap_helper(heap_addr, heap_size);
+}
diff --git a/plat/socionext/uniphier/uniphier_topology.c b/plat/socionext/uniphier/uniphier_topology.c
new file mode 100644
index 0000000..c106c98
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_topology.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <plat/common/platform.h>
+
+#include "uniphier.h"
+
+static unsigned char uniphier_power_domain_tree_desc[UNIPHIER_CLUSTER_COUNT + 1];
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+ int i;
+
+ uniphier_power_domain_tree_desc[0] = UNIPHIER_CLUSTER_COUNT;
+
+ for (i = 0; i < UNIPHIER_CLUSTER_COUNT; i++)
+ uniphier_power_domain_tree_desc[i + 1] =
+ UNIPHIER_MAX_CPUS_PER_CLUSTER;
+
+ return uniphier_power_domain_tree_desc;
+}
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ unsigned int cluster_id, cpu_id;
+
+ cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+ if (cluster_id >= UNIPHIER_CLUSTER_COUNT)
+ return -1;
+
+ cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+ if (cpu_id >= UNIPHIER_MAX_CPUS_PER_CLUSTER)
+ return -1;
+
+ return uniphier_calc_core_pos(mpidr);
+}
diff --git a/plat/socionext/uniphier/uniphier_usb.c b/plat/socionext/uniphier/uniphier_usb.c
new file mode 100644
index 0000000..7469ad1
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_usb.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/io/io_block.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+#include "uniphier.h"
+
+#define UNIPHIER_LD11_USB_DESC_BASE 0x30010000
+#define UNIPHIER_LD20_USB_DESC_BASE 0x30014000
+#define UNIPHIER_PXS3_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;
+};
+
+struct uniphier_pxs3_op {
+ uint8_t __pad[184];
+ 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 void uniphier_pxs3_usb_init(void)
+{
+ struct uniphier_pxs3_op *op = (void *)UNIPHIER_PXS3_USB_DESC_BASE;
+
+ op->trans_op = (void *)(op + 1);
+
+ op->dev_desc = op->trans_op + 1;
+}
+
+static int uniphier_pxs3_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))0x39e8;
+
+ /* ROM-API - return 1 on success, 0 on error */
+ ret = rom_usb_read(UNIPHIER_PXS3_USB_DESC_BASE, lba, size, buf);
+
+ return ret ? 0 : -1;
+}
+
+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] = {
+ .init = uniphier_pxs3_usb_init,
+ .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 = {
+ .ops = {
+ .read = uniphier_usb_read,
+ },
+ .block_size = 512,
+};
+
+int uniphier_usb_init(unsigned int soc,
+ struct io_block_dev_spec **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 = &uniphier_usb_dev_spec;
+
+ return 0;
+}
diff --git a/plat/socionext/uniphier/uniphier_xlat_setup.c b/plat/socionext/uniphier/uniphier_xlat_setup.c
new file mode 100644
index 0000000..5043f4b
--- /dev/null
+++ b/plat/socionext/uniphier/uniphier_xlat_setup.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <common/debug.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include "uniphier.h"
+
+struct uniphier_reg_region {
+ uintptr_t base;
+ size_t size;
+};
+
+static const struct uniphier_reg_region uniphier_reg_region[] = {
+ [UNIPHIER_SOC_LD11] = {
+ .base = 0x50000000UL,
+ .size = 0x20000000UL,
+ },
+ [UNIPHIER_SOC_LD20] = {
+ .base = 0x50000000UL,
+ .size = 0x20000000UL,
+ },
+ [UNIPHIER_SOC_PXS3] = {
+ .base = 0x50000000UL,
+ .size = 0x20000000UL,
+ },
+};
+
+void uniphier_mmap_setup(unsigned int soc)
+{
+ VERBOSE("Trusted RAM seen by this BL image: %p - %p\n",
+ (void *)BL_CODE_BASE, (void *)BL_END);
+ mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
+ round_up(BL_END, PAGE_SIZE) - BL_CODE_BASE,
+ 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);
+
+ /* register region */
+ assert(soc < ARRAY_SIZE(uniphier_reg_region));
+ mmap_add_region(uniphier_reg_region[soc].base,
+ uniphier_reg_region[soc].base,
+ uniphier_reg_region[soc].size,
+ MT_DEVICE | MT_RW | MT_SECURE);
+
+ init_xlat_tables();
+
+ enable_mmu(0);
+
+#if PLAT_RO_XLAT_TABLES
+ {
+ int ret;
+
+ ret = xlat_make_tables_readonly();
+ if (ret) {
+ ERROR("Failed to make translation tables read-only.");
+ plat_error_handler(ret);
+ }
+ }
+#endif
+}