diff options
Diffstat (limited to 'plat/xilinx/common/ipi.c')
-rw-r--r-- | plat/xilinx/common/ipi.c | 222 |
1 files changed, 222 insertions, 0 deletions
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)); +} |