xref: /rk3399_ARM-atf/services/std_svc/lfa/lfa_main.c (revision 3b98554064bf572b9781720f935a097761f707b5)
1cf48f49fSManish V Badarkhe /*
2cf48f49fSManish V Badarkhe  * Copyright (c) 2025, Arm Limited. All rights reserved.
310f81c86SVarun Wadekar  * Copyright (c) 2025, NVIDIA Corporation. All rights reserved.
4cf48f49fSManish V Badarkhe  *
5cf48f49fSManish V Badarkhe  * SPDX-License-Identifier: BSD-3-Clause
6cf48f49fSManish V Badarkhe  */
7cf48f49fSManish V Badarkhe 
807de22d2SManish V Badarkhe #include <errno.h>
9c0d32ee6Sazimmerman #include <string.h>
1007de22d2SManish V Badarkhe 
11c8e08212SVarun Wadekar #include <lib/spinlock.h>
12b9dee50cSManish V Badarkhe #include <plat/common/platform.h>
13b9dee50cSManish V Badarkhe #include <services/bl31_lfa.h>
14cf48f49fSManish V Badarkhe #include <services/lfa_svc.h>
15b9dee50cSManish V Badarkhe #include <services/rmmd_rmm_lfa.h>
16cf48f49fSManish V Badarkhe #include <smccc_helpers.h>
17cf48f49fSManish V Badarkhe 
18b9dee50cSManish V Badarkhe static uint32_t lfa_component_count;
19b9dee50cSManish V Badarkhe static plat_lfa_component_info_t *lfa_components;
20b9dee50cSManish V Badarkhe static struct lfa_component_status current_activation;
21b9dee50cSManish V Badarkhe static bool is_lfa_initialized;
22b9dee50cSManish V Badarkhe 
23c8e08212SVarun Wadekar /*
24c8e08212SVarun Wadekar  * Spinlock to serialize LFA operations (PRIME, ACTIVATE).
25c8e08212SVarun Wadekar  * This ensures that these calls from different CPUs are properly
26c8e08212SVarun Wadekar  * serialized and do not execute concurrently, while still allowing
27c8e08212SVarun Wadekar  * the same operation to be invoked from any CPU.
28c8e08212SVarun Wadekar  */
29c8e08212SVarun Wadekar static spinlock_t lfa_lock;
30c8e08212SVarun Wadekar 
lfa_reset_activation(void)31b9dee50cSManish V Badarkhe void lfa_reset_activation(void)
32b9dee50cSManish V Badarkhe {
33b9dee50cSManish V Badarkhe 	current_activation.component_id = LFA_INVALID_COMPONENT;
34b9dee50cSManish V Badarkhe 	current_activation.prime_status = PRIME_NONE;
3507de22d2SManish V Badarkhe 	current_activation.cpu_rendezvous_required = false;
36b9dee50cSManish V Badarkhe }
37b9dee50cSManish V Badarkhe 
convert_to_lfa_error(int ret)3867fa182fSManish V Badarkhe static int convert_to_lfa_error(int ret)
3967fa182fSManish V Badarkhe {
4067fa182fSManish V Badarkhe 	switch (ret) {
4167fa182fSManish V Badarkhe 	case 0:
4267fa182fSManish V Badarkhe 		return LFA_SUCCESS;
4367fa182fSManish V Badarkhe 	case -EAUTH:
4467fa182fSManish V Badarkhe 		return LFA_AUTH_ERROR;
4567fa182fSManish V Badarkhe 	case -ENOMEM:
4667fa182fSManish V Badarkhe 		return LFA_NO_MEMORY;
4767fa182fSManish V Badarkhe 	default:
4867fa182fSManish V Badarkhe 		return LFA_DEVICE_ERROR;
4967fa182fSManish V Badarkhe 	}
5067fa182fSManish V Badarkhe }
5167fa182fSManish V Badarkhe 
lfa_initialize_components(void)52b9dee50cSManish V Badarkhe static bool lfa_initialize_components(void)
53b9dee50cSManish V Badarkhe {
54b9dee50cSManish V Badarkhe 	lfa_component_count = plat_lfa_get_components(&lfa_components);
55b9dee50cSManish V Badarkhe 
56b9dee50cSManish V Badarkhe 	if (lfa_component_count == 0U || lfa_components == NULL) {
57b9dee50cSManish V Badarkhe 		/* unlikely to reach here */
58b9dee50cSManish V Badarkhe 		ERROR("Invalid LFA component setup: count = 0 or components are NULL");
59b9dee50cSManish V Badarkhe 		return false;
60b9dee50cSManish V Badarkhe 	}
61b9dee50cSManish V Badarkhe 
62b9dee50cSManish V Badarkhe 	return true;
63b9dee50cSManish V Badarkhe }
64b9dee50cSManish V Badarkhe 
get_fw_activation_flags(uint32_t fw_seq_id)6506a6f296SManish V Badarkhe static uint64_t get_fw_activation_flags(uint32_t fw_seq_id)
6606a6f296SManish V Badarkhe {
6706a6f296SManish V Badarkhe 	const plat_lfa_component_info_t *comp =
6806a6f296SManish V Badarkhe 				&lfa_components[fw_seq_id];
6906a6f296SManish V Badarkhe 	uint64_t flags = 0ULL;
7006a6f296SManish V Badarkhe 
7106a6f296SManish V Badarkhe 	flags |= ((comp->activator == NULL ? 0ULL : 1ULL)
7206a6f296SManish V Badarkhe 		 << LFA_ACTIVATION_CAPABLE_SHIFT);
7306a6f296SManish V Badarkhe 	flags |= (uint64_t)(comp->activation_pending)
7406a6f296SManish V Badarkhe 		 << LFA_ACTIVATION_PENDING_SHIFT;
7506a6f296SManish V Badarkhe 
7606a6f296SManish V Badarkhe 	if (comp->activator != NULL) {
7706a6f296SManish V Badarkhe 		flags |= ((comp->activator->may_reset_cpu ? 1ULL : 0ULL)
7806a6f296SManish V Badarkhe 			 << LFA_MAY_RESET_CPU_SHIFT);
7906a6f296SManish V Badarkhe 		flags |= ((comp->activator->cpu_rendezvous_required ? 0ULL : 1ULL)
8006a6f296SManish V Badarkhe 			 << LFA_CPU_RENDEZVOUS_OPTIONAL_SHIFT);
8106a6f296SManish V Badarkhe 	}
8206a6f296SManish V Badarkhe 
8306a6f296SManish V Badarkhe 	return flags;
8406a6f296SManish V Badarkhe }
8506a6f296SManish V Badarkhe 
lfa_cancel(uint32_t component_id)863f7b2862SManish V Badarkhe static int lfa_cancel(uint32_t component_id)
873f7b2862SManish V Badarkhe {
883f7b2862SManish V Badarkhe 	int ret = LFA_SUCCESS;
893f7b2862SManish V Badarkhe 
903f7b2862SManish V Badarkhe 	if (lfa_component_count == 0U) {
913f7b2862SManish V Badarkhe 		return LFA_WRONG_STATE;
923f7b2862SManish V Badarkhe 	}
933f7b2862SManish V Badarkhe 
943f7b2862SManish V Badarkhe 	/* Check if component ID is in range. */
953f7b2862SManish V Badarkhe 	if ((component_id >= lfa_component_count) ||
963f7b2862SManish V Badarkhe 	    (component_id != current_activation.component_id)) {
973f7b2862SManish V Badarkhe 		return LFA_INVALID_PARAMETERS;
983f7b2862SManish V Badarkhe 	}
993f7b2862SManish V Badarkhe 
1003f7b2862SManish V Badarkhe 	ret = plat_lfa_cancel(component_id);
1013f7b2862SManish V Badarkhe 	if (ret != LFA_SUCCESS) {
1023f7b2862SManish V Badarkhe 		return LFA_BUSY;
1033f7b2862SManish V Badarkhe 	}
1043f7b2862SManish V Badarkhe 
1053f7b2862SManish V Badarkhe 	/* TODO: add proper termination prime and activate phases */
1063f7b2862SManish V Badarkhe 	lfa_reset_activation();
1073f7b2862SManish V Badarkhe 
1083f7b2862SManish V Badarkhe 	return ret;
1093f7b2862SManish V Badarkhe }
1103f7b2862SManish V Badarkhe 
lfa_activate(uint32_t component_id,uint64_t flags,uint64_t ep_address,uint64_t context_id)11107de22d2SManish V Badarkhe static int lfa_activate(uint32_t component_id, uint64_t flags,
11207de22d2SManish V Badarkhe 			uint64_t ep_address, uint64_t context_id)
11307de22d2SManish V Badarkhe {
11407de22d2SManish V Badarkhe 	int ret = LFA_ACTIVATION_FAILED;
11507de22d2SManish V Badarkhe 	struct lfa_component_ops *activator;
11607de22d2SManish V Badarkhe 
11707de22d2SManish V Badarkhe 	if ((lfa_component_count == 0U) ||
11807de22d2SManish V Badarkhe 	    (!lfa_components[component_id].activation_pending) ||
11907de22d2SManish V Badarkhe 	    (current_activation.prime_status != PRIME_COMPLETE)) {
12007de22d2SManish V Badarkhe 		return LFA_COMPONENT_WRONG_STATE;
12107de22d2SManish V Badarkhe 	}
12207de22d2SManish V Badarkhe 
12307de22d2SManish V Badarkhe 	/* Check if fw_seq_id is in range. */
12407de22d2SManish V Badarkhe 	if ((component_id >= lfa_component_count) ||
12507de22d2SManish V Badarkhe 	    (current_activation.component_id != component_id)) {
12607de22d2SManish V Badarkhe 		return LFA_INVALID_PARAMETERS;
12707de22d2SManish V Badarkhe 	}
12807de22d2SManish V Badarkhe 
12907de22d2SManish V Badarkhe 	if (lfa_components[component_id].activator == NULL) {
13007de22d2SManish V Badarkhe 		return LFA_NOT_SUPPORTED;
13107de22d2SManish V Badarkhe 	}
13207de22d2SManish V Badarkhe 
1335084b7f1SManish V Badarkhe 	ret = plat_lfa_notify_activate(component_id);
1345084b7f1SManish V Badarkhe 	if (ret != 0) {
1355084b7f1SManish V Badarkhe 		return LFA_ACTIVATION_FAILED;
1365084b7f1SManish V Badarkhe 	}
1375084b7f1SManish V Badarkhe 
13807de22d2SManish V Badarkhe 	activator = lfa_components[component_id].activator;
13907de22d2SManish V Badarkhe 	if (activator->activate != NULL) {
14007de22d2SManish V Badarkhe 		/*
14107de22d2SManish V Badarkhe 		 * Pass skip_cpu_rendezvous (flag[0]) only if flag[0]==1
14207de22d2SManish V Badarkhe 		 * & CPU_RENDEZVOUS is not required.
14307de22d2SManish V Badarkhe 		 */
14407de22d2SManish V Badarkhe 		if (flags & LFA_SKIP_CPU_RENDEZVOUS_BIT) {
14507de22d2SManish V Badarkhe 			if (!activator->cpu_rendezvous_required) {
14607de22d2SManish V Badarkhe 				INFO("Skipping rendezvous requested by caller.\n");
14707de22d2SManish V Badarkhe 				current_activation.cpu_rendezvous_required = false;
14807de22d2SManish V Badarkhe 			}
14907de22d2SManish V Badarkhe 			/*
15007de22d2SManish V Badarkhe 			 * Return error if caller tries to skip rendezvous when
15107de22d2SManish V Badarkhe 			 * it is required.
15207de22d2SManish V Badarkhe 			 */
15307de22d2SManish V Badarkhe 			else {
15407de22d2SManish V Badarkhe 				ERROR("CPU Rendezvous is required, can't skip.\n");
15507de22d2SManish V Badarkhe 				return LFA_INVALID_PARAMETERS;
15607de22d2SManish V Badarkhe 			}
15707de22d2SManish V Badarkhe 		}
15807de22d2SManish V Badarkhe 
15907de22d2SManish V Badarkhe 		ret = activator->activate(&current_activation, ep_address,
16007de22d2SManish V Badarkhe 					  context_id);
16107de22d2SManish V Badarkhe 	}
16207de22d2SManish V Badarkhe 
16307de22d2SManish V Badarkhe 	lfa_components[component_id].activation_pending = false;
16407de22d2SManish V Badarkhe 
16507de22d2SManish V Badarkhe 	return ret;
16607de22d2SManish V Badarkhe }
16707de22d2SManish V Badarkhe 
lfa_prime(uint32_t component_id,uint64_t * flags)16867fa182fSManish V Badarkhe static int lfa_prime(uint32_t component_id, uint64_t *flags)
16967fa182fSManish V Badarkhe {
17067fa182fSManish V Badarkhe 	int ret = LFA_SUCCESS;
17167fa182fSManish V Badarkhe 	struct lfa_component_ops *activator;
17267fa182fSManish V Badarkhe 
17367fa182fSManish V Badarkhe 	if (lfa_component_count == 0U ||
17467fa182fSManish V Badarkhe 	    !lfa_components[component_id].activation_pending) {
17567fa182fSManish V Badarkhe 		return LFA_WRONG_STATE;
17667fa182fSManish V Badarkhe 	}
17767fa182fSManish V Badarkhe 
17867fa182fSManish V Badarkhe 	/* Check if fw_seq_id is in range. */
17967fa182fSManish V Badarkhe 	if (component_id >= lfa_component_count) {
18067fa182fSManish V Badarkhe 		return LFA_INVALID_PARAMETERS;
18167fa182fSManish V Badarkhe 	}
18267fa182fSManish V Badarkhe 
18367fa182fSManish V Badarkhe 	if (lfa_components[component_id].activator == NULL) {
18467fa182fSManish V Badarkhe 		return LFA_NOT_SUPPORTED;
18567fa182fSManish V Badarkhe 	}
18667fa182fSManish V Badarkhe 
18767fa182fSManish V Badarkhe 	switch (current_activation.prime_status) {
18867fa182fSManish V Badarkhe 	case PRIME_NONE:
18967fa182fSManish V Badarkhe 		current_activation.component_id = component_id;
19067fa182fSManish V Badarkhe 		current_activation.prime_status = PRIME_STARTED;
19167fa182fSManish V Badarkhe 		break;
19267fa182fSManish V Badarkhe 
19367fa182fSManish V Badarkhe 	case PRIME_STARTED:
19467fa182fSManish V Badarkhe 		if (current_activation.component_id != component_id) {
19567fa182fSManish V Badarkhe 			/* Mismatched component trying to continue PRIME - error */
19667fa182fSManish V Badarkhe 			return LFA_WRONG_STATE;
19767fa182fSManish V Badarkhe 		}
19867fa182fSManish V Badarkhe 		break;
19967fa182fSManish V Badarkhe 
20067fa182fSManish V Badarkhe 	case PRIME_COMPLETE:
20167fa182fSManish V Badarkhe 	default:
20267fa182fSManish V Badarkhe 		break;
20367fa182fSManish V Badarkhe 	}
20467fa182fSManish V Badarkhe 
205*59b826ceSVarun Wadekar 	/* Initialise the flags to start with. Only valid if ret=LFA_SUCCESS. */
206*59b826ceSVarun Wadekar 	*flags = 0ULL;
20767fa182fSManish V Badarkhe 
208*59b826ceSVarun Wadekar 	ret = plat_lfa_load_auth_image(component_id);
209*59b826ceSVarun Wadekar 	if (ret == 0) {
21067fa182fSManish V Badarkhe 		activator = lfa_components[component_id].activator;
21167fa182fSManish V Badarkhe 		if (activator->prime != NULL) {
21267fa182fSManish V Badarkhe 			ret = activator->prime(&current_activation);
21367fa182fSManish V Badarkhe 			if (ret != LFA_SUCCESS) {
21467fa182fSManish V Badarkhe 				/*
21567fa182fSManish V Badarkhe 				* TODO: it should be LFA_PRIME_FAILED but specification
21667fa182fSManish V Badarkhe 				* has not define this error yet
21767fa182fSManish V Badarkhe 				*/
21867fa182fSManish V Badarkhe 				return ret;
21967fa182fSManish V Badarkhe 			}
22067fa182fSManish V Badarkhe 		}
22167fa182fSManish V Badarkhe 
22267fa182fSManish V Badarkhe 		current_activation.prime_status = PRIME_COMPLETE;
223*59b826ceSVarun Wadekar 	}
22467fa182fSManish V Badarkhe 
225*59b826ceSVarun Wadekar 	/*
226*59b826ceSVarun Wadekar 	 * Set lfa_flags to indicate that LFA_PRIME must be called again and
227*59b826ceSVarun Wadekar 	 * reset ret to 0, as LFA_PRIME must return LFA_SUCCESS if it is
228*59b826ceSVarun Wadekar 	 * incomplete.
229*59b826ceSVarun Wadekar 	 */
230*59b826ceSVarun Wadekar 	if (ret == -EAGAIN) {
231*59b826ceSVarun Wadekar 		ret = 0;
232*59b826ceSVarun Wadekar 		*flags = LFA_CALL_AGAIN;
233*59b826ceSVarun Wadekar 	}
23467fa182fSManish V Badarkhe 
235*59b826ceSVarun Wadekar 	return convert_to_lfa_error(ret);
23667fa182fSManish V Badarkhe }
23767fa182fSManish V Badarkhe 
lfa_is_prime_complete(uint32_t lfa_component_id)238b17fc0a6SManish V Badarkhe bool lfa_is_prime_complete(uint32_t lfa_component_id)
239ce78f3cdSManish V Badarkhe {
240b17fc0a6SManish V Badarkhe 	if (lfa_component_id >= lfa_component_count) {
241ce78f3cdSManish V Badarkhe 		return false;
242ce78f3cdSManish V Badarkhe 	}
243ce78f3cdSManish V Badarkhe 
244b17fc0a6SManish V Badarkhe 	return (current_activation.component_id == lfa_component_id &&
245ce78f3cdSManish V Badarkhe 		current_activation.prime_status == PRIME_COMPLETE &&
246b17fc0a6SManish V Badarkhe 		lfa_components[lfa_component_id].activation_pending == true);
247ce78f3cdSManish V Badarkhe }
248ce78f3cdSManish V Badarkhe 
lfa_setup(void)249cf48f49fSManish V Badarkhe int lfa_setup(void)
250cf48f49fSManish V Badarkhe {
251b9dee50cSManish V Badarkhe 	is_lfa_initialized = lfa_initialize_components();
252b9dee50cSManish V Badarkhe 	if (!is_lfa_initialized) {
253b9dee50cSManish V Badarkhe 		return -1;
254b9dee50cSManish V Badarkhe 	}
255b9dee50cSManish V Badarkhe 
256b9dee50cSManish V Badarkhe 	lfa_reset_activation();
257b9dee50cSManish V Badarkhe 
258b9dee50cSManish V Badarkhe 	return 0;
259cf48f49fSManish V Badarkhe }
260cf48f49fSManish V Badarkhe 
lfa_smc_handler(uint32_t smc_fid,u_register_t x1,u_register_t x2,u_register_t x3,u_register_t x4,void * cookie,void * handle,u_register_t flags)261cf48f49fSManish V Badarkhe uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
262cf48f49fSManish V Badarkhe 			 u_register_t x3, u_register_t x4, void *cookie,
263cf48f49fSManish V Badarkhe 			 void *handle, u_register_t flags)
264cf48f49fSManish V Badarkhe {
26506a6f296SManish V Badarkhe 	uint64_t retx1, retx2;
26667fa182fSManish V Badarkhe 	uint64_t lfa_flags;
26706a6f296SManish V Badarkhe 	uint8_t *uuid_p;
26806a6f296SManish V Badarkhe 	uint32_t fw_seq_id = (uint32_t)x1;
2693f7b2862SManish V Badarkhe 	int ret;
27006a6f296SManish V Badarkhe 
271cf48f49fSManish V Badarkhe 	/**
272cf48f49fSManish V Badarkhe 	 * TODO: Acquire serialization lock.
273cf48f49fSManish V Badarkhe 	 */
274b9dee50cSManish V Badarkhe 
275b9dee50cSManish V Badarkhe 	if (!is_lfa_initialized) {
276b9dee50cSManish V Badarkhe 		return LFA_NOT_SUPPORTED;
277b9dee50cSManish V Badarkhe 	}
278b9dee50cSManish V Badarkhe 
279cf48f49fSManish V Badarkhe 	switch (smc_fid) {
280cf48f49fSManish V Badarkhe 	case LFA_VERSION:
281cf48f49fSManish V Badarkhe 		SMC_RET1(handle, LFA_VERSION_VAL);
282cf48f49fSManish V Badarkhe 		break;
283cf48f49fSManish V Badarkhe 
284cf48f49fSManish V Badarkhe 	case LFA_FEATURES:
285cf48f49fSManish V Badarkhe 		SMC_RET1(handle, is_lfa_fid(x1) ? LFA_SUCCESS : LFA_NOT_SUPPORTED);
286cf48f49fSManish V Badarkhe 		break;
287cf48f49fSManish V Badarkhe 
288cf48f49fSManish V Badarkhe 	case LFA_GET_INFO:
289b9dee50cSManish V Badarkhe 		/**
290b9dee50cSManish V Badarkhe 		 * The current specification limits this input parameter to be zero for
291b9dee50cSManish V Badarkhe 		 * version 1.0 of LFA
292b9dee50cSManish V Badarkhe 		 */
293b9dee50cSManish V Badarkhe 		if (x1 == 0ULL) {
294b9dee50cSManish V Badarkhe 			SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0);
295b9dee50cSManish V Badarkhe 		} else {
296b9dee50cSManish V Badarkhe 			SMC_RET1(handle, LFA_INVALID_PARAMETERS);
297b9dee50cSManish V Badarkhe 		}
298cf48f49fSManish V Badarkhe 		break;
299cf48f49fSManish V Badarkhe 
300cf48f49fSManish V Badarkhe 	case LFA_GET_INVENTORY:
30106a6f296SManish V Badarkhe 		if (lfa_component_count == 0U) {
30206a6f296SManish V Badarkhe 			SMC_RET1(handle, LFA_WRONG_STATE);
30306a6f296SManish V Badarkhe 		}
30406a6f296SManish V Badarkhe 
30506a6f296SManish V Badarkhe 		/*
30606a6f296SManish V Badarkhe 		 * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan
30706a6f296SManish V Badarkhe 		 * platform firmware and create a valid number of firmware components.
30806a6f296SManish V Badarkhe 		 */
30906a6f296SManish V Badarkhe 		if (fw_seq_id >= lfa_component_count) {
31006a6f296SManish V Badarkhe 			SMC_RET1(handle, LFA_INVALID_PARAMETERS);
31106a6f296SManish V Badarkhe 		}
31206a6f296SManish V Badarkhe 
31306a6f296SManish V Badarkhe 		/*
31406a6f296SManish V Badarkhe 		 * grab the UUID of asked fw_seq_id and set the return UUID
31506a6f296SManish V Badarkhe 		 * variables
31606a6f296SManish V Badarkhe 		 */
31706a6f296SManish V Badarkhe 		uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid;
31806a6f296SManish V Badarkhe 		memcpy(&retx1, uuid_p, sizeof(uint64_t));
31906a6f296SManish V Badarkhe 		memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t));
32006a6f296SManish V Badarkhe 
32106a6f296SManish V Badarkhe 		/*
32206a6f296SManish V Badarkhe 		 * check the given fw_seq_id's update available
32306a6f296SManish V Badarkhe 		 * and accordingly set the active_pending flag
32406a6f296SManish V Badarkhe 		 */
32506a6f296SManish V Badarkhe 		lfa_components[fw_seq_id].activation_pending =
32606a6f296SManish V Badarkhe 				is_plat_lfa_activation_pending(fw_seq_id);
32706a6f296SManish V Badarkhe 
32806a6f296SManish V Badarkhe 		INFO("Component %lu %s live activation:\n", x1,
32906a6f296SManish V Badarkhe 		      lfa_components[fw_seq_id].activator ? "supports" :
33006a6f296SManish V Badarkhe 		      "does not support");
33106a6f296SManish V Badarkhe 
33206a6f296SManish V Badarkhe 		if (lfa_components[fw_seq_id].activator != NULL) {
33306a6f296SManish V Badarkhe 			INFO("Activation pending: %s\n",
33406a6f296SManish V Badarkhe 			      lfa_components[fw_seq_id].activation_pending ? "true" : "false");
33506a6f296SManish V Badarkhe 		}
33606a6f296SManish V Badarkhe 
33706a6f296SManish V Badarkhe 		INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2);
33806a6f296SManish V Badarkhe 
33906a6f296SManish V Badarkhe 		SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id));
34006a6f296SManish V Badarkhe 
341cf48f49fSManish V Badarkhe 		break;
342cf48f49fSManish V Badarkhe 
343cf48f49fSManish V Badarkhe 	case LFA_PRIME:
344c8e08212SVarun Wadekar 		/*
345c8e08212SVarun Wadekar 		 * Acquire lock to serialize PRIME operations across CPUs.
346c8e08212SVarun Wadekar 		 * This ensures that multiple PRIME calls to the same component
347c8e08212SVarun Wadekar 		 * do not execute concurrently, even if issued from different
348c8e08212SVarun Wadekar 		 * CPUs.
349c8e08212SVarun Wadekar 		 */
350c8e08212SVarun Wadekar 		if (!spin_trylock(&lfa_lock)) {
351c8e08212SVarun Wadekar 			SMC_RET1(handle, LFA_BUSY);
352c8e08212SVarun Wadekar 		}
353c8e08212SVarun Wadekar 
35467fa182fSManish V Badarkhe 		ret = lfa_prime(x1, &lfa_flags);
355c8e08212SVarun Wadekar 
356c8e08212SVarun Wadekar 		spin_unlock(&lfa_lock);
357c8e08212SVarun Wadekar 
35867fa182fSManish V Badarkhe 		if (ret != LFA_SUCCESS) {
35967fa182fSManish V Badarkhe 			SMC_RET1(handle, ret);
36067fa182fSManish V Badarkhe 		} else {
36167fa182fSManish V Badarkhe 			SMC_RET2(handle, ret, lfa_flags);
36267fa182fSManish V Badarkhe 		}
363cf48f49fSManish V Badarkhe 		break;
364cf48f49fSManish V Badarkhe 
365cf48f49fSManish V Badarkhe 	case LFA_ACTIVATE:
36607de22d2SManish V Badarkhe 		ret = lfa_activate(fw_seq_id, x2, x3, x4);
36707de22d2SManish V Badarkhe 		/* TODO: implement activate again */
36807de22d2SManish V Badarkhe 		SMC_RET2(handle, ret, 0ULL);
36907de22d2SManish V Badarkhe 
370cf48f49fSManish V Badarkhe 		break;
371cf48f49fSManish V Badarkhe 
372cf48f49fSManish V Badarkhe 	case LFA_CANCEL:
3733f7b2862SManish V Badarkhe 		ret = lfa_cancel(x1);
3743f7b2862SManish V Badarkhe 		SMC_RET1(handle, ret);
375cf48f49fSManish V Badarkhe 		break;
376cf48f49fSManish V Badarkhe 
377cf48f49fSManish V Badarkhe 	default:
378cf48f49fSManish V Badarkhe 		WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid);
379cf48f49fSManish V Badarkhe 		SMC_RET1(handle, SMC_UNK);
380cf48f49fSManish V Badarkhe 		break; /* unreachable */
381cf48f49fSManish V Badarkhe 
382cf48f49fSManish V Badarkhe 	}
383cf48f49fSManish V Badarkhe 
384cf48f49fSManish V Badarkhe 	SMC_RET1(handle, SMC_UNK);
385cf48f49fSManish V Badarkhe 
386cf48f49fSManish V Badarkhe 	return 0;
387cf48f49fSManish V Badarkhe }
388