diff options
Diffstat (limited to '')
-rw-r--r-- | plat/xilinx/common/include/ipi.h | 77 | ||||
-rw-r--r-- | plat/xilinx/common/include/plat_startup.h | 41 | ||||
-rw-r--r-- | plat/xilinx/common/include/pm_client.h | 33 | ||||
-rw-r--r-- | plat/xilinx/common/include/pm_common.h | 62 | ||||
-rw-r--r-- | plat/xilinx/common/include/pm_ipi.h | 36 | ||||
-rw-r--r-- | plat/xilinx/common/ipi.c | 222 | ||||
-rw-r--r-- | plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c | 133 | ||||
-rw-r--r-- | plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h | 39 | ||||
-rw-r--r-- | plat/xilinx/common/plat_startup.c | 260 | ||||
-rw-r--r-- | plat/xilinx/common/pm_service/pm_ipi.c | 300 |
10 files changed, 1203 insertions, 0 deletions
diff --git a/plat/xilinx/common/include/ipi.h b/plat/xilinx/common/include/ipi.h new file mode 100644 index 0000000..1d62f3e --- /dev/null +++ b/plat/xilinx/common/include/ipi.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018, Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* Xilinx IPI management configuration data and macros */ + +#ifndef IPI_H +#define IPI_H + +#include <stdint.h> + +/********************************************************************* + * IPI mailbox status macros + ********************************************************************/ +#define IPI_MB_STATUS_IDLE (0U) +#define IPI_MB_STATUS_SEND_PENDING (1U) +#define IPI_MB_STATUS_RECV_PENDING (2U) + +/********************************************************************* + * IPI mailbox call is secure or not macros + ********************************************************************/ +#define IPI_MB_CALL_NOTSECURE (0U) +#define IPI_MB_CALL_SECURE (1U) + +/********************************************************************* + * IPI secure check + ********************************************************************/ +#define IPI_SECURE_MASK (0x1U) +#define IPI_IS_SECURE(I) ((ipi_table[(I)].secure_only & \ + IPI_SECURE_MASK) ? 1 : 0) + +/********************************************************************* + * Struct definitions + ********************************************************************/ + +/* structure to maintain IPI configuration information */ +struct ipi_config { + unsigned int ipi_bit_mask; + unsigned int ipi_reg_base; + unsigned char secure_only; +}; + +/********************************************************************* + * IPI APIs declarations + ********************************************************************/ + +/* Initialize IPI configuration table */ +void ipi_config_table_init(const struct ipi_config *ipi_config_table, + uint32_t total_ipi); + +/* Validate IPI mailbox access */ +int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure); + +/* Open the IPI mailbox */ +void ipi_mb_open(uint32_t local, uint32_t remote); + +/* Release the IPI mailbox */ +void ipi_mb_release(uint32_t local, uint32_t remote); + +/* Enquire IPI mailbox status */ +int ipi_mb_enquire_status(uint32_t local, uint32_t remote); + +/* Trigger notification on the IPI mailbox */ +void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking); + +/* Ack IPI mailbox notification */ +void ipi_mb_ack(uint32_t local, uint32_t remote); + +/* Disable IPI mailbox notification interrupt */ +void ipi_mb_disable_irq(uint32_t local, uint32_t remote); + +/* Enable IPI mailbox notification interrupt */ +void ipi_mb_enable_irq(uint32_t local, uint32_t remote); + +#endif /* IPI_H */ diff --git a/plat/xilinx/common/include/plat_startup.h b/plat/xilinx/common/include/plat_startup.h new file mode 100644 index 0000000..1733930 --- /dev/null +++ b/plat/xilinx/common/include/plat_startup.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_STARTUP_H +#define PLAT_STARTUP_H + +#include <common/bl_common.h> + +/* For FSBL handover */ +enum fsbl_handoff { + FSBL_HANDOFF_SUCCESS = 0, + FSBL_HANDOFF_NO_STRUCT, + FSBL_HANDOFF_INVAL_STRUCT, + FSBL_HANDOFF_TOO_MANY_PARTS +}; + +#define FSBL_MAX_PARTITIONS 8U + +/* Structure corresponding to each partition entry */ +struct xfsbl_partition { + uint64_t entry_point; + uint64_t flags; +}; + +/* Structure for handoff parameters to ARM Trusted Firmware (ATF) */ +struct xfsbl_atf_handoff_params { + uint8_t magic[4]; + uint32_t num_entries; + struct xfsbl_partition partition[FSBL_MAX_PARTITIONS]; +}; + +#define ATF_HANDOFF_PARAMS_MAX_SIZE sizeof(struct xfsbl_atf_handoff_params) + +enum fsbl_handoff fsbl_atf_handover(entry_point_info_t *bl32, + entry_point_info_t *bl33, + uint64_t atf_handoff_addr); + +#endif /* PLAT_STARTUP_H */ diff --git a/plat/xilinx/common/include/pm_client.h b/plat/xilinx/common/include/pm_client.h new file mode 100644 index 0000000..eae1d98 --- /dev/null +++ b/plat/xilinx/common/include/pm_client.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Contains APU specific macros and macros to be defined depending on + * the execution environment. + */ + +#ifndef PM_CLIENT_H +#define PM_CLIENT_H + +#include "pm_common.h" +#include "pm_defs.h" + +/* Functions to be implemented by each PU */ +void pm_client_suspend(const struct pm_proc *proc, uint32_t state); +void pm_client_abort_suspend(void); +void pm_client_wakeup(const struct pm_proc *proc); + +/* Global variables to be set in pm_client.c */ +extern const struct pm_proc *primary_proc; + +#if defined(PLAT_zynqmp) +enum pm_ret_status pm_set_suspend_mode(uint32_t mode); +const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid); +#endif /* PLAT_zynqmp */ + +#endif /* PM_CLIENT_H */ diff --git a/plat/xilinx/common/include/pm_common.h b/plat/xilinx/common/include/pm_common.h new file mode 100644 index 0000000..89626e5 --- /dev/null +++ b/plat/xilinx/common/include/pm_common.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Contains definitions of commonly used macros and data types needed + * for PU Power Management. This file should be common for all PU's. + */ + +#ifndef PM_COMMON_H +#define PM_COMMON_H + +#include <stdint.h> +#include <plat_pm_common.h> + +#if IPI_CRC_CHECK +#define PAYLOAD_ARG_CNT 8U +#define IPI_W0_TO_W6_SIZE 28U +#define PAYLOAD_CRC_POS 7U +#define CRC_INIT_VALUE 0x4F4EU +#define CRC_ORDER 16U +#define CRC_POLYNOM 0x8005U +#else +#define PAYLOAD_ARG_CNT 6U +#endif +#define PAYLOAD_ARG_SIZE 4U /* size in bytes */ + +#define TZ_VERSION_MAJOR 1 +#define TZ_VERSION_MINOR 0 +#define TZ_VERSION ((TZ_VERSION_MAJOR << 16) | \ + TZ_VERSION_MINOR) + +/** + * pm_ipi - struct for capturing IPI-channel specific info + * @local_ipi_id Local IPI agent ID + * @remote_ipi_id Remote IPI Agent ID + * @buffer_base base address for payload buffer + */ +struct pm_ipi { + const uint32_t local_ipi_id; + const uint32_t remote_ipi_id; + const uintptr_t buffer_base; +}; + +/** + * pm_proc - struct for capturing processor related info + * @node_id node-ID of the processor + * @pwrdn_mask cpu-specific mask to be used for power control register + * @ipi pointer to IPI channel structure + * (in APU all processors share one IPI channel) + */ +struct pm_proc { + const uint32_t node_id; + const uint32_t pwrdn_mask; + const struct pm_ipi *ipi; +}; + +const struct pm_proc *pm_get_proc(uint32_t cpuid); + +#endif /* PM_COMMON_H */ diff --git a/plat/xilinx/common/include/pm_ipi.h b/plat/xilinx/common/include/pm_ipi.h new file mode 100644 index 0000000..52dfc47 --- /dev/null +++ b/plat/xilinx/common/include/pm_ipi.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PM_IPI_H +#define PM_IPI_H + +#include <plat_ipi.h> +#include <stddef.h> +#include "pm_common.h" + +#define IPI_BLOCKING 1 +#define IPI_NON_BLOCKING 0 + +void pm_ipi_init(const struct pm_proc *proc); + +enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT]); +enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT]); +enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT], + uint32_t *value, size_t count); +void pm_ipi_buff_read_callb(uint32_t *value, size_t count); +void pm_ipi_irq_enable(const struct pm_proc *proc); +void pm_ipi_irq_clear(const struct pm_proc *proc); +uint32_t pm_ipi_irq_status(const struct pm_proc *proc); +#if IPI_CRC_CHECK +uint32_t calculate_crc(uint32_t payload[PAYLOAD_ARG_CNT], uint32_t buffersize); +#endif + +#endif /* PM_IPI_H */ diff --git a/plat/xilinx/common/ipi.c b/plat/xilinx/common/ipi.c new file mode 100644 index 0000000..6438896 --- /dev/null +++ b/plat/xilinx/common/ipi.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020-2022, Xilinx, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Xilinx IPI agent registers access management + */ + +#include <errno.h> +#include <string.h> + +#include <common/debug.h> +#include <common/runtime_svc.h> +#include <lib/bakery_lock.h> +#include <lib/mmio.h> + +#include <ipi.h> +#include <plat_private.h> + +/********************************************************************* + * Macros definitions + ********************************************************************/ + +/* IPI registers offsets macros */ +#define IPI_TRIG_OFFSET 0x00U +#define IPI_OBR_OFFSET 0x04U +#define IPI_ISR_OFFSET 0x10U +#define IPI_IMR_OFFSET 0x14U +#define IPI_IER_OFFSET 0x18U +#define IPI_IDR_OFFSET 0x1CU + +/* IPI register start offset */ +#define IPI_REG_BASE(I) (ipi_table[(I)].ipi_reg_base) + +/* IPI register bit mask */ +#define IPI_BIT_MASK(I) (ipi_table[(I)].ipi_bit_mask) + +/* IPI configuration table */ +const static struct ipi_config *ipi_table; + +/* Total number of IPI */ +static uint32_t ipi_total; + +/** + * ipi_config_init() - Initialize IPI configuration data + * + * @ipi_config_table - IPI configuration table + * @ipi_total - Total number of IPI available + * + */ +void ipi_config_table_init(const struct ipi_config *ipi_config_table, + uint32_t total_ipi) +{ + ipi_table = ipi_config_table; + ipi_total = total_ipi; +} + +/* is_ipi_mb_within_range() - verify if IPI mailbox is within range + * + * @local - local IPI ID + * @remote - remote IPI ID + * + * return - 1 if within range, 0 if not + */ +static inline int is_ipi_mb_within_range(uint32_t local, uint32_t remote) +{ + int ret = 1; + + if (remote >= ipi_total || local >= ipi_total) { + ret = 0; + } + + return ret; +} + +/** + * ipi_mb_validate() - validate IPI mailbox access + * + * @local - local IPI ID + * @remote - remote IPI ID + * @is_secure - indicate if the requester is from secure software + * + * return - 0 success, negative value for errors + */ +int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure) +{ + int ret = 0; + + if (!is_ipi_mb_within_range(local, remote)) { + ret = -EINVAL; + } else if (IPI_IS_SECURE(local) && !is_secure) { + ret = -EPERM; + } else if (IPI_IS_SECURE(remote) && !is_secure) { + ret = -EPERM; + } else { + /* To fix the misra 15.7 warning */ + } + + return ret; +} + +/** + * ipi_mb_open() - Open IPI mailbox. + * + * @local - local IPI ID + * @remote - remote IPI ID + * + */ +void ipi_mb_open(uint32_t local, uint32_t remote) +{ + mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET, + IPI_BIT_MASK(remote)); + mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET, + IPI_BIT_MASK(remote)); +} + +/** + * ipi_mb_release() - Open IPI mailbox. + * + * @local - local IPI ID + * @remote - remote IPI ID + * + */ +void ipi_mb_release(uint32_t local, uint32_t remote) +{ + mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET, + IPI_BIT_MASK(remote)); +} + +/** + * ipi_mb_enquire_status() - Enquire IPI mailbox status + * + * @local - local IPI ID + * @remote - remote IPI ID + * + * return - 0 idle, positive value for pending sending or receiving, + * negative value for errors + */ +int ipi_mb_enquire_status(uint32_t local, uint32_t remote) +{ + int ret = 0U; + uint32_t status; + + status = mmio_read_32(IPI_REG_BASE(local) + IPI_OBR_OFFSET); + if (status & IPI_BIT_MASK(remote)) { + ret |= IPI_MB_STATUS_SEND_PENDING; + } + status = mmio_read_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET); + if (status & IPI_BIT_MASK(remote)) { + ret |= IPI_MB_STATUS_RECV_PENDING; + } + + return ret; +} + +/* ipi_mb_notify() - Trigger IPI mailbox notification + * + * @local - local IPI ID + * @remote - remote IPI ID + * @is_blocking - if to trigger the notification in blocking mode or not. + * + * It sets the remote bit in the IPI agent trigger register. + * + */ +void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking) +{ + uint32_t status; + + mmio_write_32(IPI_REG_BASE(local) + IPI_TRIG_OFFSET, + IPI_BIT_MASK(remote)); + if (is_blocking) { + do { + status = mmio_read_32(IPI_REG_BASE(local) + + IPI_OBR_OFFSET); + } while (status & IPI_BIT_MASK(remote)); + } +} + +/* ipi_mb_ack() - Ack IPI mailbox notification from the other end + * + * @local - local IPI ID + * @remote - remote IPI ID + * + * It will clear the remote bit in the isr register. + * + */ +void ipi_mb_ack(uint32_t local, uint32_t remote) +{ + mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET, + IPI_BIT_MASK(remote)); +} + +/* ipi_mb_disable_irq() - Disable IPI mailbox notification interrupt + * + * @local - local IPI ID + * @remote - remote IPI ID + * + * It will mask the remote bit in the idr register. + * + */ +void ipi_mb_disable_irq(uint32_t local, uint32_t remote) +{ + mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET, + IPI_BIT_MASK(remote)); +} + +/* ipi_mb_enable_irq() - Enable IPI mailbox notification interrupt + * + * @local - local IPI ID + * @remote - remote IPI ID + * + * It will mask the remote bit in the idr register. + * + */ +void ipi_mb_enable_irq(uint32_t local, uint32_t remote) +{ + mmio_write_32(IPI_REG_BASE(local) + IPI_IER_OFFSET, + IPI_BIT_MASK(remote)); +} diff --git a/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c new file mode 100644 index 0000000..cb6aaa5 --- /dev/null +++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Top-level SMC handler for ZynqMP IPI Mailbox doorbell functions. + */ + +#include <errno.h> +#include <string.h> + +#include <common/debug.h> +#include <common/runtime_svc.h> +#include <lib/bakery_lock.h> +#include <lib/mmio.h> + +#include <ipi.h> +#include <plat_ipi.h> +#include <plat_private.h> + +#include "ipi_mailbox_svc.h" +#include "../../../services/spd/trusty/smcall.h" + +/********************************************************************* + * Macros definitions + ********************************************************************/ + +/* IPI SMC calls macros: */ +#define IPI_SMC_OPEN_IRQ_MASK 0x00000001U /* IRQ enable bit in IPI + * open SMC call + */ +#define IPI_SMC_NOTIFY_BLOCK_MASK 0x00000001U /* Flag to indicate if + * IPI notification needs + * to be blocking. + */ +#define IPI_SMC_ENQUIRY_DIRQ_MASK 0x00000001U /* Flag to indicate if + * notification interrupt + * to be disabled. + */ +#define IPI_SMC_ACK_EIRQ_MASK 0x00000001U /* Flag to indicate if + * notification interrupt + * to be enable. + */ + +#define UNSIGNED32_MASK 0xFFFFFFFFU /* 32bit mask */ + +/** + * ipi_smc_handler() - SMC handler for IPI SMC calls + * + * @smc_fid - Function identifier + * @x1 - x4 - Arguments + * @cookie - Unused + * @handler - Pointer to caller's context structure + * + * @return - Unused + * + * Determines that smc_fid is valid and supported PM SMC Function ID from the + * list of pm_api_ids, otherwise completes the request with + * the unknown SMC Function ID + * + * The SMC calls for PM service are forwarded from SIP Service SMC handler + * function with rt_svc_handle signature + */ +uint64_t ipi_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, + uint64_t x3, uint64_t x4, const void *cookie, + void *handle, uint64_t flags) +{ + int32_t ret; + uint32_t ipi_local_id; + uint32_t ipi_remote_id; + uint32_t is_secure; + + ipi_local_id = x1 & UNSIGNED32_MASK; + ipi_remote_id = x2 & UNSIGNED32_MASK; + + if (SMC_ENTITY(smc_fid) >= SMC_ENTITY_TRUSTED_APP) + is_secure = 1; + else + is_secure = 0; + + /* Validate IPI mailbox access */ + ret = ipi_mb_validate(ipi_local_id, ipi_remote_id, is_secure); + if (ret) + SMC_RET1(handle, ret); + + switch (SMC_FUNCTION(smc_fid)) { + case IPI_MAILBOX_OPEN: + ipi_mb_open(ipi_local_id, ipi_remote_id); + SMC_RET1(handle, 0); + case IPI_MAILBOX_RELEASE: + ipi_mb_release(ipi_local_id, ipi_remote_id); + SMC_RET1(handle, 0); + case IPI_MAILBOX_STATUS_ENQUIRY: + { + int32_t disable_irq; + + disable_irq = (x3 & IPI_SMC_ENQUIRY_DIRQ_MASK) ? 1 : 0; + ret = ipi_mb_enquire_status(ipi_local_id, ipi_remote_id); + if ((ret & IPI_MB_STATUS_RECV_PENDING) && disable_irq) + ipi_mb_disable_irq(ipi_local_id, ipi_remote_id); + SMC_RET1(handle, ret); + } + case IPI_MAILBOX_NOTIFY: + { + uint32_t is_blocking; + + is_blocking = (x3 & IPI_SMC_NOTIFY_BLOCK_MASK) ? 1 : 0; + ipi_mb_notify(ipi_local_id, ipi_remote_id, is_blocking); + SMC_RET1(handle, 0); + } + case IPI_MAILBOX_ACK: + { + int32_t enable_irq; + + enable_irq = (x3 & IPI_SMC_ACK_EIRQ_MASK) ? 1 : 0; + ipi_mb_ack(ipi_local_id, ipi_remote_id); + if (enable_irq) + ipi_mb_enable_irq(ipi_local_id, ipi_remote_id); + SMC_RET1(handle, 0); + } + case IPI_MAILBOX_ENABLE_IRQ: + ipi_mb_enable_irq(ipi_local_id, ipi_remote_id); + SMC_RET1(handle, 0); + case IPI_MAILBOX_DISABLE_IRQ: + ipi_mb_disable_irq(ipi_local_id, ipi_remote_id); + SMC_RET1(handle, 0); + default: + WARN("Unimplemented IPI service call: 0x%x\n", smc_fid); + SMC_RET1(handle, SMC_UNK); + } +} diff --git a/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h new file mode 100644 index 0000000..af13db9 --- /dev/null +++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* ZynqMP IPI mailbox doorbell service enums and defines */ + +#ifndef IPI_MAILBOX_SVC_H +#define IPI_MAILBOX_SVC_H + +#include <stdint.h> + +/********************************************************************* + * Enum definitions + ********************************************************************/ + +/* IPI SMC function numbers enum definition */ +enum ipi_api_id { + /* IPI mailbox operations functions: */ + IPI_MAILBOX_OPEN = 0x1000, + IPI_MAILBOX_RELEASE, + IPI_MAILBOX_STATUS_ENQUIRY, + IPI_MAILBOX_NOTIFY, + IPI_MAILBOX_ACK, + IPI_MAILBOX_ENABLE_IRQ, + IPI_MAILBOX_DISABLE_IRQ +}; + +/********************************************************************* + * IPI mailbox service APIs declarations + ********************************************************************/ + +/* IPI SMC handler */ +uint64_t ipi_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, + uint64_t x3, uint64_t x4, const void *cookie, void *handle, + uint64_t flags); + +#endif /* IPI_MAILBOX_SVC_H */ diff --git a/plat/xilinx/common/plat_startup.c b/plat/xilinx/common/plat_startup.c new file mode 100644 index 0000000..de9cf4d --- /dev/null +++ b/plat/xilinx/common/plat_startup.c @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <inttypes.h> +#include <stdint.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <plat_startup.h> + + +/* + * ATFHandoffParams + * Parameter bitfield encoding + * ----------------------------------------------------------------------------- + * Exec State 0 0 -> Aarch64, 1-> Aarch32 + * endianness 1 0 -> LE, 1 -> BE + * secure (TZ) 2 0 -> Non secure, 1 -> secure + * EL 3:4 00 -> EL0, 01 -> EL1, 10 -> EL2, 11 -> EL3 + * CPU# 5:6 00 -> A53_0, 01 -> A53_1, 10 -> A53_2, 11 -> A53_3 + */ + +#define FSBL_FLAGS_ESTATE_SHIFT 0U +#define FSBL_FLAGS_ESTATE_MASK (1U << FSBL_FLAGS_ESTATE_SHIFT) +#define FSBL_FLAGS_ESTATE_A64 0U +#define FSBL_FLAGS_ESTATE_A32 1U + +#define FSBL_FLAGS_ENDIAN_SHIFT 1U +#define FSBL_FLAGS_ENDIAN_MASK (1U << FSBL_FLAGS_ENDIAN_SHIFT) +#define FSBL_FLAGS_ENDIAN_LE 0U +#define FSBL_FLAGS_ENDIAN_BE 1U + +#define FSBL_FLAGS_TZ_SHIFT 2U +#define FSBL_FLAGS_TZ_MASK (1U << FSBL_FLAGS_TZ_SHIFT) +#define FSBL_FLAGS_NON_SECURE 0U +#define FSBL_FLAGS_SECURE 1U + +#define FSBL_FLAGS_EL_SHIFT 3U +#define FSBL_FLAGS_EL_MASK (3U << FSBL_FLAGS_EL_SHIFT) +#define FSBL_FLAGS_EL0 0U +#define FSBL_FLAGS_EL1 1U +#define FSBL_FLAGS_EL2 2U +#define FSBL_FLAGS_EL3 3U + +#define FSBL_FLAGS_CPU_SHIFT 5U +#define FSBL_FLAGS_CPU_MASK (3U << FSBL_FLAGS_CPU_SHIFT) +#define FSBL_FLAGS_A53_0 0U +#define FSBL_FLAGS_A53_1 1U +#define FSBL_FLAGS_A53_2 2U +#define FSBL_FLAGS_A53_3 3U + +/** + * @partition: Pointer to partition struct + * + * Get the target CPU for @partition. + * + * Return: FSBL_FLAGS_A53_0, FSBL_FLAGS_A53_1, FSBL_FLAGS_A53_2 or FSBL_FLAGS_A53_3 + */ +static int32_t get_fsbl_cpu(const struct xfsbl_partition *partition) +{ + uint64_t flags = partition->flags & FSBL_FLAGS_CPU_MASK; + + return flags >> FSBL_FLAGS_CPU_SHIFT; +} + +/** + * @partition: Pointer to partition struct + * + * Get the target exception level for @partition. + * + * Return: FSBL_FLAGS_EL0, FSBL_FLAGS_EL1, FSBL_FLAGS_EL2 or FSBL_FLAGS_EL3 + */ +static int32_t get_fsbl_el(const struct xfsbl_partition *partition) +{ + uint64_t flags = partition->flags & FSBL_FLAGS_EL_MASK; + + return flags >> FSBL_FLAGS_EL_SHIFT; +} + +/** + * @partition: Pointer to partition struct + * + * Get the target security state for @partition. + * + * Return: FSBL_FLAGS_NON_SECURE or FSBL_FLAGS_SECURE + */ +static int32_t get_fsbl_ss(const struct xfsbl_partition *partition) +{ + uint64_t flags = partition->flags & FSBL_FLAGS_TZ_MASK; + + return flags >> FSBL_FLAGS_TZ_SHIFT; +} + +/** + * @partition: Pointer to partition struct + * + * Get the target endianness for @partition. + * + * Return: SPSR_E_LITTLE or SPSR_E_BIG + */ +static int32_t get_fsbl_endian(const struct xfsbl_partition *partition) +{ + uint64_t flags = partition->flags & FSBL_FLAGS_ENDIAN_MASK; + + flags >>= FSBL_FLAGS_ENDIAN_SHIFT; + + if (flags == FSBL_FLAGS_ENDIAN_BE) { + return SPSR_E_BIG; + } else { + return SPSR_E_LITTLE; + } +} + +/** + * @partition: Pointer to partition struct + * + * Get the target execution state for @partition. + * + * Return: FSBL_FLAGS_ESTATE_A32 or FSBL_FLAGS_ESTATE_A64 + */ +static int32_t get_fsbl_estate(const struct xfsbl_partition *partition) +{ + uint64_t flags = partition->flags & FSBL_FLAGS_ESTATE_MASK; + + return flags >> FSBL_FLAGS_ESTATE_SHIFT; +} + +/** + * Populates the bl32 and bl33 image info structures + * @bl32: BL32 image info structure + * @bl33: BL33 image info structure + * atf_handoff_addr: ATF handoff address + * + * Process the handoff paramters from the FSBL and populate the BL32 and BL33 + * image info structures accordingly. + * + * Return: Return the status of the handoff. The value will be from the + * fsbl_handoff enum. + */ +enum fsbl_handoff fsbl_atf_handover(entry_point_info_t *bl32, + entry_point_info_t *bl33, + uint64_t atf_handoff_addr) +{ + const struct xfsbl_atf_handoff_params *ATFHandoffParams; + if (!atf_handoff_addr) { + WARN("BL31: No ATF handoff structure passed\n"); + return FSBL_HANDOFF_NO_STRUCT; + } + + ATFHandoffParams = (struct xfsbl_atf_handoff_params *)atf_handoff_addr; + if ((ATFHandoffParams->magic[0] != 'X') || + (ATFHandoffParams->magic[1] != 'L') || + (ATFHandoffParams->magic[2] != 'N') || + (ATFHandoffParams->magic[3] != 'X')) { + ERROR("BL31: invalid ATF handoff structure at %" PRIx64 "\n", + atf_handoff_addr); + return FSBL_HANDOFF_INVAL_STRUCT; + } + + VERBOSE("BL31: ATF handoff params at:0x%" PRIx64 ", entries:%u\n", + atf_handoff_addr, ATFHandoffParams->num_entries); + if (ATFHandoffParams->num_entries > FSBL_MAX_PARTITIONS) { + ERROR("BL31: ATF handoff params: too many partitions (%u/%u)\n", + ATFHandoffParams->num_entries, FSBL_MAX_PARTITIONS); + return FSBL_HANDOFF_TOO_MANY_PARTS; + } + + /* + * we loop over all passed entries but only populate two image structs + * (bl32, bl33). I.e. the last applicable images in the handoff + * structure will be used for the hand off + */ + for (size_t i = 0; i < ATFHandoffParams->num_entries; i++) { + entry_point_info_t *image; + int32_t target_estate, target_secure, target_cpu; + uint32_t target_endianness, target_el; + + VERBOSE("BL31: %zd: entry:0x%" PRIx64 ", flags:0x%" PRIx64 "\n", i, + ATFHandoffParams->partition[i].entry_point, + ATFHandoffParams->partition[i].flags); + + target_cpu = get_fsbl_cpu(&ATFHandoffParams->partition[i]); + if (target_cpu != FSBL_FLAGS_A53_0) { + WARN("BL31: invalid target CPU (%i)\n", target_cpu); + continue; + } + + target_el = get_fsbl_el(&ATFHandoffParams->partition[i]); + if ((target_el == FSBL_FLAGS_EL3) || + (target_el == FSBL_FLAGS_EL0)) { + WARN("BL31: invalid exception level (%i)\n", target_el); + continue; + } + + target_secure = get_fsbl_ss(&ATFHandoffParams->partition[i]); + if (target_secure == FSBL_FLAGS_SECURE && + target_el == FSBL_FLAGS_EL2) { + WARN("BL31: invalid security state (%i) for exception level (%i)\n", + target_secure, target_el); + continue; + } + + target_estate = get_fsbl_estate(&ATFHandoffParams->partition[i]); + target_endianness = get_fsbl_endian(&ATFHandoffParams->partition[i]); + + if (target_secure == FSBL_FLAGS_SECURE) { + image = bl32; + + if (target_estate == FSBL_FLAGS_ESTATE_A32) { + bl32->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, + target_endianness, + DISABLE_ALL_EXCEPTIONS); + } else { + bl32->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); + } + } else { + image = bl33; + + if (target_estate == FSBL_FLAGS_ESTATE_A32) { + if (target_el == FSBL_FLAGS_EL2) { + target_el = MODE32_hyp; + } else { + target_el = MODE32_sys; + } + + bl33->spsr = SPSR_MODE32(target_el, SPSR_T_ARM, + target_endianness, + DISABLE_ALL_EXCEPTIONS); + } else { + if (target_el == FSBL_FLAGS_EL2) { + target_el = MODE_EL2; + } else { + target_el = MODE_EL1; + } + + bl33->spsr = SPSR_64(target_el, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); + } + } + + VERBOSE("Setting up %s entry point to:%" PRIx64 ", el:%x\n", + target_secure == FSBL_FLAGS_SECURE ? "BL32" : "BL33", + ATFHandoffParams->partition[i].entry_point, + target_el); + image->pc = ATFHandoffParams->partition[i].entry_point; + + if (target_endianness == SPSR_E_BIG) { + EP_SET_EE(image->h.attr, EP_EE_BIG); + } else { + EP_SET_EE(image->h.attr, EP_EE_LITTLE); + } + } + + return FSBL_HANDOFF_SUCCESS; +} diff --git a/plat/xilinx/common/pm_service/pm_ipi.c b/plat/xilinx/common/pm_service/pm_ipi.c new file mode 100644 index 0000000..513d6be --- /dev/null +++ b/plat/xilinx/common/pm_service/pm_ipi.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#include <arch_helpers.h> +#include <lib/bakery_lock.h> +#include <lib/mmio.h> +#include <ipi.h> +#include <plat_ipi.h> +#include <plat_private.h> +#include <plat/common/platform.h> + +#include "pm_defs.h" +#include "pm_ipi.h" + +#define ERROR_CODE_MASK (0xFFFFU) +#define PM_OFFSET (0U) + +DEFINE_BAKERY_LOCK(pm_secure_lock); + +/** + * pm_ipi_init() - Initialize IPI peripheral for communication with + * remote processor + * + * @proc Pointer to the processor who is initiating request + * @return On success, the initialization function must return 0. + * Any other return value will cause the framework to ignore + * the service + * + * Called from pm_setup initialization function + */ +void pm_ipi_init(const struct pm_proc *proc) +{ + bakery_lock_init(&pm_secure_lock); + ipi_mb_open(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id); +} + +/** + * pm_ipi_send_common() - Sends IPI request to the remote processor + * @proc Pointer to the processor who is initiating request + * @payload API id and call arguments to be written in IPI buffer + * + * Send an IPI request to the power controller. Caller needs to hold + * the 'pm_secure_lock' lock. + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT], + uint32_t is_blocking) +{ + uint32_t offset = PM_OFFSET; + uintptr_t buffer_base = proc->ipi->buffer_base + + IPI_BUFFER_TARGET_REMOTE_OFFSET + + IPI_BUFFER_REQ_OFFSET; +#if IPI_CRC_CHECK + payload[PAYLOAD_CRC_POS] = calculate_crc(payload, IPI_W0_TO_W6_SIZE); +#endif + + /* Write payload into IPI buffer */ + for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) { + mmio_write_32(buffer_base + offset, payload[i]); + offset += PAYLOAD_ARG_SIZE; + } + + /* Generate IPI to remote processor */ + ipi_mb_notify(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id, + is_blocking); + + return PM_RET_SUCCESS; +} + +/** + * pm_ipi_send_non_blocking() - Sends IPI request to the remote processor + * without blocking notification + * @proc Pointer to the processor who is initiating request + * @payload API id and call arguments to be written in IPI buffer + * + * Send an IPI request to the power controller. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT]) +{ + enum pm_ret_status ret; + + bakery_lock_get(&pm_secure_lock); + + ret = pm_ipi_send_common(proc, payload, IPI_NON_BLOCKING); + + bakery_lock_release(&pm_secure_lock); + + return ret; +} + +/** + * pm_ipi_send() - Sends IPI request to the remote processor + * @proc Pointer to the processor who is initiating request + * @payload API id and call arguments to be written in IPI buffer + * + * Send an IPI request to the power controller. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT]) +{ + enum pm_ret_status ret; + + bakery_lock_get(&pm_secure_lock); + + ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING); + + bakery_lock_release(&pm_secure_lock); + + return ret; +} + + +/** + * pm_ipi_buff_read() - Reads IPI response after remote processor has handled + * interrupt + * @proc Pointer to the processor who is waiting and reading response + * @value Used to return value from IPI buffer element (optional) + * @count Number of values to return in @value + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc, + uint32_t *value, size_t count) +{ + size_t i; +#if IPI_CRC_CHECK + size_t j; + uint32_t response_payload[PAYLOAD_ARG_CNT]; +#endif + uintptr_t buffer_base = proc->ipi->buffer_base + + IPI_BUFFER_TARGET_REMOTE_OFFSET + + IPI_BUFFER_RESP_OFFSET; + + /* + * Read response from IPI buffer + * buf-0: success or error+reason + * buf-1: value + * buf-2: unused + * buf-3: unused + */ + for (i = 1; i <= count; i++) { + *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE)); + value++; + } +#if IPI_CRC_CHECK + for (j = 0; j < PAYLOAD_ARG_CNT; j++) { + response_payload[j] = mmio_read_32(buffer_base + + (j * PAYLOAD_ARG_SIZE)); + } + + if (response_payload[PAYLOAD_CRC_POS] != + calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) { + NOTICE("ERROR in CRC response payload value:0x%x\n", + response_payload[PAYLOAD_CRC_POS]); + } +#endif + + return mmio_read_32(buffer_base); +} + +/** + * pm_ipi_buff_read_callb() - Reads IPI response after remote processor has + * handled interrupt + * @value Used to return value from IPI buffer element (optional) + * @count Number of values to return in @value + * + * @return Returns status, either success or error+reason + */ +void pm_ipi_buff_read_callb(uint32_t *value, size_t count) +{ + size_t i; +#if IPI_CRC_CHECK + size_t j; + unsigned int response_payload[PAYLOAD_ARG_CNT] = {0}; +#endif + uintptr_t buffer_base = IPI_BUFFER_REMOTE_BASE + + IPI_BUFFER_TARGET_LOCAL_OFFSET + + IPI_BUFFER_REQ_OFFSET; + + if (count > IPI_BUFFER_MAX_WORDS) { + count = IPI_BUFFER_MAX_WORDS; + } + + for (i = 0; i <= count; i++) { + *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE)); + value++; + } +#if IPI_CRC_CHECK + for (j = 0; j < PAYLOAD_ARG_CNT; j++) { + response_payload[j] = mmio_read_32(buffer_base + + (j * PAYLOAD_ARG_SIZE)); + } + + if (response_payload[PAYLOAD_CRC_POS] != + calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) { + NOTICE("ERROR in CRC response payload value:0x%x\n", + response_payload[PAYLOAD_CRC_POS]); + } +#endif +} + +/** + * pm_ipi_send_sync() - Sends IPI request to the remote processor + * @proc Pointer to the processor who is initiating request + * @payload API id and call arguments to be written in IPI buffer + * @value Used to return value from IPI buffer element (optional) + * @count Number of values to return in @value + * + * Send an IPI request to the power controller and wait for it to be handled. + * + * @return Returns status, either success or error+reason and, optionally, + * @value + */ +enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, + uint32_t payload[PAYLOAD_ARG_CNT], + uint32_t *value, size_t count) +{ + enum pm_ret_status ret; + + bakery_lock_get(&pm_secure_lock); + + ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING); + if (ret != PM_RET_SUCCESS) { + goto unlock; + } + + ret = ERROR_CODE_MASK & (pm_ipi_buff_read(proc, value, count)); + +unlock: + bakery_lock_release(&pm_secure_lock); + + return ret; +} + +void pm_ipi_irq_enable(const struct pm_proc *proc) +{ + ipi_mb_enable_irq(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id); +} + +void pm_ipi_irq_clear(const struct pm_proc *proc) +{ + ipi_mb_ack(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id); +} + +uint32_t pm_ipi_irq_status(const struct pm_proc *proc) +{ + int32_t ret; + + ret = ipi_mb_enquire_status(proc->ipi->local_ipi_id, + proc->ipi->remote_ipi_id); + if (ret & IPI_MB_STATUS_RECV_PENDING) { + return 1; + } else { + return 0; + } +} + +#if IPI_CRC_CHECK +uint32_t calculate_crc(uint32_t payload[PAYLOAD_ARG_CNT], uint32_t bufsize) +{ + uint32_t crcinit = CRC_INIT_VALUE; + uint32_t order = CRC_ORDER; + uint32_t polynom = CRC_POLYNOM; + uint32_t i, j, c, bit, datain, crcmask, crchighbit; + uint32_t crc = crcinit; + + crcmask = ((uint32_t)((1U << (order - 1U)) - 1U) << 1U) | 1U; + crchighbit = (uint32_t)(1U << (order - 1U)); + + for (i = 0U; i < bufsize; i++) { + datain = mmio_read_8((unsigned long)payload + i); + c = datain; + j = 0x80U; + while (j != 0U) { + bit = crc & crchighbit; + crc <<= 1U; + if (0U != (c & j)) + bit ^= crchighbit; + if (bit != 0U) + crc ^= polynom; + j >>= 1U; + } + crc &= crcmask; + } + return crc; +} +#endif |