diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 17:43:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 17:43:51 +0000 |
commit | be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b (patch) | |
tree | 779c248fb61c83f65d1f0dc867f2053d76b4e03a /plat/socionext | |
parent | Initial commit. (diff) | |
download | arm-trusted-firmware-be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b.tar.xz arm-trusted-firmware-be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b.zip |
Adding upstream version 2.10.0+dfsg.upstream/2.10.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plat/socionext')
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 +} |