diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c index 342714935..9a53408fd 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c @@ -65,6 +65,10 @@ unsigned int pm_get_shutdown_scope(void) PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4); \ } +#define EM_PACK_PAYLOAD1(pl, arg0) { \ + pl[0] = (uint16_t)(0xE) << 16 | (uint16_t)arg0; \ +} + /** * pm_self_suspend() - PM call for processor to suspend itself * @nid Node id of the processor or subsystem @@ -1617,3 +1621,30 @@ enum pm_ret_status pm_efuse_access(uint32_t address_high, return pm_ipi_send_sync(primary_proc, payload, value, 1); } + +enum pm_ret_status em_set_action(unsigned int *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + EM_PACK_PAYLOAD1(payload, EM_SET_ACTION); + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} + +enum pm_ret_status em_remove_action(unsigned int *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + EM_PACK_PAYLOAD1(payload, EM_REMOVE_ACTION); + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} + +enum pm_ret_status em_send_errors(unsigned int *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + EM_PACK_PAYLOAD1(payload, EM_SEND_ERRORS); + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h index b3ebb2752..b0c26529d 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h +++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h @@ -198,5 +198,8 @@ enum pm_ret_status pm_pll_set_mode(enum pm_node_id nid, enum pm_pll_mode mode); enum pm_ret_status pm_pll_get_mode(enum pm_node_id nid, enum pm_pll_mode *mode); enum pm_ret_status pm_efuse_access(uint32_t address_high, uint32_t address_low, uint32_t *value); +enum pm_ret_status em_set_action(unsigned int *value); +enum pm_ret_status em_remove_action(unsigned int *value); +enum pm_ret_status em_send_errors(unsigned int *value); #endif /* PM_API_SYS_H */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h index da8789301..ee31c9267 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_defs.h +++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h @@ -33,6 +33,7 @@ #define PM_STATE_CPU_IDLE 0x0U #define PM_STATE_SUSPEND_TO_RAM 0xFU +#define EM_FUNID_NUM_MASK 0xF0000U /********************************************************************* * Enum definitions ********************************************************************/ @@ -323,4 +324,13 @@ enum pm_clock_div_id { PM_CLOCK_DIV1_ID, }; +/** + * EM API IDs + */ +enum em_api_id { + EM_SET_ACTION = 1, + EM_REMOVE_ACTION, + EM_SEND_ERRORS, +}; + #endif /* PM_DEFS_H */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c index 5b3e73724..a4bc1ac08 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c @@ -628,3 +628,56 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, SMC_RET1(handle, SMC_UNK); } } + +/** + * em_smc_handler() - SMC handler for EM-API calls coming from EL1/EL2. + * @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 EM SMC Function ID from the + * list of em_api_ids, otherwise completes the request with + * the unknown SMC Function ID + * + * The SMC calls for EM service are forwarded from SIP Service SMC handler + * function with rt_svc_handle signature + */ +uint64_t em_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) +{ + enum pm_ret_status ret; + + switch (smc_fid & FUNCID_NUM_MASK) { + /* EM API Functions */ + case EM_SET_ACTION: + { + uint32_t value; + + ret = em_set_action(&value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case EM_REMOVE_ACTION: + { + uint32_t value; + + ret = em_remove_action(&value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case EM_SEND_ERRORS: + { + uint32_t value; + + ret = em_send_errors(&value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + default: + WARN("Unimplemented EM Service Call: 0x%x\n", smc_fid); + SMC_RET1(handle, SMC_UNK); + } +} diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.h b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h index 0968f64cb..abadd4065 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.h +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -14,4 +14,7 @@ uint64_t pm_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); +uint64_t em_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 /* PM_SVC_MAIN_H */ diff --git a/plat/xilinx/zynqmp/sip_svc_setup.c b/plat/xilinx/zynqmp/sip_svc_setup.c index 9b182749c..4c29da231 100644 --- a/plat/xilinx/zynqmp/sip_svc_setup.c +++ b/plat/xilinx/zynqmp/sip_svc_setup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -25,6 +25,9 @@ #define PM_FID_MASK 0xf000u #define PM_FID_VALUE 0u #define IPI_FID_VALUE 0x1000u +#define EM_FID_MASK 0xf0000u +#define EM_FID_VALUE 0xE0000u +#define is_em_fid(_fid) (((_fid) & EM_FID_MASK) == EM_FID_VALUE) #define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE) #define is_ipi_fid(_fid) (((_fid) & PM_FID_MASK) == IPI_FID_VALUE) @@ -61,8 +64,12 @@ uintptr_t sip_svc_smc_handler(uint32_t smc_fid, void *handle, u_register_t flags) { + /* Let EM SMC handler deal with EM-related requests */ + if (is_em_fid(smc_fid)) { + return em_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, + flags); + } else if (is_pm_fid(smc_fid)) { /* Let PM SMC handler deal with PM-related requests */ - if (is_pm_fid(smc_fid)) { return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); }