10cc5e210SSenthil Nathan Thangaraj /*
20cc5e210SSenthil Nathan Thangaraj * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
30cc5e210SSenthil Nathan Thangaraj * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
40cc5e210SSenthil Nathan Thangaraj *
50cc5e210SSenthil Nathan Thangaraj * SPDX-License-Identifier: BSD-3-Clause
60cc5e210SSenthil Nathan Thangaraj */
70cc5e210SSenthil Nathan Thangaraj
80cc5e210SSenthil Nathan Thangaraj /*
9f91fbc6bSPrasad Kummari * Top-level SMC handler for Versal Gen 2 power management calls and
100cc5e210SSenthil Nathan Thangaraj * IPI setup functions for communication with PMC.
110cc5e210SSenthil Nathan Thangaraj */
120cc5e210SSenthil Nathan Thangaraj
130cc5e210SSenthil Nathan Thangaraj #include <errno.h>
140cc5e210SSenthil Nathan Thangaraj #include <stdbool.h>
150cc5e210SSenthil Nathan Thangaraj
160cc5e210SSenthil Nathan Thangaraj #include "../drivers/arm/gic/v3/gicv3_private.h"
170cc5e210SSenthil Nathan Thangaraj
184fd510e0SRonak Jain #include <common/ep_info.h>
190cc5e210SSenthil Nathan Thangaraj #include <common/runtime_svc.h>
200cc5e210SSenthil Nathan Thangaraj #include <drivers/arm/gicv3.h>
210cc5e210SSenthil Nathan Thangaraj #include <lib/psci/psci.h>
220cc5e210SSenthil Nathan Thangaraj #include <plat/arm/common/plat_arm.h>
230cc5e210SSenthil Nathan Thangaraj #include <plat/common/platform.h>
240cc5e210SSenthil Nathan Thangaraj
250cc5e210SSenthil Nathan Thangaraj #include <plat_private.h>
260cc5e210SSenthil Nathan Thangaraj #include "pm_api_sys.h"
270cc5e210SSenthil Nathan Thangaraj #include "pm_client.h"
280cc5e210SSenthil Nathan Thangaraj #include "pm_ipi.h"
290cc5e210SSenthil Nathan Thangaraj #include "pm_svc_main.h"
300cc5e210SSenthil Nathan Thangaraj
310cc5e210SSenthil Nathan Thangaraj #define MODE 0x80000000U
320cc5e210SSenthil Nathan Thangaraj
330cc5e210SSenthil Nathan Thangaraj #define INVALID_SGI 0xFFU
340cc5e210SSenthil Nathan Thangaraj #define PM_INIT_SUSPEND_CB (30U)
350cc5e210SSenthil Nathan Thangaraj #define PM_NOTIFY_CB (32U)
360cc5e210SSenthil Nathan Thangaraj #define EVENT_CPU_PWRDWN (4U)
370cc5e210SSenthil Nathan Thangaraj #define MBOX_SGI_SHARED_IPI (7U)
380cc5e210SSenthil Nathan Thangaraj
390cc5e210SSenthil Nathan Thangaraj /**
400cc5e210SSenthil Nathan Thangaraj * upper_32_bits - return bits 32-63 of a number
410cc5e210SSenthil Nathan Thangaraj * @n: the number we're accessing
420cc5e210SSenthil Nathan Thangaraj */
430cc5e210SSenthil Nathan Thangaraj #define upper_32_bits(n) ((uint32_t)((n) >> 32U))
440cc5e210SSenthil Nathan Thangaraj
450cc5e210SSenthil Nathan Thangaraj /**
460cc5e210SSenthil Nathan Thangaraj * lower_32_bits - return bits 0-31 of a number
470cc5e210SSenthil Nathan Thangaraj * @n: the number we're accessing
480cc5e210SSenthil Nathan Thangaraj */
490cc5e210SSenthil Nathan Thangaraj #define lower_32_bits(n) ((uint32_t)((n) & 0xffffffffU))
500cc5e210SSenthil Nathan Thangaraj
510cc5e210SSenthil Nathan Thangaraj /**
520cc5e210SSenthil Nathan Thangaraj * EXTRACT_SMC_ARGS - extracts 32-bit payloads from 64-bit SMC arguments
530cc5e210SSenthil Nathan Thangaraj * @pm_arg: array of 32-bit payloads
540cc5e210SSenthil Nathan Thangaraj * @x: array of 64-bit SMC arguments
550cc5e210SSenthil Nathan Thangaraj */
560cc5e210SSenthil Nathan Thangaraj #define EXTRACT_ARGS(pm_arg, x) \
570cc5e210SSenthil Nathan Thangaraj for (uint32_t i = 0U; i < (PAYLOAD_ARG_CNT - 1U); i++) { \
580cc5e210SSenthil Nathan Thangaraj if ((i % 2U) != 0U) { \
590cc5e210SSenthil Nathan Thangaraj pm_arg[i] = lower_32_bits(x[(i / 2U) + 1U]); \
600cc5e210SSenthil Nathan Thangaraj } else { \
610cc5e210SSenthil Nathan Thangaraj pm_arg[i] = upper_32_bits(x[i / 2U]); \
620cc5e210SSenthil Nathan Thangaraj } \
630cc5e210SSenthil Nathan Thangaraj }
640cc5e210SSenthil Nathan Thangaraj
650cc5e210SSenthil Nathan Thangaraj /* 1 sec of wait timeout for secondary core down */
660cc5e210SSenthil Nathan Thangaraj #define PWRDWN_WAIT_TIMEOUT (1000U)
670cc5e210SSenthil Nathan Thangaraj DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6)
680cc5e210SSenthil Nathan Thangaraj
690cc5e210SSenthil Nathan Thangaraj /* pm_up = true - UP, pm_up = false - DOWN */
700cc5e210SSenthil Nathan Thangaraj static bool pm_up;
710cc5e210SSenthil Nathan Thangaraj static uint32_t sgi = (uint32_t)INVALID_SGI;
72c0719d21SDevanshi Chauhan static bool pwrdwn_req_received;
73c0719d21SDevanshi Chauhan
pm_pwrdwn_req_status(void)74c0719d21SDevanshi Chauhan bool pm_pwrdwn_req_status(void)
75c0719d21SDevanshi Chauhan {
76c0719d21SDevanshi Chauhan return pwrdwn_req_received;
77c0719d21SDevanshi Chauhan }
780cc5e210SSenthil Nathan Thangaraj
notify_os(void)790cc5e210SSenthil Nathan Thangaraj static void notify_os(void)
800cc5e210SSenthil Nathan Thangaraj {
810cc5e210SSenthil Nathan Thangaraj plat_ic_raise_ns_sgi((int)sgi, read_mpidr_el1());
820cc5e210SSenthil Nathan Thangaraj }
830cc5e210SSenthil Nathan Thangaraj
cpu_pwrdwn_req_handler(uint32_t id,uint32_t flags,void * handle,void * cookie)840cc5e210SSenthil Nathan Thangaraj static uint64_t cpu_pwrdwn_req_handler(uint32_t id, uint32_t flags,
850cc5e210SSenthil Nathan Thangaraj void *handle, void *cookie)
860cc5e210SSenthil Nathan Thangaraj {
870cc5e210SSenthil Nathan Thangaraj uint32_t cpu_id = plat_my_core_pos();
880cc5e210SSenthil Nathan Thangaraj
890cc5e210SSenthil Nathan Thangaraj VERBOSE("Powering down CPU %d\n", cpu_id);
900cc5e210SSenthil Nathan Thangaraj
910cc5e210SSenthil Nathan Thangaraj /* Deactivate CPU power down SGI */
920cc5e210SSenthil Nathan Thangaraj plat_ic_end_of_interrupt(CPU_PWR_DOWN_REQ_INTR);
930cc5e210SSenthil Nathan Thangaraj
940cc5e210SSenthil Nathan Thangaraj return (uint64_t) psci_cpu_off();
950cc5e210SSenthil Nathan Thangaraj }
960cc5e210SSenthil Nathan Thangaraj
970cc5e210SSenthil Nathan Thangaraj /**
980cc5e210SSenthil Nathan Thangaraj * raise_pwr_down_interrupt() - Callback function to raise SGI.
990cc5e210SSenthil Nathan Thangaraj * @mpidr: MPIDR for the target CPU.
1000cc5e210SSenthil Nathan Thangaraj *
1010cc5e210SSenthil Nathan Thangaraj * Raise SGI interrupt to trigger the CPU power down sequence on all the
1020cc5e210SSenthil Nathan Thangaraj * online secondary cores.
1030cc5e210SSenthil Nathan Thangaraj */
raise_pwr_down_interrupt(u_register_t mpidr)1040cc5e210SSenthil Nathan Thangaraj static void raise_pwr_down_interrupt(u_register_t mpidr)
1050cc5e210SSenthil Nathan Thangaraj {
1060cc5e210SSenthil Nathan Thangaraj plat_ic_raise_el3_sgi((int)CPU_PWR_DOWN_REQ_INTR, mpidr);
1070cc5e210SSenthil Nathan Thangaraj }
1080cc5e210SSenthil Nathan Thangaraj
request_cpu_pwrdwn(void)1090cc5e210SSenthil Nathan Thangaraj void request_cpu_pwrdwn(void)
1100cc5e210SSenthil Nathan Thangaraj {
1110cc5e210SSenthil Nathan Thangaraj int ret;
1120cc5e210SSenthil Nathan Thangaraj
1130cc5e210SSenthil Nathan Thangaraj VERBOSE("CPU power down request received\n");
1140cc5e210SSenthil Nathan Thangaraj
1150cc5e210SSenthil Nathan Thangaraj /* Send powerdown request to online secondary core(s) */
1160cc5e210SSenthil Nathan Thangaraj ret = psci_stop_other_cores(plat_my_core_pos(), (unsigned int)PWRDWN_WAIT_TIMEOUT, raise_pwr_down_interrupt);
1170cc5e210SSenthil Nathan Thangaraj if (ret != (int)PSCI_E_SUCCESS) {
1180cc5e210SSenthil Nathan Thangaraj ERROR("Failed to powerdown secondary core(s)\n");
1190cc5e210SSenthil Nathan Thangaraj }
1200cc5e210SSenthil Nathan Thangaraj
1210cc5e210SSenthil Nathan Thangaraj /* Clear IPI IRQ */
1220cc5e210SSenthil Nathan Thangaraj pm_ipi_irq_clear(primary_proc);
1230cc5e210SSenthil Nathan Thangaraj
1240cc5e210SSenthil Nathan Thangaraj /* Deactivate IPI IRQ */
1250cc5e210SSenthil Nathan Thangaraj plat_ic_end_of_interrupt(PLAT_VERSAL_IPI_IRQ);
1260cc5e210SSenthil Nathan Thangaraj }
1270cc5e210SSenthil Nathan Thangaraj
ipi_fiq_handler(uint32_t id,uint32_t flags,void * handle,void * cookie)1280cc5e210SSenthil Nathan Thangaraj static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle,
1290cc5e210SSenthil Nathan Thangaraj void *cookie)
1300cc5e210SSenthil Nathan Thangaraj {
1310cc5e210SSenthil Nathan Thangaraj uint32_t payload[4] = {0};
1320cc5e210SSenthil Nathan Thangaraj enum pm_ret_status ret;
1330cc5e210SSenthil Nathan Thangaraj uint32_t ipi_status, i;
1340cc5e210SSenthil Nathan Thangaraj
1350cc5e210SSenthil Nathan Thangaraj VERBOSE("Received IPI FIQ from firmware\n");
1360cc5e210SSenthil Nathan Thangaraj
1370cc5e210SSenthil Nathan Thangaraj console_flush();
1380cc5e210SSenthil Nathan Thangaraj (void)plat_ic_acknowledge_interrupt();
1390cc5e210SSenthil Nathan Thangaraj
1400cc5e210SSenthil Nathan Thangaraj /* Check status register for each IPI except PMC */
1410cc5e210SSenthil Nathan Thangaraj for (i = IPI_ID_APU; i <= IPI_ID_5; i++) {
142bdba3c84SDevanshi Chauhan Alpeshbhai ipi_status = ipi_mb_enquire_status(IPI_ID_APU, i);
1430cc5e210SSenthil Nathan Thangaraj
1440cc5e210SSenthil Nathan Thangaraj /* If any agent other than PMC has generated IPI FIQ then send SGI to mbox driver */
1450cc5e210SSenthil Nathan Thangaraj if ((ipi_status & (uint32_t)IPI_MB_STATUS_RECV_PENDING) > (uint32_t) 0) {
1460cc5e210SSenthil Nathan Thangaraj plat_ic_raise_ns_sgi((int)MBOX_SGI_SHARED_IPI, read_mpidr_el1());
1470cc5e210SSenthil Nathan Thangaraj break;
1480cc5e210SSenthil Nathan Thangaraj }
1490cc5e210SSenthil Nathan Thangaraj }
1500cc5e210SSenthil Nathan Thangaraj
1510cc5e210SSenthil Nathan Thangaraj /* If PMC has not generated interrupt then end ISR */
152bdba3c84SDevanshi Chauhan Alpeshbhai ipi_status = ipi_mb_enquire_status(IPI_ID_APU, IPI_ID_PMC);
153bdba3c84SDevanshi Chauhan Alpeshbhai if ((ipi_status & IPI_MB_STATUS_RECV_PENDING) == (uint32_t)0) {
1540cc5e210SSenthil Nathan Thangaraj plat_ic_end_of_interrupt(id);
1550cc5e210SSenthil Nathan Thangaraj goto end;
1560cc5e210SSenthil Nathan Thangaraj }
1570cc5e210SSenthil Nathan Thangaraj
1580cc5e210SSenthil Nathan Thangaraj /* Handle PMC case */
1590cc5e210SSenthil Nathan Thangaraj ret = pm_get_callbackdata(payload, ARRAY_SIZE(payload), 0, 0);
1600cc5e210SSenthil Nathan Thangaraj if (ret != PM_RET_SUCCESS) {
1610cc5e210SSenthil Nathan Thangaraj payload[0] = (uint32_t) ret;
1620cc5e210SSenthil Nathan Thangaraj }
1630cc5e210SSenthil Nathan Thangaraj
1640cc5e210SSenthil Nathan Thangaraj switch (payload[0]) {
1650cc5e210SSenthil Nathan Thangaraj case PM_INIT_SUSPEND_CB:
1660cc5e210SSenthil Nathan Thangaraj if (sgi != INVALID_SGI) {
1670cc5e210SSenthil Nathan Thangaraj notify_os();
1680cc5e210SSenthil Nathan Thangaraj }
1690cc5e210SSenthil Nathan Thangaraj break;
1700cc5e210SSenthil Nathan Thangaraj case PM_NOTIFY_CB:
1710cc5e210SSenthil Nathan Thangaraj if (sgi != INVALID_SGI) {
172244f9fb9SNaman Trivedi if ((payload[2] == EVENT_CPU_PWRDWN) &&
173244f9fb9SNaman Trivedi (NODECLASS(payload[1]) == (uint32_t)XPM_NODECLASS_DEVICE)) {
1740cc5e210SSenthil Nathan Thangaraj if (pwrdwn_req_received) {
1750cc5e210SSenthil Nathan Thangaraj pwrdwn_req_received = false;
1760cc5e210SSenthil Nathan Thangaraj request_cpu_pwrdwn();
1770cc5e210SSenthil Nathan Thangaraj (void)psci_cpu_off();
1780cc5e210SSenthil Nathan Thangaraj break;
1790cc5e210SSenthil Nathan Thangaraj } else {
1800cc5e210SSenthil Nathan Thangaraj /* No action needed, added for MISRA
1810cc5e210SSenthil Nathan Thangaraj * complaince
1820cc5e210SSenthil Nathan Thangaraj */
1830cc5e210SSenthil Nathan Thangaraj }
1840cc5e210SSenthil Nathan Thangaraj pwrdwn_req_received = true;
1850cc5e210SSenthil Nathan Thangaraj
1860cc5e210SSenthil Nathan Thangaraj } else {
1870cc5e210SSenthil Nathan Thangaraj /* No action needed, added for MISRA
1880cc5e210SSenthil Nathan Thangaraj * complaince
1890cc5e210SSenthil Nathan Thangaraj */
1900cc5e210SSenthil Nathan Thangaraj }
1910cc5e210SSenthil Nathan Thangaraj notify_os();
192244f9fb9SNaman Trivedi } else if ((payload[2] == EVENT_CPU_PWRDWN) &&
193244f9fb9SNaman Trivedi (NODECLASS(payload[1]) == (uint32_t)XPM_NODECLASS_DEVICE)) {
1940cc5e210SSenthil Nathan Thangaraj request_cpu_pwrdwn();
1950cc5e210SSenthil Nathan Thangaraj (void)psci_cpu_off();
1960cc5e210SSenthil Nathan Thangaraj } else {
1970cc5e210SSenthil Nathan Thangaraj /* No action needed, added for MISRA
1980cc5e210SSenthil Nathan Thangaraj * complaince
1990cc5e210SSenthil Nathan Thangaraj */
2000cc5e210SSenthil Nathan Thangaraj }
2010cc5e210SSenthil Nathan Thangaraj break;
2020cc5e210SSenthil Nathan Thangaraj case (uint32_t) PM_RET_ERROR_INVALID_CRC:
2030cc5e210SSenthil Nathan Thangaraj pm_ipi_irq_clear(primary_proc);
2040cc5e210SSenthil Nathan Thangaraj WARN("Invalid CRC in the payload\n");
2050cc5e210SSenthil Nathan Thangaraj break;
2060cc5e210SSenthil Nathan Thangaraj
2070cc5e210SSenthil Nathan Thangaraj default:
2080cc5e210SSenthil Nathan Thangaraj pm_ipi_irq_clear(primary_proc);
2090cc5e210SSenthil Nathan Thangaraj WARN("Invalid IPI payload\n");
2100cc5e210SSenthil Nathan Thangaraj break;
2110cc5e210SSenthil Nathan Thangaraj }
2120cc5e210SSenthil Nathan Thangaraj
2130cc5e210SSenthil Nathan Thangaraj /* Clear FIQ */
2140cc5e210SSenthil Nathan Thangaraj plat_ic_end_of_interrupt(id);
2150cc5e210SSenthil Nathan Thangaraj
2160cc5e210SSenthil Nathan Thangaraj end:
2170cc5e210SSenthil Nathan Thangaraj return 0;
2180cc5e210SSenthil Nathan Thangaraj }
2190cc5e210SSenthil Nathan Thangaraj
2200cc5e210SSenthil Nathan Thangaraj /**
2210cc5e210SSenthil Nathan Thangaraj * pm_register_sgi() - PM register the IPI interrupt.
2220cc5e210SSenthil Nathan Thangaraj * @sgi_num: SGI number to be used for communication.
2230cc5e210SSenthil Nathan Thangaraj * @reset: Reset to invalid SGI when reset=1.
2240cc5e210SSenthil Nathan Thangaraj *
2250cc5e210SSenthil Nathan Thangaraj * Return: On success, the initialization function must return 0.
2260cc5e210SSenthil Nathan Thangaraj * Any other return value will cause the framework to ignore
2270cc5e210SSenthil Nathan Thangaraj * the service.
2280cc5e210SSenthil Nathan Thangaraj *
2290cc5e210SSenthil Nathan Thangaraj * Update the SGI number to be used.
2300cc5e210SSenthil Nathan Thangaraj *
2310cc5e210SSenthil Nathan Thangaraj */
pm_register_sgi(uint32_t sgi_num,uint32_t reset)2320cc5e210SSenthil Nathan Thangaraj int32_t pm_register_sgi(uint32_t sgi_num, uint32_t reset)
2330cc5e210SSenthil Nathan Thangaraj {
2340cc5e210SSenthil Nathan Thangaraj int32_t ret;
2350cc5e210SSenthil Nathan Thangaraj
2360cc5e210SSenthil Nathan Thangaraj if (reset == 1U) {
2370cc5e210SSenthil Nathan Thangaraj sgi = INVALID_SGI;
2380cc5e210SSenthil Nathan Thangaraj ret = 0;
2390cc5e210SSenthil Nathan Thangaraj goto end;
2400cc5e210SSenthil Nathan Thangaraj }
2410cc5e210SSenthil Nathan Thangaraj
2420cc5e210SSenthil Nathan Thangaraj if (sgi != INVALID_SGI) {
2430cc5e210SSenthil Nathan Thangaraj ret = -EBUSY;
2440cc5e210SSenthil Nathan Thangaraj goto end;
2450cc5e210SSenthil Nathan Thangaraj }
2460cc5e210SSenthil Nathan Thangaraj
2470cc5e210SSenthil Nathan Thangaraj if (sgi_num >= GICV3_MAX_SGI_TARGETS) {
2480cc5e210SSenthil Nathan Thangaraj ret = -EINVAL;
2490cc5e210SSenthil Nathan Thangaraj goto end;
2500cc5e210SSenthil Nathan Thangaraj }
2510cc5e210SSenthil Nathan Thangaraj
2520cc5e210SSenthil Nathan Thangaraj sgi = (uint32_t)sgi_num;
2530cc5e210SSenthil Nathan Thangaraj ret = 0;
2540cc5e210SSenthil Nathan Thangaraj end:
2550cc5e210SSenthil Nathan Thangaraj return ret;
2560cc5e210SSenthil Nathan Thangaraj }
2570cc5e210SSenthil Nathan Thangaraj
2580cc5e210SSenthil Nathan Thangaraj /**
2590cc5e210SSenthil Nathan Thangaraj * pm_setup() - PM service setup.
2600cc5e210SSenthil Nathan Thangaraj *
2610cc5e210SSenthil Nathan Thangaraj * Return: On success, the initialization function must return 0.
2620cc5e210SSenthil Nathan Thangaraj * Any other return value will cause the framework to ignore
2630cc5e210SSenthil Nathan Thangaraj * the service.
2640cc5e210SSenthil Nathan Thangaraj *
2650cc5e210SSenthil Nathan Thangaraj * Initialization functions for Versal power management for
2660cc5e210SSenthil Nathan Thangaraj * communicaton with PMC.
2670cc5e210SSenthil Nathan Thangaraj *
2680cc5e210SSenthil Nathan Thangaraj * Called from sip_svc_setup initialization function with the
2690cc5e210SSenthil Nathan Thangaraj * rt_svc_init signature.
2700cc5e210SSenthil Nathan Thangaraj *
2710cc5e210SSenthil Nathan Thangaraj */
pm_setup(void)2720cc5e210SSenthil Nathan Thangaraj int32_t pm_setup(void)
2730cc5e210SSenthil Nathan Thangaraj {
2740cc5e210SSenthil Nathan Thangaraj int32_t ret = 0;
2750cc5e210SSenthil Nathan Thangaraj
2760cc5e210SSenthil Nathan Thangaraj pm_ipi_init(primary_proc);
2770cc5e210SSenthil Nathan Thangaraj pm_up = true;
278c0719d21SDevanshi Chauhan pwrdwn_req_received = false;
2790cc5e210SSenthil Nathan Thangaraj
2800cc5e210SSenthil Nathan Thangaraj /* register SGI handler for CPU power down request */
2810cc5e210SSenthil Nathan Thangaraj ret = request_intr_type_el3(CPU_PWR_DOWN_REQ_INTR, cpu_pwrdwn_req_handler);
2820cc5e210SSenthil Nathan Thangaraj if (ret != 0) {
2830cc5e210SSenthil Nathan Thangaraj WARN("BL31: registering SGI interrupt failed\n");
2840cc5e210SSenthil Nathan Thangaraj }
2850cc5e210SSenthil Nathan Thangaraj
2860cc5e210SSenthil Nathan Thangaraj /*
2870cc5e210SSenthil Nathan Thangaraj * Enable IPI IRQ
2880cc5e210SSenthil Nathan Thangaraj * assume the rich OS is OK to handle callback IRQs now.
2890cc5e210SSenthil Nathan Thangaraj * Even if we were wrong, it would not enable the IRQ in
2900cc5e210SSenthil Nathan Thangaraj * the GIC.
2910cc5e210SSenthil Nathan Thangaraj */
2920cc5e210SSenthil Nathan Thangaraj pm_ipi_irq_enable(primary_proc);
2930cc5e210SSenthil Nathan Thangaraj
2940cc5e210SSenthil Nathan Thangaraj ret = request_intr_type_el3(PLAT_VERSAL_IPI_IRQ, ipi_fiq_handler);
2950cc5e210SSenthil Nathan Thangaraj if (ret != 0) {
2960cc5e210SSenthil Nathan Thangaraj WARN("BL31: registering IPI interrupt failed\n");
2970cc5e210SSenthil Nathan Thangaraj }
2980cc5e210SSenthil Nathan Thangaraj
2990cc5e210SSenthil Nathan Thangaraj gicd_write_irouter(gicv3_driver_data->gicd_base, PLAT_VERSAL_IPI_IRQ, MODE);
3000cc5e210SSenthil Nathan Thangaraj
3010cc5e210SSenthil Nathan Thangaraj /* Register for idle callback during force power down/restart */
3020cc5e210SSenthil Nathan Thangaraj ret = (int32_t)pm_register_notifier(primary_proc->node_id, EVENT_CPU_PWRDWN,
3034fd510e0SRonak Jain 0x0U, 0x1U, SECURE);
3040cc5e210SSenthil Nathan Thangaraj if (ret != 0) {
3050cc5e210SSenthil Nathan Thangaraj WARN("BL31: registering idle callback for restart/force power down failed\n");
3060cc5e210SSenthil Nathan Thangaraj }
3070cc5e210SSenthil Nathan Thangaraj
3080cc5e210SSenthil Nathan Thangaraj return ret;
3090cc5e210SSenthil Nathan Thangaraj }
3100cc5e210SSenthil Nathan Thangaraj
3110cc5e210SSenthil Nathan Thangaraj /**
3120cc5e210SSenthil Nathan Thangaraj * eemi_psci_debugfs_handler() - EEMI API invoked from PSCI.
3130cc5e210SSenthil Nathan Thangaraj * @api_id: identifier for the API being called.
3140cc5e210SSenthil Nathan Thangaraj * @pm_arg: pointer to the argument data for the API call.
3150cc5e210SSenthil Nathan Thangaraj * @handle: Pointer to caller's context structure.
3164fd510e0SRonak Jain * @security_flag: SECURE or NON_SECURE.
3170cc5e210SSenthil Nathan Thangaraj *
3180cc5e210SSenthil Nathan Thangaraj * These EEMI APIs performs CPU specific power management tasks.
3190cc5e210SSenthil Nathan Thangaraj * These EEMI APIs are invoked either from PSCI or from debugfs in kernel.
3200cc5e210SSenthil Nathan Thangaraj * These calls require CPU specific processing before sending IPI request to
3210cc5e210SSenthil Nathan Thangaraj * Platform Management Controller. For example enable/disable CPU specific
3220cc5e210SSenthil Nathan Thangaraj * interrupts. This requires separate handler for these calls and may not be
3230cc5e210SSenthil Nathan Thangaraj * handled using common eemi handler.
3240cc5e210SSenthil Nathan Thangaraj *
3250cc5e210SSenthil Nathan Thangaraj * Return: If EEMI API found then, uintptr_t type address, else 0.
3260cc5e210SSenthil Nathan Thangaraj *
3270cc5e210SSenthil Nathan Thangaraj */
eemi_psci_debugfs_handler(uint32_t api_id,uint32_t * pm_arg,void * handle,uint32_t security_flag)3280cc5e210SSenthil Nathan Thangaraj static uintptr_t eemi_psci_debugfs_handler(uint32_t api_id, uint32_t *pm_arg,
3290cc5e210SSenthil Nathan Thangaraj void *handle, uint32_t security_flag)
3300cc5e210SSenthil Nathan Thangaraj {
3310cc5e210SSenthil Nathan Thangaraj enum pm_ret_status ret;
332*633cf6b7SNaman Trivedi uint32_t pm_api_id = api_id & API_ID_MASK;
3330cc5e210SSenthil Nathan Thangaraj
334*633cf6b7SNaman Trivedi switch (pm_api_id) {
3350cc5e210SSenthil Nathan Thangaraj
3360cc5e210SSenthil Nathan Thangaraj case (uint32_t)PM_SELF_SUSPEND:
3370cc5e210SSenthil Nathan Thangaraj ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
3380cc5e210SSenthil Nathan Thangaraj pm_arg[3], security_flag);
3390cc5e210SSenthil Nathan Thangaraj SMC_RET1(handle, (u_register_t)ret);
3400cc5e210SSenthil Nathan Thangaraj
3410cc5e210SSenthil Nathan Thangaraj case (uint32_t)PM_FORCE_POWERDOWN:
3420cc5e210SSenthil Nathan Thangaraj ret = pm_force_powerdown(pm_arg[0], (uint8_t)pm_arg[1], security_flag);
3430cc5e210SSenthil Nathan Thangaraj SMC_RET1(handle, (u_register_t)ret);
3440cc5e210SSenthil Nathan Thangaraj
3450cc5e210SSenthil Nathan Thangaraj case (uint32_t)PM_SYSTEM_SHUTDOWN:
3460cc5e210SSenthil Nathan Thangaraj ret = pm_system_shutdown(pm_arg[0], pm_arg[1], security_flag);
3470cc5e210SSenthil Nathan Thangaraj SMC_RET1(handle, (u_register_t)ret);
3480cc5e210SSenthil Nathan Thangaraj
3490cc5e210SSenthil Nathan Thangaraj default:
3500cc5e210SSenthil Nathan Thangaraj return (uintptr_t)0;
3510cc5e210SSenthil Nathan Thangaraj }
3520cc5e210SSenthil Nathan Thangaraj }
3530cc5e210SSenthil Nathan Thangaraj
3540cc5e210SSenthil Nathan Thangaraj /**
3550cc5e210SSenthil Nathan Thangaraj * TF_A_specific_handler() - SMC handler for TF-A specific functionality.
3560cc5e210SSenthil Nathan Thangaraj * @api_id: identifier for the API being called.
3570cc5e210SSenthil Nathan Thangaraj * @pm_arg: pointer to the argument data for the API call.
3580cc5e210SSenthil Nathan Thangaraj * @handle: Pointer to caller's context structure.
3594fd510e0SRonak Jain * @security_flag: SECURE or NON_SECURE.
3600cc5e210SSenthil Nathan Thangaraj *
3610cc5e210SSenthil Nathan Thangaraj * These EEMI calls performs functionality that does not require
3620cc5e210SSenthil Nathan Thangaraj * IPI transaction. The handler ends in TF-A and returns requested data to
3630cc5e210SSenthil Nathan Thangaraj * kernel from TF-A.
3640cc5e210SSenthil Nathan Thangaraj *
3650cc5e210SSenthil Nathan Thangaraj * Return: If TF-A specific API found then, uintptr_t type address, else 0
3660cc5e210SSenthil Nathan Thangaraj *
3670cc5e210SSenthil Nathan Thangaraj */
TF_A_specific_handler(uint32_t api_id,uint32_t * pm_arg,void * handle,uint32_t security_flag)3680cc5e210SSenthil Nathan Thangaraj static uintptr_t TF_A_specific_handler(uint32_t api_id, uint32_t *pm_arg,
3690cc5e210SSenthil Nathan Thangaraj void *handle, uint32_t security_flag)
3700cc5e210SSenthil Nathan Thangaraj {
3710cc5e210SSenthil Nathan Thangaraj switch (api_id) {
3720cc5e210SSenthil Nathan Thangaraj
3730cc5e210SSenthil Nathan Thangaraj case TF_A_FEATURE_CHECK:
3740cc5e210SSenthil Nathan Thangaraj {
3750cc5e210SSenthil Nathan Thangaraj enum pm_ret_status ret;
3760cc5e210SSenthil Nathan Thangaraj uint32_t result[PAYLOAD_ARG_CNT] = {0U};
3770cc5e210SSenthil Nathan Thangaraj
378e25fad87SDevanshi Chauhan ret = tfa_api_feature_check(pm_arg[0], result);
3790cc5e210SSenthil Nathan Thangaraj SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U));
3800cc5e210SSenthil Nathan Thangaraj }
3810cc5e210SSenthil Nathan Thangaraj
3820cc5e210SSenthil Nathan Thangaraj case TF_A_PM_REGISTER_SGI:
3830cc5e210SSenthil Nathan Thangaraj {
3840cc5e210SSenthil Nathan Thangaraj int32_t ret;
3850cc5e210SSenthil Nathan Thangaraj
3860cc5e210SSenthil Nathan Thangaraj ret = pm_register_sgi(pm_arg[0], pm_arg[1]);
3870cc5e210SSenthil Nathan Thangaraj if (ret != 0) {
3880cc5e210SSenthil Nathan Thangaraj SMC_RET1(handle, (uint32_t)PM_RET_ERROR_ARGS);
3890cc5e210SSenthil Nathan Thangaraj }
3900cc5e210SSenthil Nathan Thangaraj
3910cc5e210SSenthil Nathan Thangaraj SMC_RET1(handle, (uint32_t)PM_RET_SUCCESS);
3920cc5e210SSenthil Nathan Thangaraj }
3930cc5e210SSenthil Nathan Thangaraj
3940cc5e210SSenthil Nathan Thangaraj case PM_GET_CALLBACK_DATA:
3950cc5e210SSenthil Nathan Thangaraj {
3960cc5e210SSenthil Nathan Thangaraj uint32_t result[4] = {0};
3970cc5e210SSenthil Nathan Thangaraj enum pm_ret_status ret;
3980cc5e210SSenthil Nathan Thangaraj
3990cc5e210SSenthil Nathan Thangaraj ret = pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag, 1U);
4000cc5e210SSenthil Nathan Thangaraj if (ret != PM_RET_SUCCESS) {
4010cc5e210SSenthil Nathan Thangaraj result[0] = (uint32_t) ret;
4020cc5e210SSenthil Nathan Thangaraj }
4030cc5e210SSenthil Nathan Thangaraj
4040cc5e210SSenthil Nathan Thangaraj SMC_RET2(handle,
4050cc5e210SSenthil Nathan Thangaraj (uint64_t)result[0] | ((uint64_t)result[1] << 32U),
4060cc5e210SSenthil Nathan Thangaraj (uint64_t)result[2] | ((uint64_t)result[3] << 32U));
4070cc5e210SSenthil Nathan Thangaraj }
4080cc5e210SSenthil Nathan Thangaraj
4090cc5e210SSenthil Nathan Thangaraj case PM_GET_TRUSTZONE_VERSION:
4100cc5e210SSenthil Nathan Thangaraj SMC_RET1(handle, ((uint64_t)PM_RET_SUCCESS) |
4110cc5e210SSenthil Nathan Thangaraj (((uint64_t)TZ_VERSION) << 32U));
4120cc5e210SSenthil Nathan Thangaraj
4130cc5e210SSenthil Nathan Thangaraj default:
4140cc5e210SSenthil Nathan Thangaraj return (uintptr_t)0U;
4150cc5e210SSenthil Nathan Thangaraj }
4160cc5e210SSenthil Nathan Thangaraj }
4170cc5e210SSenthil Nathan Thangaraj
4180cc5e210SSenthil Nathan Thangaraj /**
4190cc5e210SSenthil Nathan Thangaraj * eemi_api_handler() - Prepare EEMI payload and perform IPI transaction.
4200cc5e210SSenthil Nathan Thangaraj * @api_id: identifier for the API being called.
4210cc5e210SSenthil Nathan Thangaraj * @pm_arg: pointer to the argument data for the API call.
4220cc5e210SSenthil Nathan Thangaraj * @handle: Pointer to caller's context structure.
4234fd510e0SRonak Jain * @security_flag: SECURE or NON_SECURE.
4240cc5e210SSenthil Nathan Thangaraj *
4250cc5e210SSenthil Nathan Thangaraj * EEMI - Embedded Energy Management Interface is AMD-Xilinx proprietary
4260cc5e210SSenthil Nathan Thangaraj * protocol to allow communication between power management controller and
4270cc5e210SSenthil Nathan Thangaraj * different processing clusters.
4280cc5e210SSenthil Nathan Thangaraj *
4290cc5e210SSenthil Nathan Thangaraj * This handler prepares EEMI protocol payload received from kernel and performs
4300cc5e210SSenthil Nathan Thangaraj * IPI transaction.
4310cc5e210SSenthil Nathan Thangaraj *
4320cc5e210SSenthil Nathan Thangaraj * Return: If EEMI API found then, uintptr_t type address, else 0
4330cc5e210SSenthil Nathan Thangaraj */
eemi_api_handler(uint32_t api_id,const uint32_t * pm_arg,void * handle,uint32_t security_flag)4340cc5e210SSenthil Nathan Thangaraj static uintptr_t eemi_api_handler(uint32_t api_id, const uint32_t *pm_arg,
4350cc5e210SSenthil Nathan Thangaraj void *handle, uint32_t security_flag)
4360cc5e210SSenthil Nathan Thangaraj {
4370cc5e210SSenthil Nathan Thangaraj enum pm_ret_status ret;
4380cc5e210SSenthil Nathan Thangaraj uint32_t buf[RET_PAYLOAD_ARG_CNT] = {0U};
4390cc5e210SSenthil Nathan Thangaraj uint32_t payload[PAYLOAD_ARG_CNT] = {0U};
4400cc5e210SSenthil Nathan Thangaraj uint32_t module_id;
4410cc5e210SSenthil Nathan Thangaraj
4420cc5e210SSenthil Nathan Thangaraj module_id = (api_id & MODULE_ID_MASK) >> 8U;
4430cc5e210SSenthil Nathan Thangaraj
4440cc5e210SSenthil Nathan Thangaraj PM_PACK_PAYLOAD7(payload, module_id, security_flag, api_id,
4450cc5e210SSenthil Nathan Thangaraj pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3],
4460cc5e210SSenthil Nathan Thangaraj pm_arg[4], pm_arg[5]);
4470cc5e210SSenthil Nathan Thangaraj
4480cc5e210SSenthil Nathan Thangaraj ret = pm_ipi_send_sync(primary_proc, payload, (uint32_t *)buf,
4490cc5e210SSenthil Nathan Thangaraj RET_PAYLOAD_ARG_CNT);
4500cc5e210SSenthil Nathan Thangaraj
4510cc5e210SSenthil Nathan Thangaraj SMC_RET4(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32U),
4520cc5e210SSenthil Nathan Thangaraj (uint64_t)buf[1] | ((uint64_t)buf[2] << 32U),
4530cc5e210SSenthil Nathan Thangaraj (uint64_t)buf[3] | ((uint64_t)buf[4] << 32U),
4540cc5e210SSenthil Nathan Thangaraj (uint64_t)buf[5]);
4550cc5e210SSenthil Nathan Thangaraj }
4560cc5e210SSenthil Nathan Thangaraj
4570cc5e210SSenthil Nathan Thangaraj /**
4580cc5e210SSenthil Nathan Thangaraj * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
4590cc5e210SSenthil Nathan Thangaraj * @smc_fid: Function Identifier.
4600cc5e210SSenthil Nathan Thangaraj * @x1: SMC64 Arguments from kernel.
4610cc5e210SSenthil Nathan Thangaraj * @x2: SMC64 Arguments from kernel.
4620cc5e210SSenthil Nathan Thangaraj * @x3: SMC64 Arguments from kernel (upper 32-bits).
4630cc5e210SSenthil Nathan Thangaraj * @x4: Unused.
4640cc5e210SSenthil Nathan Thangaraj * @cookie: Unused.
4650cc5e210SSenthil Nathan Thangaraj * @handle: Pointer to caller's context structure.
4664fd510e0SRonak Jain * @flags: SECURE or NON_SECURE.
4670cc5e210SSenthil Nathan Thangaraj *
4680cc5e210SSenthil Nathan Thangaraj * Return: Unused.
4690cc5e210SSenthil Nathan Thangaraj *
4700cc5e210SSenthil Nathan Thangaraj * Determines that smc_fid is valid and supported PM SMC Function ID from the
4710cc5e210SSenthil Nathan Thangaraj * list of pm_api_ids, otherwise completes the request with
4720cc5e210SSenthil Nathan Thangaraj * the unknown SMC Function ID.
4730cc5e210SSenthil Nathan Thangaraj *
4740cc5e210SSenthil Nathan Thangaraj * The SMC calls for PM service are forwarded from SIP Service SMC handler
4750cc5e210SSenthil Nathan Thangaraj * function with rt_svc_handle signature.
4760cc5e210SSenthil Nathan Thangaraj *
4770cc5e210SSenthil Nathan Thangaraj */
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)4780cc5e210SSenthil Nathan Thangaraj uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
4790cc5e210SSenthil Nathan Thangaraj uint64_t x4, const void *cookie, void *handle, uint64_t flags)
4800cc5e210SSenthil Nathan Thangaraj {
4810cc5e210SSenthil Nathan Thangaraj uintptr_t ret;
4820cc5e210SSenthil Nathan Thangaraj uint32_t pm_arg[PAYLOAD_ARG_CNT] = {0};
4834fd510e0SRonak Jain uint32_t security_flag = NON_SECURE;
4840cc5e210SSenthil Nathan Thangaraj uint32_t api_id;
4850cc5e210SSenthil Nathan Thangaraj bool status = false, status_tmp = false;
4860cc5e210SSenthil Nathan Thangaraj uint64_t x[4] = {x1, x2, x3, x4};
4870cc5e210SSenthil Nathan Thangaraj
4880cc5e210SSenthil Nathan Thangaraj /* Handle case where PM wasn't initialized properly */
4890cc5e210SSenthil Nathan Thangaraj if (pm_up == false) {
4900cc5e210SSenthil Nathan Thangaraj SMC_RET1(handle, SMC_UNK);
4910cc5e210SSenthil Nathan Thangaraj }
4920cc5e210SSenthil Nathan Thangaraj
4930cc5e210SSenthil Nathan Thangaraj /*
4940cc5e210SSenthil Nathan Thangaraj * Mark BIT24 payload (i.e 1st bit of pm_arg[3] ) as secure (0)
4950cc5e210SSenthil Nathan Thangaraj * if smc called is secure
4960cc5e210SSenthil Nathan Thangaraj *
4970cc5e210SSenthil Nathan Thangaraj * Add redundant macro call to immune the code from glitches
4980cc5e210SSenthil Nathan Thangaraj */
4990cc5e210SSenthil Nathan Thangaraj SECURE_REDUNDANT_CALL(status, status_tmp, is_caller_secure, flags);
5000cc5e210SSenthil Nathan Thangaraj if ((status != false) && (status_tmp != false)) {
5014fd510e0SRonak Jain security_flag = SECURE;
5020cc5e210SSenthil Nathan Thangaraj }
5030cc5e210SSenthil Nathan Thangaraj
5040cc5e210SSenthil Nathan Thangaraj if ((smc_fid & FUNCID_NUM_MASK) == PASS_THROUGH_FW_CMD_ID) {
5050cc5e210SSenthil Nathan Thangaraj api_id = lower_32_bits(x[0]);
5060cc5e210SSenthil Nathan Thangaraj
5070cc5e210SSenthil Nathan Thangaraj EXTRACT_ARGS(pm_arg, x);
5080cc5e210SSenthil Nathan Thangaraj
509*633cf6b7SNaman Trivedi ret = eemi_psci_debugfs_handler(api_id, pm_arg, handle, (uint32_t)flags);
510*633cf6b7SNaman Trivedi if (ret != (uintptr_t)0) {
511*633cf6b7SNaman Trivedi return ret;
512*633cf6b7SNaman Trivedi }
513*633cf6b7SNaman Trivedi
5140cc5e210SSenthil Nathan Thangaraj return eemi_api_handler(api_id, pm_arg, handle, security_flag);
5150cc5e210SSenthil Nathan Thangaraj }
5160cc5e210SSenthil Nathan Thangaraj
5170cc5e210SSenthil Nathan Thangaraj pm_arg[0] = (uint32_t)x1;
5180cc5e210SSenthil Nathan Thangaraj pm_arg[1] = (uint32_t)(x1 >> 32U);
5190cc5e210SSenthil Nathan Thangaraj pm_arg[2] = (uint32_t)x2;
5200cc5e210SSenthil Nathan Thangaraj pm_arg[3] = (uint32_t)(x2 >> 32U);
5210cc5e210SSenthil Nathan Thangaraj pm_arg[4] = (uint32_t)x3;
5220cc5e210SSenthil Nathan Thangaraj (void)(x4);
5230cc5e210SSenthil Nathan Thangaraj api_id = smc_fid & FUNCID_NUM_MASK;
5240cc5e210SSenthil Nathan Thangaraj
5250cc5e210SSenthil Nathan Thangaraj ret = TF_A_specific_handler(api_id, pm_arg, handle, security_flag);
5260cc5e210SSenthil Nathan Thangaraj
5270cc5e210SSenthil Nathan Thangaraj return ret;
5280cc5e210SSenthil Nathan Thangaraj }
529