xref: /rk3399_ARM-atf/plat/amd/versal2/pm_service/pm_svc_main.c (revision 047b1b9afce13993db8363f55be6e0cbfb69bf0d)
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