From dc1dfe831f02e4a0cda1a106518a63186f09e67f Mon Sep 17 00:00:00 2001 From: Wendy Liang Date: Wed, 13 Sep 2017 11:02:42 -0700 Subject: [PATCH 1/3] Introduce ZynqMP IPI implementation Previously, ZynqMP IPI in ATF is only for ZynqMP PM, This patch is to have a ZynqMP IPI implementation to handle both ZynqMP PM IPI requirement and IPI mailbox service requirement which will be introduced next. We control IPI agents registers access but not IPI buffers access in this implementation. Each IPI mailbox user will directly access the IPI buffers. Signed-off-by: Wendy Liang --- plat/xilinx/zynqmp/platform.mk | 1 + plat/xilinx/zynqmp/zynqmp_ipi.c | 283 ++++++++++++++++++++++++++++++++ plat/xilinx/zynqmp/zynqmp_ipi.h | 70 ++++++++ 3 files changed, 354 insertions(+) create mode 100644 plat/xilinx/zynqmp/zynqmp_ipi.c create mode 100644 plat/xilinx/zynqmp/zynqmp_ipi.h diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk index cb3b44218..a31e31d05 100644 --- a/plat/xilinx/zynqmp/platform.mk +++ b/plat/xilinx/zynqmp/platform.mk @@ -71,6 +71,7 @@ BL31_SOURCES += drivers/arm/cci/cci.c \ plat/xilinx/zynqmp/plat_startup.c \ plat/xilinx/zynqmp/plat_topology.c \ plat/xilinx/zynqmp/sip_svc_setup.c \ + plat/xilinx/zynqmp/zynqmp_ipi.c \ plat/xilinx/zynqmp/pm_service/pm_svc_main.c \ plat/xilinx/zynqmp/pm_service/pm_api_sys.c \ plat/xilinx/zynqmp/pm_service/pm_ipi.c \ diff --git a/plat/xilinx/zynqmp/zynqmp_ipi.c b/plat/xilinx/zynqmp/zynqmp_ipi.c new file mode 100644 index 000000000..755a3b7a7 --- /dev/null +++ b/plat/xilinx/zynqmp/zynqmp_ipi.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Zynq UltraScale+ MPSoC IPI agent registers access management + */ + +#include +#include +#include +#include +#include +#include +#include "zynqmp_ipi.h" +#include "../zynqmp_private.h" + +/********************************************************************* + * Macros definitions + ********************************************************************/ + +/* IPI registers base address */ +#define IPI_REGS_BASE 0xFF300000U + +/* 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) (zynqmp_ipi_table[(I)].ipi_reg_base) + +/* IPI register bit mask */ +#define IPI_BIT_MASK(I) (zynqmp_ipi_table[(I)].ipi_bit_mask) + +/* IPI secure check */ +#define IPI_SECURE_MASK 0x1U +#define IPI_IS_SECURE(I) ((zynqmp_ipi_table[(I)].secure_only & \ + IPI_SECURE_MASK) ? 1 : 0) + +/********************************************************************* + * Struct definitions + ********************************************************************/ + +/* structure to maintain IPI configuration information */ +struct zynqmp_ipi_config { + unsigned int ipi_bit_mask; + unsigned int ipi_reg_base; + unsigned char secure_only; +}; + +/* Zynqmp ipi configuration table */ +const static struct zynqmp_ipi_config zynqmp_ipi_table[] = { + /* APU IPI */ + { + .ipi_bit_mask = 0x1, + .ipi_reg_base = 0xFF300000, + .secure_only = 0, + }, + /* RPU0 IPI */ + { + .ipi_bit_mask = 0x100, + .ipi_reg_base = 0xFF310000, + .secure_only = 0, + }, + /* RPU1 IPI */ + { + .ipi_bit_mask = 0x200, + .ipi_reg_base = 0xFF320000, + .secure_only = 0, + }, + /* PMU0 IPI */ + { + .ipi_bit_mask = 0x10000, + .ipi_reg_base = 0xFF330000, + .secure_only = IPI_SECURE_MASK, + }, + /* PMU1 IPI */ + { + .ipi_bit_mask = 0x20000, + .ipi_reg_base = 0xFF331000, + .secure_only = IPI_SECURE_MASK, + }, + /* PMU2 IPI */ + { + .ipi_bit_mask = 0x40000, + .ipi_reg_base = 0xFF332000, + .secure_only = IPI_SECURE_MASK, + }, + /* PMU3 IPI */ + { + .ipi_bit_mask = 0x80000, + .ipi_reg_base = 0xFF333000, + .secure_only = IPI_SECURE_MASK, + }, + /* PL0 IPI */ + { + .ipi_bit_mask = 0x1000000, + .ipi_reg_base = 0xFF340000, + .secure_only = 0, + }, + /* PL1 IPI */ + { + .ipi_bit_mask = 0x2000000, + .ipi_reg_base = 0xFF350000, + .secure_only = 0, + }, + /* PL2 IPI */ + { + .ipi_bit_mask = 0x4000000, + .ipi_reg_base = 0xFF360000, + .secure_only = 0, + }, + /* PL3 IPI */ + { + .ipi_bit_mask = 0x8000000, + .ipi_reg_base = 0xFF370000, + .secure_only = 0, + }, +}; + +/* 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; + uint32_t ipi_total = ARRAY_SIZE(zynqmp_ipi_table); + + 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; + + 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 = 0; + 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/zynqmp/zynqmp_ipi.h b/plat/xilinx/zynqmp/zynqmp_ipi.h new file mode 100644 index 000000000..0544ddbfb --- /dev/null +++ b/plat/xilinx/zynqmp/zynqmp_ipi.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* ZynqMP IPI management enums and defines */ + +#ifndef _ZYNQMP_IPI_H_ +#define _ZYNQMP_IPI_H_ + +#include + +/********************************************************************* + * IPI agent IDs macros + ********************************************************************/ +#define IPI_ID_APU 0U +#define IPI_ID_RPU0 1U +#define IPI_ID_RPU1 2U +#define IPI_ID_PMU0 3U +#define IPI_ID_PMU1 4U +#define IPI_ID_PMU2 5U +#define IPI_ID_PMU3 6U +#define IPI_ID_PL0 7U +#define IPI_ID_PL1 8U +#define IPI_ID_PL2 9U +#define IPI_ID_PL3 10U + +/********************************************************************* + * IPI mailbox status macros + ********************************************************************/ +#define IPI_MB_STATUS_IDLE 0 +#define IPI_MB_STATUS_SEND_PENDING 1 +#define IPI_MB_STATUS_RECV_PENDING 2 + +/********************************************************************* + * IPI mailbox call is secure or not macros + ********************************************************************/ +#define IPI_MB_CALL_NOTSECURE 0 +#define IPI_MB_CALL_SECURE 1 + +/********************************************************************* + * IPI APIs declarations + ********************************************************************/ + +/* 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 /* _ZYNQMP_IPI_H_ */ From e8ffe79d062d03dd6113e8ac733e7a5f34453784 Mon Sep 17 00:00:00 2001 From: Wendy Liang Date: Wed, 6 Sep 2017 09:39:55 -0700 Subject: [PATCH 2/3] Add Xilinx ZynqMP IPI mailbox service Add IPI mailbox service to manage Xilinx ZynqMP IPI(Inter Processors Interrupt) access. Signed-off-by: Wendy Liang --- .../ipi_mailbox_service/ipi_mailbox_svc.c | 129 ++++++++++++++++++ .../ipi_mailbox_service/ipi_mailbox_svc.h | 39 ++++++ plat/xilinx/zynqmp/platform.mk | 6 +- plat/xilinx/zynqmp/sip_svc_setup.c | 14 +- 4 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c create mode 100644 plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h diff --git a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c b/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c new file mode 100644 index 000000000..bfc19d339 --- /dev/null +++ b/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Top-level SMC handler for ZynqMP IPI Mailbox doorbell functions. + */ + +#include +#include +#include +#include +#include +#include +#include "ipi_mailbox_svc.h" +#include "../zynqmp_ipi.h" +#include "../zynqmp_private.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, void *cookie, + void *handle, uint64_t flags) +{ + int ret; + uint32_t ipi_local_id; + uint32_t ipi_remote_id; + unsigned int 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: + { + int 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: + { + int 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/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h b/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h new file mode 100644 index 000000000..387ffd237 --- /dev/null +++ b/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017, 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 + +/********************************************************************* + * 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, void *cookie, void *handle, + uint64_t flags); + +#endif /* _IPI_MAILBOX_SVC_H_ */ diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk index a31e31d05..bdd194bda 100644 --- a/plat/xilinx/zynqmp/platform.mk +++ b/plat/xilinx/zynqmp/platform.mk @@ -42,7 +42,8 @@ $(eval $(call add_define_val,ZYNQMP_CONSOLE,ZYNQMP_CONSOLE_ID_${ZYNQMP_CONSOLE}) PLAT_INCLUDES := -Iinclude/plat/arm/common/ \ -Iinclude/plat/arm/common/aarch64/ \ -Iplat/xilinx/zynqmp/include/ \ - -Iplat/xilinx/zynqmp/pm_service/ + -Iplat/xilinx/zynqmp/pm_service/ \ + -Iplat/xilinx/zynqmp/ipi_mailbox_service/ PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch64/xlat_tables.c \ @@ -75,4 +76,5 @@ BL31_SOURCES += drivers/arm/cci/cci.c \ plat/xilinx/zynqmp/pm_service/pm_svc_main.c \ plat/xilinx/zynqmp/pm_service/pm_api_sys.c \ plat/xilinx/zynqmp/pm_service/pm_ipi.c \ - plat/xilinx/zynqmp/pm_service/pm_client.c + plat/xilinx/zynqmp/pm_service/pm_client.c \ + plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c diff --git a/plat/xilinx/zynqmp/sip_svc_setup.c b/plat/xilinx/zynqmp/sip_svc_setup.c index ae6ecafcd..8b44eaa8d 100644 --- a/plat/xilinx/zynqmp/sip_svc_setup.c +++ b/plat/xilinx/zynqmp/sip_svc_setup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -8,7 +8,9 @@ #include #include +#include "ipi_mailbox_svc.h" #include "pm_svc_main.h" +#include "zynqmp_ipi.h" /* SMC function IDs for SiP Service queries */ #define ZYNQMP_SIP_SVC_CALL_COUNT 0x8200ff00 @@ -19,10 +21,12 @@ #define SIP_SVC_VERSION_MAJOR 0 #define SIP_SVC_VERSION_MINOR 1 -/* These macros are used to identify PM calls from the SMC function ID */ +/* These macros are used to identify PM, IPI calls from the SMC function ID */ #define PM_FID_MASK 0xf000u #define PM_FID_VALUE 0u +#define IPI_FID_VALUE 0x1000u #define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE) +#define is_ipi_fid(_fid) (((_fid) & PM_FID_MASK) == IPI_FID_VALUE) /* SiP Service UUID */ DEFINE_SVC_UUID(zynqmp_sip_uuid, @@ -63,6 +67,12 @@ uint64_t sip_svc_smc_handler(uint32_t smc_fid, flags); } + /* Let IPI SMC handler deal with IPI-related requests */ + if (is_ipi_fid(smc_fid)) { + return ipi_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, + flags); + } + switch (smc_fid) { case ZYNQMP_SIP_SVC_CALL_COUNT: /* PM functions + default functions */ From ebc05162ae59467359dace8634133d49bfeade33 Mon Sep 17 00:00:00 2001 From: Wendy Liang Date: Tue, 3 Oct 2017 23:21:11 -0700 Subject: [PATCH 3/3] zynqmp: pm_service: use zynqmp_ipi APIs Use zynqmp_ipi APIs to access IPI registers in pm_service. As the zynqmp_ipi APIs doesn't cover IPI buffers, the pm_ipi in pm_service will still directly access the IPI buffers. Signed-off-by: Wendy Liang --- plat/xilinx/zynqmp/pm_service/pm_api_sys.c | 5 +- plat/xilinx/zynqmp/pm_service/pm_common.h | 8 +- plat/xilinx/zynqmp/pm_service/pm_ipi.c | 88 +++------------------ plat/xilinx/zynqmp/pm_service/pm_ipi.h | 9 +-- plat/xilinx/zynqmp/pm_service/pm_svc_main.c | 17 ++-- 5 files changed, 32 insertions(+), 95 deletions(-) diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c index 90c670d14..9e2106774 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -542,7 +542,6 @@ enum pm_ret_status pm_get_chipid(uint32_t *value) */ void pm_get_callbackdata(uint32_t *data, size_t count) { - pm_ipi_buff_read_callb(data, count); - pm_ipi_irq_clear(); + pm_ipi_irq_clear(primary_proc); } diff --git a/plat/xilinx/zynqmp/pm_service/pm_common.h b/plat/xilinx/zynqmp/pm_service/pm_common.h index 03351c246..5dcbb0d86 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_common.h +++ b/plat/xilinx/zynqmp/pm_service/pm_common.h @@ -21,13 +21,13 @@ /** * pm_ipi - struct for capturing IPI-channel specific info - * @mask mask for enabling/disabling and triggering the IPI - * @base base address for IPI + * @apu_ipi_id APU IPI agent ID + * @pmu_ipi_id PMU Agent ID * @buffer_base base address for payload buffer */ struct pm_ipi { - const unsigned int mask; - const uintptr_t base; + const uint32_t apu_ipi_id; + const uint32_t pmu_ipi_id; const uintptr_t buffer_base; }; diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.c b/plat/xilinx/zynqmp/pm_service/pm_ipi.c index fdffde772..58faf0e70 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_ipi.c +++ b/plat/xilinx/zynqmp/pm_service/pm_ipi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -8,28 +8,17 @@ #include #include #include +#include "../zynqmp_ipi.h" #include "../zynqmp_private.h" #include "pm_ipi.h" /* IPI message buffers */ #define IPI_BUFFER_BASEADDR 0xFF990000U -#define IPI_BUFFER_RPU_0_BASE (IPI_BUFFER_BASEADDR + 0x0U) -#define IPI_BUFFER_RPU_1_BASE (IPI_BUFFER_BASEADDR + 0x200U) #define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U) -#define IPI_BUFFER_PL_0_BASE (IPI_BUFFER_BASEADDR + 0x600U) -#define IPI_BUFFER_PL_1_BASE (IPI_BUFFER_BASEADDR + 0x800U) -#define IPI_BUFFER_PL_2_BASE (IPI_BUFFER_BASEADDR + 0xA00U) -#define IPI_BUFFER_PL_3_BASE (IPI_BUFFER_BASEADDR + 0xC00U) #define IPI_BUFFER_PMU_BASE (IPI_BUFFER_BASEADDR + 0xE00U) -#define IPI_BUFFER_TARGET_RPU_0_OFFSET 0x0U -#define IPI_BUFFER_TARGET_RPU_1_OFFSET 0x40U #define IPI_BUFFER_TARGET_APU_OFFSET 0x80U -#define IPI_BUFFER_TARGET_PL_0_OFFSET 0xC0U -#define IPI_BUFFER_TARGET_PL_1_OFFSET 0x100U -#define IPI_BUFFER_TARGET_PL_2_OFFSET 0x140U -#define IPI_BUFFER_TARGET_PL_3_OFFSET 0x180U #define IPI_BUFFER_TARGET_PMU_OFFSET 0x1C0U #define IPI_BUFFER_MAX_WORDS 8 @@ -37,75 +26,32 @@ #define IPI_BUFFER_REQ_OFFSET 0x0U #define IPI_BUFFER_RESP_OFFSET 0x20U -/* IPI Base Address */ -#define IPI_BASEADDR 0XFF300000 - -/* APU's IPI registers */ -#define IPI_APU_ISR (IPI_BASEADDR + 0X00000010) -#define IPI_APU_IER (IPI_BASEADDR + 0X00000018) -#define IPI_APU_IDR (IPI_BASEADDR + 0X0000001C) -#define IPI_APU_IXR_PMU_0_MASK (1 << 16) - -#define IPI_TRIG_OFFSET 0 -#define IPI_OBS_OFFSET 4 - -/* Power Management IPI interrupt number */ -#define PM_INT_NUM 0 -#define IPI_PMU_PM_INT_BASE (IPI_PMU_0_TRIG + (PM_INT_NUM * 0x1000)) -#define IPI_PMU_PM_INT_MASK (IPI_APU_IXR_PMU_0_MASK << PM_INT_NUM) -#if (PM_INT_NUM < 0 || PM_INT_NUM > 3) - #error PM_INT_NUM value out of range -#endif - -#define IPI_APU_MASK 1U - DEFINE_BAKERY_LOCK(pm_secure_lock); const struct pm_ipi apu_ipi = { - .mask = IPI_APU_MASK, - .base = IPI_BASEADDR, + .apu_ipi_id = IPI_ID_APU, + .pmu_ipi_id = IPI_ID_PMU0, .buffer_base = IPI_BUFFER_APU_BASE, }; /** * pm_ipi_init() - Initialize IPI peripheral for communication with PMU * + * @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 */ -int pm_ipi_init(void) +int pm_ipi_init(const struct pm_proc *proc) { bakery_lock_init(&pm_secure_lock); - - /* IPI Interrupts Clear & Disable */ - mmio_write_32(IPI_APU_ISR, 0xffffffff); - mmio_write_32(IPI_APU_IDR, 0xffffffff); + ipi_mb_open(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id); return 0; } -/** - * pm_ipi_wait() - wait for pmu to handle request - * @proc proc which is waiting for PMU to handle request - */ -static enum pm_ret_status pm_ipi_wait(const struct pm_proc *proc) -{ - int status; - - /* Wait until previous interrupt is handled by PMU */ - do { - status = mmio_read_32(proc->ipi->base + IPI_OBS_OFFSET) & - IPI_PMU_PM_INT_MASK; - /* TODO: 1) Use timer to add delay between read attempts */ - /* TODO: 2) Return PM_RET_ERR_TIMEOUT if this times out */ - } while (status); - - return PM_RET_SUCCESS; -} - /** * pm_ipi_send_common() - Sends IPI request to the PMU * @proc Pointer to the processor who is initiating request @@ -124,16 +70,13 @@ static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc, IPI_BUFFER_TARGET_PMU_OFFSET + IPI_BUFFER_REQ_OFFSET; - /* Wait until previous interrupt is handled by PMU */ - pm_ipi_wait(proc); - /* 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 PMU */ - mmio_write_32(proc->ipi->base + IPI_TRIG_OFFSET, IPI_PMU_PM_INT_MASK); + ipi_mb_notify(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id, 1); return PM_RET_SUCCESS; } @@ -178,8 +121,6 @@ static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc, IPI_BUFFER_TARGET_PMU_OFFSET + IPI_BUFFER_RESP_OFFSET; - pm_ipi_wait(proc); - /* * Read response from IPI buffer * buf-0: success or error+reason @@ -250,17 +191,12 @@ unlock: return ret; } -void pm_ipi_irq_enable(void) +void pm_ipi_irq_enable(const struct pm_proc *proc) { - mmio_write_32(IPI_APU_IER, IPI_APU_IXR_PMU_0_MASK); + ipi_mb_enable_irq(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id); } -void pm_ipi_irq_disable(void) +void pm_ipi_irq_clear(const struct pm_proc *proc) { - mmio_write_32(IPI_APU_IDR, IPI_APU_IXR_PMU_0_MASK); -} - -void pm_ipi_irq_clear(void) -{ - mmio_write_32(IPI_APU_ISR, IPI_APU_IXR_PMU_0_MASK); + ipi_mb_ack(proc->ipi->apu_ipi_id, proc->ipi->pmu_ipi_id); } diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.h b/plat/xilinx/zynqmp/pm_service/pm_ipi.h index a76298bd0..e6b36f529 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_ipi.h +++ b/plat/xilinx/zynqmp/pm_service/pm_ipi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -9,7 +9,7 @@ #include "pm_common.h" -int pm_ipi_init(void); +int 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]); @@ -17,8 +17,7 @@ enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, uint32_t payload[PAYLOAD_ARG_CNT], unsigned int *value, size_t count); void pm_ipi_buff_read_callb(unsigned int *value, size_t count); -void pm_ipi_irq_enable(void); -void pm_ipi_irq_disable(void); -void pm_ipi_irq_clear(void); +void pm_ipi_irq_enable(const struct pm_proc *proc); +void pm_ipi_irq_clear(const struct pm_proc *proc); #endif /* _PM_IPI_H_ */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c index f4e679bc4..fb64bc5cc 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -49,22 +49,25 @@ static struct { */ int pm_setup(void) { - int status; + int status, ret; if (!zynqmp_is_pmu_up()) return -ENODEV; - status = pm_ipi_init(); + status = pm_ipi_init(primary_proc); - if (status == 0) + if (status >= 0) { INFO("BL31: PM Service Init Complete: API v%d.%d\n", PM_VERSION_MAJOR, PM_VERSION_MINOR); - else + ret = 0; + } else { INFO("BL31: PM Service Init Failed, Error Code %d!\n", status); + ret = status; + } pm_down = status; - return status; + return ret; } /** @@ -163,7 +166,7 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, * Even if we were wrong, it would not enable the IRQ in * the GIC. */ - pm_ipi_irq_enable(); + pm_ipi_irq_enable(primary_proc); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)pm_ctx.api_version << 32));