Merge pull request #1427 from b49020/integration
Add support for Socionext Synquacer SC2A11 SoC based Developerbox platform.
diff --git a/docs/plat/synquacer.rst b/docs/plat/synquacer.rst
new file mode 100644
index 0000000..ca53deb
--- /dev/null
+++ b/docs/plat/synquacer.rst
@@ -0,0 +1,117 @@
+Trusted Firmware-A for Socionext Synquacer SoCs
+===============================================
+
+Socionext's Synquacer SC2A11 is a multi-core processor with 24 cores of Arm
+Cortex-A53. The Developerbox, of 96boards, is a platform that contains this
+processor. This port of the Trusted Firmware only supports this platform at
+the moment.
+
+More information are listed in `link`_.
+
+How to build
+============
+
+Code Locations
+--------------
+
+- Trusted Firmware-A:
+ `link <https://github.com/ARM-software/arm-trusted-firmware>`__
+
+- edk2:
+ `link <https://github.com/tianocore/edk2>`__
+
+- edk2-platforms:
+ `link <https://github.com/tianocore/edk2-platforms>`__
+
+- edk2-non-osi:
+ `link <https://github.com/tianocore/edk2-non-osi>`__
+
+Boot Flow
+---------
+
+SCP firmware --> TF-A BL31 --> UEFI(edk2)
+
+Build Procedure
+---------------
+
+- Firstly, in addition to the “normal” build tools you will also need a
+ few specialist tools. On a Debian or Ubuntu operating system try:
+
+ .. code:: shell
+
+ sudo apt install acpica-tools device-tree-compiler uuid-dev
+
+- Secondly, create a new working directory and store the absolute path to this
+ directory in an environment variable, WORKSPACE. It does not matter where
+ this directory is created but as an example:
+
+ .. code:: shell
+
+ export WORKSPACE=$HOME/build/developerbox-firmware
+ mkdir -p $WORKSPACE
+
+- Run the following commands to clone the source code:
+
+ .. code:: shell
+
+ cd $WORKSPACE
+ git clone https://github.com/ARM-software/arm-trusted-firmware -b master
+ git clone https://github.com/tianocore/edk2.git -b master
+ git clone https://github.com/tianocore/edk2-platforms.git -b master
+ git clone https://github.com/tianocore/edk2-non-osi.git -b master
+
+- Build ATF:
+
+ .. code:: shell
+
+ cd $WORKSPACE/arm-trusted-firmware
+ make -j`nproc` PLAT=synquacer PRELOADED_BL33_BASE=0x8200000 bl31 fiptool
+ tools/fiptool/fiptool create \
+ --tb-fw ./build/synquacer/release/bl31.bin \
+ --soc-fw ./build/synquacer/release/bl31.bin \
+ --scp-fw ./build/synquacer/release/bl31.bin \
+ ../edk2-non-osi/Platform/Socionext/DeveloperBox/fip_all_arm_tf.bin
+
+- Build EDK2:
+
+ .. code:: shell
+
+ cd $WORKSPACE
+ export PACKAGES_PATH=$WORKSPACE/edk2:$WORKSPACE/edk2-platforms:$WORKSPACE/edk2-non-osi
+ export ACTIVE_PLATFORM="Platform/Socionext/DeveloperBox/DeveloperBox.dsc"
+ export GCC5_AARCH64_PREFIX=aarch64-linux-gnu-
+ unset ARCH
+
+ . edk2/edksetup.sh
+ make -C edk2/BaseTools
+
+ build -p $ACTIVE_PLATFORM -b RELEASE -a AARCH64 -t GCC5 -n `nproc` -D DO_X86EMU=TRUE
+
+- The firmware image, which comprises the option ROM, ARM trusted firmware and
+ EDK2 itself, can be found $WORKSPACE/../Build/DeveloperBox/RELEASE_GCC5/FV/.
+ Use SYNQUACERFIRMWAREUPDATECAPSULEFMPPKCS7.Cap for UEFI capsule update and
+ SPI_NOR_IMAGE.fd for the serial flasher.
+
+ Note #1: -t GCC5 can be loosely translated as “enable link-time-optimization”;
+ any version of gcc >= 5 will support this feature and may be used to build EDK2.
+
+ Note #2: Replace -b RELEASE with -b DEBUG to build a debug.
+
+Install the System Firmware
+---------------------------
+
+- Providing your Developerbox is fully working and has on operating system
+ installed then you can adopt your the newly compiled system firmware using
+ the capsule update method:.
+
+ .. code:: shell
+
+ sudo apt install fwupdate
+ sudo fwupdate --apply {50b94ce5-8b63-4849-8af4-ea479356f0e3} \
+ SYNQUACERFIRMWAREUPDATECAPSULEFMPPKCS7.Cap
+ sudo reboot
+
+- Alternatively you can install SPI_NOR_IMAGE.fd using the `board recovery method`_.
+
+.. _link: https://www.96boards.org/product/developerbox/
+.. _board recovery method: https://www.96boards.org/documentation/enterprise/developerbox/installation/board-recovery.md.html
diff --git a/maintainers.rst b/maintainers.rst
index 96ff0e0..4466a56 100644
--- a/maintainers.rst
+++ b/maintainers.rst
@@ -132,6 +132,16 @@
- plat/rockchip/\*
+Synquacer platform sub-maintainer
+---------------------------------
+
+Sumit Garg (sumit.garg@linaro.org, `b49020`_)
+
+Files:
+
+- docs/plat/synquacer.rst
+- plat/socionext/synquacer/\*
+
Texas Instruments platform sub-maintainer
-----------------------------------------
@@ -183,3 +193,4 @@
.. _etienne-lms: https://github.com/etienne-lms
.. _qoriq-open-source: https://github.com/qoriq-open-source
.. _Andre-ARM: https://github.com/Andre-ARM
+.. _b49020: https://github.com/b49020
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..5c2a635
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/mhu/sq_mhu.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bakery_lock.h>
+#include <mmio.h>
+#include <platform_def.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..bef117d
--- /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/scpi/sq_scpi.c b/plat/socionext/synquacer/drivers/scpi/sq_scpi.c
new file mode 100644
index 0000000..170b7e1
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scpi/sq_scpi.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <platform_def.h>
+#include <sq_common.h>
+#include <debug.h>
+#include <string.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..30fa5c7
--- /dev/null
+++ b/plat/socionext/synquacer/drivers/scpi/sq_scpi.h
@@ -0,0 +1,82 @@
+/*
+ * 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);
+
+#endif /* __SQ_SCPI_H__ */
diff --git a/plat/socionext/synquacer/include/plat_macros.S b/plat/socionext/synquacer/include/plat_macros.S
new file mode 100644
index 0000000..3dc06aa
--- /dev/null
+++ b/plat/socionext/synquacer/include/plat_macros.S
@@ -0,0 +1,15 @@
+/*
+ * 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..3e16642
--- /dev/null
+++ b/plat/socionext/synquacer/include/platform_def.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLATFORM_DEF_H__
+#define __PLATFORM_DEF_H__
+
+#include <common_def.h>
+
+/* CPU topology */
+#define PLAT_MAX_CORES_PER_CLUSTER 2
+#define PLAT_CLUSTER_COUNT 12
+#define PLATFORM_CORE_COUNT (PLAT_CLUSTER_COUNT * \
+ PLAT_MAX_CORES_PER_CLUSTER)
+
+#define PLAT_MAX_PWR_LVL 1
+#define PLAT_MAX_RET_STATE 1
+#define PLAT_MAX_OFF_STATE 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 4
+#define MAX_MMAP_REGIONS 6
+
+#define PLATFORM_STACK_SIZE 0x400
+
+#define BL31_BASE 0x04000000
+#define BL31_SIZE 0x00080000
+#define BL31_LIMIT (BL31_BASE + BL31_SIZE)
+
+#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 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
+
+#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..58b1e24
--- /dev/null
+++ b/plat/socionext/synquacer/include/sq_common.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __SQ_COMMON_H__
+#define __SQ_COMMON_H__
+
+#include <sys/types.h>
+#include <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 scpi_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);
+
+void sq_mmap_setup(uintptr_t total_base, size_t total_size,
+ const struct mmap_region *mmap);
+
+#endif /* __SQ_COMMON_H__ */
diff --git a/plat/socionext/synquacer/platform.mk b/plat/socionext/synquacer/platform.mk
new file mode 100644
index 0000000..546f84a
--- /dev/null
+++ b/plat/socionext/synquacer/platform.mk
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+override RESET_TO_BL31 := 1
+override ENABLE_PLAT_COMPAT := 0
+override MULTI_CONSOLE_API := 1
+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
+
+# 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
+
+PLAT_BL_COMMON_SOURCES += $(PLAT_PATH)/sq_helpers.S \
+ drivers/arm/pl011/pl011_console.S \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ ${XLAT_TABLES_LIB_SRCS}
+
+BL31_SOURCES += drivers/arm/ccn/ccn.c \
+ drivers/arm/gic/common/gic_common.c \
+ drivers/arm/gic/v3/gicv3_helpers.c \
+ drivers/arm/gic/v3/gicv3_main.c \
+ lib/cpus/aarch64/cortex_a53.S \
+ 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)/sq_xlat_setup.c \
+ $(PLAT_PATH)/drivers/scpi/sq_scpi.c \
+ $(PLAT_PATH)/drivers/mhu/sq_mhu.c
diff --git a/plat/socionext/synquacer/sq_bl31_setup.c b/plat/socionext/synquacer/sq_bl31_setup.c
new file mode 100644
index 0000000..461c8de
--- /dev/null
+++ b/plat/socionext/synquacer/sq_bl31_setup.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <platform_def.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <pl011.h>
+#include <debug.h>
+#include <mmio.h>
+#include <sq_common.h>
+
+static console_pl011_t console;
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+ assert(sec_state_is_valid(type));
+ return type == NON_SECURE ? &bl33_image_ep_info : &bl32_image_ep_info;
+}
+
+/*******************************************************************************
+ * 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_setup(bl31_params_t *from_bl2,
+ void *plat_params_from_bl2)
+{
+ /* 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, CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME);
+
+ /* There are no parameters from BL2 if BL31 is a reset vector */
+ assert(from_bl2 == NULL);
+ assert(plat_params_from_bl2 == NULL);
+
+#ifdef BL32_BASE
+ /* 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();
+#endif /* BL32_BASE */
+
+ /* 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);
+}
+
+static void sq_configure_sys_timer(void)
+{
+ unsigned int reg_val;
+
+ 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);
+}
+
+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(0) | CNTCR_EN);
+
+ /* Allow access to the System counter timer module */
+ sq_configure_sys_timer();
+
+ /* Initialize power controller before setting up topology */
+ plat_sq_pwrc_setup();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+ struct draminfo *di = (struct draminfo *)(unsigned long)DRAMINFO_BASE;
+
+ scpi_get_draminfo(di);
+}
+
+void bl31_plat_arch_setup(void)
+{
+ sq_mmap_setup(BL31_BASE, BL31_SIZE, NULL);
+ enable_mmu_el3(XLAT_TABLE_NC);
+}
+
+void bl31_plat_enable_mmu(uint32_t flags)
+{
+ enable_mmu_el3(flags | XLAT_TABLE_NC);
+}
+
+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;
+}
diff --git a/plat/socionext/synquacer/sq_ccn.c b/plat/socionext/synquacer/sq_ccn.c
new file mode 100644
index 0000000..bb70d5d
--- /dev/null
+++ b/plat/socionext/synquacer/sq_ccn.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <ccn.h>
+#include <platform_def.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..94e5a66
--- /dev/null
+++ b/plat/socionext/synquacer/sq_gicv3.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <gicv3.h>
+#include <interrupt_props.h>
+#include <platform.h>
+#include <platform_def.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..558aa15
--- /dev/null
+++ b/plat/socionext/synquacer/sq_helpers.S
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <platform_def.h>
+
+ .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
+ ldr x0, sq_sec_entrypoint
+
+ /* 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
+
+/*
+ * int plat_crash_console_flush(int c)
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : return -1 on error else return 0.
+ * Clobber list : x0, x1
+ */
+func plat_crash_console_flush
+ mov_imm x0, PLAT_SQ_BOOT_UART_BASE
+ b console_pl011_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/socionext/synquacer/sq_psci.c b/plat/socionext/synquacer/sq_psci.c
new file mode 100644
index 0000000..c327f1d
--- /dev/null
+++ b/plat/socionext/synquacer/sq_psci.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <cassert.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <generic_delay_timer.h>
+#include <platform_def.h>
+#include <sq_common.h>
+#include "sq_scpi.h"
+#include <psci.h>
+
+/* 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)
+
+uintptr_t sq_sec_entrypoint;
+
+int sq_pwr_domain_on(u_register_t mpidr)
+{
+ /*
+ * 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);
+
+ 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();
+}
+
+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);
+}
+
+void sq_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ sq_power_down_common(target_state);
+}
+
+void __dead2 sq_system_off(void)
+{
+ 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();
+}
+
+void __dead2 sq_system_reset(void)
+{
+ 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();
+}
+
+void sq_cpu_standby(plat_local_state_t cpu_state)
+{
+ unsigned int 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)
+{
+ sq_sec_entrypoint = sec_entrypoint;
+ flush_dcache_range((uint64_t)&sq_sec_entrypoint,
+ sizeof(sq_sec_entrypoint));
+
+ *psci_ops = &sq_psci_ops;
+
+ return 0;
+}
diff --git a/plat/socionext/synquacer/sq_topology.c b/plat/socionext/synquacer/sq_topology.c
new file mode 100644
index 0000000..aa20355
--- /dev/null
+++ b/plat/socionext/synquacer/sq_topology.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <sq_common.h>
+#include <platform_def.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..ae14700
--- /dev/null
+++ b/plat/socionext/synquacer/sq_xlat_setup.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <platform_def.h>
+#include <xlat_tables_v2.h>
+
+#define 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/readme.rst b/readme.rst
index 3738c97..c87936c 100644
--- a/readme.rst
+++ b/readme.rst
@@ -182,7 +182,7 @@
- QEMU emulator
- Raspberry Pi 3 board
- RockChip RK3328, RK3368 and RK3399 SoCs
-- Socionext UniPhier SoC family
+- Socionext UniPhier SoC family and SynQuacer SC2A11 SoCs
- Texas Instruments K3 SoCs
- Xilinx Zynq UltraScale + MPSoC