From: Jay Buddhabhatti Date: Thu, 22 Dec 2022 07:03:35 +0000 (-0800) Subject: refactor(xilinx): move versal files to common place X-Git-Tag: baikal/aarch64/sdk5.10~1^2~127^2 X-Git-Url: https://git.baikalelectronics.ru/?a=commitdiff_plain;h=a92681d9264467e98042f94df36a2184a5cf8270;p=arm-tf.git refactor(xilinx): move versal files to common place Moved necessary files to common place so that it can be used for Versal NET. Signed-off-by: Jay Buddhabhatti Change-Id: I611fa849207b082e6599acfb65c55d27b9c99435 --- diff --git a/plat/xilinx/common/include/pm_api_sys.h b/plat/xilinx/common/include/pm_api_sys.h new file mode 100644 index 000000000..e7b1567dd --- /dev/null +++ b/plat/xilinx/common/include/pm_api_sys.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PM_API_SYS_H +#define PM_API_SYS_H + +#include +#include "pm_defs.h" + +/********************************************************************* + * Target module IDs macros + ********************************************************************/ +#define LIBPM_MODULE_ID 0x2U +#define LOADER_MODULE_ID 0x7U + +#define MODULE_ID_MASK 0x0000ff00U +/********************************************************** + * PM API function declarations + **********************************************************/ + +enum pm_ret_status pm_handle_eemi_call(uint32_t flag, uint32_t x0, uint32_t x1, + uint32_t x2, uint32_t x3, uint32_t x4, + uint32_t x5, uint64_t *result); +enum pm_ret_status pm_self_suspend(uint32_t nid, + uint32_t latency, + uint32_t state, + uintptr_t address, uint32_t flag); +enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason, uint32_t flag); +enum pm_ret_status pm_req_suspend(uint32_t target, + uint8_t ack, + uint32_t latency, + uint32_t state, uint32_t flag); +enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address, + uintptr_t address, uint8_t ack, uint32_t flag); +enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t device_id, + uint8_t enable, uint32_t flag); +enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag, + uint32_t ack); +enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param, + uint32_t value, uint32_t flag); +enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param, + uint32_t *value, uint32_t flag); +enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode, + uint32_t flag); +enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode, + uint32_t flag); +enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack, + uint32_t flag); +enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype, + uint32_t flag); +enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id, + uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t *value, uint32_t flag); +enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2, + uint32_t arg3, uint32_t *data, uint32_t flag); +uint32_t pm_get_shutdown_scope(void); +enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *ret_payload, + uint32_t flag); +enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low, + uint32_t address_high, uint32_t flag); +enum pm_ret_status pm_register_notifier(uint32_t device_id, uint32_t event, + uint32_t wake, uint32_t enable, + uint32_t flag); + +/** + * Assigning of argument values into array elements. + */ +#define PM_PACK_PAYLOAD1(pl, mid, flag, arg0) { \ + pl[0] = (uint32_t)(((uint32_t)(arg0) & 0xFFU) | ((mid) << 8U) | ((flag) << 24U)); \ +} + +#define PM_PACK_PAYLOAD2(pl, mid, flag, arg0, arg1) { \ + pl[1] = (uint32_t)(arg1); \ + PM_PACK_PAYLOAD1(pl, (mid), (flag), (arg0)); \ +} + +#define PM_PACK_PAYLOAD3(pl, mid, flag, arg0, arg1, arg2) { \ + pl[2] = (uint32_t)(arg2); \ + PM_PACK_PAYLOAD2(pl, (mid), (flag), (arg0), (arg1)); \ +} + +#define PM_PACK_PAYLOAD4(pl, mid, flag, arg0, arg1, arg2, arg3) { \ + pl[3] = (uint32_t)(arg3); \ + PM_PACK_PAYLOAD3(pl, (mid), (flag), (arg0), (arg1), (arg2)); \ +} + +#define PM_PACK_PAYLOAD5(pl, mid, flag, arg0, arg1, arg2, arg3, arg4) { \ + pl[4] = (uint32_t)(arg4); \ + PM_PACK_PAYLOAD4(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3)); \ +} + +#define PM_PACK_PAYLOAD6(pl, mid, flag, arg0, arg1, arg2, arg3, arg4, arg5) { \ + pl[5] = (uint32_t)(arg5); \ + PM_PACK_PAYLOAD5(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3), (arg4)); \ +} + +#endif /* PM_API_SYS_H */ diff --git a/plat/xilinx/common/include/pm_node.h b/plat/xilinx/common/include/pm_node.h new file mode 100644 index 000000000..371c72d7e --- /dev/null +++ b/plat/xilinx/common/include/pm_node.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2019, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* Versal PM nodes enums and defines */ + +#ifndef PM_NODE_H +#define PM_NODE_H + +/********************************************************************* + * Macro definitions + ********************************************************************/ + +#define NODE_CLASS_SHIFT 26U +#define NODE_SUBCLASS_SHIFT 20U +#define NODE_TYPE_SHIFT 14U +#define NODE_INDEX_SHIFT 0U +#define NODE_CLASS_MASK_BITS 0x3F +#define NODE_SUBCLASS_MASK_BITS 0x3F +#define NODE_TYPE_MASK_BITS 0x3F +#define NODE_INDEX_MASK_BITS 0x3FFF +#define NODE_CLASS_MASK (NODE_CLASS_MASK_BITS << NODE_CLASS_SHIFT) +#define NODE_SUBCLASS_MASK (NODE_SUBCLASS_MASK_BITS << NODE_SUBCLASS_SHIFT) +#define NODE_TYPE_MASK (NODE_TYPE_MASK_BITS << NODE_TYPE_SHIFT) +#define NODE_INDEX_MASK (NODE_INDEX_MASK_BITS << NODE_INDEX_SHIFT) + +#define NODEID(CLASS, SUBCLASS, TYPE, INDEX) \ + ((((CLASS) & NODE_CLASS_MASK_BITS) << NODE_CLASS_SHIFT) | \ + (((SUBCLASS) & NODE_SUBCLASS_MASK_BITS) << NODE_SUBCLASS_SHIFT) | \ + (((TYPE) & NODE_TYPE_MASK_BITS) << NODE_TYPE_SHIFT) | \ + (((INDEX) & NODE_INDEX_MASK_BITS) << NODE_INDEX_SHIFT)) + +#define NODECLASS(ID) (((ID) & NODE_CLASS_MASK) >> NODE_CLASS_SHIFT) +#define NODESUBCLASS(ID) (((ID) & NODE_SUBCLASS_MASK) >> \ + NODE_SUBCLASS_SHIFT) +#define NODETYPE(ID) (((ID) & NODE_TYPE_MASK) >> NODE_TYPE_SHIFT) +#define NODEINDEX(ID) (((ID) & NODE_INDEX_MASK) >> NODE_INDEX_SHIFT) + +/********************************************************************* + * Enum definitions + ********************************************************************/ + +/* Node class types */ +enum pm_node_class { + XPM_NODECLASS_MIN, + + XPM_NODECLASS_POWER, + XPM_NODECLASS_CLOCK, + XPM_NODECLASS_RESET, + XPM_NODECLASS_MEMIC, + XPM_NODECLASS_STMIC, + XPM_NODECLASS_DEVICE, + + XPM_NODECLASS_MAX +}; + +enum pm_device_node_subclass { + /* Device types */ + XPM_NODESUBCL_DEV_CORE = 1, + XPM_NODESUBCL_DEV_PERIPH, + XPM_NODESUBCL_DEV_MEM, + XPM_NODESUBCL_DEV_SOC, + XPM_NODESUBCL_DEV_MEM_CTRLR, + XPM_NODESUBCL_DEV_PHY, +}; + +enum pm_device_node_type { + /* Device types */ + XPM_NODETYPE_DEV_CORE_PMC = 1, + XPM_NODETYPE_DEV_CORE_PSM, + XPM_NODETYPE_DEV_CORE_APU, + XPM_NODETYPE_DEV_CORE_RPU, + XPM_NODETYPE_DEV_OCM, + XPM_NODETYPE_DEV_TCM, + XPM_NODETYPE_DEV_L2CACHE, + XPM_NODETYPE_DEV_DDR, + XPM_NODETYPE_DEV_PERIPH, + XPM_NODETYPE_DEV_SOC, + XPM_NODETYPE_DEV_GT, +}; + +/* Device node Indexes */ +enum pm_device_node_idx { + /* Device nodes */ + XPM_NODEIDX_DEV_MIN, + + /* Processor devices */ + XPM_NODEIDX_DEV_PMC_PROC, + XPM_NODEIDX_DEV_PSM_PROC, + XPM_NODEIDX_DEV_ACPU_0, + XPM_NODEIDX_DEV_ACPU_1, + XPM_NODEIDX_DEV_RPU0_0, + XPM_NODEIDX_DEV_RPU0_1, + + /* Memory devices */ + XPM_NODEIDX_DEV_OCM_0, + XPM_NODEIDX_DEV_OCM_1, + XPM_NODEIDX_DEV_OCM_2, + XPM_NODEIDX_DEV_OCM_3, + XPM_NODEIDX_DEV_TCM_0_A, + XPM_NODEIDX_DEV_TCM_0_B, + XPM_NODEIDX_DEV_TCM_1_A, + XPM_NODEIDX_DEV_TCM_1_B, + XPM_NODEIDX_DEV_L2_BANK_0, + XPM_NODEIDX_DEV_DDR_0, + XPM_NODEIDX_DEV_DDR_1, + XPM_NODEIDX_DEV_DDR_2, + XPM_NODEIDX_DEV_DDR_3, + XPM_NODEIDX_DEV_DDR_4, + XPM_NODEIDX_DEV_DDR_5, + XPM_NODEIDX_DEV_DDR_6, + XPM_NODEIDX_DEV_DDR_7, + + /* LPD Peripheral devices */ + XPM_NODEIDX_DEV_USB_0, + XPM_NODEIDX_DEV_GEM_0, + XPM_NODEIDX_DEV_GEM_1, + XPM_NODEIDX_DEV_SPI_0, + XPM_NODEIDX_DEV_SPI_1, + XPM_NODEIDX_DEV_I2C_0, + XPM_NODEIDX_DEV_I2C_1, + XPM_NODEIDX_DEV_CAN_FD_0, + XPM_NODEIDX_DEV_CAN_FD_1, + XPM_NODEIDX_DEV_UART_0, + XPM_NODEIDX_DEV_UART_1, + XPM_NODEIDX_DEV_GPIO, + XPM_NODEIDX_DEV_TTC_0, + XPM_NODEIDX_DEV_TTC_1, + XPM_NODEIDX_DEV_TTC_2, + XPM_NODEIDX_DEV_TTC_3, + XPM_NODEIDX_DEV_SWDT_LPD, + + /* FPD Peripheral devices */ + XPM_NODEIDX_DEV_SWDT_FPD, + + /* PMC Peripheral devices */ + XPM_NODEIDX_DEV_OSPI, + XPM_NODEIDX_DEV_QSPI, + XPM_NODEIDX_DEV_GPIO_PMC, + XPM_NODEIDX_DEV_I2C_PMC, + XPM_NODEIDX_DEV_SDIO_0, + XPM_NODEIDX_DEV_SDIO_1, + + XPM_NODEIDX_DEV_PL_0, + XPM_NODEIDX_DEV_PL_1, + XPM_NODEIDX_DEV_PL_2, + XPM_NODEIDX_DEV_PL_3, + XPM_NODEIDX_DEV_RTC, + XPM_NODEIDX_DEV_ADMA_0, + XPM_NODEIDX_DEV_ADMA_1, + XPM_NODEIDX_DEV_ADMA_2, + XPM_NODEIDX_DEV_ADMA_3, + XPM_NODEIDX_DEV_ADMA_4, + XPM_NODEIDX_DEV_ADMA_5, + XPM_NODEIDX_DEV_ADMA_6, + XPM_NODEIDX_DEV_ADMA_7, + XPM_NODEIDX_DEV_IPI_0, + XPM_NODEIDX_DEV_IPI_1, + XPM_NODEIDX_DEV_IPI_2, + XPM_NODEIDX_DEV_IPI_3, + XPM_NODEIDX_DEV_IPI_4, + XPM_NODEIDX_DEV_IPI_5, + XPM_NODEIDX_DEV_IPI_6, + + /* Entire SoC */ + XPM_NODEIDX_DEV_SOC, + + /* DDR memory controllers */ + XPM_NODEIDX_DEV_DDRMC_0, + XPM_NODEIDX_DEV_DDRMC_1, + XPM_NODEIDX_DEV_DDRMC_2, + XPM_NODEIDX_DEV_DDRMC_3, + + /* GT devices */ + XPM_NODEIDX_DEV_GT_0, + XPM_NODEIDX_DEV_GT_1, + XPM_NODEIDX_DEV_GT_2, + XPM_NODEIDX_DEV_GT_3, + XPM_NODEIDX_DEV_GT_4, + XPM_NODEIDX_DEV_GT_5, + XPM_NODEIDX_DEV_GT_6, + XPM_NODEIDX_DEV_GT_7, + XPM_NODEIDX_DEV_GT_8, + XPM_NODEIDX_DEV_GT_9, + XPM_NODEIDX_DEV_GT_10, + + XPM_NODEIDX_DEV_MAX +}; + +#endif /* PM_NODE_H */ diff --git a/plat/xilinx/common/include/pm_svc_main.h b/plat/xilinx/common/include/pm_svc_main.h new file mode 100644 index 000000000..1a27bdfae --- /dev/null +++ b/plat/xilinx/common/include/pm_svc_main.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PM_SVC_MAIN_H +#define PM_SVC_MAIN_H + +#include + +int32_t pm_setup(void); +uint64_t pm_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 pm_register_sgi(uint32_t sgi_num, uint32_t reset); +#endif /* PM_SVC_MAIN_H */ diff --git a/plat/xilinx/common/pm_service/pm_api_sys.c b/plat/xilinx/common/pm_service/pm_api_sys.c new file mode 100644 index 000000000..6ff61af9e --- /dev/null +++ b/plat/xilinx/common/pm_service/pm_api_sys.c @@ -0,0 +1,593 @@ +/* + * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Versal system level PM-API functions and communication with PMC via + * IPI interrupts + */ + +#include +#include +#include +#include "pm_api_sys.h" +#include "pm_client.h" +#include "pm_defs.h" +#include "pm_svc_main.h" + +/* default shutdown/reboot scope is system(2) */ +static uint32_t pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM; + +/** + * pm_get_shutdown_scope() - Get the currently set shutdown scope + * + * @return Shutdown scope value + */ +uint32_t pm_get_shutdown_scope(void) +{ + return pm_shutdown_scope; +} + +/* PM API functions */ + +/** + * pm_handle_eemi_call() - PM call for processor to send eemi payload + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * @x0 to x5 Arguments received per SMC64 standard + * @result Payload received from firmware + * + * @return PM_RET_SUCCESS on success or error code + */ +enum pm_ret_status pm_handle_eemi_call(uint32_t flag, uint32_t x0, uint32_t x1, + uint32_t x2, uint32_t x3, uint32_t x4, + uint32_t x5, uint64_t *result) +{ + uint32_t payload[PAYLOAD_ARG_CNT] = {0}; + uint32_t module_id; + + module_id = (x0 & MODULE_ID_MASK) >> 8U; + + //default module id is for LIBPM + if (module_id == 0) { + module_id = LIBPM_MODULE_ID; + } + + PM_PACK_PAYLOAD6(payload, module_id, flag, x0, x1, x2, x3, x4, x5); + return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, PAYLOAD_ARG_CNT); +} + +/** + * pm_self_suspend() - PM call for processor to suspend itself + * @nid Node id of the processor or subsystem + * @latency Requested maximum wakeup latency (not supported) + * @state Requested state + * @address Resume address + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * This is a blocking call, it will return only once PMU has responded. + * On a wakeup, resume address will be automatically set by PMU. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_self_suspend(uint32_t nid, + uint32_t latency, + uint32_t state, + uintptr_t address, uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + uint32_t cpuid = plat_my_core_pos(); + const struct pm_proc *proc = pm_get_proc(cpuid); + + if (proc == NULL) { + WARN("Failed to get proc %d\n", cpuid); + return PM_RET_ERROR_INTERNAL; + } + + /* + * Do client specific suspend operations + * (e.g. set powerdown request bit) + */ + pm_client_suspend(proc, state); + + /* Send request to the PLM */ + PM_PACK_PAYLOAD6(payload, LIBPM_MODULE_ID, flag, PM_SELF_SUSPEND, + proc->node_id, latency, state, address, + (address >> 32)); + return pm_ipi_send_sync(proc, payload, NULL, 0); +} + +/** + * pm_abort_suspend() - PM call to announce that a prior suspend request + * is to be aborted. + * @reason Reason for the abort + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * Calling PU expects the PMU to abort the initiated suspend procedure. + * This is a non-blocking call without any acknowledge. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason, uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* + * Do client specific abort suspend operations + * (e.g. enable interrupts and clear powerdown request bit) + */ + pm_client_abort_suspend(); + + /* Send request to the PLM */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_ABORT_SUSPEND, + reason, primary_proc->node_id); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_req_suspend() - PM call to request for another PU or subsystem to + * be suspended gracefully. + * @target Node id of the targeted PU or subsystem + * @ack Flag to specify whether acknowledge is requested + * @latency Requested wakeup latency (not supported) + * @state Requested state (not supported) + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_req_suspend(uint32_t target, uint8_t ack, + uint32_t latency, uint32_t state, + uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_REQ_SUSPEND, target, + latency, state); + if (ack == IPI_BLOCKING) { + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); + } else { + return pm_ipi_send(primary_proc, payload); + } +} + +/** + * pm_req_wakeup() - PM call for processor to wake up selected processor + * or subsystem + * @target Device ID of the processor or subsystem to wake up + * @set_address Resume address presence indicator + * 1 - resume address specified, 0 - otherwise + * @address Resume address + * @ack Flag to specify whether acknowledge requested + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * This API function is either used to power up another APU core for SMP + * (by PSCI) or to power up an entirely different PU or subsystem, such + * as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be + * automatically set by PMC. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address, + uintptr_t address, uint8_t ack, uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC to perform the wake of the PU */ + PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_REQ_WAKEUP, target, + set_address, address, ack); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_get_callbackdata() - Read from IPI response buffer + * @data - array of PAYLOAD_ARG_CNT elements + * @flag - 0 - Call from secure source + * 1 - Call from non-secure source + * @ack - 0 - Do not ack IPI after reading payload + * 1 - Ack IPI after reading payload + * + * Read value from ipi buffer response buffer. + * @return Returns status, either success or error + */ +enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag, uint32_t ack) +{ + enum pm_ret_status ret = PM_RET_SUCCESS; + /* Return if interrupt is not from PMU */ + if (pm_ipi_irq_status(primary_proc) == 0) { + return ret; + } + + ret = pm_ipi_buff_read_callb(data, count); + + if (ack != 0U) { + pm_ipi_irq_clear(primary_proc); + } + + return ret; +} + +/** + * pm_pll_set_param() - Set PLL parameter + * + * This API is deprecated and maintained here for backward compatibility. + * New use of this API should be avoided for versal platform. + * This API and its use cases will be removed for versal platform. + * + * @clk_id PLL clock ID + * @param PLL parameter ID + * @value Value to set for PLL parameter + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param, + uint32_t value, uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_PLL_SET_PARAMETER, + clk_id, param, value); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_pll_get_param() - Get PLL parameter value + * + * This API is deprecated and maintained here for backward compatibility. + * New use of this API should be avoided for versal platform. + * This API and its use cases will be removed for versal platform. + * + * @clk_id PLL clock ID + * @param PLL parameter ID + * @value: Buffer to store PLL parameter value + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param, + uint32_t *value, uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_PLL_GET_PARAMETER, + clk_id, param); + + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} + +/** + * pm_pll_set_mode() - Set PLL mode + * + * This API is deprecated and maintained here for backward compatibility. + * New use of this API should be avoided for versal platform. + * This API and its use cases will be removed for versal platform. + * + * @clk_id PLL clock ID + * @mode PLL mode + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode, + uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_PLL_SET_MODE, + clk_id, mode); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_pll_get_mode() - Get PLL mode + * + * This API is deprecated and maintained here for backward compatibility. + * New use of this API should be avoided for versal platform. + * This API and its use cases will be removed for versal platform. + * + * @clk_id PLL clock ID + * @mode: Buffer to store PLL mode + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode, + uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, PM_PLL_GET_MODE, + clk_id); + + return pm_ipi_send_sync(primary_proc, payload, mode, 1); +} + +/** + * pm_force_powerdown() - PM call to request for another PU or subsystem to + * be powered down forcefully + * @target Device ID of the PU node to be forced powered down. + * @ack Flag to specify whether acknowledge is requested + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack, + uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_FORCE_POWERDOWN, + target, ack); + + if (ack == IPI_BLOCKING) { + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); + } else { + return pm_ipi_send(primary_proc, payload); + } +} + +/** + * pm_system_shutdown() - PM call to request a system shutdown or restart + * @type Shutdown or restart? 0=shutdown, 1=restart, 2=setscope + * @subtype Scope: 0=APU-subsystem, 1=PS, 2=system + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype, + uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + if (type == XPM_SHUTDOWN_TYPE_SETSCOPE_ONLY) { + /* Setting scope for subsequent PSCI reboot or shutdown */ + pm_shutdown_scope = subtype; + return PM_RET_SUCCESS; + } + + /* Send request to the PMC */ + PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_SYSTEM_SHUTDOWN, + type, subtype); + + return pm_ipi_send_non_blocking(primary_proc, payload); +} + +/** + * pm_query_data() - PM API for querying firmware data + * + * This API is deprecated and maintained here for backward compatibility. + * New use of this API should be avoided for versal platform. + * This API and its use cases will be removed for versal platform. + * + * @qid The type of data to query + * @arg1 Argument 1 to requested query data call + * @arg2 Argument 2 to requested query data call + * @arg3 Argument 3 to requested query data call + * @data Returned output data + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * @retur - 0 if success else non-zero error code of type + * enum pm_ret_status + */ +enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2, + uint32_t arg3, uint32_t *data, uint32_t flag) +{ + uint32_t ret; + uint32_t version[PAYLOAD_ARG_CNT] = {0}; + uint32_t payload[PAYLOAD_ARG_CNT]; + uint32_t fw_api_version; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_QUERY_DATA, qid, + arg1, arg2, arg3); + + ret = pm_feature_check(PM_QUERY_DATA, &version[0], flag); + if (ret == PM_RET_SUCCESS) { + fw_api_version = version[0] & 0xFFFFU; + if ((fw_api_version == 2U) && + ((qid == XPM_QID_CLOCK_GET_NAME) || + (qid == XPM_QID_PINCTRL_GET_FUNCTION_NAME))) { + ret = pm_ipi_send_sync(primary_proc, payload, data, PAYLOAD_ARG_CNT); + if (ret == PM_RET_SUCCESS) { + ret = data[0]; + data[0] = data[1]; + data[1] = data[2]; + data[2] = data[3]; + } + } else { + ret = pm_ipi_send_sync(primary_proc, payload, data, PAYLOAD_ARG_CNT); + } + } + return ret; +} +/** + * pm_api_ioctl() - PM IOCTL API for device control and configs + * + * This API is deprecated and maintained here for backward compatibility. + * New use of this API should be avoided for versal platform. + * This API and its use cases will be removed for versal platform. + * + * @device_id Device ID + * @ioctl_id ID of the requested IOCTL + * @arg1 Argument 1 to requested IOCTL call + * @arg2 Argument 2 to requested IOCTL call + * @arg3 Argument 3 to requested IOCTL call + * @value Returned output value + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * This function calls IOCTL to firmware for device control and configuration. + * + * @return Returns status, either 0 on success or non-zero error code + * of type enum pm_ret_status + */ +enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id, + uint32_t arg1, uint32_t arg2, uint32_t arg3, + uint32_t *value, uint32_t flag) +{ + enum pm_ret_status ret; + + switch (ioctl_id) { + case IOCTL_SET_PLL_FRAC_MODE: + ret = pm_pll_set_mode(arg1, arg2, flag); + break; + case IOCTL_GET_PLL_FRAC_MODE: + ret = pm_pll_get_mode(arg1, value, flag); + break; + case IOCTL_SET_PLL_FRAC_DATA: + ret = pm_pll_set_param(arg1, PM_PLL_PARAM_DATA, arg2, flag); + break; + case IOCTL_GET_PLL_FRAC_DATA: + ret = pm_pll_get_param(arg1, PM_PLL_PARAM_DATA, value, flag); + break; + case IOCTL_SET_SGI: + /* Get the sgi number */ + ret = pm_register_sgi(arg1, arg2); + if (ret != 0) { + return PM_RET_ERROR_ARGS; + } + ret = PM_RET_SUCCESS; + break; + default: + return PM_RET_ERROR_NOTSUPPORTED; + } + + return ret; +} + +/** + * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended + * @target Device id of the targeted PU or subsystem + * @wkup_node Device id of the wakeup peripheral + * @enable Enable or disable the specified peripheral as wake source + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t wkup_device, + uint8_t enable, uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_SET_WAKEUP_SOURCE, + target, wkup_device, enable); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_feature_check() - Returns the supported API version if supported + * @api_id API ID to check + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * @ret_payload pointer to array of PAYLOAD_ARG_CNT number of + * words Returned supported API version and bitmasks + * for IOCTL and QUERY ID + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *ret_payload, + uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + uint32_t module_id; + + /* Return version of API which are implemented in ATF only */ + switch (api_id) { + case PM_GET_CALLBACK_DATA: + case PM_GET_TRUSTZONE_VERSION: + ret_payload[0] = PM_API_VERSION_2; + return PM_RET_SUCCESS; + case TF_A_PM_REGISTER_SGI: + ret_payload[0] = PM_API_BASE_VERSION; + return PM_RET_SUCCESS; + default: + break; + } + + module_id = (api_id & MODULE_ID_MASK) >> 8U; + + /* + * feature check should be done only for LIBPM module + * If module_id is 0, then we consider it LIBPM module as default id + */ + if ((module_id > 0) && (module_id != LIBPM_MODULE_ID)) { + return PM_RET_SUCCESS; + } + + PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, + PM_FEATURE_CHECK, api_id); + return pm_ipi_send_sync(primary_proc, payload, ret_payload, PAYLOAD_ARG_CNT); +} + +/** + * pm_load_pdi() - Load the PDI + * + * This function provides support to load PDI from linux + * + * src: Source device of pdi(DDR, OCM, SD etc) + * address_low: lower 32-bit Linear memory space address + * address_high: higher 32-bit Linear memory space address + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low, + uint32_t address_high, uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD4(payload, LOADER_MODULE_ID, flag, PM_LOAD_PDI, src, + address_high, address_low); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_register_notifier() - PM call to register a subsystem to be notified + * about the device event + * @device_id Device ID for the Node to which the event is related + * @event Event in question + * @wake Wake subsystem upon capturing the event if value 1 + * @enable Enable the registration for value 1, disable for value 0 + * @flag 0 - Call from secure source + * 1 - Call from non-secure source + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_register_notifier(uint32_t device_id, uint32_t event, + uint32_t wake, uint32_t enable, + uint32_t flag) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMC */ + PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_REGISTER_NOTIFIER, + device_id, event, wake, enable); + + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} diff --git a/plat/xilinx/common/pm_service/pm_svc_main.c b/plat/xilinx/common/pm_service/pm_svc_main.c new file mode 100644 index 000000000..6fd7f0d52 --- /dev/null +++ b/plat/xilinx/common/pm_service/pm_svc_main.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved. + * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Top-level SMC handler for Versal power management calls and + * IPI setup functions for communication with PMC. + */ + +#include +#include +#include +#include +#include +#include "pm_api_sys.h" +#include "pm_client.h" +#include "pm_ipi.h" +#include +#include "../drivers/arm/gic/v3/gicv3_private.h" + +#define MODE 0x80000000U + +#define XSCUGIC_SGIR_EL1_INITID_SHIFT 24U +#define INVALID_SGI 0xFFU +#define PM_INIT_SUSPEND_CB (30U) +#define PM_NOTIFY_CB (32U) +DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6) + +/* pm_up = true - UP, pm_up = false - DOWN */ +static bool pm_up; +static uint32_t sgi = (uint32_t)INVALID_SGI; + +static void notify_os(void) +{ + int32_t cpu; + uint32_t reg; + + cpu = plat_my_core_pos() + 1U; + + reg = (cpu | (sgi << XSCUGIC_SGIR_EL1_INITID_SHIFT)); + write_icc_asgi1r_el1(reg); +} + +static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle, + void *cookie) +{ + uint32_t payload[4] = {0}; + enum pm_ret_status ret; + + VERBOSE("Received IPI FIQ from firmware\n"); + + (void)plat_ic_acknowledge_interrupt(); + + ret = pm_get_callbackdata(payload, ARRAY_SIZE(payload), 0, 0); + if (ret != PM_RET_SUCCESS) { + payload[0] = ret; + } + + switch (payload[0]) { + case PM_INIT_SUSPEND_CB: + case PM_NOTIFY_CB: + if (sgi != INVALID_SGI) { + notify_os(); + } + break; + case PM_RET_ERROR_INVALID_CRC: + pm_ipi_irq_clear(primary_proc); + WARN("Invalid CRC in the payload\n"); + break; + + default: + pm_ipi_irq_clear(primary_proc); + WARN("Invalid IPI payload\n"); + break; + } + + /* Clear FIQ */ + plat_ic_end_of_interrupt(id); + + return 0; +} + +/** + * pm_register_sgi() - PM register the IPI interrupt + * + * @sgi - SGI number to be used for communication. + * @reset - Reset to invalid SGI when reset=1. + * @return On success, the initialization function must return 0. + * Any other return value will cause the framework to ignore + * the service + * + * Update the SGI number to be used. + * + */ +int32_t pm_register_sgi(uint32_t sgi_num, uint32_t reset) +{ + if (reset == 1U) { + sgi = INVALID_SGI; + return 0; + } + + if (sgi != INVALID_SGI) { + return -EBUSY; + } + + if (sgi_num >= GICV3_MAX_SGI_TARGETS) { + return -EINVAL; + } + + sgi = (uint32_t)sgi_num; + return 0; +} + +/** + * pm_setup() - PM service setup + * + * @return On success, the initialization function must return 0. + * Any other return value will cause the framework to ignore + * the service + * + * Initialization functions for Versal power management for + * communicaton with PMC. + * + * Called from sip_svc_setup initialization function with the + * rt_svc_init signature. + */ +int32_t pm_setup(void) +{ + int32_t ret = 0; + + pm_ipi_init(primary_proc); + pm_up = true; + + /* + * Enable IPI IRQ + * assume the rich OS is OK to handle callback IRQs now. + * Even if we were wrong, it would not enable the IRQ in + * the GIC. + */ + pm_ipi_irq_enable(primary_proc); + + ret = request_intr_type_el3(PLAT_VERSAL_IPI_IRQ, ipi_fiq_handler); + if (ret != 0) { + WARN("BL31: registering IPI interrupt failed\n"); + } + + gicd_write_irouter(gicv3_driver_data->gicd_base, PLAT_VERSAL_IPI_IRQ, MODE); + return ret; +} + +/** + * eemi_for_compatibility() - EEMI calls handler for deprecated calls + * + * @return - If EEMI API found then, uintptr_t type address, else 0 + * + * Some EEMI API's use case needs to be changed in Linux driver, so they + * can take advantage of common EEMI handler in TF-A. As of now the old + * implementation of these APIs are required to maintain backward compatibility + * until their use case in linux driver changes. + */ +static uintptr_t eemi_for_compatibility(uint32_t api_id, uint32_t *pm_arg, + void *handle, uint32_t security_flag) +{ + enum pm_ret_status ret; + + switch (api_id) { + + case PM_IOCTL: + { + uint32_t value = 0U; + + ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3], pm_arg[4], + &value, security_flag); + if (ret == PM_RET_ERROR_NOTSUPPORTED) + return (uintptr_t)0; + + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); + } + + case PM_QUERY_DATA: + { + uint32_t data[PAYLOAD_ARG_CNT] = { 0 }; + + ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3], data, security_flag); + + SMC_RET2(handle, (uint64_t)ret | ((uint64_t)data[0] << 32U), + (uint64_t)data[1] | ((uint64_t)data[2] << 32U)); + } + + case PM_FEATURE_CHECK: + { + uint32_t result[PAYLOAD_ARG_CNT] = {0U}; + + ret = pm_feature_check(pm_arg[0], result, security_flag); + SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U), + (uint64_t)result[1] | ((uint64_t)result[2] << 32U)); + } + + case PM_LOAD_PDI: + { + ret = pm_load_pdi(pm_arg[0], pm_arg[1], pm_arg[2], + security_flag); + SMC_RET1(handle, (uint64_t)ret); + } + + default: + return (uintptr_t)0; + } +} + +/** + * eemi_psci_debugfs_handler() - EEMI API invoked from PSCI + * + * These EEMI APIs performs CPU specific power management tasks. + * These EEMI APIs are invoked either from PSCI or from debugfs in kernel. + * These calls require CPU specific processing before sending IPI request to + * Platform Management Controller. For example enable/disable CPU specific + * interrupts. This requires separate handler for these calls and may not be + * handled using common eemi handler + */ +static uintptr_t eemi_psci_debugfs_handler(uint32_t api_id, uint32_t *pm_arg, + void *handle, uint32_t security_flag) +{ + enum pm_ret_status ret; + + switch (api_id) { + + case PM_SELF_SUSPEND: + ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3], security_flag); + SMC_RET1(handle, (u_register_t)ret); + + case PM_FORCE_POWERDOWN: + ret = pm_force_powerdown(pm_arg[0], pm_arg[1], security_flag); + SMC_RET1(handle, (u_register_t)ret); + + case PM_REQ_SUSPEND: + ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3], security_flag); + SMC_RET1(handle, (u_register_t)ret); + + case PM_ABORT_SUSPEND: + ret = pm_abort_suspend(pm_arg[0], security_flag); + SMC_RET1(handle, (u_register_t)ret); + + case PM_SYSTEM_SHUTDOWN: + ret = pm_system_shutdown(pm_arg[0], pm_arg[1], security_flag); + SMC_RET1(handle, (u_register_t)ret); + + default: + return (uintptr_t)0; + } +} + +/** + * TF_A_specific_handler() - SMC handler for TF-A specific functionality + * + * These EEMI calls performs functionality that does not require + * IPI transaction. The handler ends in TF-A and returns requested data to + * kernel from TF-A. + */ +static uintptr_t TF_A_specific_handler(uint32_t api_id, uint32_t *pm_arg, + void *handle, uint32_t security_flag) +{ + switch (api_id) { + + case TF_A_PM_REGISTER_SGI: + { + int32_t ret; + + ret = pm_register_sgi(pm_arg[0], pm_arg[1]); + if (ret != 0) { + SMC_RET1(handle, (uint32_t)PM_RET_ERROR_ARGS); + } + + SMC_RET1(handle, (uint32_t)PM_RET_SUCCESS); + } + + case PM_GET_CALLBACK_DATA: + { + uint32_t result[4] = {0}; + enum pm_ret_status ret; + + ret = pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag, 1U); + if (ret != 0) { + result[0] = ret; + } + + SMC_RET2(handle, + (uint64_t)result[0] | ((uint64_t)result[1] << 32U), + (uint64_t)result[2] | ((uint64_t)result[3] << 32U)); + } + + case PM_GET_TRUSTZONE_VERSION: + SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | + ((uint64_t)TZ_VERSION << 32U)); + + default: + return (uintptr_t)0; + } +} + +/** + * eemi_handler() - Prepare EEMI payload and perform IPI transaction + * + * EEMI - Embedded Energy Management Interface is Xilinx proprietary protocol + * to allow communication between power management controller and different + * processing clusters. + * + * This handler prepares EEMI protocol payload received from kernel and performs + * IPI transaction. + */ +static uintptr_t eemi_handler(uint32_t api_id, uint32_t *pm_arg, + void *handle, uint32_t security_flag) +{ + enum pm_ret_status ret; + uint32_t buf[PAYLOAD_ARG_CNT] = {0}; + + ret = pm_handle_eemi_call(security_flag, api_id, pm_arg[0], pm_arg[1], + pm_arg[2], pm_arg[3], pm_arg[4], + (uint64_t *)buf); + /* + * Two IOCTLs, to get clock name and pinctrl name of pm_query_data API + * receives 5 words of respoonse from firmware. Currently linux driver can + * receive only 4 words from TF-A. So, this needs to be handled separately + * than other eemi calls. + */ + if (api_id == PM_QUERY_DATA) { + if ((pm_arg[0] == XPM_QID_CLOCK_GET_NAME || + pm_arg[0] == XPM_QID_PINCTRL_GET_FUNCTION_NAME) && + ret == PM_RET_SUCCESS) { + SMC_RET2(handle, (uint64_t)buf[0] | ((uint64_t)buf[1] << 32U), + (uint64_t)buf[2] | ((uint64_t)buf[3] << 32U)); + } + } + + SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32U), + (uint64_t)buf[1] | ((uint64_t)buf[2] << 32U)); +} + +/** + * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2. + * @smc_fid - Function Identifier + * @x1 - x4 - SMC64 Arguments from kernel + * x3 (upper 32-bits) and x4 are Unused + * @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 pm_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) +{ + uintptr_t ret; + uint32_t pm_arg[PAYLOAD_ARG_CNT] = {0}; + uint32_t security_flag = SECURE_FLAG; + uint32_t api_id; + + /* Handle case where PM wasn't initialized properly */ + if (pm_up == false) { + SMC_RET1(handle, SMC_UNK); + } + + /* + * Mark BIT24 payload (i.e 1st bit of pm_arg[3] ) as non-secure (1) + * if smc called is non secure + */ + if (is_caller_non_secure(flags) != 0) { + security_flag = NON_SECURE_FLAG; + } + + pm_arg[0] = (uint32_t)x1; + pm_arg[1] = (uint32_t)(x1 >> 32U); + pm_arg[2] = (uint32_t)x2; + pm_arg[3] = (uint32_t)(x2 >> 32U); + pm_arg[4] = (uint32_t)x3; + (void)(x4); + api_id = smc_fid & FUNCID_NUM_MASK; + + ret = eemi_for_compatibility(api_id, pm_arg, handle, security_flag); + if (ret != (uintptr_t)0) { + return ret; + } + + ret = eemi_psci_debugfs_handler(api_id, pm_arg, handle, flags); + if (ret != (uintptr_t)0) { + return ret; + } + + ret = TF_A_specific_handler(api_id, pm_arg, handle, security_flag); + if (ret != (uintptr_t)0) { + return ret; + } + + ret = eemi_handler(api_id, pm_arg, handle, security_flag); + + return ret; +} diff --git a/plat/xilinx/versal/platform.mk b/plat/xilinx/versal/platform.mk index 8087297a2..71f680261 100644 --- a/plat/xilinx/versal/platform.mk +++ b/plat/xilinx/versal/platform.mk @@ -1,4 +1,5 @@ # Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause @@ -82,6 +83,8 @@ BL31_SOURCES += drivers/arm/cci/cci.c \ plat/xilinx/common/plat_startup.c \ plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \ plat/xilinx/common/pm_service/pm_ipi.c \ + plat/xilinx/common/pm_service/pm_api_sys.c \ + plat/xilinx/common/pm_service/pm_svc_main.c \ plat/xilinx/versal/bl31_versal_setup.c \ plat/xilinx/versal/plat_psci.c \ plat/xilinx/versal/plat_versal.c \ @@ -89,8 +92,6 @@ BL31_SOURCES += drivers/arm/cci/cci.c \ plat/xilinx/versal/sip_svc_setup.c \ plat/xilinx/versal/versal_gicv3.c \ plat/xilinx/versal/versal_ipi.c \ - plat/xilinx/versal/pm_service/pm_svc_main.c \ - plat/xilinx/versal/pm_service/pm_api_sys.c \ plat/xilinx/versal/pm_service/pm_client.c ifeq ($(HARDEN_SLS_ALL), 1) diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.c b/plat/xilinx/versal/pm_service/pm_api_sys.c deleted file mode 100644 index cc99f1197..000000000 --- a/plat/xilinx/versal/pm_service/pm_api_sys.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - * 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 - */ - -/* - * Versal system level PM-API functions and communication with PMC via - * IPI interrupts - */ - -#include -#include -#include -#include "pm_api_sys.h" -#include "pm_client.h" -#include "pm_defs.h" -#include "pm_svc_main.h" - -/* default shutdown/reboot scope is system(2) */ -static uint32_t pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM; - -/** - * pm_get_shutdown_scope() - Get the currently set shutdown scope - * - * @return Shutdown scope value - */ -uint32_t pm_get_shutdown_scope(void) -{ - return pm_shutdown_scope; -} - -/* PM API functions */ - -/** - * pm_handle_eemi_call() - PM call for processor to send eemi payload - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * @x0 to x5 Arguments received per SMC64 standard - * @result Payload received from firmware - * - * @return PM_RET_SUCCESS on success or error code - */ -enum pm_ret_status pm_handle_eemi_call(uint32_t flag, uint32_t x0, uint32_t x1, - uint32_t x2, uint32_t x3, uint32_t x4, - uint32_t x5, uint64_t *result) -{ - uint32_t payload[PAYLOAD_ARG_CNT] = {0}; - uint32_t module_id; - - module_id = (x0 & MODULE_ID_MASK) >> 8U; - - //default module id is for LIBPM - if (module_id == 0) { - module_id = LIBPM_MODULE_ID; - } - - PM_PACK_PAYLOAD6(payload, module_id, flag, x0, x1, x2, x3, x4, x5); - return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, PAYLOAD_ARG_CNT); -} - -/** - * pm_self_suspend() - PM call for processor to suspend itself - * @nid Node id of the processor or subsystem - * @latency Requested maximum wakeup latency (not supported) - * @state Requested state - * @address Resume address - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * This is a blocking call, it will return only once PMU has responded. - * On a wakeup, resume address will be automatically set by PMU. - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_self_suspend(uint32_t nid, - uint32_t latency, - uint32_t state, - uintptr_t address, uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - uint32_t cpuid = plat_my_core_pos(); - const struct pm_proc *proc = pm_get_proc(cpuid); - - if (proc == NULL) { - WARN("Failed to get proc %d\n", cpuid); - return PM_RET_ERROR_INTERNAL; - } - - /* - * Do client specific suspend operations - * (e.g. set powerdown request bit) - */ - pm_client_suspend(proc, state); - - /* Send request to the PLM */ - PM_PACK_PAYLOAD6(payload, LIBPM_MODULE_ID, flag, PM_SELF_SUSPEND, - proc->node_id, latency, state, address, - (address >> 32)); - return pm_ipi_send_sync(proc, payload, NULL, 0); -} - -/** - * pm_abort_suspend() - PM call to announce that a prior suspend request - * is to be aborted. - * @reason Reason for the abort - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * Calling PU expects the PMU to abort the initiated suspend procedure. - * This is a non-blocking call without any acknowledge. - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason, uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* - * Do client specific abort suspend operations - * (e.g. enable interrupts and clear powerdown request bit) - */ - pm_client_abort_suspend(); - - /* Send request to the PLM */ - PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_ABORT_SUSPEND, - reason, primary_proc->node_id); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_req_suspend() - PM call to request for another PU or subsystem to - * be suspended gracefully. - * @target Node id of the targeted PU or subsystem - * @ack Flag to specify whether acknowledge is requested - * @latency Requested wakeup latency (not supported) - * @state Requested state (not supported) - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_req_suspend(uint32_t target, uint8_t ack, - uint32_t latency, uint32_t state, - uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_REQ_SUSPEND, target, - latency, state); - if (ack == IPI_BLOCKING) { - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); - } else { - return pm_ipi_send(primary_proc, payload); - } -} - -/** - * pm_req_wakeup() - PM call for processor to wake up selected processor - * or subsystem - * @target Device ID of the processor or subsystem to wake up - * @set_address Resume address presence indicator - * 1 - resume address specified, 0 - otherwise - * @address Resume address - * @ack Flag to specify whether acknowledge requested - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * This API function is either used to power up another APU core for SMP - * (by PSCI) or to power up an entirely different PU or subsystem, such - * as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be - * automatically set by PMC. - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address, - uintptr_t address, uint8_t ack, uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMC to perform the wake of the PU */ - PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_REQ_WAKEUP, target, - set_address, address, ack); - - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_get_callbackdata() - Read from IPI response buffer - * @data - array of PAYLOAD_ARG_CNT elements - * @flag - 0 - Call from secure source - * 1 - Call from non-secure source - * @ack - 0 - Do not ack IPI after reading payload - * 1 - Ack IPI after reading payload - * - * Read value from ipi buffer response buffer. - * @return Returns status, either success or error - */ -enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag, uint32_t ack) -{ - enum pm_ret_status ret = PM_RET_SUCCESS; - /* Return if interrupt is not from PMU */ - if (pm_ipi_irq_status(primary_proc) == 0) { - return ret; - } - - ret = pm_ipi_buff_read_callb(data, count); - - if (ack != 0U) { - pm_ipi_irq_clear(primary_proc); - } - - return ret; -} - -/** - * pm_pll_set_param() - Set PLL parameter - * - * This API is deprecated and maintained here for backward compatibility. - * New use of this API should be avoided for versal platform. - * This API and its use cases will be removed for versal platform. - * - * @clk_id PLL clock ID - * @param PLL parameter ID - * @value Value to set for PLL parameter - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param, - uint32_t value, uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMC */ - PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_PLL_SET_PARAMETER, - clk_id, param, value); - - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_pll_get_param() - Get PLL parameter value - * - * This API is deprecated and maintained here for backward compatibility. - * New use of this API should be avoided for versal platform. - * This API and its use cases will be removed for versal platform. - * - * @clk_id PLL clock ID - * @param PLL parameter ID - * @value: Buffer to store PLL parameter value - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param, - uint32_t *value, uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMC */ - PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_PLL_GET_PARAMETER, - clk_id, param); - - return pm_ipi_send_sync(primary_proc, payload, value, 1); -} - -/** - * pm_pll_set_mode() - Set PLL mode - * - * This API is deprecated and maintained here for backward compatibility. - * New use of this API should be avoided for versal platform. - * This API and its use cases will be removed for versal platform. - * - * @clk_id PLL clock ID - * @mode PLL mode - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode, - uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMC */ - PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_PLL_SET_MODE, - clk_id, mode); - - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_pll_get_mode() - Get PLL mode - * - * This API is deprecated and maintained here for backward compatibility. - * New use of this API should be avoided for versal platform. - * This API and its use cases will be removed for versal platform. - * - * @clk_id PLL clock ID - * @mode: Buffer to store PLL mode - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode, - uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMC */ - PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, PM_PLL_GET_MODE, - clk_id); - - return pm_ipi_send_sync(primary_proc, payload, mode, 1); -} - -/** - * pm_force_powerdown() - PM call to request for another PU or subsystem to - * be powered down forcefully - * @target Device ID of the PU node to be forced powered down. - * @ack Flag to specify whether acknowledge is requested - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack, - uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMC */ - PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_FORCE_POWERDOWN, - target, ack); - - if (ack == IPI_BLOCKING) { - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); - } else { - return pm_ipi_send(primary_proc, payload); - } -} - -/** - * pm_system_shutdown() - PM call to request a system shutdown or restart - * @type Shutdown or restart? 0=shutdown, 1=restart, 2=setscope - * @subtype Scope: 0=APU-subsystem, 1=PS, 2=system - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype, - uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - if (type == XPM_SHUTDOWN_TYPE_SETSCOPE_ONLY) { - /* Setting scope for subsequent PSCI reboot or shutdown */ - pm_shutdown_scope = subtype; - return PM_RET_SUCCESS; - } - - /* Send request to the PMC */ - PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_SYSTEM_SHUTDOWN, - type, subtype); - - return pm_ipi_send_non_blocking(primary_proc, payload); -} - -/** - * pm_query_data() - PM API for querying firmware data - * - * This API is deprecated and maintained here for backward compatibility. - * New use of this API should be avoided for versal platform. - * This API and its use cases will be removed for versal platform. - * - * @qid The type of data to query - * @arg1 Argument 1 to requested query data call - * @arg2 Argument 2 to requested query data call - * @arg3 Argument 3 to requested query data call - * @data Returned output data - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * @retur - 0 if success else non-zero error code of type - * enum pm_ret_status - */ -enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2, - uint32_t arg3, uint32_t *data, uint32_t flag) -{ - uint32_t ret; - uint32_t version[PAYLOAD_ARG_CNT] = {0}; - uint32_t payload[PAYLOAD_ARG_CNT]; - uint32_t fw_api_version; - - /* Send request to the PMC */ - PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_QUERY_DATA, qid, - arg1, arg2, arg3); - - ret = pm_feature_check(PM_QUERY_DATA, &version[0], flag); - if (ret == PM_RET_SUCCESS) { - fw_api_version = version[0] & 0xFFFFU; - if ((fw_api_version == 2U) && - ((qid == XPM_QID_CLOCK_GET_NAME) || - (qid == XPM_QID_PINCTRL_GET_FUNCTION_NAME))) { - ret = pm_ipi_send_sync(primary_proc, payload, data, PAYLOAD_ARG_CNT); - if (ret == PM_RET_SUCCESS) { - ret = data[0]; - data[0] = data[1]; - data[1] = data[2]; - data[2] = data[3]; - } - } else { - ret = pm_ipi_send_sync(primary_proc, payload, data, PAYLOAD_ARG_CNT); - } - } - return ret; -} -/** - * pm_api_ioctl() - PM IOCTL API for device control and configs - * - * This API is deprecated and maintained here for backward compatibility. - * New use of this API should be avoided for versal platform. - * This API and its use cases will be removed for versal platform. - * - * @device_id Device ID - * @ioctl_id ID of the requested IOCTL - * @arg1 Argument 1 to requested IOCTL call - * @arg2 Argument 2 to requested IOCTL call - * @arg3 Argument 3 to requested IOCTL call - * @value Returned output value - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * This function calls IOCTL to firmware for device control and configuration. - * - * @return Returns status, either 0 on success or non-zero error code - * of type enum pm_ret_status - */ -enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id, - uint32_t arg1, uint32_t arg2, uint32_t arg3, - uint32_t *value, uint32_t flag) -{ - enum pm_ret_status ret; - - switch (ioctl_id) { - case IOCTL_SET_PLL_FRAC_MODE: - ret = pm_pll_set_mode(arg1, arg2, flag); - break; - case IOCTL_GET_PLL_FRAC_MODE: - ret = pm_pll_get_mode(arg1, value, flag); - break; - case IOCTL_SET_PLL_FRAC_DATA: - ret = pm_pll_set_param(arg1, PM_PLL_PARAM_DATA, arg2, flag); - break; - case IOCTL_GET_PLL_FRAC_DATA: - ret = pm_pll_get_param(arg1, PM_PLL_PARAM_DATA, value, flag); - break; - case IOCTL_SET_SGI: - /* Get the sgi number */ - ret = pm_register_sgi(arg1, arg2); - if (ret != 0) { - return PM_RET_ERROR_ARGS; - } - ret = PM_RET_SUCCESS; - break; - default: - return PM_RET_ERROR_NOTSUPPORTED; - } - - return ret; -} - -/** - * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended - * @target Device id of the targeted PU or subsystem - * @wkup_node Device id of the wakeup peripheral - * @enable Enable or disable the specified peripheral as wake source - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t wkup_device, - uint8_t enable, uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_SET_WAKEUP_SOURCE, - target, wkup_device, enable); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_feature_check() - Returns the supported API version if supported - * @api_id API ID to check - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * @ret_payload pointer to array of PAYLOAD_ARG_CNT number of - * words Returned supported API version and bitmasks - * for IOCTL and QUERY ID - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *ret_payload, - uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - uint32_t module_id; - - /* Return version of API which are implemented in ATF only */ - switch (api_id) { - case PM_GET_CALLBACK_DATA: - case PM_GET_TRUSTZONE_VERSION: - ret_payload[0] = PM_API_VERSION_2; - return PM_RET_SUCCESS; - case TF_A_PM_REGISTER_SGI: - ret_payload[0] = PM_API_BASE_VERSION; - return PM_RET_SUCCESS; - default: - break; - } - - module_id = (api_id & MODULE_ID_MASK) >> 8U; - - /* - * feature check should be done only for LIBPM module - * If module_id is 0, then we consider it LIBPM module as default id - */ - if ((module_id > 0) && (module_id != LIBPM_MODULE_ID)) { - return PM_RET_SUCCESS; - } - - PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, - PM_FEATURE_CHECK, api_id); - return pm_ipi_send_sync(primary_proc, payload, ret_payload, PAYLOAD_ARG_CNT); -} - -/** - * pm_load_pdi() - Load the PDI - * - * This function provides support to load PDI from linux - * - * src: Source device of pdi(DDR, OCM, SD etc) - * address_low: lower 32-bit Linear memory space address - * address_high: higher 32-bit Linear memory space address - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low, - uint32_t address_high, uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD4(payload, LOADER_MODULE_ID, flag, PM_LOAD_PDI, src, - address_high, address_low); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_register_notifier() - PM call to register a subsystem to be notified - * about the device event - * @device_id Device ID for the Node to which the event is related - * @event Event in question - * @wake Wake subsystem upon capturing the event if value 1 - * @enable Enable the registration for value 1, disable for value 0 - * @flag 0 - Call from secure source - * 1 - Call from non-secure source - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_register_notifier(uint32_t device_id, uint32_t event, - uint32_t wake, uint32_t enable, - uint32_t flag) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMC */ - PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_REGISTER_NOTIFIER, - device_id, event, wake, enable); - - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.h b/plat/xilinx/versal/pm_service/pm_api_sys.h deleted file mode 100644 index 8625e9568..000000000 --- a/plat/xilinx/versal/pm_service/pm_api_sys.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 - */ - -#ifndef PM_API_SYS_H -#define PM_API_SYS_H - -#include -#include "pm_defs.h" - -/********************************************************************* - * Target module IDs macros - ********************************************************************/ -#define LIBPM_MODULE_ID 0x2U -#define LOADER_MODULE_ID 0x7U - -#define MODULE_ID_MASK 0x0000ff00U -/********************************************************** - * PM API function declarations - **********************************************************/ - -enum pm_ret_status pm_handle_eemi_call(uint32_t flag, uint32_t x0, uint32_t x1, - uint32_t x2, uint32_t x3, uint32_t x4, - uint32_t x5, uint64_t *result); -enum pm_ret_status pm_self_suspend(uint32_t nid, - uint32_t latency, - uint32_t state, - uintptr_t address, uint32_t flag); -enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason, uint32_t flag); -enum pm_ret_status pm_req_suspend(uint32_t target, - uint8_t ack, - uint32_t latency, - uint32_t state, uint32_t flag); -enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address, - uintptr_t address, uint8_t ack, uint32_t flag); -enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t device_id, - uint8_t enable, uint32_t flag); -enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag, - uint32_t ack); -enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param, - uint32_t value, uint32_t flag); -enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param, - uint32_t *value, uint32_t flag); -enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode, - uint32_t flag); -enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode, - uint32_t flag); -enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack, - uint32_t flag); -enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype, - uint32_t flag); -enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id, - uint32_t arg1, uint32_t arg2, uint32_t arg3, - uint32_t *value, uint32_t flag); -enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2, - uint32_t arg3, uint32_t *data, uint32_t flag); -uint32_t pm_get_shutdown_scope(void); -enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *ret_payload, - uint32_t flag); -enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low, - uint32_t address_high, uint32_t flag); -enum pm_ret_status pm_register_notifier(uint32_t device_id, uint32_t event, - uint32_t wake, uint32_t enable, - uint32_t flag); - -/** - * Assigning of argument values into array elements. - */ -#define PM_PACK_PAYLOAD1(pl, mid, flag, arg0) { \ - pl[0] = (uint32_t)(((uint32_t)(arg0) & 0xFFU) | ((mid) << 8U) | ((flag) << 24U)); \ -} - -#define PM_PACK_PAYLOAD2(pl, mid, flag, arg0, arg1) { \ - pl[1] = (uint32_t)(arg1); \ - PM_PACK_PAYLOAD1(pl, (mid), (flag), (arg0)); \ -} - -#define PM_PACK_PAYLOAD3(pl, mid, flag, arg0, arg1, arg2) { \ - pl[2] = (uint32_t)(arg2); \ - PM_PACK_PAYLOAD2(pl, (mid), (flag), (arg0), (arg1)); \ -} - -#define PM_PACK_PAYLOAD4(pl, mid, flag, arg0, arg1, arg2, arg3) { \ - pl[3] = (uint32_t)(arg3); \ - PM_PACK_PAYLOAD3(pl, (mid), (flag), (arg0), (arg1), (arg2)); \ -} - -#define PM_PACK_PAYLOAD5(pl, mid, flag, arg0, arg1, arg2, arg3, arg4) { \ - pl[4] = (uint32_t)(arg4); \ - PM_PACK_PAYLOAD4(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3)); \ -} - -#define PM_PACK_PAYLOAD6(pl, mid, flag, arg0, arg1, arg2, arg3, arg4, arg5) { \ - pl[5] = (uint32_t)(arg5); \ - PM_PACK_PAYLOAD5(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3), (arg4)); \ -} - -#endif /* PM_API_SYS_H */ diff --git a/plat/xilinx/versal/pm_service/pm_node.h b/plat/xilinx/versal/pm_service/pm_node.h deleted file mode 100644 index 1b82ec70d..000000000 --- a/plat/xilinx/versal/pm_service/pm_node.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2019, Xilinx, Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* Versal PM nodes enums and defines */ - -#ifndef PM_NODE_H -#define PM_NODE_H - -/********************************************************************* - * Macro definitions - ********************************************************************/ - -#define NODE_CLASS_SHIFT 26U -#define NODE_SUBCLASS_SHIFT 20U -#define NODE_TYPE_SHIFT 14U -#define NODE_INDEX_SHIFT 0U -#define NODE_CLASS_MASK_BITS 0x3F -#define NODE_SUBCLASS_MASK_BITS 0x3F -#define NODE_TYPE_MASK_BITS 0x3F -#define NODE_INDEX_MASK_BITS 0x3FFF -#define NODE_CLASS_MASK (NODE_CLASS_MASK_BITS << NODE_CLASS_SHIFT) -#define NODE_SUBCLASS_MASK (NODE_SUBCLASS_MASK_BITS << NODE_SUBCLASS_SHIFT) -#define NODE_TYPE_MASK (NODE_TYPE_MASK_BITS << NODE_TYPE_SHIFT) -#define NODE_INDEX_MASK (NODE_INDEX_MASK_BITS << NODE_INDEX_SHIFT) - -#define NODEID(CLASS, SUBCLASS, TYPE, INDEX) \ - ((((CLASS) & NODE_CLASS_MASK_BITS) << NODE_CLASS_SHIFT) | \ - (((SUBCLASS) & NODE_SUBCLASS_MASK_BITS) << NODE_SUBCLASS_SHIFT) | \ - (((TYPE) & NODE_TYPE_MASK_BITS) << NODE_TYPE_SHIFT) | \ - (((INDEX) & NODE_INDEX_MASK_BITS) << NODE_INDEX_SHIFT)) - -#define NODECLASS(ID) (((ID) & NODE_CLASS_MASK) >> NODE_CLASS_SHIFT) -#define NODESUBCLASS(ID) (((ID) & NODE_SUBCLASS_MASK) >> \ - NODE_SUBCLASS_SHIFT) -#define NODETYPE(ID) (((ID) & NODE_TYPE_MASK) >> NODE_TYPE_SHIFT) -#define NODEINDEX(ID) (((ID) & NODE_INDEX_MASK) >> NODE_INDEX_SHIFT) - -/********************************************************************* - * Enum definitions - ********************************************************************/ - -/* Node class types */ -enum pm_node_class { - XPM_NODECLASS_MIN, - - XPM_NODECLASS_POWER, - XPM_NODECLASS_CLOCK, - XPM_NODECLASS_RESET, - XPM_NODECLASS_MEMIC, - XPM_NODECLASS_STMIC, - XPM_NODECLASS_DEVICE, - - XPM_NODECLASS_MAX -}; - -enum pm_device_node_subclass { - /* Device types */ - XPM_NODESUBCL_DEV_CORE = 1, - XPM_NODESUBCL_DEV_PERIPH, - XPM_NODESUBCL_DEV_MEM, - XPM_NODESUBCL_DEV_SOC, - XPM_NODESUBCL_DEV_MEM_CTRLR, - XPM_NODESUBCL_DEV_PHY, -}; - -enum pm_device_node_type { - /* Device types */ - XPM_NODETYPE_DEV_CORE_PMC = 1, - XPM_NODETYPE_DEV_CORE_PSM, - XPM_NODETYPE_DEV_CORE_APU, - XPM_NODETYPE_DEV_CORE_RPU, - XPM_NODETYPE_DEV_OCM, - XPM_NODETYPE_DEV_TCM, - XPM_NODETYPE_DEV_L2CACHE, - XPM_NODETYPE_DEV_DDR, - XPM_NODETYPE_DEV_PERIPH, - XPM_NODETYPE_DEV_SOC, - XPM_NODETYPE_DEV_GT, -}; - -/* Device node Indexes */ -enum pm_device_node_idx { - /* Device nodes */ - XPM_NODEIDX_DEV_MIN, - - /* Processor devices */ - XPM_NODEIDX_DEV_PMC_PROC, - XPM_NODEIDX_DEV_PSM_PROC, - XPM_NODEIDX_DEV_ACPU_0, - XPM_NODEIDX_DEV_ACPU_1, - XPM_NODEIDX_DEV_RPU0_0, - XPM_NODEIDX_DEV_RPU0_1, - - /* Memory devices */ - XPM_NODEIDX_DEV_OCM_0, - XPM_NODEIDX_DEV_OCM_1, - XPM_NODEIDX_DEV_OCM_2, - XPM_NODEIDX_DEV_OCM_3, - XPM_NODEIDX_DEV_TCM_0_A, - XPM_NODEIDX_DEV_TCM_0_B, - XPM_NODEIDX_DEV_TCM_1_A, - XPM_NODEIDX_DEV_TCM_1_B, - XPM_NODEIDX_DEV_L2_BANK_0, - XPM_NODEIDX_DEV_DDR_0, - XPM_NODEIDX_DEV_DDR_1, - XPM_NODEIDX_DEV_DDR_2, - XPM_NODEIDX_DEV_DDR_3, - XPM_NODEIDX_DEV_DDR_4, - XPM_NODEIDX_DEV_DDR_5, - XPM_NODEIDX_DEV_DDR_6, - XPM_NODEIDX_DEV_DDR_7, - - /* LPD Peripheral devices */ - XPM_NODEIDX_DEV_USB_0, - XPM_NODEIDX_DEV_GEM_0, - XPM_NODEIDX_DEV_GEM_1, - XPM_NODEIDX_DEV_SPI_0, - XPM_NODEIDX_DEV_SPI_1, - XPM_NODEIDX_DEV_I2C_0, - XPM_NODEIDX_DEV_I2C_1, - XPM_NODEIDX_DEV_CAN_FD_0, - XPM_NODEIDX_DEV_CAN_FD_1, - XPM_NODEIDX_DEV_UART_0, - XPM_NODEIDX_DEV_UART_1, - XPM_NODEIDX_DEV_GPIO, - XPM_NODEIDX_DEV_TTC_0, - XPM_NODEIDX_DEV_TTC_1, - XPM_NODEIDX_DEV_TTC_2, - XPM_NODEIDX_DEV_TTC_3, - XPM_NODEIDX_DEV_SWDT_LPD, - - /* FPD Peripheral devices */ - XPM_NODEIDX_DEV_SWDT_FPD, - - /* PMC Peripheral devices */ - XPM_NODEIDX_DEV_OSPI, - XPM_NODEIDX_DEV_QSPI, - XPM_NODEIDX_DEV_GPIO_PMC, - XPM_NODEIDX_DEV_I2C_PMC, - XPM_NODEIDX_DEV_SDIO_0, - XPM_NODEIDX_DEV_SDIO_1, - - XPM_NODEIDX_DEV_PL_0, - XPM_NODEIDX_DEV_PL_1, - XPM_NODEIDX_DEV_PL_2, - XPM_NODEIDX_DEV_PL_3, - XPM_NODEIDX_DEV_RTC, - XPM_NODEIDX_DEV_ADMA_0, - XPM_NODEIDX_DEV_ADMA_1, - XPM_NODEIDX_DEV_ADMA_2, - XPM_NODEIDX_DEV_ADMA_3, - XPM_NODEIDX_DEV_ADMA_4, - XPM_NODEIDX_DEV_ADMA_5, - XPM_NODEIDX_DEV_ADMA_6, - XPM_NODEIDX_DEV_ADMA_7, - XPM_NODEIDX_DEV_IPI_0, - XPM_NODEIDX_DEV_IPI_1, - XPM_NODEIDX_DEV_IPI_2, - XPM_NODEIDX_DEV_IPI_3, - XPM_NODEIDX_DEV_IPI_4, - XPM_NODEIDX_DEV_IPI_5, - XPM_NODEIDX_DEV_IPI_6, - - /* Entire SoC */ - XPM_NODEIDX_DEV_SOC, - - /* DDR memory controllers */ - XPM_NODEIDX_DEV_DDRMC_0, - XPM_NODEIDX_DEV_DDRMC_1, - XPM_NODEIDX_DEV_DDRMC_2, - XPM_NODEIDX_DEV_DDRMC_3, - - /* GT devices */ - XPM_NODEIDX_DEV_GT_0, - XPM_NODEIDX_DEV_GT_1, - XPM_NODEIDX_DEV_GT_2, - XPM_NODEIDX_DEV_GT_3, - XPM_NODEIDX_DEV_GT_4, - XPM_NODEIDX_DEV_GT_5, - XPM_NODEIDX_DEV_GT_6, - XPM_NODEIDX_DEV_GT_7, - XPM_NODEIDX_DEV_GT_8, - XPM_NODEIDX_DEV_GT_9, - XPM_NODEIDX_DEV_GT_10, - - XPM_NODEIDX_DEV_MAX -}; - -#endif /* PM_NODE_H */ diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.c b/plat/xilinx/versal/pm_service/pm_svc_main.c deleted file mode 100644 index 185bfdb65..000000000 --- a/plat/xilinx/versal/pm_service/pm_svc_main.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * 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 - */ - -/* - * Top-level SMC handler for Versal power management calls and - * IPI setup functions for communication with PMC. - */ - -#include -#include -#include -#include -#include -#include "pm_api_sys.h" -#include "pm_client.h" -#include "pm_ipi.h" -#include -#include "../drivers/arm/gic/v3/gicv3_private.h" - -#define MODE 0x80000000U - -#define XSCUGIC_SGIR_EL1_INITID_SHIFT 24U -#define INVALID_SGI 0xFFU -#define PM_INIT_SUSPEND_CB (30U) -#define PM_NOTIFY_CB (32U) -DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6) - -/* pm_up = true - UP, pm_up = false - DOWN */ -static bool pm_up; -static uint32_t sgi = (uint32_t)INVALID_SGI; - -static void notify_os(void) -{ - int32_t cpu; - uint32_t reg; - - cpu = plat_my_core_pos() + 1U; - - reg = (cpu | (sgi << XSCUGIC_SGIR_EL1_INITID_SHIFT)); - write_icc_asgi1r_el1(reg); -} - -static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle, - void *cookie) -{ - uint32_t payload[4] = {0}; - enum pm_ret_status ret; - - VERBOSE("Received IPI FIQ from firmware\n"); - - (void)plat_ic_acknowledge_interrupt(); - - ret = pm_get_callbackdata(payload, ARRAY_SIZE(payload), 0, 0); - if (ret != PM_RET_SUCCESS) { - payload[0] = ret; - } - - switch (payload[0]) { - case PM_INIT_SUSPEND_CB: - case PM_NOTIFY_CB: - if (sgi != INVALID_SGI) { - notify_os(); - } - break; - case PM_RET_ERROR_INVALID_CRC: - pm_ipi_irq_clear(primary_proc); - WARN("Invalid CRC in the payload\n"); - break; - - default: - pm_ipi_irq_clear(primary_proc); - WARN("Invalid IPI payload\n"); - break; - } - - /* Clear FIQ */ - plat_ic_end_of_interrupt(id); - - return 0; -} - -/** - * pm_register_sgi() - PM register the IPI interrupt - * - * @sgi - SGI number to be used for communication. - * @reset - Reset to invalid SGI when reset=1. - * @return On success, the initialization function must return 0. - * Any other return value will cause the framework to ignore - * the service - * - * Update the SGI number to be used. - * - */ -int32_t pm_register_sgi(uint32_t sgi_num, uint32_t reset) -{ - if (reset == 1U) { - sgi = INVALID_SGI; - return 0; - } - - if (sgi != INVALID_SGI) { - return -EBUSY; - } - - if (sgi_num >= GICV3_MAX_SGI_TARGETS) { - return -EINVAL; - } - - sgi = (uint32_t)sgi_num; - return 0; -} - -/** - * pm_setup() - PM service setup - * - * @return On success, the initialization function must return 0. - * Any other return value will cause the framework to ignore - * the service - * - * Initialization functions for Versal power management for - * communicaton with PMC. - * - * Called from sip_svc_setup initialization function with the - * rt_svc_init signature. - */ -int32_t pm_setup(void) -{ - int32_t ret = 0; - - pm_ipi_init(primary_proc); - pm_up = true; - - /* - * Enable IPI IRQ - * assume the rich OS is OK to handle callback IRQs now. - * Even if we were wrong, it would not enable the IRQ in - * the GIC. - */ - pm_ipi_irq_enable(primary_proc); - - ret = request_intr_type_el3(PLAT_VERSAL_IPI_IRQ, ipi_fiq_handler); - if (ret != 0) { - WARN("BL31: registering IPI interrupt failed\n"); - } - - gicd_write_irouter(gicv3_driver_data->gicd_base, PLAT_VERSAL_IPI_IRQ, MODE); - return ret; -} - -/** - * eemi_for_compatibility() - EEMI calls handler for deprecated calls - * - * @return - If EEMI API found then, uintptr_t type address, else 0 - * - * Some EEMI API's use case needs to be changed in Linux driver, so they - * can take advantage of common EEMI handler in TF-A. As of now the old - * implementation of these APIs are required to maintain backward compatibility - * until their use case in linux driver changes. - */ -static uintptr_t eemi_for_compatibility(uint32_t api_id, uint32_t *pm_arg, - void *handle, uint32_t security_flag) -{ - enum pm_ret_status ret; - - switch (api_id) { - - case PM_IOCTL: - { - uint32_t value = 0U; - - ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3], pm_arg[4], - &value, security_flag); - if (ret == PM_RET_ERROR_NOTSUPPORTED) - return (uintptr_t)0; - - SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); - } - - case PM_QUERY_DATA: - { - uint32_t data[PAYLOAD_ARG_CNT] = { 0 }; - - ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3], data, security_flag); - - SMC_RET2(handle, (uint64_t)ret | ((uint64_t)data[0] << 32U), - (uint64_t)data[1] | ((uint64_t)data[2] << 32U)); - } - - case PM_FEATURE_CHECK: - { - uint32_t result[PAYLOAD_ARG_CNT] = {0U}; - - ret = pm_feature_check(pm_arg[0], result, security_flag); - SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U), - (uint64_t)result[1] | ((uint64_t)result[2] << 32U)); - } - - case PM_LOAD_PDI: - { - ret = pm_load_pdi(pm_arg[0], pm_arg[1], pm_arg[2], - security_flag); - SMC_RET1(handle, (uint64_t)ret); - } - - default: - return (uintptr_t)0; - } -} - -/** - * eemi_psci_debugfs_handler() - EEMI API invoked from PSCI - * - * These EEMI APIs performs CPU specific power management tasks. - * These EEMI APIs are invoked either from PSCI or from debugfs in kernel. - * These calls require CPU specific processing before sending IPI request to - * Platform Management Controller. For example enable/disable CPU specific - * interrupts. This requires separate handler for these calls and may not be - * handled using common eemi handler - */ -static uintptr_t eemi_psci_debugfs_handler(uint32_t api_id, uint32_t *pm_arg, - void *handle, uint32_t security_flag) -{ - enum pm_ret_status ret; - - switch (api_id) { - - case PM_SELF_SUSPEND: - ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3], security_flag); - SMC_RET1(handle, (u_register_t)ret); - - case PM_FORCE_POWERDOWN: - ret = pm_force_powerdown(pm_arg[0], pm_arg[1], security_flag); - SMC_RET1(handle, (u_register_t)ret); - - case PM_REQ_SUSPEND: - ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3], security_flag); - SMC_RET1(handle, (u_register_t)ret); - - case PM_ABORT_SUSPEND: - ret = pm_abort_suspend(pm_arg[0], security_flag); - SMC_RET1(handle, (u_register_t)ret); - - case PM_SYSTEM_SHUTDOWN: - ret = pm_system_shutdown(pm_arg[0], pm_arg[1], security_flag); - SMC_RET1(handle, (u_register_t)ret); - - default: - return (uintptr_t)0; - } -} - -/** - * TF_A_specific_handler() - SMC handler for TF-A specific functionality - * - * These EEMI calls performs functionality that does not require - * IPI transaction. The handler ends in TF-A and returns requested data to - * kernel from TF-A. - */ -static uintptr_t TF_A_specific_handler(uint32_t api_id, uint32_t *pm_arg, - void *handle, uint32_t security_flag) -{ - switch (api_id) { - - case TF_A_PM_REGISTER_SGI: - { - int32_t ret; - - ret = pm_register_sgi(pm_arg[0], pm_arg[1]); - if (ret != 0) { - SMC_RET1(handle, (uint32_t)PM_RET_ERROR_ARGS); - } - - SMC_RET1(handle, (uint32_t)PM_RET_SUCCESS); - } - - case PM_GET_CALLBACK_DATA: - { - uint32_t result[4] = {0}; - enum pm_ret_status ret; - - ret = pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag, 1U); - if (ret != 0) { - result[0] = ret; - } - - SMC_RET2(handle, - (uint64_t)result[0] | ((uint64_t)result[1] << 32U), - (uint64_t)result[2] | ((uint64_t)result[3] << 32U)); - } - - case PM_GET_TRUSTZONE_VERSION: - SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | - ((uint64_t)TZ_VERSION << 32U)); - - default: - return (uintptr_t)0; - } -} - -/** - * eemi_handler() - Prepare EEMI payload and perform IPI transaction - * - * EEMI - Embedded Energy Management Interface is Xilinx proprietary protocol - * to allow communication between power management controller and different - * processing clusters. - * - * This handler prepares EEMI protocol payload received from kernel and performs - * IPI transaction. - */ -static uintptr_t eemi_handler(uint32_t api_id, uint32_t *pm_arg, - void *handle, uint32_t security_flag) -{ - enum pm_ret_status ret; - uint32_t buf[PAYLOAD_ARG_CNT] = {0}; - - ret = pm_handle_eemi_call(security_flag, api_id, pm_arg[0], pm_arg[1], - pm_arg[2], pm_arg[3], pm_arg[4], - (uint64_t *)buf); - /* - * Two IOCTLs, to get clock name and pinctrl name of pm_query_data API - * receives 5 words of respoonse from firmware. Currently linux driver can - * receive only 4 words from TF-A. So, this needs to be handled separately - * than other eemi calls. - */ - if (api_id == PM_QUERY_DATA) { - if ((pm_arg[0] == XPM_QID_CLOCK_GET_NAME || - pm_arg[0] == XPM_QID_PINCTRL_GET_FUNCTION_NAME) && - ret == PM_RET_SUCCESS) { - SMC_RET2(handle, (uint64_t)buf[0] | ((uint64_t)buf[1] << 32U), - (uint64_t)buf[2] | ((uint64_t)buf[3] << 32U)); - } - } - - SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32U), - (uint64_t)buf[1] | ((uint64_t)buf[2] << 32U)); -} - -/** - * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2. - * @smc_fid - Function Identifier - * @x1 - x4 - SMC64 Arguments from kernel - * x3 (upper 32-bits) and x4 are Unused - * @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 pm_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) -{ - uintptr_t ret; - uint32_t pm_arg[PAYLOAD_ARG_CNT] = {0}; - uint32_t security_flag = SECURE_FLAG; - uint32_t api_id; - - /* Handle case where PM wasn't initialized properly */ - if (pm_up == false) { - SMC_RET1(handle, SMC_UNK); - } - - /* - * Mark BIT24 payload (i.e 1st bit of pm_arg[3] ) as non-secure (1) - * if smc called is non secure - */ - if (is_caller_non_secure(flags) != 0) { - security_flag = NON_SECURE_FLAG; - } - - pm_arg[0] = (uint32_t)x1; - pm_arg[1] = (uint32_t)(x1 >> 32U); - pm_arg[2] = (uint32_t)x2; - pm_arg[3] = (uint32_t)(x2 >> 32U); - pm_arg[4] = (uint32_t)x3; - (void)(x4); - api_id = smc_fid & FUNCID_NUM_MASK; - - ret = eemi_for_compatibility(api_id, pm_arg, handle, security_flag); - if (ret != (uintptr_t)0) { - return ret; - } - - ret = eemi_psci_debugfs_handler(api_id, pm_arg, handle, flags); - if (ret != (uintptr_t)0) { - return ret; - } - - ret = TF_A_specific_handler(api_id, pm_arg, handle, security_flag); - if (ret != (uintptr_t)0) { - return ret; - } - - ret = eemi_handler(api_id, pm_arg, handle, security_flag); - - return ret; -} diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.h b/plat/xilinx/versal/pm_service/pm_svc_main.h deleted file mode 100644 index b6e764f2c..000000000 --- a/plat/xilinx/versal/pm_service/pm_svc_main.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef PM_SVC_MAIN_H -#define PM_SVC_MAIN_H - -#include - -int32_t pm_setup(void); -uint64_t pm_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 pm_register_sgi(uint32_t sgi_num, uint32_t reset); -#endif /* PM_SVC_MAIN_H */ diff --git a/plat/xilinx/versal_net/platform.mk b/plat/xilinx/versal_net/platform.mk index 28e329519..0bc5925b1 100644 --- a/plat/xilinx/versal_net/platform.mk +++ b/plat/xilinx/versal_net/platform.mk @@ -1,6 +1,6 @@ # Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved. # Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved. -# Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved. +# Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause @@ -87,10 +87,10 @@ BL31_SOURCES += drivers/arm/cci/cci.c \ lib/cpus/aarch64/cortex_a78.S \ plat/common/plat_psci_common.c ifeq ($(TFA_NO_PM), 0) -BL31_SOURCES += plat/xilinx/versal/pm_service/pm_api_sys.c \ +BL31_SOURCES += plat/xilinx/common/pm_service/pm_api_sys.c \ plat/xilinx/common/pm_service/pm_ipi.c \ ${PLAT_PATH}/plat_psci_pm.c \ - plat/xilinx/versal/pm_service/pm_svc_main.c \ + plat/xilinx/common/pm_service/pm_svc_main.c \ ${PLAT_PATH}/pm_service/pm_client.c \ ${PLAT_PATH}/versal_net_ipi.c else diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c index 95a266e74..8f2863615 100644 --- a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c +++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved. - * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. + * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -19,7 +19,7 @@ #include #include -#include "pm_api_sys.h" +#include "zynqmp_pm_api_sys.h" /* * Table of regions to map using the MMU. diff --git a/plat/xilinx/zynqmp/libpm.mk b/plat/xilinx/zynqmp/libpm.mk index 4ceb5765a..db3c74260 100644 --- a/plat/xilinx/zynqmp/libpm.mk +++ b/plat/xilinx/zynqmp/libpm.mk @@ -8,8 +8,8 @@ LIBPM_SRCS := $(addprefix plat/xilinx/common/pm_service/, \ pm_ipi.c) LIBPM_SRCS += $(addprefix plat/xilinx/zynqmp/pm_service/, \ - pm_svc_main.c \ - pm_api_sys.c \ + zynqmp_pm_svc_main.c \ + zynqmp_pm_api_sys.c \ pm_api_pinctrl.c \ pm_api_ioctl.c \ pm_api_clock.c \ diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c index b7408b1da..5211ace82 100644 --- a/plat/xilinx/zynqmp/plat_psci.c +++ b/plat/xilinx/zynqmp/plat_psci.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -16,8 +17,8 @@ #include #include -#include "pm_api_sys.h" #include "pm_client.h" +#include "zynqmp_pm_api_sys.h" static uintptr_t zynqmp_sec_entry; diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c index e61310aad..9f4278d6d 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -16,10 +17,10 @@ #include #include "pm_api_clock.h" -#include "pm_api_sys.h" #include "pm_client.h" #include "pm_common.h" #include "pm_ipi.h" +#include "zynqmp_pm_api_sys.h" #define CLK_NODE_MAX (6U) diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c index c0bfd51e7..45038b063 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -16,10 +17,10 @@ #include "pm_api_clock.h" #include "pm_api_ioctl.h" -#include "pm_api_sys.h" #include "pm_client.h" #include "pm_common.h" #include "pm_ipi.h" +#include "zynqmp_pm_api_sys.h" /** * pm_ioctl_get_rpu_oper_mode () - Get current RPU operation mode diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c index 8f373418c..847ec2c5d 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c +++ b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -14,10 +15,10 @@ #include #include "pm_api_pinctrl.h" -#include "pm_api_sys.h" #include "pm_client.h" #include "pm_common.h" #include "pm_ipi.h" +#include "zynqmp_pm_api_sys.h" struct pinctrl_function { char name[FUNCTION_NAME_LEN]; diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c deleted file mode 100644 index 58491a07a..000000000 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c +++ /dev/null @@ -1,1811 +0,0 @@ -/* - * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved. - * Copyright (c) 2022-2023, Advanced Micro Devices Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * ZynqMP system level PM-API functions and communication with PMU via - * IPI interrupts - */ - -#include -#include - -#include "pm_api_clock.h" -#include "pm_api_ioctl.h" -#include "pm_api_pinctrl.h" -#include "pm_api_sys.h" -#include "pm_client.h" -#include "pm_common.h" -#include "pm_ipi.h" - -#define PM_QUERY_FEATURE_BITMASK ( \ - (1ULL << (uint64_t)PM_QID_CLOCK_GET_NAME) | \ - (1ULL << (uint64_t)PM_QID_CLOCK_GET_TOPOLOGY) | \ - (1ULL << (uint64_t)PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS) | \ - (1ULL << (uint64_t)PM_QID_CLOCK_GET_PARENTS) | \ - (1ULL << (uint64_t)PM_QID_CLOCK_GET_ATTRIBUTES) | \ - (1ULL << (uint64_t)PM_QID_PINCTRL_GET_NUM_PINS) | \ - (1ULL << (uint64_t)PM_QID_PINCTRL_GET_NUM_FUNCTIONS) | \ - (1ULL << (uint64_t)PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS) | \ - (1ULL << (uint64_t)PM_QID_PINCTRL_GET_FUNCTION_NAME) | \ - (1ULL << (uint64_t)PM_QID_PINCTRL_GET_FUNCTION_GROUPS) | \ - (1ULL << (uint64_t)PM_QID_PINCTRL_GET_PIN_GROUPS) | \ - (1ULL << (uint64_t)PM_QID_CLOCK_GET_NUM_CLOCKS) | \ - (1ULL << (uint64_t)PM_QID_CLOCK_GET_MAX_DIVISOR)) - -/** - * struct eemi_api_dependency - Dependent EEMI APIs which are implemented - * on both the ATF and firmware - * - * @id: EEMI API id or IOCTL id to be checked - * @api_id: Dependent EEMI API - */ -typedef struct __attribute__((packed)) { - uint8_t id; - uint8_t api_id; -} eemi_api_dependency; - -/* Dependent APIs for ATF to check their version from firmware */ -static const eemi_api_dependency api_dep_table[] = { - { - .id = PM_SELF_SUSPEND, - .api_id = PM_SELF_SUSPEND, - }, - { - .id = PM_REQ_WAKEUP, - .api_id = PM_REQ_WAKEUP, - }, - { - .id = PM_ABORT_SUSPEND, - .api_id = PM_ABORT_SUSPEND, - }, - { - .id = PM_SET_WAKEUP_SOURCE, - .api_id = PM_SET_WAKEUP_SOURCE, - }, - { - .id = PM_SYSTEM_SHUTDOWN, - .api_id = PM_SYSTEM_SHUTDOWN, - }, - { - .id = PM_GET_API_VERSION, - .api_id = PM_GET_API_VERSION, - }, - { - .id = PM_CLOCK_ENABLE, - .api_id = PM_PLL_SET_MODE, - }, - { - .id = PM_CLOCK_ENABLE, - .api_id = PM_CLOCK_ENABLE, - }, - { - .id = PM_CLOCK_DISABLE, - .api_id = PM_PLL_SET_MODE, - }, - { - .id = PM_CLOCK_DISABLE, - .api_id = PM_CLOCK_DISABLE, - }, - { - .id = PM_CLOCK_GETSTATE, - .api_id = PM_PLL_GET_MODE, - }, - { - .id = PM_CLOCK_GETSTATE, - .api_id = PM_CLOCK_GETSTATE, - }, - { - .id = PM_CLOCK_SETDIVIDER, - .api_id = PM_PLL_SET_PARAMETER, - }, - { - .id = PM_CLOCK_SETDIVIDER, - .api_id = PM_CLOCK_SETDIVIDER, - }, - { - .id = PM_CLOCK_GETDIVIDER, - .api_id = PM_PLL_GET_PARAMETER, - }, - { - .id = PM_CLOCK_GETDIVIDER, - .api_id = PM_CLOCK_GETDIVIDER, - }, - { - .id = PM_CLOCK_SETPARENT, - .api_id = PM_PLL_SET_PARAMETER, - }, - { - .id = PM_CLOCK_SETPARENT, - .api_id = PM_CLOCK_SETPARENT, - }, - { - .id = PM_CLOCK_GETPARENT, - .api_id = PM_PLL_GET_PARAMETER, - }, - { - .id = PM_CLOCK_GETPARENT, - .api_id = PM_CLOCK_GETPARENT, - }, - { - .id = PM_PLL_SET_PARAMETER, - .api_id = PM_PLL_SET_PARAMETER, - }, - { - .id = PM_PLL_GET_PARAMETER, - .api_id = PM_PLL_GET_PARAMETER, - }, - { - .id = PM_PLL_SET_MODE, - .api_id = PM_PLL_SET_MODE, - }, - { - .id = PM_PLL_GET_MODE, - .api_id = PM_PLL_GET_MODE, - }, - { - .id = PM_REGISTER_ACCESS, - .api_id = PM_MMIO_WRITE, - }, - { - .id = PM_REGISTER_ACCESS, - .api_id = PM_MMIO_READ, - }, - { - .id = PM_FEATURE_CHECK, - .api_id = PM_FEATURE_CHECK, - }, - { - .id = IOCTL_SET_TAPDELAY_BYPASS, - .api_id = PM_MMIO_WRITE, - }, - { - .id = IOCTL_SET_SGMII_MODE, - .api_id = PM_MMIO_WRITE, - }, - { - .id = IOCTL_SD_DLL_RESET, - .api_id = PM_MMIO_WRITE, - }, - { - .id = IOCTL_SET_SD_TAPDELAY, - .api_id = PM_MMIO_WRITE, - }, - { - .id = IOCTL_SET_SD_TAPDELAY, - .api_id = PM_MMIO_READ, - }, - { - .id = IOCTL_SET_PLL_FRAC_DATA, - .api_id = PM_PLL_SET_PARAMETER, - }, - { - .id = IOCTL_GET_PLL_FRAC_DATA, - .api_id = PM_PLL_GET_PARAMETER, - }, - { - .id = IOCTL_WRITE_GGS, - .api_id = PM_MMIO_WRITE, - }, - { - .id = IOCTL_READ_GGS, - .api_id = PM_MMIO_READ, - }, - { - .id = IOCTL_WRITE_PGGS, - .api_id = PM_MMIO_WRITE, - }, - { - .id = IOCTL_READ_PGGS, - .api_id = PM_MMIO_READ, - }, - { - .id = IOCTL_ULPI_RESET, - .api_id = PM_MMIO_WRITE, - }, - { - .id = IOCTL_SET_BOOT_HEALTH_STATUS, - .api_id = PM_MMIO_WRITE, - }, - { - .id = IOCTL_AFI, - .api_id = PM_MMIO_WRITE, - }, -}; - -/* Expected firmware API version to ATF */ -static const uint8_t atf_expected_ver_id[] = { - [PM_SELF_SUSPEND] = FW_API_BASE_VERSION, - [PM_REQ_WAKEUP] = FW_API_BASE_VERSION, - [PM_ABORT_SUSPEND] = FW_API_BASE_VERSION, - [PM_SET_WAKEUP_SOURCE] = FW_API_BASE_VERSION, - [PM_SYSTEM_SHUTDOWN] = FW_API_BASE_VERSION, - [PM_GET_API_VERSION] = FW_API_BASE_VERSION, - [PM_PLL_SET_MODE] = FW_API_BASE_VERSION, - [PM_PLL_GET_MODE] = FW_API_BASE_VERSION, - [PM_CLOCK_ENABLE] = FW_API_BASE_VERSION, - [PM_CLOCK_DISABLE] = FW_API_BASE_VERSION, - [PM_CLOCK_GETSTATE] = FW_API_BASE_VERSION, - [PM_PLL_SET_PARAMETER] = FW_API_BASE_VERSION, - [PM_PLL_GET_PARAMETER] = FW_API_BASE_VERSION, - [PM_CLOCK_SETDIVIDER] = FW_API_BASE_VERSION, - [PM_CLOCK_GETDIVIDER] = FW_API_BASE_VERSION, - [PM_CLOCK_SETPARENT] = FW_API_BASE_VERSION, - [PM_CLOCK_GETPARENT] = FW_API_BASE_VERSION, - [PM_MMIO_WRITE] = FW_API_BASE_VERSION, - [PM_MMIO_READ] = FW_API_BASE_VERSION, - [PM_FEATURE_CHECK] = FW_API_VERSION_2, -}; - -/* default shutdown/reboot scope is system(2) */ -static uint32_t pm_shutdown_scope = PMF_SHUTDOWN_SUBTYPE_SYSTEM; - -/** - * pm_get_shutdown_scope() - Get the currently set shutdown scope - * - * @return Shutdown scope value - */ -uint32_t pm_get_shutdown_scope(void) -{ - return pm_shutdown_scope; -} - -/** - * pm_self_suspend() - PM call for processor to suspend itself - * @nid Node id of the processor or subsystem - * @latency Requested maximum wakeup latency (not supported) - * @state Requested state - * @address Resume address - * - * This is a blocking call, it will return only once PMU has responded. - * On a wakeup, resume address will be automatically set by PMU. - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_self_suspend(enum pm_node_id nid, - uint32_t latency, - uint32_t state, - uintptr_t address) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - uint32_t cpuid = plat_my_core_pos(); - const struct pm_proc *proc = pm_get_proc(cpuid); - - /* - * Do client specific suspend operations - * (e.g. set powerdown request bit) - */ - pm_client_suspend(proc, state); - /* Send request to the PMU */ - PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency, - state, address, (address >> 32)); - return pm_ipi_send_sync(proc, payload, NULL, 0); -} - -/** - * pm_req_suspend() - PM call to request for another PU or subsystem to - * be suspended gracefully. - * @target Node id of the targeted PU or subsystem - * @ack Flag to specify whether acknowledge is requested - * @latency Requested wakeup latency (not supported) - * @state Requested state (not supported) - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_req_suspend(enum pm_node_id target, - enum pm_request_ack ack, - uint32_t latency, uint32_t state) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD5(payload, PM_REQ_SUSPEND, target, ack, latency, state); - if (ack == REQ_ACK_BLOCKING) { - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); - } else { - return pm_ipi_send(primary_proc, payload); - } -} - -/** - * pm_req_wakeup() - PM call for processor to wake up selected processor - * or subsystem - * @target Node id of the processor or subsystem to wake up - * @ack Flag to specify whether acknowledge requested - * @set_address Resume address presence indicator - * 1 resume address specified, 0 otherwise - * @address Resume address - * - * This API function is either used to power up another APU core for SMP - * (by PSCI) or to power up an entirely different PU or subsystem, such - * as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be - * automatically set by PMU. - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_req_wakeup(enum pm_node_id target, - uint32_t set_address, - uintptr_t address, - enum pm_request_ack ack) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - uint64_t encoded_address; - - - /* encode set Address into 1st bit of address */ - encoded_address = address; - encoded_address |= !!set_address; - - /* Send request to the PMU to perform the wake of the PU */ - PM_PACK_PAYLOAD5(payload, PM_REQ_WAKEUP, target, encoded_address, - encoded_address >> 32, ack); - - if (ack == REQ_ACK_BLOCKING) { - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); - } else { - return pm_ipi_send(primary_proc, payload); - } -} - -/** - * pm_force_powerdown() - PM call to request for another PU or subsystem to - * be powered down forcefully - * @target Node id of the targeted PU or subsystem - * @ack Flag to specify whether acknowledge is requested - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_force_powerdown(enum pm_node_id target, - enum pm_request_ack ack) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD3(payload, PM_FORCE_POWERDOWN, target, ack); - - if (ack == REQ_ACK_BLOCKING) { - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); - } else { - return pm_ipi_send(primary_proc, payload); - } -} - -/** - * pm_abort_suspend() - PM call to announce that a prior suspend request - * is to be aborted. - * @reason Reason for the abort - * - * Calling PU expects the PMU to abort the initiated suspend procedure. - * This is a non-blocking call without any acknowledge. - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* - * Do client specific abort suspend operations - * (e.g. enable interrupts and clear powerdown request bit) - */ - pm_client_abort_suspend(); - /* Send request to the PMU */ - /* TODO: allow passing the node ID of the affected CPU */ - PM_PACK_PAYLOAD3(payload, PM_ABORT_SUSPEND, reason, - primary_proc->node_id); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended - * @target Node id of the targeted PU or subsystem - * @wkup_node Node id of the wakeup peripheral - * @enable Enable or disable the specified peripheral as wake source - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target, - enum pm_node_id wkup_node, - uint32_t enable) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - PM_PACK_PAYLOAD4(payload, PM_SET_WAKEUP_SOURCE, target, wkup_node, - enable); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_system_shutdown() - PM call to request a system shutdown or restart - * @type Shutdown or restart? 0=shutdown, 1=restart, 2=setscope - * @subtype Scope: 0=APU-subsystem, 1=PS, 2=system - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - if (type == PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY) { - /* Setting scope for subsequent PSCI reboot or shutdown */ - pm_shutdown_scope = subtype; - return PM_RET_SUCCESS; - } - - PM_PACK_PAYLOAD3(payload, PM_SYSTEM_SHUTDOWN, type, subtype); - return pm_ipi_send_non_blocking(primary_proc, payload); -} - -/* APIs for managing PM slaves: */ - -/** - * pm_req_node() - PM call to request a node with specific capabilities - * @nid Node id of the slave - * @capabilities Requested capabilities of the slave - * @qos Quality of service (not supported) - * @ack Flag to specify whether acknowledge is requested - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_req_node(enum pm_node_id nid, - uint32_t capabilities, - uint32_t qos, - enum pm_request_ack ack) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - PM_PACK_PAYLOAD5(payload, PM_REQ_NODE, nid, capabilities, qos, ack); - - if (ack == REQ_ACK_BLOCKING) { - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); - } else { - return pm_ipi_send(primary_proc, payload); - } -} - -/** - * pm_set_requirement() - PM call to set requirement for PM slaves - * @nid Node id of the slave - * @capabilities Requested capabilities of the slave - * @qos Quality of service (not supported) - * @ack Flag to specify whether acknowledge is requested - * - * This API function is to be used for slaves a PU already has requested - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_set_requirement(enum pm_node_id nid, - uint32_t capabilities, - uint32_t qos, - enum pm_request_ack ack) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - PM_PACK_PAYLOAD5(payload, PM_SET_REQUIREMENT, nid, capabilities, qos, - ack); - - if (ack == REQ_ACK_BLOCKING) { - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); - } else { - return pm_ipi_send(primary_proc, payload); - } -} - -/* Miscellaneous API functions */ - -/** - * pm_get_api_version() - Get version number of PMU PM firmware - * @version Returns 32-bit version number of PMU Power Management Firmware - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_get_api_version(uint32_t *version) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD1(payload, PM_GET_API_VERSION); - return pm_ipi_send_sync(primary_proc, payload, version, 1); -} - -/** - * pm_get_node_status() - PM call to request a node's current status - * @nid Node id - * @ret_buff Buffer for the return values: - * [0] - Current power state of the node - * [1] - Current requirements for the node (slave nodes only) - * [2] - Current usage status for the node (slave nodes only) - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_get_node_status(enum pm_node_id nid, - uint32_t *ret_buff) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - PM_PACK_PAYLOAD2(payload, PM_GET_NODE_STATUS, nid); - return pm_ipi_send_sync(primary_proc, payload, ret_buff, 3); -} - -/** - * pm_mmio_write() - Perform write to protected mmio - * @address Address to write to - * @mask Mask to apply - * @value Value to write - * - * This function provides access to PM-related control registers - * that may not be directly accessible by a particular PU. - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_mmio_write(uintptr_t address, - uint32_t mask, - uint32_t value) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD4(payload, PM_MMIO_WRITE, address, mask, value); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_mmio_read() - Read value from protected mmio - * @address Address to write to - * @value Value to write - * - * This function provides access to PM-related control registers - * that may not be directly accessible by a particular PU. - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_mmio_read(uintptr_t address, uint32_t *value) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD2(payload, PM_MMIO_READ, address); - return pm_ipi_send_sync(primary_proc, payload, value, 1); -} - -/** - * pm_fpga_load() - Load the bitstream into the PL. - * - * This function provides access to the xilfpga library to load - * the Bit-stream into PL. - * - * address_low: lower 32-bit Linear memory space address - * - * address_high: higher 32-bit Linear memory space address - * - * size: Number of 32bit words - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_fpga_load(uint32_t address_low, - uint32_t address_high, - uint32_t size, - uint32_t flags) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD5(payload, PM_FPGA_LOAD, address_high, address_low, - size, flags); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_fpga_get_status() - Read value from fpga status register - * @value Value to read - * - * This function provides access to the xilfpga library to get - * the fpga status - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_fpga_get_status(uint32_t *value) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD1(payload, PM_FPGA_GET_STATUS); - return pm_ipi_send_sync(primary_proc, payload, value, 1); -} - -/** - * pm_get_chipid() - Read silicon ID registers - * @value Buffer for return values. Must be large enough - * to hold 8 bytes. - * - * @return Returns silicon ID registers - */ -enum pm_ret_status pm_get_chipid(uint32_t *value) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD1(payload, PM_GET_CHIPID); - return pm_ipi_send_sync(primary_proc, payload, value, 2); -} - -/** - * pm_secure_rsaaes() - Load the secure images. - * - * This function provides access to the xilsecure library to load - * the authenticated, encrypted, and authenicated/encrypted images. - * - * address_low: lower 32-bit Linear memory space address - * - * address_high: higher 32-bit Linear memory space address - * - * size: Number of 32bit words - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_secure_rsaaes(uint32_t address_low, - uint32_t address_high, - uint32_t size, - uint32_t flags) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD5(payload, PM_SECURE_RSA_AES, address_high, address_low, - size, flags); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_aes_engine() - Aes data blob encryption/decryption - * This function provides access to the xilsecure library to - * encrypt/decrypt data blobs. - * - * address_low: lower 32-bit address of the AesParams structure - * - * address_high: higher 32-bit address of the AesParams structure - * - * value: Returned output value - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_aes_engine(uint32_t address_high, - uint32_t address_low, - uint32_t *value) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD3(payload, PM_SECURE_AES, address_high, address_low); - return pm_ipi_send_sync(primary_proc, payload, value, 1); -} - -/** - * pm_get_callbackdata() - Read from IPI response buffer - * @data - array of PAYLOAD_ARG_CNT elements - * - * Read value from ipi buffer response buffer. - * @return Returns status, either success or error - */ -enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count) -{ - enum pm_ret_status ret = PM_RET_SUCCESS; - /* Return if interrupt is not from PMU */ - if (!pm_ipi_irq_status(primary_proc)) { - return ret; - } - - ret = pm_ipi_buff_read_callb(data, count); - pm_ipi_irq_clear(primary_proc); - return ret; -} - -/** - * pm_ioctl() - PM IOCTL API for device control and configs - * @node_id Node ID of the device - * @ioctl_id ID of the requested IOCTL - * @arg1 Argument 1 to requested IOCTL call - * @arg2 Argument 2 to requested IOCTL call - * @out Returned output value - * - * This function calls IOCTL to firmware for device control and configuration. - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_ioctl(enum pm_node_id nid, - uint32_t ioctl_id, - uint32_t arg1, - uint32_t arg2, - uint32_t *value) -{ - return pm_api_ioctl(nid, ioctl_id, arg1, arg2, value); -} - -/** - * fw_api_version() - Returns API version implemented in firmware - * @api_id API ID to check - * @version Returned supported API version - * @len Number of words to be returned - * - * @return Returns status, either success or error+reason - */ -static enum pm_ret_status fw_api_version(uint32_t id, uint32_t *version, - uint32_t len) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - PM_PACK_PAYLOAD2(payload, PM_FEATURE_CHECK, id); - return pm_ipi_send_sync(primary_proc, payload, version, len); -} - -/** - * check_api_dependency() - API to check dependent EEMI API version - * @id EEMI API ID to check - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status check_api_dependency(uint8_t id) -{ - uint8_t i; - uint32_t version; - int ret; - - for (i = 0U; i < ARRAY_SIZE(api_dep_table); i++) { - if (api_dep_table[i].id == id) { - if (api_dep_table[i].api_id == 0U) { - break; - } - - ret = fw_api_version(api_dep_table[i].api_id, - &version, 1); - if (ret != PM_RET_SUCCESS) { - return ret; - } - - /* Check if fw version matches ATF expected version */ - if (version != atf_expected_ver_id[api_dep_table[i].api_id]) { - return PM_RET_ERROR_NOTSUPPORTED; - } - } - } - - return PM_RET_SUCCESS; -} - -/** - * feature_check_atf() - These are API's completely implemented in ATF - * @api_id API ID to check - * @version Returned supported API version - * - * @return Returns status, either success or error+reason - */ -static enum pm_ret_status feature_check_atf(uint32_t api_id, uint32_t *version, - uint32_t *bit_mask) -{ - switch (api_id) { - case PM_QUERY_DATA: - *version = TFA_API_QUERY_DATA_VERSION; - bit_mask[0] = (uint32_t)(PM_QUERY_FEATURE_BITMASK); - bit_mask[1] = (uint32_t)(PM_QUERY_FEATURE_BITMASK >> 32); - return PM_RET_SUCCESS; - case PM_GET_CALLBACK_DATA: - case PM_GET_TRUSTZONE_VERSION: - case PM_SET_SUSPEND_MODE: - *version = ATF_API_BASE_VERSION; - return PM_RET_SUCCESS; - default: - return PM_RET_ERROR_NO_FEATURE; - } -} - -/** - * get_atf_version_for_partial_apis() - Return ATF version for partially - * implemented APIs - * @api_id API ID to check - * @version Returned supported API version - * - * @return Returns status, either success or error+reason - */ -static enum pm_ret_status get_atf_version_for_partial_apis(uint32_t api_id, - uint32_t *version) -{ - switch (api_id) { - case PM_SELF_SUSPEND: - case PM_REQ_WAKEUP: - case PM_ABORT_SUSPEND: - case PM_SET_WAKEUP_SOURCE: - case PM_SYSTEM_SHUTDOWN: - case PM_GET_API_VERSION: - case PM_CLOCK_ENABLE: - case PM_CLOCK_DISABLE: - case PM_CLOCK_GETSTATE: - case PM_CLOCK_SETDIVIDER: - case PM_CLOCK_GETDIVIDER: - case PM_CLOCK_SETPARENT: - case PM_CLOCK_GETPARENT: - case PM_PLL_SET_PARAMETER: - case PM_PLL_GET_PARAMETER: - case PM_PLL_SET_MODE: - case PM_PLL_GET_MODE: - case PM_REGISTER_ACCESS: - *version = ATF_API_BASE_VERSION; - return PM_RET_SUCCESS; - case PM_FEATURE_CHECK: - *version = FW_API_VERSION_2; - return PM_RET_SUCCESS; - default: - return PM_RET_ERROR_ARGS; - } -} - -/** - * feature_check_partial() - These are API's partially implemented in - * ATF and firmware both - * @api_id API ID to check - * @version Returned supported API version - * - * @return Returns status, either success or error+reason - */ -static enum pm_ret_status feature_check_partial(uint32_t api_id, - uint32_t *version) -{ - uint32_t status; - - switch (api_id) { - case PM_SELF_SUSPEND: - case PM_REQ_WAKEUP: - case PM_ABORT_SUSPEND: - case PM_SET_WAKEUP_SOURCE: - case PM_SYSTEM_SHUTDOWN: - case PM_GET_API_VERSION: - case PM_CLOCK_ENABLE: - case PM_CLOCK_DISABLE: - case PM_CLOCK_GETSTATE: - case PM_CLOCK_SETDIVIDER: - case PM_CLOCK_GETDIVIDER: - case PM_CLOCK_SETPARENT: - case PM_CLOCK_GETPARENT: - case PM_PLL_SET_PARAMETER: - case PM_PLL_GET_PARAMETER: - case PM_PLL_SET_MODE: - case PM_PLL_GET_MODE: - case PM_REGISTER_ACCESS: - case PM_FEATURE_CHECK: - status = check_api_dependency(api_id); - if (status != PM_RET_SUCCESS) { - return status; - } - return get_atf_version_for_partial_apis(api_id, version); - default: - return PM_RET_ERROR_NO_FEATURE; - } -} - -/** - * pm_feature_check() - Returns the supported API version if supported - * @api_id API ID to check - * @version Returned supported API version - * @bit_mask Returned supported IOCTL id version - * @len Number of bytes to be returned in bit_mask variable - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *version, - uint32_t *bit_mask, uint8_t len) -{ - uint32_t ret_payload[PAYLOAD_ARG_CNT] = {0U}; - uint32_t status; - - /* Get API version implemented in ATF */ - status = feature_check_atf(api_id, version, bit_mask); - if (status != PM_RET_ERROR_NO_FEATURE) { - return status; - } - - /* Get API version implemented by firmware and ATF both */ - status = feature_check_partial(api_id, version); - if (status != PM_RET_ERROR_NO_FEATURE) { - return status; - } - - /* Get API version implemented by firmware */ - status = fw_api_version(api_id, ret_payload, 3); - /* IOCTL call may return failure whose ID is not implemented in - * firmware but implemented in ATF - */ - if ((api_id != PM_IOCTL) && (status != PM_RET_SUCCESS)) { - return status; - } - - *version = ret_payload[0]; - - /* Update IOCTL bit mask which are implemented in ATF */ - if ((api_id == PM_IOCTL) || (api_id == PM_GET_OP_CHARACTERISTIC)) { - if (len < 2) { - return PM_RET_ERROR_ARGS; - } - bit_mask[0] = ret_payload[1]; - bit_mask[1] = ret_payload[2]; - if (api_id == PM_IOCTL) { - /* Get IOCTL's implemented by ATF */ - status = atf_ioctl_bitmask(bit_mask); - } - } else { - /* Requires for MISRA */ - } - - return status; -} - -/** - * pm_clock_get_max_divisor - PM call to get max divisor - * @clock_id Clock ID - * @div_type Divisor ID (TYPE_DIV1 or TYPE_DIV2) - * @max_div Maximum supported divisor - * - * This function is used by master to get maximum supported value. - * - * Return: Returns status, either success or error+reason. - */ -static enum pm_ret_status pm_clock_get_max_divisor(uint32_t clock_id, - uint8_t div_type, - uint32_t *max_div) -{ - return pm_api_clock_get_max_divisor(clock_id, div_type, max_div); -} - -/** - * pm_clock_get_num_clocks - PM call to request number of clocks - * @nclockss: Number of clocks - * - * This function is used by master to get number of clocks. - * - * Return: Returns status, either success or error+reason. - */ -static enum pm_ret_status pm_clock_get_num_clocks(uint32_t *nclocks) -{ - return pm_api_clock_get_num_clocks(nclocks); -} - -/** - * pm_clock_get_name() - PM call to request a clock's name - * @clock_id Clock ID - * @name Name of clock (max 16 bytes) - * - * This function is used by master to get nmae of clock specified - * by given clock ID. - */ -static void pm_clock_get_name(uint32_t clock_id, char *name) -{ - pm_api_clock_get_name(clock_id, name); -} - -/** - * pm_clock_get_topology() - PM call to request a clock's topology - * @clock_id Clock ID - * @index Topology index for next toplogy node - * @topology Buffer to store nodes in topology and flags - * - * This function is used by master to get topology information for the - * clock specified by given clock ID. Each response would return 3 - * topology nodes. To get next nodes, caller needs to call this API with - * index of next node. Index starts from 0. - * - * @return Returns status, either success or error+reason - */ -static enum pm_ret_status pm_clock_get_topology(uint32_t clock_id, - uint32_t index, - uint32_t *topology) -{ - return pm_api_clock_get_topology(clock_id, index, topology); -} - -/** - * pm_clock_get_fixedfactor_params() - PM call to request a clock's fixed factor - * parameters for fixed clock - * @clock_id Clock ID - * @mul Multiplication value - * @div Divisor value - * - * This function is used by master to get fixed factor parameers for the - * fixed clock. This API is application only for the fixed clock. - * - * @return Returns status, either success or error+reason - */ -static enum pm_ret_status pm_clock_get_fixedfactor_params(uint32_t clock_id, - uint32_t *mul, - uint32_t *div) -{ - return pm_api_clock_get_fixedfactor_params(clock_id, mul, div); -} - -/** - * pm_clock_get_parents() - PM call to request a clock's first 3 parents - * @clock_id Clock ID - * @index Index of next parent - * @parents Parents of the given clock - * - * This function is used by master to get clock's parents information. - * This API will return 3 parents with a single response. To get other - * parents, master should call same API in loop with new parent index - * till error is returned. - * - * E.g First call should have index 0 which will return parents 0, 1 and - * 2. Next call, index should be 3 which will return parent 3,4 and 5 and - * so on. - * - * @return Returns status, either success or error+reason - */ -static enum pm_ret_status pm_clock_get_parents(uint32_t clock_id, - uint32_t index, - uint32_t *parents) -{ - return pm_api_clock_get_parents(clock_id, index, parents); -} - -/** - * pm_clock_get_attributes() - PM call to request a clock's attributes - * @clock_id Clock ID - * @attr Clock attributes - * - * This function is used by master to get clock's attributes - * (e.g. valid, clock type, etc). - * - * @return Returns status, either success or error+reason - */ -static enum pm_ret_status pm_clock_get_attributes(uint32_t clock_id, - uint32_t *attr) -{ - return pm_api_clock_get_attributes(clock_id, attr); -} - -/** - * pm_clock_gate() - Configure clock gate - * @clock_id Id of the clock to be configured - * @enable Flag 0=disable (gate the clock), !0=enable (activate the clock) - * - * @return Error if an argument is not valid or status as returned by the - * PM controller (PMU) - */ -static enum pm_ret_status pm_clock_gate(uint32_t clock_id, - uint8_t enable) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - enum pm_ret_status status; - enum pm_api_id api_id; - - /* Check if clock ID is valid and return an error if it is not */ - status = pm_clock_id_is_valid(clock_id); - if (status != PM_RET_SUCCESS) { - return status; - } - - if (enable) { - api_id = PM_CLOCK_ENABLE; - } else { - api_id = PM_CLOCK_DISABLE; - } - - /* Send request to the PMU */ - PM_PACK_PAYLOAD2(payload, api_id, clock_id); - status = pm_ipi_send_sync(primary_proc, payload, NULL, 0); - - /* If action fails due to the lack of permissions filter the error */ - if (status == PM_RET_ERROR_ACCESS) { - status = PM_RET_SUCCESS; - } - - return status; -} - -/** - * pm_clock_enable() - Enable the clock for given id - * @clock_id: Id of the clock to be enabled - * - * This function is used by master to enable the clock - * including peripherals and PLL clocks. - * - * @return: Error if an argument is not valid or status as returned by the - * pm_clock_gate - */ -enum pm_ret_status pm_clock_enable(uint32_t clock_id) -{ - struct pm_pll *pll; - - /* First try to handle it as a PLL */ - pll = pm_clock_get_pll(clock_id); - if (pll) { - return pm_clock_pll_enable(pll); - } - - /* It's an on-chip clock, PMU should configure clock's gate */ - return pm_clock_gate(clock_id, 1); -} - -/** - * pm_clock_disable - Disable the clock for given id - * @clock_id: Id of the clock to be disable - * - * This function is used by master to disable the clock - * including peripherals and PLL clocks. - * - * @return: Error if an argument is not valid or status as returned by the - * pm_clock_gate - */ -enum pm_ret_status pm_clock_disable(uint32_t clock_id) -{ - struct pm_pll *pll; - - /* First try to handle it as a PLL */ - pll = pm_clock_get_pll(clock_id); - if (pll) { - return pm_clock_pll_disable(pll); - } - - /* It's an on-chip clock, PMU should configure clock's gate */ - return pm_clock_gate(clock_id, 0); -} - -/** - * pm_clock_getstate - Get the clock state for given id - * @clock_id: Id of the clock to be queried - * @state: 1/0 (Enabled/Disabled) - * - * This function is used by master to get the state of clock - * including peripherals and PLL clocks. - * - * Return: Returns status, either success or error+reason. - */ -enum pm_ret_status pm_clock_getstate(uint32_t clock_id, - uint32_t *state) -{ - struct pm_pll *pll; - uint32_t payload[PAYLOAD_ARG_CNT]; - enum pm_ret_status status; - - /* First try to handle it as a PLL */ - pll = pm_clock_get_pll(clock_id); - if (pll) - return pm_clock_pll_get_state(pll, state); - - /* Check if clock ID is a valid on-chip clock */ - status = pm_clock_id_is_valid(clock_id); - if (status != PM_RET_SUCCESS) { - return status; - } - - /* Send request to the PMU */ - PM_PACK_PAYLOAD2(payload, PM_CLOCK_GETSTATE, clock_id); - return pm_ipi_send_sync(primary_proc, payload, state, 1); -} - -/** - * pm_clock_setdivider - Set the clock divider for given id - * @clock_id: Id of the clock - * @divider: divider value - * - * This function is used by master to set divider for any clock - * to achieve desired rate. - * - * Return: Returns status, either success or error+reason. - */ -enum pm_ret_status pm_clock_setdivider(uint32_t clock_id, - uint32_t divider) -{ - enum pm_ret_status status; - enum pm_node_id nid; - enum pm_clock_div_id div_id; - uint32_t payload[PAYLOAD_ARG_CNT]; - const uint32_t div0 = 0xFFFF0000; - const uint32_t div1 = 0x0000FFFF; - uint32_t val; - - /* Get PLL node ID using PLL clock ID */ - status = pm_clock_get_pll_node_id(clock_id, &nid); - if (status == PM_RET_SUCCESS) { - return pm_pll_set_parameter(nid, PM_PLL_PARAM_FBDIV, divider); - } - - /* Check if clock ID is a valid on-chip clock */ - status = pm_clock_id_is_valid(clock_id); - if (status != PM_RET_SUCCESS) { - return status; - } - - if (div0 == (divider & div0)) { - div_id = PM_CLOCK_DIV0_ID; - val = divider & ~div0; - } else if (div1 == (divider & div1)) { - div_id = PM_CLOCK_DIV1_ID; - val = (divider & ~div1) >> 16; - } else { - return PM_RET_ERROR_ARGS; - } - - /* Send request to the PMU */ - PM_PACK_PAYLOAD4(payload, PM_CLOCK_SETDIVIDER, clock_id, div_id, val); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_clock_getdivider - Get the clock divider for given id - * @clock_id: Id of the clock - * @divider: divider value - * - * This function is used by master to get divider values - * for any clock. - * - * Return: Returns status, either success or error+reason. - */ -enum pm_ret_status pm_clock_getdivider(uint32_t clock_id, - uint32_t *divider) -{ - enum pm_ret_status status; - enum pm_node_id nid; - uint32_t payload[PAYLOAD_ARG_CNT]; - uint32_t val; - - /* Get PLL node ID using PLL clock ID */ - status = pm_clock_get_pll_node_id(clock_id, &nid); - if (status == PM_RET_SUCCESS) { - return pm_pll_get_parameter(nid, PM_PLL_PARAM_FBDIV, divider); - } - - /* Check if clock ID is a valid on-chip clock */ - status = pm_clock_id_is_valid(clock_id); - if (status != PM_RET_SUCCESS) { - return status; - } - - if (pm_clock_has_div(clock_id, PM_CLOCK_DIV0_ID)) { - /* Send request to the PMU to get div0 */ - PM_PACK_PAYLOAD3(payload, PM_CLOCK_GETDIVIDER, clock_id, - PM_CLOCK_DIV0_ID); - status = pm_ipi_send_sync(primary_proc, payload, &val, 1); - if (status != PM_RET_SUCCESS) { - return status; - } - *divider = val; - } - - if (pm_clock_has_div(clock_id, PM_CLOCK_DIV1_ID)) { - /* Send request to the PMU to get div1 */ - PM_PACK_PAYLOAD3(payload, PM_CLOCK_GETDIVIDER, clock_id, - PM_CLOCK_DIV1_ID); - status = pm_ipi_send_sync(primary_proc, payload, &val, 1); - if (status != PM_RET_SUCCESS) { - return status; - } - *divider |= val << 16; - } - - return status; -} - -/** - * pm_clock_setrate - Set the clock rate for given id - * @clock_id: Id of the clock - * @rate: rate value in hz - * - * This function is used by master to set rate for any clock. - * - * Return: Returns status, either success or error+reason. - */ -enum pm_ret_status pm_clock_setrate(uint32_t clock_id, - uint64_t rate) -{ - return PM_RET_ERROR_NOTSUPPORTED; -} - -/** - * pm_clock_getrate - Get the clock rate for given id - * @clock_id: Id of the clock - * @rate: rate value in hz - * - * This function is used by master to get rate - * for any clock. - * - * Return: Returns status, either success or error+reason. - */ -enum pm_ret_status pm_clock_getrate(uint32_t clock_id, - uint64_t *rate) -{ - return PM_RET_ERROR_NOTSUPPORTED; -} - -/** - * pm_clock_setparent - Set the clock parent for given id - * @clock_id: Id of the clock - * @parent_index: Index of the parent clock into clock's parents array - * - * This function is used by master to set parent for any clock. - * - * Return: Returns status, either success or error+reason. - */ -enum pm_ret_status pm_clock_setparent(uint32_t clock_id, - uint32_t parent_index) -{ - struct pm_pll *pll; - uint32_t payload[PAYLOAD_ARG_CNT]; - enum pm_ret_status status; - - /* First try to handle it as a PLL */ - pll = pm_clock_get_pll_by_related_clk(clock_id); - if (pll) { - return pm_clock_pll_set_parent(pll, clock_id, parent_index); - } - - /* Check if clock ID is a valid on-chip clock */ - status = pm_clock_id_is_valid(clock_id); - if (status != PM_RET_SUCCESS) { - return status; - } - - /* Send request to the PMU */ - PM_PACK_PAYLOAD3(payload, PM_CLOCK_SETPARENT, clock_id, parent_index); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_clock_getparent - Get the clock parent for given id - * @clock_id: Id of the clock - * @parent_index: parent index - * - * This function is used by master to get parent index - * for any clock. - * - * Return: Returns status, either success or error+reason. - */ -enum pm_ret_status pm_clock_getparent(uint32_t clock_id, - uint32_t *parent_index) -{ - struct pm_pll *pll; - uint32_t payload[PAYLOAD_ARG_CNT]; - enum pm_ret_status status; - - /* First try to handle it as a PLL */ - pll = pm_clock_get_pll_by_related_clk(clock_id); - if (pll) { - return pm_clock_pll_get_parent(pll, clock_id, parent_index); - } - - /* Check if clock ID is a valid on-chip clock */ - status = pm_clock_id_is_valid(clock_id); - if (status != PM_RET_SUCCESS) { - return status; - } - - /* Send request to the PMU */ - PM_PACK_PAYLOAD2(payload, PM_CLOCK_GETPARENT, clock_id); - return pm_ipi_send_sync(primary_proc, payload, parent_index, 1); -} - -/** - * pm_pinctrl_get_num_pins - PM call to request number of pins - * @npins: Number of pins - * - * This function is used by master to get number of pins - * - * Return: Returns status, either success or error+reason. - */ -static enum pm_ret_status pm_pinctrl_get_num_pins(uint32_t *npins) -{ - return pm_api_pinctrl_get_num_pins(npins); -} - -/** - * pm_pinctrl_get_num_functions - PM call to request number of functions - * @nfuncs: Number of functions - * - * This function is used by master to get number of functions - * - * Return: Returns status, either success or error+reason. - */ -static enum pm_ret_status pm_pinctrl_get_num_functions(uint32_t *nfuncs) -{ - return pm_api_pinctrl_get_num_functions(nfuncs); -} - -/** - * pm_pinctrl_get_num_function_groups - PM call to request number of - * function groups - * @fid: Id of function - * @ngroups: Number of function groups - * - * This function is used by master to get number of function groups specified - * by given function Id - * - * Return: Returns status, either success or error+reason. - */ -static enum pm_ret_status pm_pinctrl_get_num_function_groups(uint32_t fid, - uint32_t *ngroups) -{ - return pm_api_pinctrl_get_num_func_groups(fid, ngroups); -} - -/** - * pm_pinctrl_get_function_name - PM call to request function name - * @fid: Id of function - * @name: Name of function - * - * This function is used by master to get name of function specified - * by given function Id - */ -static void pm_pinctrl_get_function_name(uint32_t fid, char *name) -{ - pm_api_pinctrl_get_function_name(fid, name); -} - -/** - * pm_pinctrl_get_function_groups - PM call to request function groups - * @fid: Id of function - * @index: Index of next function groups - * @groups: Function groups - * - * This function is used by master to get function groups specified - * by given function Id. This API will return 6 function groups with - * a single response. To get other function groups, master should call - * same API in loop with new function groups index till error is returned. - * - * E.g First call should have index 0 which will return function groups - * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return - * function groups 6, 7, 8, 9, 10 and 11 and so on. - * - * Return: Returns status, either success or error+reason. - */ -static enum pm_ret_status pm_pinctrl_get_function_groups(uint32_t fid, - uint32_t index, - uint16_t *groups) -{ - return pm_api_pinctrl_get_function_groups(fid, index, groups); -} - -/** - * pm_pinctrl_get_pin_groups - PM call to request pin groups - * @pin_id: Id of pin - * @index: Index of next pin groups - * @groups: pin groups - * - * This function is used by master to get pin groups specified - * by given pin Id. This API will return 6 pin groups with - * a single response. To get other pin groups, master should call - * same API in loop with new pin groups index till error is returned. - * - * E.g First call should have index 0 which will return pin groups - * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return - * pin groups 6, 7, 8, 9, 10 and 11 and so on. - * - * Return: Returns status, either success or error+reason. - */ -static enum pm_ret_status pm_pinctrl_get_pin_groups(uint32_t pin_id, - uint32_t index, - uint16_t *groups) -{ - return pm_api_pinctrl_get_pin_groups(pin_id, index, groups); -} - -/** - * pm_query_data() - PM API for querying firmware data - * @arg1 Argument 1 to requested IOCTL call - * @arg2 Argument 2 to requested IOCTL call - * @arg3 Argument 3 to requested IOCTL call - * @arg4 Argument 4 to requested IOCTL call - * @data Returned output data - * - * This function returns requested data. - */ -void pm_query_data(enum pm_query_id qid, uint32_t arg1, uint32_t arg2, - uint32_t arg3, uint32_t *data) -{ - switch (qid) { - case PM_QID_CLOCK_GET_NAME: - pm_clock_get_name(arg1, (char *)data); - break; - case PM_QID_CLOCK_GET_TOPOLOGY: - data[0] = pm_clock_get_topology(arg1, arg2, &data[1]); - break; - case PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS: - data[0] = pm_clock_get_fixedfactor_params(arg1, &data[1], - &data[2]); - break; - case PM_QID_CLOCK_GET_PARENTS: - data[0] = pm_clock_get_parents(arg1, arg2, &data[1]); - break; - case PM_QID_CLOCK_GET_ATTRIBUTES: - data[0] = pm_clock_get_attributes(arg1, &data[1]); - break; - case PM_QID_PINCTRL_GET_NUM_PINS: - data[0] = pm_pinctrl_get_num_pins(&data[1]); - break; - case PM_QID_PINCTRL_GET_NUM_FUNCTIONS: - data[0] = pm_pinctrl_get_num_functions(&data[1]); - break; - case PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS: - data[0] = pm_pinctrl_get_num_function_groups(arg1, &data[1]); - break; - case PM_QID_PINCTRL_GET_FUNCTION_NAME: - pm_pinctrl_get_function_name(arg1, (char *)data); - break; - case PM_QID_PINCTRL_GET_FUNCTION_GROUPS: - data[0] = pm_pinctrl_get_function_groups(arg1, arg2, - (uint16_t *)&data[1]); - break; - case PM_QID_PINCTRL_GET_PIN_GROUPS: - data[0] = pm_pinctrl_get_pin_groups(arg1, arg2, - (uint16_t *)&data[1]); - break; - case PM_QID_CLOCK_GET_NUM_CLOCKS: - data[0] = pm_clock_get_num_clocks(&data[1]); - break; - - case PM_QID_CLOCK_GET_MAX_DIVISOR: - data[0] = pm_clock_get_max_divisor(arg1, arg2, &data[1]); - break; - default: - data[0] = PM_RET_ERROR_ARGS; - WARN("Unimplemented query service call: 0x%x\n", qid); - break; - } -} - -enum pm_ret_status pm_sha_hash(uint32_t address_high, - uint32_t address_low, - uint32_t size, - uint32_t flags) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD5(payload, PM_SECURE_SHA, address_high, address_low, - size, flags); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -enum pm_ret_status pm_rsa_core(uint32_t address_high, - uint32_t address_low, - uint32_t size, - uint32_t flags) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD5(payload, PM_SECURE_RSA, address_high, address_low, - size, flags); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -enum pm_ret_status pm_secure_image(uint32_t address_low, - uint32_t address_high, - uint32_t key_lo, - uint32_t key_hi, - uint32_t *value) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD5(payload, PM_SECURE_IMAGE, address_high, address_low, - key_hi, key_lo); - return pm_ipi_send_sync(primary_proc, payload, value, 2); -} - -/** - * pm_fpga_read - Perform the fpga configuration readback - * - * @reg_numframes: Configuration register offset (or) Number of frames to read - * @address_low: lower 32-bit Linear memory space address - * @address_high: higher 32-bit Linear memory space address - * @readback_type: Type of fpga readback operation - * 0 -- Configuration Register readback - * 1 -- Configuration Data readback - * @value: Value to read - * - * This function provides access to the xilfpga library to read - * the PL configuration. - * - * Return: Returns status, either success or error+reason. - */ -enum pm_ret_status pm_fpga_read(uint32_t reg_numframes, - uint32_t address_low, - uint32_t address_high, - uint32_t readback_type, - uint32_t *value) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD5(payload, PM_FPGA_READ, reg_numframes, address_low, - address_high, readback_type); - return pm_ipi_send_sync(primary_proc, payload, value, 1); -} - -/* - * pm_pll_set_parameter() - Set the PLL parameter value - * @nid Node id of the target PLL - * @param_id ID of the PLL parameter - * @value Parameter value to be set - * - * Setting the parameter will have physical effect once the PLL mode is set to - * integer or fractional. - * - * @return Error if an argument is not valid or status as returned by the - * PM controller (PMU) - */ -enum pm_ret_status pm_pll_set_parameter(enum pm_node_id nid, - enum pm_pll_param param_id, - uint32_t value) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Check if given node ID is a PLL node */ - if (nid < NODE_APLL || nid > NODE_IOPLL) { - return PM_RET_ERROR_ARGS; - } - - /* Check if parameter ID is valid and return an error if it's not */ - if (param_id >= PM_PLL_PARAM_MAX) { - return PM_RET_ERROR_ARGS; - } - - /* Send request to the PMU */ - PM_PACK_PAYLOAD4(payload, PM_PLL_SET_PARAMETER, nid, param_id, value); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_pll_get_parameter() - Get the PLL parameter value - * @nid Node id of the target PLL - * @param_id ID of the PLL parameter - * @value Location to store the parameter value - * - * @return Error if an argument is not valid or status as returned by the - * PM controller (PMU) - */ -enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid, - enum pm_pll_param param_id, - uint32_t *value) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Check if given node ID is a PLL node */ - if (nid < NODE_APLL || nid > NODE_IOPLL) { - return PM_RET_ERROR_ARGS; - } - - /* Check if parameter ID is valid and return an error if it's not */ - if (param_id >= PM_PLL_PARAM_MAX) { - return PM_RET_ERROR_ARGS; - } - - /* Send request to the PMU */ - PM_PACK_PAYLOAD3(payload, PM_PLL_GET_PARAMETER, nid, param_id); - return pm_ipi_send_sync(primary_proc, payload, value, 1); -} - -/** - * pm_pll_set_mode() - Set the PLL mode - * @nid Node id of the target PLL - * @mode PLL mode to be set - * - * If reset mode is set the PM controller will first bypass the PLL and then - * assert the reset. If integer or fractional mode is set the PM controller will - * ensure that the complete PLL programming sequence is satisfied. After this - * function returns success the PLL is locked and its bypass is deasserted. - * - * @return Error if an argument is not valid or status as returned by the - * PM controller (PMU) - */ -enum pm_ret_status pm_pll_set_mode(enum pm_node_id nid, enum pm_pll_mode mode) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Check if given node ID is a PLL node */ - if (nid < NODE_APLL || nid > NODE_IOPLL) { - return PM_RET_ERROR_ARGS; - } - - /* Check if PLL mode is valid */ - if (mode >= PM_PLL_MODE_MAX) { - return PM_RET_ERROR_ARGS; - } - - /* Send request to the PMU */ - PM_PACK_PAYLOAD3(payload, PM_PLL_SET_MODE, nid, mode); - return pm_ipi_send_sync(primary_proc, payload, NULL, 0); -} - -/** - * pm_pll_get_mode() - Get the PLL mode - * @nid Node id of the target PLL - * @mode Location to store the mode of the PLL - * - * @return Error if an argument is not valid or status as returned by the - * PM controller (PMU) - */ -enum pm_ret_status pm_pll_get_mode(enum pm_node_id nid, enum pm_pll_mode *mode) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Check if given node ID is a PLL node */ - if (nid < NODE_APLL || nid > NODE_IOPLL) { - return PM_RET_ERROR_ARGS; - } - - /* Send request to the PMU */ - PM_PACK_PAYLOAD2(payload, PM_PLL_GET_MODE, nid); - return pm_ipi_send_sync(primary_proc, payload, mode, 1); -} - -/** - * pm_register_access() - PM API for register read/write access data - * - * @register_access_id Register_access_id which says register read/write - * - * @address Address of the register to be accessed - * - * @mask Mask value to be used while writing value - * - * @value Value to be written to register - * - * @out Returned output data - * - * This function returns requested data. - * - * @return Returns status, either success or error+reason - */ -enum pm_ret_status pm_register_access(uint32_t register_access_id, - uint32_t address, - uint32_t mask, - uint32_t value, - uint32_t *out) -{ - enum pm_ret_status ret; - - if (((ZYNQMP_CSU_BASEADDR & address) != ZYNQMP_CSU_BASEADDR) && - ((CSUDMA_BASE & address) != CSUDMA_BASE) && - ((RSA_CORE_BASE & address) != RSA_CORE_BASE) && - ((PMU_GLOBAL_BASE & address) != PMU_GLOBAL_BASE)) { - return PM_RET_ERROR_ACCESS; - } - - switch (register_access_id) { - case CONFIG_REG_WRITE: - ret = pm_mmio_write(address, mask, value); - break; - case CONFIG_REG_READ: - ret = pm_mmio_read(address, out); - break; - default: - ret = PM_RET_ERROR_ARGS; - WARN("Unimplemented register_access call\n\r"); - break; - } - return ret; -} - -/** - * pm_efuse_access() - To program or read efuse bits. - * - * This function provides access to the xilskey library to program/read - * efuse bits. - * - * address_low: lower 32-bit Linear memory space address - * address_high: higher 32-bit Linear memory space address - * - * value: Returned output value - * - * @return Returns status, either success or error+reason - * - */ -enum pm_ret_status pm_efuse_access(uint32_t address_high, - uint32_t address_low, - uint32_t *value) -{ - uint32_t payload[PAYLOAD_ARG_CNT]; - - /* Send request to the PMU */ - PM_PACK_PAYLOAD3(payload, PM_EFUSE_ACCESS, address_high, address_low); - - 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 deleted file mode 100644 index 1341e7b37..000000000 --- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved. - * Copyright (c) 2023, Advanced Micro Devices Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef PM_API_SYS_H -#define PM_API_SYS_H - -#include - -#include "pm_defs.h" - -enum pm_query_id { - PM_QID_INVALID, - PM_QID_CLOCK_GET_NAME, - PM_QID_CLOCK_GET_TOPOLOGY, - PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS, - PM_QID_CLOCK_GET_PARENTS, - PM_QID_CLOCK_GET_ATTRIBUTES, - PM_QID_PINCTRL_GET_NUM_PINS, - PM_QID_PINCTRL_GET_NUM_FUNCTIONS, - PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS, - PM_QID_PINCTRL_GET_FUNCTION_NAME, - PM_QID_PINCTRL_GET_FUNCTION_GROUPS, - PM_QID_PINCTRL_GET_PIN_GROUPS, - PM_QID_CLOCK_GET_NUM_CLOCKS, - PM_QID_CLOCK_GET_MAX_DIVISOR, -}; - -enum pm_register_access_id { - CONFIG_REG_WRITE, - CONFIG_REG_READ, -}; - -/** - * Assigning of argument values into array elements. - */ -#define PM_PACK_PAYLOAD1(pl, arg0) { \ - pl[0] = (uint32_t)(arg0); \ -} - -#define PM_PACK_PAYLOAD2(pl, arg0, arg1) { \ - pl[1] = (uint32_t)(arg1); \ - PM_PACK_PAYLOAD1(pl, arg0); \ -} - -#define PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2) { \ - pl[2] = (uint32_t)(arg2); \ - PM_PACK_PAYLOAD2(pl, arg0, arg1); \ -} - -#define PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3) { \ - pl[3] = (uint32_t)(arg3); \ - PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2); \ -} - -#define PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4) { \ - pl[4] = (uint32_t)(arg4); \ - PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3); \ -} - -#define PM_PACK_PAYLOAD6(pl, arg0, arg1, arg2, arg3, arg4, arg5) { \ - pl[5] = (uint32_t)(arg5); \ - PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4); \ -} - -/********************************************************** - * System-level API function declarations - **********************************************************/ -enum pm_ret_status pm_req_suspend(enum pm_node_id target, - enum pm_request_ack ack, - uint32_t latency, - uint32_t state); - -enum pm_ret_status pm_self_suspend(enum pm_node_id nid, - uint32_t latency, - uint32_t state, - uintptr_t address); - -enum pm_ret_status pm_force_powerdown(enum pm_node_id target, - enum pm_request_ack ack); - -enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason); - -enum pm_ret_status pm_req_wakeup(enum pm_node_id target, - uint32_t set_address, - uintptr_t address, - enum pm_request_ack ack); - -enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target, - enum pm_node_id wkup_node, - uint32_t enable); - -enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype); - -/* API functions for managing PM Slaves */ -enum pm_ret_status pm_req_node(enum pm_node_id nid, - uint32_t capabilities, - uint32_t qos, - enum pm_request_ack ack); - -enum pm_ret_status pm_set_requirement(enum pm_node_id nid, - uint32_t capabilities, - uint32_t qos, - enum pm_request_ack ack); - -/* Miscellaneous API functions */ -enum pm_ret_status pm_get_api_version(uint32_t *version); -enum pm_ret_status pm_get_node_status(enum pm_node_id nid, - uint32_t *ret_buff); - -/* Direct-Control API functions */ -enum pm_ret_status pm_mmio_write(uintptr_t address, - uint32_t mask, - uint32_t value); -enum pm_ret_status pm_mmio_read(uintptr_t address, uint32_t *value); -enum pm_ret_status pm_fpga_load(uint32_t address_low, - uint32_t address_high, - uint32_t size, - uint32_t flags); -enum pm_ret_status pm_fpga_get_status(uint32_t *value); - -enum pm_ret_status pm_get_chipid(uint32_t *value); -enum pm_ret_status pm_secure_rsaaes(uint32_t address_low, - uint32_t address_high, - uint32_t size, - uint32_t flags); -uint32_t pm_get_shutdown_scope(void); -enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count); -enum pm_ret_status pm_ioctl(enum pm_node_id nid, - uint32_t ioctl_id, - uint32_t arg1, - uint32_t arg2, - uint32_t *value); -enum pm_ret_status pm_clock_enable(uint32_t clock_id); -enum pm_ret_status pm_clock_disable(uint32_t clock_id); -enum pm_ret_status pm_clock_getstate(uint32_t clock_id, - uint32_t *state); -enum pm_ret_status pm_clock_setdivider(uint32_t clock_id, - uint32_t divider); -enum pm_ret_status pm_clock_getdivider(uint32_t clock_id, - uint32_t *divider); -enum pm_ret_status pm_clock_setrate(uint32_t clock_id, - uint64_t rate); -enum pm_ret_status pm_clock_getrate(uint32_t clock_id, - uint64_t *rate); -enum pm_ret_status pm_clock_setparent(uint32_t clock_id, - uint32_t parent_index); -enum pm_ret_status pm_clock_getparent(uint32_t clock_id, - uint32_t *parent_index); -void pm_query_data(enum pm_query_id qid, uint32_t arg1, uint32_t arg2, - uint32_t arg3, uint32_t *data); -enum pm_ret_status pm_sha_hash(uint32_t address_high, - uint32_t address_low, - uint32_t size, - uint32_t flags); -enum pm_ret_status pm_rsa_core(uint32_t address_high, - uint32_t address_low, - uint32_t size, - uint32_t flags); -enum pm_ret_status pm_secure_image(uint32_t address_low, - uint32_t address_high, - uint32_t key_lo, - uint32_t key_hi, - uint32_t *value); -enum pm_ret_status pm_fpga_read(uint32_t reg_numframes, - uint32_t address_low, - uint32_t address_high, - uint32_t readback_type, - uint32_t *value); -enum pm_ret_status pm_aes_engine(uint32_t address_high, - uint32_t address_low, - uint32_t *value); -enum pm_ret_status pm_register_access(uint32_t register_access_id, - uint32_t address, - uint32_t mask, - uint32_t value, - uint32_t *out); -enum pm_ret_status pm_pll_set_parameter(enum pm_node_id nid, - enum pm_pll_param param_id, - uint32_t value); -enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid, - enum pm_pll_param param_id, - uint32_t *value); -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 pm_feature_check(uint32_t api_id, uint32_t *version, - uint32_t *bit_mask, uint8_t len); -enum pm_ret_status check_api_dependency(uint8_t id); - -#endif /* PM_API_SYS_H */ diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.c b/plat/xilinx/zynqmp/pm_service/pm_client.c index 7217fa145..f752525a2 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_client.c +++ b/plat/xilinx/zynqmp/pm_service/pm_client.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -21,9 +22,9 @@ #include #include -#include "pm_api_sys.h" #include "pm_client.h" #include "pm_ipi.h" +#include "zynqmp_pm_api_sys.h" #define IRQ_MAX 84U #define NUM_GICD_ISENABLER ((IRQ_MAX >> 5U) + 1U) diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c deleted file mode 100644 index b35859d5d..000000000 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c +++ /dev/null @@ -1,575 +0,0 @@ -/* - * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved. - * Copyright (c) 2023, Advanced Micro Devices Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * Top-level SMC handler for ZynqMP power management calls and - * IPI setup functions for communication with PMU. - */ - -#include - -#include -#if ZYNQMP_WDT_RESTART -#include -#include -#include -#include -#include -#endif - -#include -#include "pm_api_sys.h" -#include "pm_client.h" -#include "pm_defs.h" -#include "pm_ipi.h" - -/* pm_up = !0 - UP, pm_up = 0 - DOWN */ -static int32_t pm_up, ipi_irq_flag; - -#if ZYNQMP_WDT_RESTART -static spinlock_t inc_lock; -static int active_cores = 0; -#endif - -/** - * pm_context - Structure which contains data for power management - * @api_version version of PM API, must match with one on PMU side - * @payload payload array used to store received - * data from ipi buffer registers - */ -static struct { - uint32_t api_version; - uint32_t payload[PAYLOAD_ARG_CNT]; -} pm_ctx; - -#if ZYNQMP_WDT_RESTART -/** - * trigger_wdt_restart() - Trigger warm restart event to APU cores - * - * This function triggers SGI for all active APU CPUs. SGI handler then - * power down CPU and call system reset. - */ -static void trigger_wdt_restart(void) -{ - uint32_t core_count = 0; - uint32_t core_status[3]; - uint32_t target_cpu_list = 0; - int i; - - for (i = 0; i < 4; i++) { - pm_get_node_status(NODE_APU_0 + i, core_status); - if (core_status[0] == 1) { - core_count++; - target_cpu_list |= (1 << i); - } - } - - spin_lock(&inc_lock); - active_cores = core_count; - spin_unlock(&inc_lock); - - INFO("Active Cores: %d\n", active_cores); - - for (i = PLATFORM_CORE_COUNT - 1; i >= 0; i--) { - if (target_cpu_list & (1 << i)) { - /* trigger SGI to active cores */ - plat_ic_raise_el3_sgi(ARM_IRQ_SEC_SGI_7, i); - } - } -} - -/** - * ttc_fiq_handler() - TTC Handler for timer event - * @id number of the highest priority pending interrupt of the type - * that this handler was registered for - * @flags security state, bit[0] - * @handler pointer to 'cpu_context' structure of the current CPU for the - * security state specified in the 'flags' parameter - * @cookie unused - * - * Function registered as INTR_TYPE_EL3 interrupt handler - * - * When WDT event is received in PMU, PMU needs to notify master to do cleanup - * if required. PMU sets up timer and starts timer to overflow in zero time upon - * WDT event. ATF handles this timer event and takes necessary action required - * for warm restart. - * - * In presence of non-secure software layers (EL1/2) sets the interrupt - * at registered entrance in GIC and informs that PMU responsed or demands - * action. - */ -static uint64_t ttc_fiq_handler(uint32_t id, uint32_t flags, void *handle, - void *cookie) -{ - INFO("BL31: Got TTC FIQ\n"); - - plat_ic_end_of_interrupt(id); - - /* Clear TTC interrupt by reading interrupt register */ - mmio_read_32(TTC3_INTR_REGISTER_1); - - /* Disable the timer interrupts */ - mmio_write_32(TTC3_INTR_ENABLE_1, 0); - - trigger_wdt_restart(); - - return 0; -} - -/** - * zynqmp_sgi7_irq() - Handler for SGI7 IRQ - * @id number of the highest priority pending interrupt of the type - * that this handler was registered for - * @flags security state, bit[0] - * @handler pointer to 'cpu_context' structure of the current CPU for the - * security state specified in the 'flags' parameter - * @cookie unused - * - * Function registered as INTR_TYPE_EL3 interrupt handler - * - * On receiving WDT event from PMU, ATF generates SGI7 to all running CPUs. - * In response to SGI7 interrupt, each CPUs do clean up if required and last - * running CPU calls system restart. - */ -static uint64_t __unused __dead2 zynqmp_sgi7_irq(uint32_t id, uint32_t flags, - void *handle, void *cookie) -{ - int i; - uint32_t value; - - /* enter wfi and stay there */ - INFO("Entering wfi\n"); - - spin_lock(&inc_lock); - active_cores--; - - for (i = 0; i < 4; i++) { - mmio_write_32(BASE_GICD_BASE + GICD_CPENDSGIR + 4 * i, - 0xffffffff); - } - - dsb(); - - spin_unlock(&inc_lock); - - if (active_cores == 0) { - pm_mmio_read(PMU_GLOBAL_GEN_STORAGE4, &value); - value = (value & RESTART_SCOPE_MASK) >> RESTART_SCOPE_SHIFT; - pm_system_shutdown(PMF_SHUTDOWN_TYPE_RESET, value); - } - - /* enter wfi and stay there */ - while (1) - wfi(); -} - -/** - * pm_wdt_restart_setup() - Setup warm restart interrupts - * - * This function sets up handler for SGI7 and TTC interrupts - * used for warm restart. - */ -static int pm_wdt_restart_setup(void) -{ - int ret; - - /* register IRQ handler for SGI7 */ - ret = request_intr_type_el3(ARM_IRQ_SEC_SGI_7, zynqmp_sgi7_irq); - if (ret) { - WARN("BL31: registering SGI7 interrupt failed\n"); - goto err; - } - - ret = request_intr_type_el3(IRQ_TTC3_1, ttc_fiq_handler); - if (ret) - WARN("BL31: registering TTC3 interrupt failed\n"); - -err: - return ret; -} -#endif - -/** - * pm_setup() - PM service setup - * - * @return On success, the initialization function must return 0. - * Any other return value will cause the framework to ignore - * the service - * - * Initialization functions for ZynqMP power management for - * communicaton with PMU. - * - * Called from sip_svc_setup initialization function with the - * rt_svc_init signature. - */ -int32_t pm_setup(void) -{ - enum pm_ret_status err; - - pm_ipi_init(primary_proc); - - err = pm_get_api_version(&pm_ctx.api_version); - if (err != PM_RET_SUCCESS) { - ERROR("BL31: Failed to read Platform Management API version. " - "Return: %d\n", err); - return -EINVAL; - } - if (pm_ctx.api_version < PM_VERSION) { - ERROR("BL31: Platform Management API version error. Expected: " - "v%d.%d - Found: v%d.%d\n", PM_VERSION_MAJOR, - PM_VERSION_MINOR, pm_ctx.api_version >> 16, - pm_ctx.api_version & 0xFFFFU); - return -EINVAL; - } - - int32_t status = 0, ret = 0; -#if ZYNQMP_WDT_RESTART - status = pm_wdt_restart_setup(); - if (status) - WARN("BL31: warm-restart setup failed\n"); -#endif - - if (status >= 0) { - INFO("BL31: PM Service Init Complete: API v%d.%d\n", - PM_VERSION_MAJOR, PM_VERSION_MINOR); - ret = 0; - } else { - INFO("BL31: PM Service Init Failed, Error Code %d!\n", status); - ret = status; - } - - pm_up = !status; - - return ret; -} - -/** - * pm_smc_handler() - SMC handler for PM-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 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 pm_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) -{ - enum pm_ret_status ret; - uint32_t payload[PAYLOAD_ARG_CNT]; - - uint32_t pm_arg[5]; - uint32_t result[PAYLOAD_ARG_CNT] = {0}; - uint32_t api_id; - - /* Handle case where PM wasn't initialized properly */ - if (pm_up == 0) - SMC_RET1(handle, SMC_UNK); - - pm_arg[0] = (uint32_t)x1; - pm_arg[1] = (uint32_t)(x1 >> 32); - pm_arg[2] = (uint32_t)x2; - pm_arg[3] = (uint32_t)(x2 >> 32); - pm_arg[4] = (uint32_t)x3; - - api_id = smc_fid & FUNCID_NUM_MASK; - - switch (api_id) { - /* PM API Functions */ - case PM_SELF_SUSPEND: - ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_REQ_SUSPEND: - ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_REQ_WAKEUP: - { - /* Use address flag is encoded in the 1st bit of the low-word */ - uint32_t set_addr = pm_arg[1] & 0x1U; - uint64_t address = (uint64_t)pm_arg[2] << 32U; - - address |= pm_arg[1] & (~0x1U); - ret = pm_req_wakeup(pm_arg[0], set_addr, address, - pm_arg[3]); - SMC_RET1(handle, (uint64_t)ret); - } - - case PM_FORCE_POWERDOWN: - ret = pm_force_powerdown(pm_arg[0], pm_arg[1]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_ABORT_SUSPEND: - ret = pm_abort_suspend(pm_arg[0]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_SET_WAKEUP_SOURCE: - ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_SYSTEM_SHUTDOWN: - ret = pm_system_shutdown(pm_arg[0], pm_arg[1]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_REQ_NODE: - ret = pm_req_node(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_SET_REQUIREMENT: - ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_GET_API_VERSION: - if (ipi_irq_flag == 0U) { - /* - * Enable IPI IRQ - * assume the rich OS is OK to handle callback IRQs now. - * Even if we were wrong, it would not enable the IRQ in - * the GIC. - */ - pm_ipi_irq_enable(primary_proc); - ipi_irq_flag = 1U; - } - SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | - ((uint64_t)pm_ctx.api_version << 32)); - case PM_FPGA_LOAD: - ret = pm_fpga_load(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_FPGA_GET_STATUS: - { - uint32_t value = 0U; - - ret = pm_fpga_get_status(&value); - SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); - } - - case PM_SECURE_RSA_AES: - ret = pm_secure_rsaaes(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_GET_CALLBACK_DATA: - ret = pm_get_callbackdata(result, ARRAY_SIZE(result)); - if (ret != PM_RET_SUCCESS) { - result[0] = ret; - } - - SMC_RET2(handle, - (uint64_t)result[0] | ((uint64_t)result[1] << 32), - (uint64_t)result[2] | ((uint64_t)result[3] << 32)); - case PM_IOCTL: - { - uint32_t value = 0U; - - ret = pm_ioctl(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3], &value); - SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); - } - - case PM_QUERY_DATA: - { - uint32_t data[4] = { 0 }; - - pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3], data); - SMC_RET2(handle, (uint64_t)data[0] | ((uint64_t)data[1] << 32), - (uint64_t)data[2] | ((uint64_t)data[3] << 32)); - } - - case PM_CLOCK_ENABLE: - ret = pm_clock_enable(pm_arg[0]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_CLOCK_DISABLE: - ret = pm_clock_disable(pm_arg[0]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_CLOCK_GETSTATE: - { - uint32_t value = 0U; - - ret = pm_clock_getstate(pm_arg[0], &value); - SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); - } - - case PM_CLOCK_SETDIVIDER: - ret = pm_clock_setdivider(pm_arg[0], pm_arg[1]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_CLOCK_GETDIVIDER: - { - uint32_t value = 0U; - - ret = pm_clock_getdivider(pm_arg[0], &value); - SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); - } - - case PM_CLOCK_SETRATE: - ret = pm_clock_setrate(pm_arg[0], - ((uint64_t)pm_arg[2]) << 32 | pm_arg[1]); - - SMC_RET1(handle, (uint64_t)ret); - - case PM_CLOCK_GETRATE: - { - uint64_t value = 0; - - ret = pm_clock_getrate(pm_arg[0], &value); - SMC_RET2(handle, (uint64_t)ret | - (((uint64_t)value & 0xFFFFFFFFU) << 32U), - (value >> 32U) & 0xFFFFFFFFU); - - } - - case PM_CLOCK_SETPARENT: - ret = pm_clock_setparent(pm_arg[0], pm_arg[1]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_CLOCK_GETPARENT: - { - uint32_t value = 0U; - - ret = pm_clock_getparent(pm_arg[0], &value); - SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); - } - - case PM_GET_TRUSTZONE_VERSION: - SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | - ((uint64_t)ZYNQMP_TZ_VERSION << 32U)); - - case PM_SET_SUSPEND_MODE: - ret = pm_set_suspend_mode(pm_arg[0]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_SECURE_SHA: - ret = pm_sha_hash(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_SECURE_RSA: - ret = pm_rsa_core(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_SECURE_IMAGE: - { - ret = pm_secure_image(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3], &result[0]); - SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U), - result[1]); - } - - case PM_FPGA_READ: - { - uint32_t value = 0U; - - ret = pm_fpga_read(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3], - &value); - SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); - } - - case PM_SECURE_AES: - { - uint32_t value = 0U; - - ret = pm_aes_engine(pm_arg[0], pm_arg[1], &value); - SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); - } - - case PM_PLL_SET_PARAMETER: - ret = pm_pll_set_parameter(pm_arg[0], pm_arg[1], pm_arg[2]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_PLL_GET_PARAMETER: - { - uint32_t value = 0U; - - ret = pm_pll_get_parameter(pm_arg[0], pm_arg[1], &value); - SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32U)); - } - - case PM_PLL_SET_MODE: - ret = pm_pll_set_mode(pm_arg[0], pm_arg[1]); - SMC_RET1(handle, (uint64_t)ret); - - case PM_PLL_GET_MODE: - { - uint32_t mode = 0U; - - ret = pm_pll_get_mode(pm_arg[0], &mode); - SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32U)); - } - - case PM_REGISTER_ACCESS: - { - uint32_t value = 0U; - - ret = pm_register_access(pm_arg[0], pm_arg[1], pm_arg[2], - pm_arg[3], &value); - SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); - } - - case PM_EFUSE_ACCESS: - { - uint32_t value = 0U; - -#if defined(ZYNQMP_SECURE_EFUSES) - if (is_caller_non_secure(flags)) { - SMC_RET1(handle, - (((uint64_t)PM_RET_ERROR_NOT_ENABLED) << 32U) | - (uint64_t)PM_RET_ERROR_ACCESS); - } -#endif - ret = pm_efuse_access(pm_arg[0], pm_arg[1], &value); - SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); - } - - case PM_FPGA_GET_VERSION: - case PM_FPGA_GET_FEATURE_LIST: - { - uint32_t ret_payload[PAYLOAD_ARG_CNT]; - - PM_PACK_PAYLOAD5(payload, smc_fid & FUNCID_NUM_MASK, - pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); - ret = pm_ipi_send_sync(primary_proc, payload, ret_payload, 3U); - SMC_RET2(handle, (uint64_t)ret | (uint64_t)ret_payload[0] << 32U, - (uint64_t)ret_payload[1] | (uint64_t)ret_payload[2] << 32U); - } - - case PM_FEATURE_CHECK: - { - uint32_t version = 0; - uint32_t bit_mask[2] = {0}; - - ret = pm_feature_check(pm_arg[0], &version, bit_mask, - ARRAY_SIZE(bit_mask)); - SMC_RET2(handle, (uint64_t)ret | ((uint64_t)version << 32U), - (uint64_t)bit_mask[0] | ((uint64_t)bit_mask[1] << 32U)); - } - - default: - /* Send request to the PMU */ - PM_PACK_PAYLOAD6(payload, api_id, pm_arg[0], pm_arg[1], - pm_arg[2], pm_arg[3], pm_arg[4]); - ret = pm_ipi_send_sync(primary_proc, payload, result, - PAYLOAD_ARG_CNT); - SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U), - (uint64_t)result[1] | ((uint64_t)result[2] << 32U)); - } -} diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.h b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h deleted file mode 100644 index 3c3082faf..000000000 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. - * Copyright (c) 2023, Advanced Micro Devices Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef PM_SVC_MAIN_H -#define PM_SVC_MAIN_H - -#include "pm_common.h" - -int32_t pm_setup(void); -uint64_t pm_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 /* PM_SVC_MAIN_H */ diff --git a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c new file mode 100644 index 000000000..d11d6ff7a --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.c @@ -0,0 +1,1811 @@ +/* + * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2022-2023, Advanced Micro Devices Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * ZynqMP system level PM-API functions and communication with PMU via + * IPI interrupts + */ + +#include +#include + +#include "pm_api_clock.h" +#include "pm_api_ioctl.h" +#include "pm_api_pinctrl.h" +#include "pm_client.h" +#include "pm_common.h" +#include "pm_ipi.h" +#include "zynqmp_pm_api_sys.h" + +#define PM_QUERY_FEATURE_BITMASK ( \ + (1ULL << (uint64_t)PM_QID_CLOCK_GET_NAME) | \ + (1ULL << (uint64_t)PM_QID_CLOCK_GET_TOPOLOGY) | \ + (1ULL << (uint64_t)PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS) | \ + (1ULL << (uint64_t)PM_QID_CLOCK_GET_PARENTS) | \ + (1ULL << (uint64_t)PM_QID_CLOCK_GET_ATTRIBUTES) | \ + (1ULL << (uint64_t)PM_QID_PINCTRL_GET_NUM_PINS) | \ + (1ULL << (uint64_t)PM_QID_PINCTRL_GET_NUM_FUNCTIONS) | \ + (1ULL << (uint64_t)PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS) | \ + (1ULL << (uint64_t)PM_QID_PINCTRL_GET_FUNCTION_NAME) | \ + (1ULL << (uint64_t)PM_QID_PINCTRL_GET_FUNCTION_GROUPS) | \ + (1ULL << (uint64_t)PM_QID_PINCTRL_GET_PIN_GROUPS) | \ + (1ULL << (uint64_t)PM_QID_CLOCK_GET_NUM_CLOCKS) | \ + (1ULL << (uint64_t)PM_QID_CLOCK_GET_MAX_DIVISOR)) + +/** + * struct eemi_api_dependency - Dependent EEMI APIs which are implemented + * on both the ATF and firmware + * + * @id: EEMI API id or IOCTL id to be checked + * @api_id: Dependent EEMI API + */ +typedef struct __attribute__((packed)) { + uint8_t id; + uint8_t api_id; +} eemi_api_dependency; + +/* Dependent APIs for ATF to check their version from firmware */ +static const eemi_api_dependency api_dep_table[] = { + { + .id = PM_SELF_SUSPEND, + .api_id = PM_SELF_SUSPEND, + }, + { + .id = PM_REQ_WAKEUP, + .api_id = PM_REQ_WAKEUP, + }, + { + .id = PM_ABORT_SUSPEND, + .api_id = PM_ABORT_SUSPEND, + }, + { + .id = PM_SET_WAKEUP_SOURCE, + .api_id = PM_SET_WAKEUP_SOURCE, + }, + { + .id = PM_SYSTEM_SHUTDOWN, + .api_id = PM_SYSTEM_SHUTDOWN, + }, + { + .id = PM_GET_API_VERSION, + .api_id = PM_GET_API_VERSION, + }, + { + .id = PM_CLOCK_ENABLE, + .api_id = PM_PLL_SET_MODE, + }, + { + .id = PM_CLOCK_ENABLE, + .api_id = PM_CLOCK_ENABLE, + }, + { + .id = PM_CLOCK_DISABLE, + .api_id = PM_PLL_SET_MODE, + }, + { + .id = PM_CLOCK_DISABLE, + .api_id = PM_CLOCK_DISABLE, + }, + { + .id = PM_CLOCK_GETSTATE, + .api_id = PM_PLL_GET_MODE, + }, + { + .id = PM_CLOCK_GETSTATE, + .api_id = PM_CLOCK_GETSTATE, + }, + { + .id = PM_CLOCK_SETDIVIDER, + .api_id = PM_PLL_SET_PARAMETER, + }, + { + .id = PM_CLOCK_SETDIVIDER, + .api_id = PM_CLOCK_SETDIVIDER, + }, + { + .id = PM_CLOCK_GETDIVIDER, + .api_id = PM_PLL_GET_PARAMETER, + }, + { + .id = PM_CLOCK_GETDIVIDER, + .api_id = PM_CLOCK_GETDIVIDER, + }, + { + .id = PM_CLOCK_SETPARENT, + .api_id = PM_PLL_SET_PARAMETER, + }, + { + .id = PM_CLOCK_SETPARENT, + .api_id = PM_CLOCK_SETPARENT, + }, + { + .id = PM_CLOCK_GETPARENT, + .api_id = PM_PLL_GET_PARAMETER, + }, + { + .id = PM_CLOCK_GETPARENT, + .api_id = PM_CLOCK_GETPARENT, + }, + { + .id = PM_PLL_SET_PARAMETER, + .api_id = PM_PLL_SET_PARAMETER, + }, + { + .id = PM_PLL_GET_PARAMETER, + .api_id = PM_PLL_GET_PARAMETER, + }, + { + .id = PM_PLL_SET_MODE, + .api_id = PM_PLL_SET_MODE, + }, + { + .id = PM_PLL_GET_MODE, + .api_id = PM_PLL_GET_MODE, + }, + { + .id = PM_REGISTER_ACCESS, + .api_id = PM_MMIO_WRITE, + }, + { + .id = PM_REGISTER_ACCESS, + .api_id = PM_MMIO_READ, + }, + { + .id = PM_FEATURE_CHECK, + .api_id = PM_FEATURE_CHECK, + }, + { + .id = IOCTL_SET_TAPDELAY_BYPASS, + .api_id = PM_MMIO_WRITE, + }, + { + .id = IOCTL_SET_SGMII_MODE, + .api_id = PM_MMIO_WRITE, + }, + { + .id = IOCTL_SD_DLL_RESET, + .api_id = PM_MMIO_WRITE, + }, + { + .id = IOCTL_SET_SD_TAPDELAY, + .api_id = PM_MMIO_WRITE, + }, + { + .id = IOCTL_SET_SD_TAPDELAY, + .api_id = PM_MMIO_READ, + }, + { + .id = IOCTL_SET_PLL_FRAC_DATA, + .api_id = PM_PLL_SET_PARAMETER, + }, + { + .id = IOCTL_GET_PLL_FRAC_DATA, + .api_id = PM_PLL_GET_PARAMETER, + }, + { + .id = IOCTL_WRITE_GGS, + .api_id = PM_MMIO_WRITE, + }, + { + .id = IOCTL_READ_GGS, + .api_id = PM_MMIO_READ, + }, + { + .id = IOCTL_WRITE_PGGS, + .api_id = PM_MMIO_WRITE, + }, + { + .id = IOCTL_READ_PGGS, + .api_id = PM_MMIO_READ, + }, + { + .id = IOCTL_ULPI_RESET, + .api_id = PM_MMIO_WRITE, + }, + { + .id = IOCTL_SET_BOOT_HEALTH_STATUS, + .api_id = PM_MMIO_WRITE, + }, + { + .id = IOCTL_AFI, + .api_id = PM_MMIO_WRITE, + }, +}; + +/* Expected firmware API version to ATF */ +static const uint8_t atf_expected_ver_id[] = { + [PM_SELF_SUSPEND] = FW_API_BASE_VERSION, + [PM_REQ_WAKEUP] = FW_API_BASE_VERSION, + [PM_ABORT_SUSPEND] = FW_API_BASE_VERSION, + [PM_SET_WAKEUP_SOURCE] = FW_API_BASE_VERSION, + [PM_SYSTEM_SHUTDOWN] = FW_API_BASE_VERSION, + [PM_GET_API_VERSION] = FW_API_BASE_VERSION, + [PM_PLL_SET_MODE] = FW_API_BASE_VERSION, + [PM_PLL_GET_MODE] = FW_API_BASE_VERSION, + [PM_CLOCK_ENABLE] = FW_API_BASE_VERSION, + [PM_CLOCK_DISABLE] = FW_API_BASE_VERSION, + [PM_CLOCK_GETSTATE] = FW_API_BASE_VERSION, + [PM_PLL_SET_PARAMETER] = FW_API_BASE_VERSION, + [PM_PLL_GET_PARAMETER] = FW_API_BASE_VERSION, + [PM_CLOCK_SETDIVIDER] = FW_API_BASE_VERSION, + [PM_CLOCK_GETDIVIDER] = FW_API_BASE_VERSION, + [PM_CLOCK_SETPARENT] = FW_API_BASE_VERSION, + [PM_CLOCK_GETPARENT] = FW_API_BASE_VERSION, + [PM_MMIO_WRITE] = FW_API_BASE_VERSION, + [PM_MMIO_READ] = FW_API_BASE_VERSION, + [PM_FEATURE_CHECK] = FW_API_VERSION_2, +}; + +/* default shutdown/reboot scope is system(2) */ +static uint32_t pm_shutdown_scope = PMF_SHUTDOWN_SUBTYPE_SYSTEM; + +/** + * pm_get_shutdown_scope() - Get the currently set shutdown scope + * + * @return Shutdown scope value + */ +uint32_t pm_get_shutdown_scope(void) +{ + return pm_shutdown_scope; +} + +/** + * pm_self_suspend() - PM call for processor to suspend itself + * @nid Node id of the processor or subsystem + * @latency Requested maximum wakeup latency (not supported) + * @state Requested state + * @address Resume address + * + * This is a blocking call, it will return only once PMU has responded. + * On a wakeup, resume address will be automatically set by PMU. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_self_suspend(enum pm_node_id nid, + uint32_t latency, + uint32_t state, + uintptr_t address) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + uint32_t cpuid = plat_my_core_pos(); + const struct pm_proc *proc = pm_get_proc(cpuid); + + /* + * Do client specific suspend operations + * (e.g. set powerdown request bit) + */ + pm_client_suspend(proc, state); + /* Send request to the PMU */ + PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency, + state, address, (address >> 32)); + return pm_ipi_send_sync(proc, payload, NULL, 0); +} + +/** + * pm_req_suspend() - PM call to request for another PU or subsystem to + * be suspended gracefully. + * @target Node id of the targeted PU or subsystem + * @ack Flag to specify whether acknowledge is requested + * @latency Requested wakeup latency (not supported) + * @state Requested state (not supported) + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_req_suspend(enum pm_node_id target, + enum pm_request_ack ack, + uint32_t latency, uint32_t state) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD5(payload, PM_REQ_SUSPEND, target, ack, latency, state); + if (ack == REQ_ACK_BLOCKING) { + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); + } else { + return pm_ipi_send(primary_proc, payload); + } +} + +/** + * pm_req_wakeup() - PM call for processor to wake up selected processor + * or subsystem + * @target Node id of the processor or subsystem to wake up + * @ack Flag to specify whether acknowledge requested + * @set_address Resume address presence indicator + * 1 resume address specified, 0 otherwise + * @address Resume address + * + * This API function is either used to power up another APU core for SMP + * (by PSCI) or to power up an entirely different PU or subsystem, such + * as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be + * automatically set by PMU. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_req_wakeup(enum pm_node_id target, + uint32_t set_address, + uintptr_t address, + enum pm_request_ack ack) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + uint64_t encoded_address; + + + /* encode set Address into 1st bit of address */ + encoded_address = address; + encoded_address |= !!set_address; + + /* Send request to the PMU to perform the wake of the PU */ + PM_PACK_PAYLOAD5(payload, PM_REQ_WAKEUP, target, encoded_address, + encoded_address >> 32, ack); + + if (ack == REQ_ACK_BLOCKING) { + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); + } else { + return pm_ipi_send(primary_proc, payload); + } +} + +/** + * pm_force_powerdown() - PM call to request for another PU or subsystem to + * be powered down forcefully + * @target Node id of the targeted PU or subsystem + * @ack Flag to specify whether acknowledge is requested + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_force_powerdown(enum pm_node_id target, + enum pm_request_ack ack) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD3(payload, PM_FORCE_POWERDOWN, target, ack); + + if (ack == REQ_ACK_BLOCKING) { + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); + } else { + return pm_ipi_send(primary_proc, payload); + } +} + +/** + * pm_abort_suspend() - PM call to announce that a prior suspend request + * is to be aborted. + * @reason Reason for the abort + * + * Calling PU expects the PMU to abort the initiated suspend procedure. + * This is a non-blocking call without any acknowledge. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* + * Do client specific abort suspend operations + * (e.g. enable interrupts and clear powerdown request bit) + */ + pm_client_abort_suspend(); + /* Send request to the PMU */ + /* TODO: allow passing the node ID of the affected CPU */ + PM_PACK_PAYLOAD3(payload, PM_ABORT_SUSPEND, reason, + primary_proc->node_id); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended + * @target Node id of the targeted PU or subsystem + * @wkup_node Node id of the wakeup peripheral + * @enable Enable or disable the specified peripheral as wake source + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target, + enum pm_node_id wkup_node, + uint32_t enable) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD4(payload, PM_SET_WAKEUP_SOURCE, target, wkup_node, + enable); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_system_shutdown() - PM call to request a system shutdown or restart + * @type Shutdown or restart? 0=shutdown, 1=restart, 2=setscope + * @subtype Scope: 0=APU-subsystem, 1=PS, 2=system + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + if (type == PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY) { + /* Setting scope for subsequent PSCI reboot or shutdown */ + pm_shutdown_scope = subtype; + return PM_RET_SUCCESS; + } + + PM_PACK_PAYLOAD3(payload, PM_SYSTEM_SHUTDOWN, type, subtype); + return pm_ipi_send_non_blocking(primary_proc, payload); +} + +/* APIs for managing PM slaves: */ + +/** + * pm_req_node() - PM call to request a node with specific capabilities + * @nid Node id of the slave + * @capabilities Requested capabilities of the slave + * @qos Quality of service (not supported) + * @ack Flag to specify whether acknowledge is requested + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_req_node(enum pm_node_id nid, + uint32_t capabilities, + uint32_t qos, + enum pm_request_ack ack) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD5(payload, PM_REQ_NODE, nid, capabilities, qos, ack); + + if (ack == REQ_ACK_BLOCKING) { + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); + } else { + return pm_ipi_send(primary_proc, payload); + } +} + +/** + * pm_set_requirement() - PM call to set requirement for PM slaves + * @nid Node id of the slave + * @capabilities Requested capabilities of the slave + * @qos Quality of service (not supported) + * @ack Flag to specify whether acknowledge is requested + * + * This API function is to be used for slaves a PU already has requested + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_set_requirement(enum pm_node_id nid, + uint32_t capabilities, + uint32_t qos, + enum pm_request_ack ack) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD5(payload, PM_SET_REQUIREMENT, nid, capabilities, qos, + ack); + + if (ack == REQ_ACK_BLOCKING) { + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); + } else { + return pm_ipi_send(primary_proc, payload); + } +} + +/* Miscellaneous API functions */ + +/** + * pm_get_api_version() - Get version number of PMU PM firmware + * @version Returns 32-bit version number of PMU Power Management Firmware + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_get_api_version(uint32_t *version) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD1(payload, PM_GET_API_VERSION); + return pm_ipi_send_sync(primary_proc, payload, version, 1); +} + +/** + * pm_get_node_status() - PM call to request a node's current status + * @nid Node id + * @ret_buff Buffer for the return values: + * [0] - Current power state of the node + * [1] - Current requirements for the node (slave nodes only) + * [2] - Current usage status for the node (slave nodes only) + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_get_node_status(enum pm_node_id nid, + uint32_t *ret_buff) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD2(payload, PM_GET_NODE_STATUS, nid); + return pm_ipi_send_sync(primary_proc, payload, ret_buff, 3); +} + +/** + * pm_mmio_write() - Perform write to protected mmio + * @address Address to write to + * @mask Mask to apply + * @value Value to write + * + * This function provides access to PM-related control registers + * that may not be directly accessible by a particular PU. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_mmio_write(uintptr_t address, + uint32_t mask, + uint32_t value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD4(payload, PM_MMIO_WRITE, address, mask, value); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_mmio_read() - Read value from protected mmio + * @address Address to write to + * @value Value to write + * + * This function provides access to PM-related control registers + * that may not be directly accessible by a particular PU. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_mmio_read(uintptr_t address, uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD2(payload, PM_MMIO_READ, address); + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} + +/** + * pm_fpga_load() - Load the bitstream into the PL. + * + * This function provides access to the xilfpga library to load + * the Bit-stream into PL. + * + * address_low: lower 32-bit Linear memory space address + * + * address_high: higher 32-bit Linear memory space address + * + * size: Number of 32bit words + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_fpga_load(uint32_t address_low, + uint32_t address_high, + uint32_t size, + uint32_t flags) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD5(payload, PM_FPGA_LOAD, address_high, address_low, + size, flags); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_fpga_get_status() - Read value from fpga status register + * @value Value to read + * + * This function provides access to the xilfpga library to get + * the fpga status + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_fpga_get_status(uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD1(payload, PM_FPGA_GET_STATUS); + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} + +/** + * pm_get_chipid() - Read silicon ID registers + * @value Buffer for return values. Must be large enough + * to hold 8 bytes. + * + * @return Returns silicon ID registers + */ +enum pm_ret_status pm_get_chipid(uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD1(payload, PM_GET_CHIPID); + return pm_ipi_send_sync(primary_proc, payload, value, 2); +} + +/** + * pm_secure_rsaaes() - Load the secure images. + * + * This function provides access to the xilsecure library to load + * the authenticated, encrypted, and authenicated/encrypted images. + * + * address_low: lower 32-bit Linear memory space address + * + * address_high: higher 32-bit Linear memory space address + * + * size: Number of 32bit words + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_secure_rsaaes(uint32_t address_low, + uint32_t address_high, + uint32_t size, + uint32_t flags) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD5(payload, PM_SECURE_RSA_AES, address_high, address_low, + size, flags); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_aes_engine() - Aes data blob encryption/decryption + * This function provides access to the xilsecure library to + * encrypt/decrypt data blobs. + * + * address_low: lower 32-bit address of the AesParams structure + * + * address_high: higher 32-bit address of the AesParams structure + * + * value: Returned output value + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_aes_engine(uint32_t address_high, + uint32_t address_low, + uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD3(payload, PM_SECURE_AES, address_high, address_low); + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} + +/** + * pm_get_callbackdata() - Read from IPI response buffer + * @data - array of PAYLOAD_ARG_CNT elements + * + * Read value from ipi buffer response buffer. + * @return Returns status, either success or error + */ +enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count) +{ + enum pm_ret_status ret = PM_RET_SUCCESS; + /* Return if interrupt is not from PMU */ + if (!pm_ipi_irq_status(primary_proc)) { + return ret; + } + + ret = pm_ipi_buff_read_callb(data, count); + pm_ipi_irq_clear(primary_proc); + return ret; +} + +/** + * pm_ioctl() - PM IOCTL API for device control and configs + * @node_id Node ID of the device + * @ioctl_id ID of the requested IOCTL + * @arg1 Argument 1 to requested IOCTL call + * @arg2 Argument 2 to requested IOCTL call + * @out Returned output value + * + * This function calls IOCTL to firmware for device control and configuration. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_ioctl(enum pm_node_id nid, + uint32_t ioctl_id, + uint32_t arg1, + uint32_t arg2, + uint32_t *value) +{ + return pm_api_ioctl(nid, ioctl_id, arg1, arg2, value); +} + +/** + * fw_api_version() - Returns API version implemented in firmware + * @api_id API ID to check + * @version Returned supported API version + * @len Number of words to be returned + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status fw_api_version(uint32_t id, uint32_t *version, + uint32_t len) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD2(payload, PM_FEATURE_CHECK, id); + return pm_ipi_send_sync(primary_proc, payload, version, len); +} + +/** + * check_api_dependency() - API to check dependent EEMI API version + * @id EEMI API ID to check + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status check_api_dependency(uint8_t id) +{ + uint8_t i; + uint32_t version; + int ret; + + for (i = 0U; i < ARRAY_SIZE(api_dep_table); i++) { + if (api_dep_table[i].id == id) { + if (api_dep_table[i].api_id == 0U) { + break; + } + + ret = fw_api_version(api_dep_table[i].api_id, + &version, 1); + if (ret != PM_RET_SUCCESS) { + return ret; + } + + /* Check if fw version matches ATF expected version */ + if (version != atf_expected_ver_id[api_dep_table[i].api_id]) { + return PM_RET_ERROR_NOTSUPPORTED; + } + } + } + + return PM_RET_SUCCESS; +} + +/** + * feature_check_atf() - These are API's completely implemented in ATF + * @api_id API ID to check + * @version Returned supported API version + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status feature_check_atf(uint32_t api_id, uint32_t *version, + uint32_t *bit_mask) +{ + switch (api_id) { + case PM_QUERY_DATA: + *version = TFA_API_QUERY_DATA_VERSION; + bit_mask[0] = (uint32_t)(PM_QUERY_FEATURE_BITMASK); + bit_mask[1] = (uint32_t)(PM_QUERY_FEATURE_BITMASK >> 32); + return PM_RET_SUCCESS; + case PM_GET_CALLBACK_DATA: + case PM_GET_TRUSTZONE_VERSION: + case PM_SET_SUSPEND_MODE: + *version = ATF_API_BASE_VERSION; + return PM_RET_SUCCESS; + default: + return PM_RET_ERROR_NO_FEATURE; + } +} + +/** + * get_atf_version_for_partial_apis() - Return ATF version for partially + * implemented APIs + * @api_id API ID to check + * @version Returned supported API version + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status get_atf_version_for_partial_apis(uint32_t api_id, + uint32_t *version) +{ + switch (api_id) { + case PM_SELF_SUSPEND: + case PM_REQ_WAKEUP: + case PM_ABORT_SUSPEND: + case PM_SET_WAKEUP_SOURCE: + case PM_SYSTEM_SHUTDOWN: + case PM_GET_API_VERSION: + case PM_CLOCK_ENABLE: + case PM_CLOCK_DISABLE: + case PM_CLOCK_GETSTATE: + case PM_CLOCK_SETDIVIDER: + case PM_CLOCK_GETDIVIDER: + case PM_CLOCK_SETPARENT: + case PM_CLOCK_GETPARENT: + case PM_PLL_SET_PARAMETER: + case PM_PLL_GET_PARAMETER: + case PM_PLL_SET_MODE: + case PM_PLL_GET_MODE: + case PM_REGISTER_ACCESS: + *version = ATF_API_BASE_VERSION; + return PM_RET_SUCCESS; + case PM_FEATURE_CHECK: + *version = FW_API_VERSION_2; + return PM_RET_SUCCESS; + default: + return PM_RET_ERROR_ARGS; + } +} + +/** + * feature_check_partial() - These are API's partially implemented in + * ATF and firmware both + * @api_id API ID to check + * @version Returned supported API version + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status feature_check_partial(uint32_t api_id, + uint32_t *version) +{ + uint32_t status; + + switch (api_id) { + case PM_SELF_SUSPEND: + case PM_REQ_WAKEUP: + case PM_ABORT_SUSPEND: + case PM_SET_WAKEUP_SOURCE: + case PM_SYSTEM_SHUTDOWN: + case PM_GET_API_VERSION: + case PM_CLOCK_ENABLE: + case PM_CLOCK_DISABLE: + case PM_CLOCK_GETSTATE: + case PM_CLOCK_SETDIVIDER: + case PM_CLOCK_GETDIVIDER: + case PM_CLOCK_SETPARENT: + case PM_CLOCK_GETPARENT: + case PM_PLL_SET_PARAMETER: + case PM_PLL_GET_PARAMETER: + case PM_PLL_SET_MODE: + case PM_PLL_GET_MODE: + case PM_REGISTER_ACCESS: + case PM_FEATURE_CHECK: + status = check_api_dependency(api_id); + if (status != PM_RET_SUCCESS) { + return status; + } + return get_atf_version_for_partial_apis(api_id, version); + default: + return PM_RET_ERROR_NO_FEATURE; + } +} + +/** + * pm_feature_check() - Returns the supported API version if supported + * @api_id API ID to check + * @version Returned supported API version + * @bit_mask Returned supported IOCTL id version + * @len Number of bytes to be returned in bit_mask variable + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *version, + uint32_t *bit_mask, uint8_t len) +{ + uint32_t ret_payload[PAYLOAD_ARG_CNT] = {0U}; + uint32_t status; + + /* Get API version implemented in ATF */ + status = feature_check_atf(api_id, version, bit_mask); + if (status != PM_RET_ERROR_NO_FEATURE) { + return status; + } + + /* Get API version implemented by firmware and ATF both */ + status = feature_check_partial(api_id, version); + if (status != PM_RET_ERROR_NO_FEATURE) { + return status; + } + + /* Get API version implemented by firmware */ + status = fw_api_version(api_id, ret_payload, 3); + /* IOCTL call may return failure whose ID is not implemented in + * firmware but implemented in ATF + */ + if ((api_id != PM_IOCTL) && (status != PM_RET_SUCCESS)) { + return status; + } + + *version = ret_payload[0]; + + /* Update IOCTL bit mask which are implemented in ATF */ + if ((api_id == PM_IOCTL) || (api_id == PM_GET_OP_CHARACTERISTIC)) { + if (len < 2) { + return PM_RET_ERROR_ARGS; + } + bit_mask[0] = ret_payload[1]; + bit_mask[1] = ret_payload[2]; + if (api_id == PM_IOCTL) { + /* Get IOCTL's implemented by ATF */ + status = atf_ioctl_bitmask(bit_mask); + } + } else { + /* Requires for MISRA */ + } + + return status; +} + +/** + * pm_clock_get_max_divisor - PM call to get max divisor + * @clock_id Clock ID + * @div_type Divisor ID (TYPE_DIV1 or TYPE_DIV2) + * @max_div Maximum supported divisor + * + * This function is used by master to get maximum supported value. + * + * Return: Returns status, either success or error+reason. + */ +static enum pm_ret_status pm_clock_get_max_divisor(uint32_t clock_id, + uint8_t div_type, + uint32_t *max_div) +{ + return pm_api_clock_get_max_divisor(clock_id, div_type, max_div); +} + +/** + * pm_clock_get_num_clocks - PM call to request number of clocks + * @nclockss: Number of clocks + * + * This function is used by master to get number of clocks. + * + * Return: Returns status, either success or error+reason. + */ +static enum pm_ret_status pm_clock_get_num_clocks(uint32_t *nclocks) +{ + return pm_api_clock_get_num_clocks(nclocks); +} + +/** + * pm_clock_get_name() - PM call to request a clock's name + * @clock_id Clock ID + * @name Name of clock (max 16 bytes) + * + * This function is used by master to get nmae of clock specified + * by given clock ID. + */ +static void pm_clock_get_name(uint32_t clock_id, char *name) +{ + pm_api_clock_get_name(clock_id, name); +} + +/** + * pm_clock_get_topology() - PM call to request a clock's topology + * @clock_id Clock ID + * @index Topology index for next toplogy node + * @topology Buffer to store nodes in topology and flags + * + * This function is used by master to get topology information for the + * clock specified by given clock ID. Each response would return 3 + * topology nodes. To get next nodes, caller needs to call this API with + * index of next node. Index starts from 0. + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_clock_get_topology(uint32_t clock_id, + uint32_t index, + uint32_t *topology) +{ + return pm_api_clock_get_topology(clock_id, index, topology); +} + +/** + * pm_clock_get_fixedfactor_params() - PM call to request a clock's fixed factor + * parameters for fixed clock + * @clock_id Clock ID + * @mul Multiplication value + * @div Divisor value + * + * This function is used by master to get fixed factor parameers for the + * fixed clock. This API is application only for the fixed clock. + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_clock_get_fixedfactor_params(uint32_t clock_id, + uint32_t *mul, + uint32_t *div) +{ + return pm_api_clock_get_fixedfactor_params(clock_id, mul, div); +} + +/** + * pm_clock_get_parents() - PM call to request a clock's first 3 parents + * @clock_id Clock ID + * @index Index of next parent + * @parents Parents of the given clock + * + * This function is used by master to get clock's parents information. + * This API will return 3 parents with a single response. To get other + * parents, master should call same API in loop with new parent index + * till error is returned. + * + * E.g First call should have index 0 which will return parents 0, 1 and + * 2. Next call, index should be 3 which will return parent 3,4 and 5 and + * so on. + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_clock_get_parents(uint32_t clock_id, + uint32_t index, + uint32_t *parents) +{ + return pm_api_clock_get_parents(clock_id, index, parents); +} + +/** + * pm_clock_get_attributes() - PM call to request a clock's attributes + * @clock_id Clock ID + * @attr Clock attributes + * + * This function is used by master to get clock's attributes + * (e.g. valid, clock type, etc). + * + * @return Returns status, either success or error+reason + */ +static enum pm_ret_status pm_clock_get_attributes(uint32_t clock_id, + uint32_t *attr) +{ + return pm_api_clock_get_attributes(clock_id, attr); +} + +/** + * pm_clock_gate() - Configure clock gate + * @clock_id Id of the clock to be configured + * @enable Flag 0=disable (gate the clock), !0=enable (activate the clock) + * + * @return Error if an argument is not valid or status as returned by the + * PM controller (PMU) + */ +static enum pm_ret_status pm_clock_gate(uint32_t clock_id, + uint8_t enable) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + enum pm_ret_status status; + enum pm_api_id api_id; + + /* Check if clock ID is valid and return an error if it is not */ + status = pm_clock_id_is_valid(clock_id); + if (status != PM_RET_SUCCESS) { + return status; + } + + if (enable) { + api_id = PM_CLOCK_ENABLE; + } else { + api_id = PM_CLOCK_DISABLE; + } + + /* Send request to the PMU */ + PM_PACK_PAYLOAD2(payload, api_id, clock_id); + status = pm_ipi_send_sync(primary_proc, payload, NULL, 0); + + /* If action fails due to the lack of permissions filter the error */ + if (status == PM_RET_ERROR_ACCESS) { + status = PM_RET_SUCCESS; + } + + return status; +} + +/** + * pm_clock_enable() - Enable the clock for given id + * @clock_id: Id of the clock to be enabled + * + * This function is used by master to enable the clock + * including peripherals and PLL clocks. + * + * @return: Error if an argument is not valid or status as returned by the + * pm_clock_gate + */ +enum pm_ret_status pm_clock_enable(uint32_t clock_id) +{ + struct pm_pll *pll; + + /* First try to handle it as a PLL */ + pll = pm_clock_get_pll(clock_id); + if (pll) { + return pm_clock_pll_enable(pll); + } + + /* It's an on-chip clock, PMU should configure clock's gate */ + return pm_clock_gate(clock_id, 1); +} + +/** + * pm_clock_disable - Disable the clock for given id + * @clock_id: Id of the clock to be disable + * + * This function is used by master to disable the clock + * including peripherals and PLL clocks. + * + * @return: Error if an argument is not valid or status as returned by the + * pm_clock_gate + */ +enum pm_ret_status pm_clock_disable(uint32_t clock_id) +{ + struct pm_pll *pll; + + /* First try to handle it as a PLL */ + pll = pm_clock_get_pll(clock_id); + if (pll) { + return pm_clock_pll_disable(pll); + } + + /* It's an on-chip clock, PMU should configure clock's gate */ + return pm_clock_gate(clock_id, 0); +} + +/** + * pm_clock_getstate - Get the clock state for given id + * @clock_id: Id of the clock to be queried + * @state: 1/0 (Enabled/Disabled) + * + * This function is used by master to get the state of clock + * including peripherals and PLL clocks. + * + * Return: Returns status, either success or error+reason. + */ +enum pm_ret_status pm_clock_getstate(uint32_t clock_id, + uint32_t *state) +{ + struct pm_pll *pll; + uint32_t payload[PAYLOAD_ARG_CNT]; + enum pm_ret_status status; + + /* First try to handle it as a PLL */ + pll = pm_clock_get_pll(clock_id); + if (pll) + return pm_clock_pll_get_state(pll, state); + + /* Check if clock ID is a valid on-chip clock */ + status = pm_clock_id_is_valid(clock_id); + if (status != PM_RET_SUCCESS) { + return status; + } + + /* Send request to the PMU */ + PM_PACK_PAYLOAD2(payload, PM_CLOCK_GETSTATE, clock_id); + return pm_ipi_send_sync(primary_proc, payload, state, 1); +} + +/** + * pm_clock_setdivider - Set the clock divider for given id + * @clock_id: Id of the clock + * @divider: divider value + * + * This function is used by master to set divider for any clock + * to achieve desired rate. + * + * Return: Returns status, either success or error+reason. + */ +enum pm_ret_status pm_clock_setdivider(uint32_t clock_id, + uint32_t divider) +{ + enum pm_ret_status status; + enum pm_node_id nid; + enum pm_clock_div_id div_id; + uint32_t payload[PAYLOAD_ARG_CNT]; + const uint32_t div0 = 0xFFFF0000; + const uint32_t div1 = 0x0000FFFF; + uint32_t val; + + /* Get PLL node ID using PLL clock ID */ + status = pm_clock_get_pll_node_id(clock_id, &nid); + if (status == PM_RET_SUCCESS) { + return pm_pll_set_parameter(nid, PM_PLL_PARAM_FBDIV, divider); + } + + /* Check if clock ID is a valid on-chip clock */ + status = pm_clock_id_is_valid(clock_id); + if (status != PM_RET_SUCCESS) { + return status; + } + + if (div0 == (divider & div0)) { + div_id = PM_CLOCK_DIV0_ID; + val = divider & ~div0; + } else if (div1 == (divider & div1)) { + div_id = PM_CLOCK_DIV1_ID; + val = (divider & ~div1) >> 16; + } else { + return PM_RET_ERROR_ARGS; + } + + /* Send request to the PMU */ + PM_PACK_PAYLOAD4(payload, PM_CLOCK_SETDIVIDER, clock_id, div_id, val); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_clock_getdivider - Get the clock divider for given id + * @clock_id: Id of the clock + * @divider: divider value + * + * This function is used by master to get divider values + * for any clock. + * + * Return: Returns status, either success or error+reason. + */ +enum pm_ret_status pm_clock_getdivider(uint32_t clock_id, + uint32_t *divider) +{ + enum pm_ret_status status; + enum pm_node_id nid; + uint32_t payload[PAYLOAD_ARG_CNT]; + uint32_t val; + + /* Get PLL node ID using PLL clock ID */ + status = pm_clock_get_pll_node_id(clock_id, &nid); + if (status == PM_RET_SUCCESS) { + return pm_pll_get_parameter(nid, PM_PLL_PARAM_FBDIV, divider); + } + + /* Check if clock ID is a valid on-chip clock */ + status = pm_clock_id_is_valid(clock_id); + if (status != PM_RET_SUCCESS) { + return status; + } + + if (pm_clock_has_div(clock_id, PM_CLOCK_DIV0_ID)) { + /* Send request to the PMU to get div0 */ + PM_PACK_PAYLOAD3(payload, PM_CLOCK_GETDIVIDER, clock_id, + PM_CLOCK_DIV0_ID); + status = pm_ipi_send_sync(primary_proc, payload, &val, 1); + if (status != PM_RET_SUCCESS) { + return status; + } + *divider = val; + } + + if (pm_clock_has_div(clock_id, PM_CLOCK_DIV1_ID)) { + /* Send request to the PMU to get div1 */ + PM_PACK_PAYLOAD3(payload, PM_CLOCK_GETDIVIDER, clock_id, + PM_CLOCK_DIV1_ID); + status = pm_ipi_send_sync(primary_proc, payload, &val, 1); + if (status != PM_RET_SUCCESS) { + return status; + } + *divider |= val << 16; + } + + return status; +} + +/** + * pm_clock_setrate - Set the clock rate for given id + * @clock_id: Id of the clock + * @rate: rate value in hz + * + * This function is used by master to set rate for any clock. + * + * Return: Returns status, either success or error+reason. + */ +enum pm_ret_status pm_clock_setrate(uint32_t clock_id, + uint64_t rate) +{ + return PM_RET_ERROR_NOTSUPPORTED; +} + +/** + * pm_clock_getrate - Get the clock rate for given id + * @clock_id: Id of the clock + * @rate: rate value in hz + * + * This function is used by master to get rate + * for any clock. + * + * Return: Returns status, either success or error+reason. + */ +enum pm_ret_status pm_clock_getrate(uint32_t clock_id, + uint64_t *rate) +{ + return PM_RET_ERROR_NOTSUPPORTED; +} + +/** + * pm_clock_setparent - Set the clock parent for given id + * @clock_id: Id of the clock + * @parent_index: Index of the parent clock into clock's parents array + * + * This function is used by master to set parent for any clock. + * + * Return: Returns status, either success or error+reason. + */ +enum pm_ret_status pm_clock_setparent(uint32_t clock_id, + uint32_t parent_index) +{ + struct pm_pll *pll; + uint32_t payload[PAYLOAD_ARG_CNT]; + enum pm_ret_status status; + + /* First try to handle it as a PLL */ + pll = pm_clock_get_pll_by_related_clk(clock_id); + if (pll) { + return pm_clock_pll_set_parent(pll, clock_id, parent_index); + } + + /* Check if clock ID is a valid on-chip clock */ + status = pm_clock_id_is_valid(clock_id); + if (status != PM_RET_SUCCESS) { + return status; + } + + /* Send request to the PMU */ + PM_PACK_PAYLOAD3(payload, PM_CLOCK_SETPARENT, clock_id, parent_index); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_clock_getparent - Get the clock parent for given id + * @clock_id: Id of the clock + * @parent_index: parent index + * + * This function is used by master to get parent index + * for any clock. + * + * Return: Returns status, either success or error+reason. + */ +enum pm_ret_status pm_clock_getparent(uint32_t clock_id, + uint32_t *parent_index) +{ + struct pm_pll *pll; + uint32_t payload[PAYLOAD_ARG_CNT]; + enum pm_ret_status status; + + /* First try to handle it as a PLL */ + pll = pm_clock_get_pll_by_related_clk(clock_id); + if (pll) { + return pm_clock_pll_get_parent(pll, clock_id, parent_index); + } + + /* Check if clock ID is a valid on-chip clock */ + status = pm_clock_id_is_valid(clock_id); + if (status != PM_RET_SUCCESS) { + return status; + } + + /* Send request to the PMU */ + PM_PACK_PAYLOAD2(payload, PM_CLOCK_GETPARENT, clock_id); + return pm_ipi_send_sync(primary_proc, payload, parent_index, 1); +} + +/** + * pm_pinctrl_get_num_pins - PM call to request number of pins + * @npins: Number of pins + * + * This function is used by master to get number of pins + * + * Return: Returns status, either success or error+reason. + */ +static enum pm_ret_status pm_pinctrl_get_num_pins(uint32_t *npins) +{ + return pm_api_pinctrl_get_num_pins(npins); +} + +/** + * pm_pinctrl_get_num_functions - PM call to request number of functions + * @nfuncs: Number of functions + * + * This function is used by master to get number of functions + * + * Return: Returns status, either success or error+reason. + */ +static enum pm_ret_status pm_pinctrl_get_num_functions(uint32_t *nfuncs) +{ + return pm_api_pinctrl_get_num_functions(nfuncs); +} + +/** + * pm_pinctrl_get_num_function_groups - PM call to request number of + * function groups + * @fid: Id of function + * @ngroups: Number of function groups + * + * This function is used by master to get number of function groups specified + * by given function Id + * + * Return: Returns status, either success or error+reason. + */ +static enum pm_ret_status pm_pinctrl_get_num_function_groups(uint32_t fid, + uint32_t *ngroups) +{ + return pm_api_pinctrl_get_num_func_groups(fid, ngroups); +} + +/** + * pm_pinctrl_get_function_name - PM call to request function name + * @fid: Id of function + * @name: Name of function + * + * This function is used by master to get name of function specified + * by given function Id + */ +static void pm_pinctrl_get_function_name(uint32_t fid, char *name) +{ + pm_api_pinctrl_get_function_name(fid, name); +} + +/** + * pm_pinctrl_get_function_groups - PM call to request function groups + * @fid: Id of function + * @index: Index of next function groups + * @groups: Function groups + * + * This function is used by master to get function groups specified + * by given function Id. This API will return 6 function groups with + * a single response. To get other function groups, master should call + * same API in loop with new function groups index till error is returned. + * + * E.g First call should have index 0 which will return function groups + * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return + * function groups 6, 7, 8, 9, 10 and 11 and so on. + * + * Return: Returns status, either success or error+reason. + */ +static enum pm_ret_status pm_pinctrl_get_function_groups(uint32_t fid, + uint32_t index, + uint16_t *groups) +{ + return pm_api_pinctrl_get_function_groups(fid, index, groups); +} + +/** + * pm_pinctrl_get_pin_groups - PM call to request pin groups + * @pin_id: Id of pin + * @index: Index of next pin groups + * @groups: pin groups + * + * This function is used by master to get pin groups specified + * by given pin Id. This API will return 6 pin groups with + * a single response. To get other pin groups, master should call + * same API in loop with new pin groups index till error is returned. + * + * E.g First call should have index 0 which will return pin groups + * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return + * pin groups 6, 7, 8, 9, 10 and 11 and so on. + * + * Return: Returns status, either success or error+reason. + */ +static enum pm_ret_status pm_pinctrl_get_pin_groups(uint32_t pin_id, + uint32_t index, + uint16_t *groups) +{ + return pm_api_pinctrl_get_pin_groups(pin_id, index, groups); +} + +/** + * pm_query_data() - PM API for querying firmware data + * @arg1 Argument 1 to requested IOCTL call + * @arg2 Argument 2 to requested IOCTL call + * @arg3 Argument 3 to requested IOCTL call + * @arg4 Argument 4 to requested IOCTL call + * @data Returned output data + * + * This function returns requested data. + */ +void pm_query_data(enum pm_query_id qid, uint32_t arg1, uint32_t arg2, + uint32_t arg3, uint32_t *data) +{ + switch (qid) { + case PM_QID_CLOCK_GET_NAME: + pm_clock_get_name(arg1, (char *)data); + break; + case PM_QID_CLOCK_GET_TOPOLOGY: + data[0] = pm_clock_get_topology(arg1, arg2, &data[1]); + break; + case PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS: + data[0] = pm_clock_get_fixedfactor_params(arg1, &data[1], + &data[2]); + break; + case PM_QID_CLOCK_GET_PARENTS: + data[0] = pm_clock_get_parents(arg1, arg2, &data[1]); + break; + case PM_QID_CLOCK_GET_ATTRIBUTES: + data[0] = pm_clock_get_attributes(arg1, &data[1]); + break; + case PM_QID_PINCTRL_GET_NUM_PINS: + data[0] = pm_pinctrl_get_num_pins(&data[1]); + break; + case PM_QID_PINCTRL_GET_NUM_FUNCTIONS: + data[0] = pm_pinctrl_get_num_functions(&data[1]); + break; + case PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS: + data[0] = pm_pinctrl_get_num_function_groups(arg1, &data[1]); + break; + case PM_QID_PINCTRL_GET_FUNCTION_NAME: + pm_pinctrl_get_function_name(arg1, (char *)data); + break; + case PM_QID_PINCTRL_GET_FUNCTION_GROUPS: + data[0] = pm_pinctrl_get_function_groups(arg1, arg2, + (uint16_t *)&data[1]); + break; + case PM_QID_PINCTRL_GET_PIN_GROUPS: + data[0] = pm_pinctrl_get_pin_groups(arg1, arg2, + (uint16_t *)&data[1]); + break; + case PM_QID_CLOCK_GET_NUM_CLOCKS: + data[0] = pm_clock_get_num_clocks(&data[1]); + break; + + case PM_QID_CLOCK_GET_MAX_DIVISOR: + data[0] = pm_clock_get_max_divisor(arg1, arg2, &data[1]); + break; + default: + data[0] = PM_RET_ERROR_ARGS; + WARN("Unimplemented query service call: 0x%x\n", qid); + break; + } +} + +enum pm_ret_status pm_sha_hash(uint32_t address_high, + uint32_t address_low, + uint32_t size, + uint32_t flags) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD5(payload, PM_SECURE_SHA, address_high, address_low, + size, flags); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +enum pm_ret_status pm_rsa_core(uint32_t address_high, + uint32_t address_low, + uint32_t size, + uint32_t flags) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD5(payload, PM_SECURE_RSA, address_high, address_low, + size, flags); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +enum pm_ret_status pm_secure_image(uint32_t address_low, + uint32_t address_high, + uint32_t key_lo, + uint32_t key_hi, + uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD5(payload, PM_SECURE_IMAGE, address_high, address_low, + key_hi, key_lo); + return pm_ipi_send_sync(primary_proc, payload, value, 2); +} + +/** + * pm_fpga_read - Perform the fpga configuration readback + * + * @reg_numframes: Configuration register offset (or) Number of frames to read + * @address_low: lower 32-bit Linear memory space address + * @address_high: higher 32-bit Linear memory space address + * @readback_type: Type of fpga readback operation + * 0 -- Configuration Register readback + * 1 -- Configuration Data readback + * @value: Value to read + * + * This function provides access to the xilfpga library to read + * the PL configuration. + * + * Return: Returns status, either success or error+reason. + */ +enum pm_ret_status pm_fpga_read(uint32_t reg_numframes, + uint32_t address_low, + uint32_t address_high, + uint32_t readback_type, + uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD5(payload, PM_FPGA_READ, reg_numframes, address_low, + address_high, readback_type); + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} + +/* + * pm_pll_set_parameter() - Set the PLL parameter value + * @nid Node id of the target PLL + * @param_id ID of the PLL parameter + * @value Parameter value to be set + * + * Setting the parameter will have physical effect once the PLL mode is set to + * integer or fractional. + * + * @return Error if an argument is not valid or status as returned by the + * PM controller (PMU) + */ +enum pm_ret_status pm_pll_set_parameter(enum pm_node_id nid, + enum pm_pll_param param_id, + uint32_t value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Check if given node ID is a PLL node */ + if (nid < NODE_APLL || nid > NODE_IOPLL) { + return PM_RET_ERROR_ARGS; + } + + /* Check if parameter ID is valid and return an error if it's not */ + if (param_id >= PM_PLL_PARAM_MAX) { + return PM_RET_ERROR_ARGS; + } + + /* Send request to the PMU */ + PM_PACK_PAYLOAD4(payload, PM_PLL_SET_PARAMETER, nid, param_id, value); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_pll_get_parameter() - Get the PLL parameter value + * @nid Node id of the target PLL + * @param_id ID of the PLL parameter + * @value Location to store the parameter value + * + * @return Error if an argument is not valid or status as returned by the + * PM controller (PMU) + */ +enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid, + enum pm_pll_param param_id, + uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Check if given node ID is a PLL node */ + if (nid < NODE_APLL || nid > NODE_IOPLL) { + return PM_RET_ERROR_ARGS; + } + + /* Check if parameter ID is valid and return an error if it's not */ + if (param_id >= PM_PLL_PARAM_MAX) { + return PM_RET_ERROR_ARGS; + } + + /* Send request to the PMU */ + PM_PACK_PAYLOAD3(payload, PM_PLL_GET_PARAMETER, nid, param_id); + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} + +/** + * pm_pll_set_mode() - Set the PLL mode + * @nid Node id of the target PLL + * @mode PLL mode to be set + * + * If reset mode is set the PM controller will first bypass the PLL and then + * assert the reset. If integer or fractional mode is set the PM controller will + * ensure that the complete PLL programming sequence is satisfied. After this + * function returns success the PLL is locked and its bypass is deasserted. + * + * @return Error if an argument is not valid or status as returned by the + * PM controller (PMU) + */ +enum pm_ret_status pm_pll_set_mode(enum pm_node_id nid, enum pm_pll_mode mode) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Check if given node ID is a PLL node */ + if (nid < NODE_APLL || nid > NODE_IOPLL) { + return PM_RET_ERROR_ARGS; + } + + /* Check if PLL mode is valid */ + if (mode >= PM_PLL_MODE_MAX) { + return PM_RET_ERROR_ARGS; + } + + /* Send request to the PMU */ + PM_PACK_PAYLOAD3(payload, PM_PLL_SET_MODE, nid, mode); + return pm_ipi_send_sync(primary_proc, payload, NULL, 0); +} + +/** + * pm_pll_get_mode() - Get the PLL mode + * @nid Node id of the target PLL + * @mode Location to store the mode of the PLL + * + * @return Error if an argument is not valid or status as returned by the + * PM controller (PMU) + */ +enum pm_ret_status pm_pll_get_mode(enum pm_node_id nid, enum pm_pll_mode *mode) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Check if given node ID is a PLL node */ + if (nid < NODE_APLL || nid > NODE_IOPLL) { + return PM_RET_ERROR_ARGS; + } + + /* Send request to the PMU */ + PM_PACK_PAYLOAD2(payload, PM_PLL_GET_MODE, nid); + return pm_ipi_send_sync(primary_proc, payload, mode, 1); +} + +/** + * pm_register_access() - PM API for register read/write access data + * + * @register_access_id Register_access_id which says register read/write + * + * @address Address of the register to be accessed + * + * @mask Mask value to be used while writing value + * + * @value Value to be written to register + * + * @out Returned output data + * + * This function returns requested data. + * + * @return Returns status, either success or error+reason + */ +enum pm_ret_status pm_register_access(uint32_t register_access_id, + uint32_t address, + uint32_t mask, + uint32_t value, + uint32_t *out) +{ + enum pm_ret_status ret; + + if (((ZYNQMP_CSU_BASEADDR & address) != ZYNQMP_CSU_BASEADDR) && + ((CSUDMA_BASE & address) != CSUDMA_BASE) && + ((RSA_CORE_BASE & address) != RSA_CORE_BASE) && + ((PMU_GLOBAL_BASE & address) != PMU_GLOBAL_BASE)) { + return PM_RET_ERROR_ACCESS; + } + + switch (register_access_id) { + case CONFIG_REG_WRITE: + ret = pm_mmio_write(address, mask, value); + break; + case CONFIG_REG_READ: + ret = pm_mmio_read(address, out); + break; + default: + ret = PM_RET_ERROR_ARGS; + WARN("Unimplemented register_access call\n\r"); + break; + } + return ret; +} + +/** + * pm_efuse_access() - To program or read efuse bits. + * + * This function provides access to the xilskey library to program/read + * efuse bits. + * + * address_low: lower 32-bit Linear memory space address + * address_high: higher 32-bit Linear memory space address + * + * value: Returned output value + * + * @return Returns status, either success or error+reason + * + */ +enum pm_ret_status pm_efuse_access(uint32_t address_high, + uint32_t address_low, + uint32_t *value) +{ + uint32_t payload[PAYLOAD_ARG_CNT]; + + /* Send request to the PMU */ + PM_PACK_PAYLOAD3(payload, PM_EFUSE_ACCESS, address_high, address_low); + + return pm_ipi_send_sync(primary_proc, payload, value, 1); +} diff --git a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.h new file mode 100644 index 000000000..7d2655499 --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_api_sys.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2023, Advanced Micro Devices Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ZYNQMP_PM_API_SYS_H +#define ZYNQMP_PM_API_SYS_H + +#include + +#include "pm_defs.h" + +enum pm_query_id { + PM_QID_INVALID, + PM_QID_CLOCK_GET_NAME, + PM_QID_CLOCK_GET_TOPOLOGY, + PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS, + PM_QID_CLOCK_GET_PARENTS, + PM_QID_CLOCK_GET_ATTRIBUTES, + PM_QID_PINCTRL_GET_NUM_PINS, + PM_QID_PINCTRL_GET_NUM_FUNCTIONS, + PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS, + PM_QID_PINCTRL_GET_FUNCTION_NAME, + PM_QID_PINCTRL_GET_FUNCTION_GROUPS, + PM_QID_PINCTRL_GET_PIN_GROUPS, + PM_QID_CLOCK_GET_NUM_CLOCKS, + PM_QID_CLOCK_GET_MAX_DIVISOR, +}; + +enum pm_register_access_id { + CONFIG_REG_WRITE, + CONFIG_REG_READ, +}; + +/** + * Assigning of argument values into array elements. + */ +#define PM_PACK_PAYLOAD1(pl, arg0) { \ + pl[0] = (uint32_t)(arg0); \ +} + +#define PM_PACK_PAYLOAD2(pl, arg0, arg1) { \ + pl[1] = (uint32_t)(arg1); \ + PM_PACK_PAYLOAD1(pl, arg0); \ +} + +#define PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2) { \ + pl[2] = (uint32_t)(arg2); \ + PM_PACK_PAYLOAD2(pl, arg0, arg1); \ +} + +#define PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3) { \ + pl[3] = (uint32_t)(arg3); \ + PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2); \ +} + +#define PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4) { \ + pl[4] = (uint32_t)(arg4); \ + PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3); \ +} + +#define PM_PACK_PAYLOAD6(pl, arg0, arg1, arg2, arg3, arg4, arg5) { \ + pl[5] = (uint32_t)(arg5); \ + PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4); \ +} + +/********************************************************** + * System-level API function declarations + **********************************************************/ +enum pm_ret_status pm_req_suspend(enum pm_node_id target, + enum pm_request_ack ack, + uint32_t latency, + uint32_t state); + +enum pm_ret_status pm_self_suspend(enum pm_node_id nid, + uint32_t latency, + uint32_t state, + uintptr_t address); + +enum pm_ret_status pm_force_powerdown(enum pm_node_id target, + enum pm_request_ack ack); + +enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason); + +enum pm_ret_status pm_req_wakeup(enum pm_node_id target, + uint32_t set_address, + uintptr_t address, + enum pm_request_ack ack); + +enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target, + enum pm_node_id wkup_node, + uint32_t enable); + +enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype); + +/* API functions for managing PM Slaves */ +enum pm_ret_status pm_req_node(enum pm_node_id nid, + uint32_t capabilities, + uint32_t qos, + enum pm_request_ack ack); + +enum pm_ret_status pm_set_requirement(enum pm_node_id nid, + uint32_t capabilities, + uint32_t qos, + enum pm_request_ack ack); + +/* Miscellaneous API functions */ +enum pm_ret_status pm_get_api_version(uint32_t *version); +enum pm_ret_status pm_get_node_status(enum pm_node_id nid, + uint32_t *ret_buff); + +/* Direct-Control API functions */ +enum pm_ret_status pm_mmio_write(uintptr_t address, + uint32_t mask, + uint32_t value); +enum pm_ret_status pm_mmio_read(uintptr_t address, uint32_t *value); +enum pm_ret_status pm_fpga_load(uint32_t address_low, + uint32_t address_high, + uint32_t size, + uint32_t flags); +enum pm_ret_status pm_fpga_get_status(uint32_t *value); + +enum pm_ret_status pm_get_chipid(uint32_t *value); +enum pm_ret_status pm_secure_rsaaes(uint32_t address_low, + uint32_t address_high, + uint32_t size, + uint32_t flags); +uint32_t pm_get_shutdown_scope(void); +enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count); +enum pm_ret_status pm_ioctl(enum pm_node_id nid, + uint32_t ioctl_id, + uint32_t arg1, + uint32_t arg2, + uint32_t *value); +enum pm_ret_status pm_clock_enable(uint32_t clock_id); +enum pm_ret_status pm_clock_disable(uint32_t clock_id); +enum pm_ret_status pm_clock_getstate(uint32_t clock_id, + uint32_t *state); +enum pm_ret_status pm_clock_setdivider(uint32_t clock_id, + uint32_t divider); +enum pm_ret_status pm_clock_getdivider(uint32_t clock_id, + uint32_t *divider); +enum pm_ret_status pm_clock_setrate(uint32_t clock_id, + uint64_t rate); +enum pm_ret_status pm_clock_getrate(uint32_t clock_id, + uint64_t *rate); +enum pm_ret_status pm_clock_setparent(uint32_t clock_id, + uint32_t parent_index); +enum pm_ret_status pm_clock_getparent(uint32_t clock_id, + uint32_t *parent_index); +void pm_query_data(enum pm_query_id qid, uint32_t arg1, uint32_t arg2, + uint32_t arg3, uint32_t *data); +enum pm_ret_status pm_sha_hash(uint32_t address_high, + uint32_t address_low, + uint32_t size, + uint32_t flags); +enum pm_ret_status pm_rsa_core(uint32_t address_high, + uint32_t address_low, + uint32_t size, + uint32_t flags); +enum pm_ret_status pm_secure_image(uint32_t address_low, + uint32_t address_high, + uint32_t key_lo, + uint32_t key_hi, + uint32_t *value); +enum pm_ret_status pm_fpga_read(uint32_t reg_numframes, + uint32_t address_low, + uint32_t address_high, + uint32_t readback_type, + uint32_t *value); +enum pm_ret_status pm_aes_engine(uint32_t address_high, + uint32_t address_low, + uint32_t *value); +enum pm_ret_status pm_register_access(uint32_t register_access_id, + uint32_t address, + uint32_t mask, + uint32_t value, + uint32_t *out); +enum pm_ret_status pm_pll_set_parameter(enum pm_node_id nid, + enum pm_pll_param param_id, + uint32_t value); +enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid, + enum pm_pll_param param_id, + uint32_t *value); +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 pm_feature_check(uint32_t api_id, uint32_t *version, + uint32_t *bit_mask, uint8_t len); +enum pm_ret_status check_api_dependency(uint8_t id); + +#endif /* ZYNQMP_PM_API_SYS_H */ diff --git a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c new file mode 100644 index 000000000..b54936e01 --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.c @@ -0,0 +1,575 @@ +/* + * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2023, Advanced Micro Devices Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Top-level SMC handler for ZynqMP power management calls and + * IPI setup functions for communication with PMU. + */ + +#include + +#include +#if ZYNQMP_WDT_RESTART +#include +#include +#include +#include +#include +#endif + +#include +#include "pm_client.h" +#include "pm_defs.h" +#include "pm_ipi.h" +#include "zynqmp_pm_api_sys.h" + +/* pm_up = !0 - UP, pm_up = 0 - DOWN */ +static int32_t pm_up, ipi_irq_flag; + +#if ZYNQMP_WDT_RESTART +static spinlock_t inc_lock; +static int active_cores = 0; +#endif + +/** + * pm_context - Structure which contains data for power management + * @api_version version of PM API, must match with one on PMU side + * @payload payload array used to store received + * data from ipi buffer registers + */ +static struct { + uint32_t api_version; + uint32_t payload[PAYLOAD_ARG_CNT]; +} pm_ctx; + +#if ZYNQMP_WDT_RESTART +/** + * trigger_wdt_restart() - Trigger warm restart event to APU cores + * + * This function triggers SGI for all active APU CPUs. SGI handler then + * power down CPU and call system reset. + */ +static void trigger_wdt_restart(void) +{ + uint32_t core_count = 0; + uint32_t core_status[3]; + uint32_t target_cpu_list = 0; + int i; + + for (i = 0; i < 4; i++) { + pm_get_node_status(NODE_APU_0 + i, core_status); + if (core_status[0] == 1) { + core_count++; + target_cpu_list |= (1 << i); + } + } + + spin_lock(&inc_lock); + active_cores = core_count; + spin_unlock(&inc_lock); + + INFO("Active Cores: %d\n", active_cores); + + for (i = PLATFORM_CORE_COUNT - 1; i >= 0; i--) { + if (target_cpu_list & (1 << i)) { + /* trigger SGI to active cores */ + plat_ic_raise_el3_sgi(ARM_IRQ_SEC_SGI_7, i); + } + } +} + +/** + * ttc_fiq_handler() - TTC Handler for timer event + * @id number of the highest priority pending interrupt of the type + * that this handler was registered for + * @flags security state, bit[0] + * @handler pointer to 'cpu_context' structure of the current CPU for the + * security state specified in the 'flags' parameter + * @cookie unused + * + * Function registered as INTR_TYPE_EL3 interrupt handler + * + * When WDT event is received in PMU, PMU needs to notify master to do cleanup + * if required. PMU sets up timer and starts timer to overflow in zero time upon + * WDT event. ATF handles this timer event and takes necessary action required + * for warm restart. + * + * In presence of non-secure software layers (EL1/2) sets the interrupt + * at registered entrance in GIC and informs that PMU responsed or demands + * action. + */ +static uint64_t ttc_fiq_handler(uint32_t id, uint32_t flags, void *handle, + void *cookie) +{ + INFO("BL31: Got TTC FIQ\n"); + + plat_ic_end_of_interrupt(id); + + /* Clear TTC interrupt by reading interrupt register */ + mmio_read_32(TTC3_INTR_REGISTER_1); + + /* Disable the timer interrupts */ + mmio_write_32(TTC3_INTR_ENABLE_1, 0); + + trigger_wdt_restart(); + + return 0; +} + +/** + * zynqmp_sgi7_irq() - Handler for SGI7 IRQ + * @id number of the highest priority pending interrupt of the type + * that this handler was registered for + * @flags security state, bit[0] + * @handler pointer to 'cpu_context' structure of the current CPU for the + * security state specified in the 'flags' parameter + * @cookie unused + * + * Function registered as INTR_TYPE_EL3 interrupt handler + * + * On receiving WDT event from PMU, ATF generates SGI7 to all running CPUs. + * In response to SGI7 interrupt, each CPUs do clean up if required and last + * running CPU calls system restart. + */ +static uint64_t __unused __dead2 zynqmp_sgi7_irq(uint32_t id, uint32_t flags, + void *handle, void *cookie) +{ + int i; + uint32_t value; + + /* enter wfi and stay there */ + INFO("Entering wfi\n"); + + spin_lock(&inc_lock); + active_cores--; + + for (i = 0; i < 4; i++) { + mmio_write_32(BASE_GICD_BASE + GICD_CPENDSGIR + 4 * i, + 0xffffffff); + } + + dsb(); + + spin_unlock(&inc_lock); + + if (active_cores == 0) { + pm_mmio_read(PMU_GLOBAL_GEN_STORAGE4, &value); + value = (value & RESTART_SCOPE_MASK) >> RESTART_SCOPE_SHIFT; + pm_system_shutdown(PMF_SHUTDOWN_TYPE_RESET, value); + } + + /* enter wfi and stay there */ + while (1) + wfi(); +} + +/** + * pm_wdt_restart_setup() - Setup warm restart interrupts + * + * This function sets up handler for SGI7 and TTC interrupts + * used for warm restart. + */ +static int pm_wdt_restart_setup(void) +{ + int ret; + + /* register IRQ handler for SGI7 */ + ret = request_intr_type_el3(ARM_IRQ_SEC_SGI_7, zynqmp_sgi7_irq); + if (ret) { + WARN("BL31: registering SGI7 interrupt failed\n"); + goto err; + } + + ret = request_intr_type_el3(IRQ_TTC3_1, ttc_fiq_handler); + if (ret) + WARN("BL31: registering TTC3 interrupt failed\n"); + +err: + return ret; +} +#endif + +/** + * pm_setup() - PM service setup + * + * @return On success, the initialization function must return 0. + * Any other return value will cause the framework to ignore + * the service + * + * Initialization functions for ZynqMP power management for + * communicaton with PMU. + * + * Called from sip_svc_setup initialization function with the + * rt_svc_init signature. + */ +int32_t pm_setup(void) +{ + enum pm_ret_status err; + + pm_ipi_init(primary_proc); + + err = pm_get_api_version(&pm_ctx.api_version); + if (err != PM_RET_SUCCESS) { + ERROR("BL31: Failed to read Platform Management API version. " + "Return: %d\n", err); + return -EINVAL; + } + if (pm_ctx.api_version < PM_VERSION) { + ERROR("BL31: Platform Management API version error. Expected: " + "v%d.%d - Found: v%d.%d\n", PM_VERSION_MAJOR, + PM_VERSION_MINOR, pm_ctx.api_version >> 16, + pm_ctx.api_version & 0xFFFFU); + return -EINVAL; + } + + int32_t status = 0, ret = 0; +#if ZYNQMP_WDT_RESTART + status = pm_wdt_restart_setup(); + if (status) + WARN("BL31: warm-restart setup failed\n"); +#endif + + if (status >= 0) { + INFO("BL31: PM Service Init Complete: API v%d.%d\n", + PM_VERSION_MAJOR, PM_VERSION_MINOR); + ret = 0; + } else { + INFO("BL31: PM Service Init Failed, Error Code %d!\n", status); + ret = status; + } + + pm_up = !status; + + return ret; +} + +/** + * pm_smc_handler() - SMC handler for PM-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 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 pm_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) +{ + enum pm_ret_status ret; + uint32_t payload[PAYLOAD_ARG_CNT]; + + uint32_t pm_arg[5]; + uint32_t result[PAYLOAD_ARG_CNT] = {0}; + uint32_t api_id; + + /* Handle case where PM wasn't initialized properly */ + if (pm_up == 0) + SMC_RET1(handle, SMC_UNK); + + pm_arg[0] = (uint32_t)x1; + pm_arg[1] = (uint32_t)(x1 >> 32); + pm_arg[2] = (uint32_t)x2; + pm_arg[3] = (uint32_t)(x2 >> 32); + pm_arg[4] = (uint32_t)x3; + + api_id = smc_fid & FUNCID_NUM_MASK; + + switch (api_id) { + /* PM API Functions */ + case PM_SELF_SUSPEND: + ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_REQ_SUSPEND: + ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_REQ_WAKEUP: + { + /* Use address flag is encoded in the 1st bit of the low-word */ + uint32_t set_addr = pm_arg[1] & 0x1U; + uint64_t address = (uint64_t)pm_arg[2] << 32U; + + address |= pm_arg[1] & (~0x1U); + ret = pm_req_wakeup(pm_arg[0], set_addr, address, + pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + } + + case PM_FORCE_POWERDOWN: + ret = pm_force_powerdown(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_ABORT_SUSPEND: + ret = pm_abort_suspend(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_SET_WAKEUP_SOURCE: + ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_SYSTEM_SHUTDOWN: + ret = pm_system_shutdown(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_REQ_NODE: + ret = pm_req_node(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_SET_REQUIREMENT: + ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_GET_API_VERSION: + if (ipi_irq_flag == 0U) { + /* + * Enable IPI IRQ + * assume the rich OS is OK to handle callback IRQs now. + * Even if we were wrong, it would not enable the IRQ in + * the GIC. + */ + pm_ipi_irq_enable(primary_proc); + ipi_irq_flag = 1U; + } + SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | + ((uint64_t)pm_ctx.api_version << 32)); + case PM_FPGA_LOAD: + ret = pm_fpga_load(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_FPGA_GET_STATUS: + { + uint32_t value = 0U; + + ret = pm_fpga_get_status(&value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case PM_SECURE_RSA_AES: + ret = pm_secure_rsaaes(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_GET_CALLBACK_DATA: + ret = pm_get_callbackdata(result, ARRAY_SIZE(result)); + if (ret != PM_RET_SUCCESS) { + result[0] = ret; + } + + SMC_RET2(handle, + (uint64_t)result[0] | ((uint64_t)result[1] << 32), + (uint64_t)result[2] | ((uint64_t)result[3] << 32)); + case PM_IOCTL: + { + uint32_t value = 0U; + + ret = pm_ioctl(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case PM_QUERY_DATA: + { + uint32_t data[4] = { 0 }; + + pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3], data); + SMC_RET2(handle, (uint64_t)data[0] | ((uint64_t)data[1] << 32), + (uint64_t)data[2] | ((uint64_t)data[3] << 32)); + } + + case PM_CLOCK_ENABLE: + ret = pm_clock_enable(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_CLOCK_DISABLE: + ret = pm_clock_disable(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_CLOCK_GETSTATE: + { + uint32_t value = 0U; + + ret = pm_clock_getstate(pm_arg[0], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case PM_CLOCK_SETDIVIDER: + ret = pm_clock_setdivider(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_CLOCK_GETDIVIDER: + { + uint32_t value = 0U; + + ret = pm_clock_getdivider(pm_arg[0], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); + } + + case PM_CLOCK_SETRATE: + ret = pm_clock_setrate(pm_arg[0], + ((uint64_t)pm_arg[2]) << 32 | pm_arg[1]); + + SMC_RET1(handle, (uint64_t)ret); + + case PM_CLOCK_GETRATE: + { + uint64_t value = 0; + + ret = pm_clock_getrate(pm_arg[0], &value); + SMC_RET2(handle, (uint64_t)ret | + (((uint64_t)value & 0xFFFFFFFFU) << 32U), + (value >> 32U) & 0xFFFFFFFFU); + + } + + case PM_CLOCK_SETPARENT: + ret = pm_clock_setparent(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_CLOCK_GETPARENT: + { + uint32_t value = 0U; + + ret = pm_clock_getparent(pm_arg[0], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); + } + + case PM_GET_TRUSTZONE_VERSION: + SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | + ((uint64_t)ZYNQMP_TZ_VERSION << 32U)); + + case PM_SET_SUSPEND_MODE: + ret = pm_set_suspend_mode(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_SECURE_SHA: + ret = pm_sha_hash(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_SECURE_RSA: + ret = pm_rsa_core(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_SECURE_IMAGE: + { + ret = pm_secure_image(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3], &result[0]); + SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U), + result[1]); + } + + case PM_FPGA_READ: + { + uint32_t value = 0U; + + ret = pm_fpga_read(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3], + &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); + } + + case PM_SECURE_AES: + { + uint32_t value = 0U; + + ret = pm_aes_engine(pm_arg[0], pm_arg[1], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); + } + + case PM_PLL_SET_PARAMETER: + ret = pm_pll_set_parameter(pm_arg[0], pm_arg[1], pm_arg[2]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_PLL_GET_PARAMETER: + { + uint32_t value = 0U; + + ret = pm_pll_get_parameter(pm_arg[0], pm_arg[1], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32U)); + } + + case PM_PLL_SET_MODE: + ret = pm_pll_set_mode(pm_arg[0], pm_arg[1]); + SMC_RET1(handle, (uint64_t)ret); + + case PM_PLL_GET_MODE: + { + uint32_t mode = 0U; + + ret = pm_pll_get_mode(pm_arg[0], &mode); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32U)); + } + + case PM_REGISTER_ACCESS: + { + uint32_t value = 0U; + + ret = pm_register_access(pm_arg[0], pm_arg[1], pm_arg[2], + pm_arg[3], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); + } + + case PM_EFUSE_ACCESS: + { + uint32_t value = 0U; + +#if defined(ZYNQMP_SECURE_EFUSES) + if (is_caller_non_secure(flags)) { + SMC_RET1(handle, + (((uint64_t)PM_RET_ERROR_NOT_ENABLED) << 32U) | + (uint64_t)PM_RET_ERROR_ACCESS); + } +#endif + ret = pm_efuse_access(pm_arg[0], pm_arg[1], &value); + SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U); + } + + case PM_FPGA_GET_VERSION: + case PM_FPGA_GET_FEATURE_LIST: + { + uint32_t ret_payload[PAYLOAD_ARG_CNT]; + + PM_PACK_PAYLOAD5(payload, smc_fid & FUNCID_NUM_MASK, + pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); + ret = pm_ipi_send_sync(primary_proc, payload, ret_payload, 3U); + SMC_RET2(handle, (uint64_t)ret | (uint64_t)ret_payload[0] << 32U, + (uint64_t)ret_payload[1] | (uint64_t)ret_payload[2] << 32U); + } + + case PM_FEATURE_CHECK: + { + uint32_t version = 0; + uint32_t bit_mask[2] = {0}; + + ret = pm_feature_check(pm_arg[0], &version, bit_mask, + ARRAY_SIZE(bit_mask)); + SMC_RET2(handle, (uint64_t)ret | ((uint64_t)version << 32U), + (uint64_t)bit_mask[0] | ((uint64_t)bit_mask[1] << 32U)); + } + + default: + /* Send request to the PMU */ + PM_PACK_PAYLOAD6(payload, api_id, pm_arg[0], pm_arg[1], + pm_arg[2], pm_arg[3], pm_arg[4]); + ret = pm_ipi_send_sync(primary_proc, payload, result, + PAYLOAD_ARG_CNT); + SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U), + (uint64_t)result[1] | ((uint64_t)result[2] << 32U)); + } +} diff --git a/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.h b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.h new file mode 100644 index 000000000..03ff6d3d8 --- /dev/null +++ b/plat/xilinx/zynqmp/pm_service/zynqmp_pm_svc_main.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2023, Advanced Micro Devices Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ZYNQMP_PM_SVC_MAIN_H +#define ZYNQMP_PM_SVC_MAIN_H + +#include "pm_common.h" + +int32_t pm_setup(void); +uint64_t pm_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 /* ZYNQMP_PM_SVC_MAIN_H */ diff --git a/plat/xilinx/zynqmp/sip_svc_setup.c b/plat/xilinx/zynqmp/sip_svc_setup.c index c55784e3f..6ec7ed492 100644 --- a/plat/xilinx/zynqmp/sip_svc_setup.c +++ b/plat/xilinx/zynqmp/sip_svc_setup.c @@ -14,7 +14,7 @@ #include #include "ipi_mailbox_svc.h" -#include "pm_svc_main.h" +#include "zynqmp_pm_svc_main.h" /* SMC function IDs for SiP Service queries */ #define ZYNQMP_SIP_SVC_CALL_COUNT U(0x8200ff00)