xref: /rk3399_ARM-atf/services/std_svc/lfa/lfa_main.c (revision 07de22d29e58edcaabfcfe313771ea1062a75bc6)
1cf48f49fSManish V Badarkhe /*
2cf48f49fSManish V Badarkhe  * Copyright (c) 2025, Arm Limited. All rights reserved.
3cf48f49fSManish V Badarkhe  *
4cf48f49fSManish V Badarkhe  * SPDX-License-Identifier: BSD-3-Clause
5cf48f49fSManish V Badarkhe  */
6cf48f49fSManish V Badarkhe 
7*07de22d2SManish V Badarkhe #include <errno.h>
8*07de22d2SManish V Badarkhe 
9b9dee50cSManish V Badarkhe #include <plat/common/platform.h>
10b9dee50cSManish V Badarkhe #include <services/bl31_lfa.h>
11cf48f49fSManish V Badarkhe #include <services/lfa_svc.h>
12b9dee50cSManish V Badarkhe #include <services/rmmd_rmm_lfa.h>
13cf48f49fSManish V Badarkhe #include <smccc_helpers.h>
14cf48f49fSManish V Badarkhe 
15b9dee50cSManish V Badarkhe static uint32_t lfa_component_count;
16b9dee50cSManish V Badarkhe static plat_lfa_component_info_t *lfa_components;
17b9dee50cSManish V Badarkhe static struct lfa_component_status current_activation;
18b9dee50cSManish V Badarkhe static bool is_lfa_initialized;
19b9dee50cSManish V Badarkhe 
20b9dee50cSManish V Badarkhe void lfa_reset_activation(void)
21b9dee50cSManish V Badarkhe {
22b9dee50cSManish V Badarkhe 	current_activation.component_id = LFA_INVALID_COMPONENT;
23b9dee50cSManish V Badarkhe 	current_activation.prime_status = PRIME_NONE;
24*07de22d2SManish V Badarkhe 	current_activation.cpu_rendezvous_required = false;
25b9dee50cSManish V Badarkhe }
26b9dee50cSManish V Badarkhe 
2767fa182fSManish V Badarkhe static int convert_to_lfa_error(int ret)
2867fa182fSManish V Badarkhe {
2967fa182fSManish V Badarkhe 	switch (ret) {
3067fa182fSManish V Badarkhe 	case 0:
3167fa182fSManish V Badarkhe 		return LFA_SUCCESS;
3267fa182fSManish V Badarkhe 	case -EAUTH:
3367fa182fSManish V Badarkhe 		return LFA_AUTH_ERROR;
3467fa182fSManish V Badarkhe 	case -ENOMEM:
3567fa182fSManish V Badarkhe 		return LFA_NO_MEMORY;
3667fa182fSManish V Badarkhe 	default:
3767fa182fSManish V Badarkhe 		return LFA_DEVICE_ERROR;
3867fa182fSManish V Badarkhe 	}
3967fa182fSManish V Badarkhe }
4067fa182fSManish V Badarkhe 
41b9dee50cSManish V Badarkhe static bool lfa_initialize_components(void)
42b9dee50cSManish V Badarkhe {
43b9dee50cSManish V Badarkhe 	lfa_component_count = plat_lfa_get_components(&lfa_components);
44b9dee50cSManish V Badarkhe 
45b9dee50cSManish V Badarkhe 	if (lfa_component_count == 0U || lfa_components == NULL) {
46b9dee50cSManish V Badarkhe 		/* unlikely to reach here */
47b9dee50cSManish V Badarkhe 		ERROR("Invalid LFA component setup: count = 0 or components are NULL");
48b9dee50cSManish V Badarkhe 		return false;
49b9dee50cSManish V Badarkhe 	}
50b9dee50cSManish V Badarkhe 
51b9dee50cSManish V Badarkhe 	return true;
52b9dee50cSManish V Badarkhe }
53b9dee50cSManish V Badarkhe 
5406a6f296SManish V Badarkhe static uint64_t get_fw_activation_flags(uint32_t fw_seq_id)
5506a6f296SManish V Badarkhe {
5606a6f296SManish V Badarkhe 	const plat_lfa_component_info_t *comp =
5706a6f296SManish V Badarkhe 				&lfa_components[fw_seq_id];
5806a6f296SManish V Badarkhe 	uint64_t flags = 0ULL;
5906a6f296SManish V Badarkhe 
6006a6f296SManish V Badarkhe 	flags |= ((comp->activator == NULL ? 0ULL : 1ULL)
6106a6f296SManish V Badarkhe 		 << LFA_ACTIVATION_CAPABLE_SHIFT);
6206a6f296SManish V Badarkhe 	flags |= (uint64_t)(comp->activation_pending)
6306a6f296SManish V Badarkhe 		 << LFA_ACTIVATION_PENDING_SHIFT;
6406a6f296SManish V Badarkhe 
6506a6f296SManish V Badarkhe 	if (comp->activator != NULL) {
6606a6f296SManish V Badarkhe 		flags |= ((comp->activator->may_reset_cpu ? 1ULL : 0ULL)
6706a6f296SManish V Badarkhe 			 << LFA_MAY_RESET_CPU_SHIFT);
6806a6f296SManish V Badarkhe 		flags |= ((comp->activator->cpu_rendezvous_required ? 0ULL : 1ULL)
6906a6f296SManish V Badarkhe 			 << LFA_CPU_RENDEZVOUS_OPTIONAL_SHIFT);
7006a6f296SManish V Badarkhe 	}
7106a6f296SManish V Badarkhe 
7206a6f296SManish V Badarkhe 	return flags;
7306a6f296SManish V Badarkhe }
7406a6f296SManish V Badarkhe 
753f7b2862SManish V Badarkhe static int lfa_cancel(uint32_t component_id)
763f7b2862SManish V Badarkhe {
773f7b2862SManish V Badarkhe 	int ret = LFA_SUCCESS;
783f7b2862SManish V Badarkhe 
793f7b2862SManish V Badarkhe 	if (lfa_component_count == 0U) {
803f7b2862SManish V Badarkhe 		return LFA_WRONG_STATE;
813f7b2862SManish V Badarkhe 	}
823f7b2862SManish V Badarkhe 
833f7b2862SManish V Badarkhe 	/* Check if component ID is in range. */
843f7b2862SManish V Badarkhe 	if ((component_id >= lfa_component_count) ||
853f7b2862SManish V Badarkhe 	    (component_id != current_activation.component_id)) {
863f7b2862SManish V Badarkhe 		return LFA_INVALID_PARAMETERS;
873f7b2862SManish V Badarkhe 	}
883f7b2862SManish V Badarkhe 
893f7b2862SManish V Badarkhe 	ret = plat_lfa_cancel(component_id);
903f7b2862SManish V Badarkhe 	if (ret != LFA_SUCCESS) {
913f7b2862SManish V Badarkhe 		return LFA_BUSY;
923f7b2862SManish V Badarkhe 	}
933f7b2862SManish V Badarkhe 
943f7b2862SManish V Badarkhe 	/* TODO: add proper termination prime and activate phases */
953f7b2862SManish V Badarkhe 	lfa_reset_activation();
963f7b2862SManish V Badarkhe 
973f7b2862SManish V Badarkhe 	return ret;
983f7b2862SManish V Badarkhe }
993f7b2862SManish V Badarkhe 
100*07de22d2SManish V Badarkhe static int lfa_activate(uint32_t component_id, uint64_t flags,
101*07de22d2SManish V Badarkhe 			uint64_t ep_address, uint64_t context_id)
102*07de22d2SManish V Badarkhe {
103*07de22d2SManish V Badarkhe 	int ret = LFA_ACTIVATION_FAILED;
104*07de22d2SManish V Badarkhe 	struct lfa_component_ops *activator;
105*07de22d2SManish V Badarkhe 
106*07de22d2SManish V Badarkhe 	if ((lfa_component_count == 0U) ||
107*07de22d2SManish V Badarkhe 	    (!lfa_components[component_id].activation_pending) ||
108*07de22d2SManish V Badarkhe 	    (current_activation.prime_status != PRIME_COMPLETE)) {
109*07de22d2SManish V Badarkhe 		return LFA_COMPONENT_WRONG_STATE;
110*07de22d2SManish V Badarkhe 	}
111*07de22d2SManish V Badarkhe 
112*07de22d2SManish V Badarkhe 	/* Check if fw_seq_id is in range. */
113*07de22d2SManish V Badarkhe 	if ((component_id >= lfa_component_count) ||
114*07de22d2SManish V Badarkhe 	    (current_activation.component_id != component_id)) {
115*07de22d2SManish V Badarkhe 		return LFA_INVALID_PARAMETERS;
116*07de22d2SManish V Badarkhe 	}
117*07de22d2SManish V Badarkhe 
118*07de22d2SManish V Badarkhe 	if (lfa_components[component_id].activator == NULL) {
119*07de22d2SManish V Badarkhe 		return LFA_NOT_SUPPORTED;
120*07de22d2SManish V Badarkhe 	}
121*07de22d2SManish V Badarkhe 
122*07de22d2SManish V Badarkhe 	activator = lfa_components[component_id].activator;
123*07de22d2SManish V Badarkhe 	if (activator->activate != NULL) {
124*07de22d2SManish V Badarkhe 		/*
125*07de22d2SManish V Badarkhe 		 * Pass skip_cpu_rendezvous (flag[0]) only if flag[0]==1
126*07de22d2SManish V Badarkhe 		 * & CPU_RENDEZVOUS is not required.
127*07de22d2SManish V Badarkhe 		 */
128*07de22d2SManish V Badarkhe 		if (flags & LFA_SKIP_CPU_RENDEZVOUS_BIT) {
129*07de22d2SManish V Badarkhe 			if (!activator->cpu_rendezvous_required) {
130*07de22d2SManish V Badarkhe 				INFO("Skipping rendezvous requested by caller.\n");
131*07de22d2SManish V Badarkhe 				current_activation.cpu_rendezvous_required = false;
132*07de22d2SManish V Badarkhe 			}
133*07de22d2SManish V Badarkhe 			/*
134*07de22d2SManish V Badarkhe 			 * Return error if caller tries to skip rendezvous when
135*07de22d2SManish V Badarkhe 			 * it is required.
136*07de22d2SManish V Badarkhe 			 */
137*07de22d2SManish V Badarkhe 			else {
138*07de22d2SManish V Badarkhe 				ERROR("CPU Rendezvous is required, can't skip.\n");
139*07de22d2SManish V Badarkhe 				return LFA_INVALID_PARAMETERS;
140*07de22d2SManish V Badarkhe 			}
141*07de22d2SManish V Badarkhe 		}
142*07de22d2SManish V Badarkhe 
143*07de22d2SManish V Badarkhe 		ret = activator->activate(&current_activation, ep_address,
144*07de22d2SManish V Badarkhe 					  context_id);
145*07de22d2SManish V Badarkhe 	}
146*07de22d2SManish V Badarkhe 
147*07de22d2SManish V Badarkhe 	lfa_components[component_id].activation_pending = false;
148*07de22d2SManish V Badarkhe 
149*07de22d2SManish V Badarkhe 	return ret;
150*07de22d2SManish V Badarkhe }
151*07de22d2SManish V Badarkhe 
15267fa182fSManish V Badarkhe static int lfa_prime(uint32_t component_id, uint64_t *flags)
15367fa182fSManish V Badarkhe {
15467fa182fSManish V Badarkhe 	int ret = LFA_SUCCESS;
15567fa182fSManish V Badarkhe 	struct lfa_component_ops *activator;
15667fa182fSManish V Badarkhe 
15767fa182fSManish V Badarkhe 	if (lfa_component_count == 0U ||
15867fa182fSManish V Badarkhe 	    !lfa_components[component_id].activation_pending) {
15967fa182fSManish V Badarkhe 		return LFA_WRONG_STATE;
16067fa182fSManish V Badarkhe 	}
16167fa182fSManish V Badarkhe 
16267fa182fSManish V Badarkhe 	/* Check if fw_seq_id is in range. */
16367fa182fSManish V Badarkhe 	if (component_id >= lfa_component_count) {
16467fa182fSManish V Badarkhe 		return LFA_INVALID_PARAMETERS;
16567fa182fSManish V Badarkhe 	}
16667fa182fSManish V Badarkhe 
16767fa182fSManish V Badarkhe 	if (lfa_components[component_id].activator == NULL) {
16867fa182fSManish V Badarkhe 		return LFA_NOT_SUPPORTED;
16967fa182fSManish V Badarkhe 	}
17067fa182fSManish V Badarkhe 
17167fa182fSManish V Badarkhe 	switch (current_activation.prime_status) {
17267fa182fSManish V Badarkhe 	case PRIME_NONE:
17367fa182fSManish V Badarkhe 		current_activation.component_id = component_id;
17467fa182fSManish V Badarkhe 		current_activation.prime_status = PRIME_STARTED;
17567fa182fSManish V Badarkhe 		break;
17667fa182fSManish V Badarkhe 
17767fa182fSManish V Badarkhe 	case PRIME_STARTED:
17867fa182fSManish V Badarkhe 		if (current_activation.component_id != component_id) {
17967fa182fSManish V Badarkhe 			/* Mismatched component trying to continue PRIME - error */
18067fa182fSManish V Badarkhe 			return LFA_WRONG_STATE;
18167fa182fSManish V Badarkhe 		}
18267fa182fSManish V Badarkhe 		break;
18367fa182fSManish V Badarkhe 
18467fa182fSManish V Badarkhe 	case PRIME_COMPLETE:
18567fa182fSManish V Badarkhe 	default:
18667fa182fSManish V Badarkhe 		break;
18767fa182fSManish V Badarkhe 	}
18867fa182fSManish V Badarkhe 
18967fa182fSManish V Badarkhe 	ret = plat_lfa_load_auth_image(component_id);
19067fa182fSManish V Badarkhe 	ret = convert_to_lfa_error(ret);
19167fa182fSManish V Badarkhe 
19267fa182fSManish V Badarkhe 	activator = lfa_components[component_id].activator;
19367fa182fSManish V Badarkhe 	if (activator->prime != NULL) {
19467fa182fSManish V Badarkhe 		ret = activator->prime(&current_activation);
19567fa182fSManish V Badarkhe 		if (ret != LFA_SUCCESS) {
19667fa182fSManish V Badarkhe 			/*
19767fa182fSManish V Badarkhe 			 * TODO: it should be LFA_PRIME_FAILED but specification
19867fa182fSManish V Badarkhe 			 * has not define this error yet
19967fa182fSManish V Badarkhe 			 */
20067fa182fSManish V Badarkhe 			return ret;
20167fa182fSManish V Badarkhe 		}
20267fa182fSManish V Badarkhe 	}
20367fa182fSManish V Badarkhe 
20467fa182fSManish V Badarkhe 	current_activation.prime_status = PRIME_COMPLETE;
20567fa182fSManish V Badarkhe 
20667fa182fSManish V Badarkhe 	/* TODO: split this into multiple PRIME calls */
20767fa182fSManish V Badarkhe 	*flags = 0ULL;
20867fa182fSManish V Badarkhe 
20967fa182fSManish V Badarkhe 	return ret;
21067fa182fSManish V Badarkhe }
21167fa182fSManish V Badarkhe 
212cf48f49fSManish V Badarkhe int lfa_setup(void)
213cf48f49fSManish V Badarkhe {
214b9dee50cSManish V Badarkhe 	is_lfa_initialized = lfa_initialize_components();
215b9dee50cSManish V Badarkhe 	if (!is_lfa_initialized) {
216b9dee50cSManish V Badarkhe 		return -1;
217b9dee50cSManish V Badarkhe 	}
218b9dee50cSManish V Badarkhe 
219b9dee50cSManish V Badarkhe 	lfa_reset_activation();
220b9dee50cSManish V Badarkhe 
221b9dee50cSManish V Badarkhe 	return 0;
222cf48f49fSManish V Badarkhe }
223cf48f49fSManish V Badarkhe 
224cf48f49fSManish V Badarkhe uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
225cf48f49fSManish V Badarkhe 			 u_register_t x3, u_register_t x4, void *cookie,
226cf48f49fSManish V Badarkhe 			 void *handle, u_register_t flags)
227cf48f49fSManish V Badarkhe {
22806a6f296SManish V Badarkhe 	uint64_t retx1, retx2;
22967fa182fSManish V Badarkhe 	uint64_t lfa_flags;
23006a6f296SManish V Badarkhe 	uint8_t *uuid_p;
23106a6f296SManish V Badarkhe 	uint32_t fw_seq_id = (uint32_t)x1;
2323f7b2862SManish V Badarkhe 	int ret;
23306a6f296SManish V Badarkhe 
234cf48f49fSManish V Badarkhe 	/**
235cf48f49fSManish V Badarkhe 	 * TODO: Acquire serialization lock.
236cf48f49fSManish V Badarkhe 	 */
237b9dee50cSManish V Badarkhe 
238b9dee50cSManish V Badarkhe 	if (!is_lfa_initialized) {
239b9dee50cSManish V Badarkhe 		return LFA_NOT_SUPPORTED;
240b9dee50cSManish V Badarkhe 	}
241b9dee50cSManish V Badarkhe 
242cf48f49fSManish V Badarkhe 	switch (smc_fid) {
243cf48f49fSManish V Badarkhe 	case LFA_VERSION:
244cf48f49fSManish V Badarkhe 		SMC_RET1(handle, LFA_VERSION_VAL);
245cf48f49fSManish V Badarkhe 		break;
246cf48f49fSManish V Badarkhe 
247cf48f49fSManish V Badarkhe 	case LFA_FEATURES:
248cf48f49fSManish V Badarkhe 		SMC_RET1(handle, is_lfa_fid(x1) ? LFA_SUCCESS : LFA_NOT_SUPPORTED);
249cf48f49fSManish V Badarkhe 		break;
250cf48f49fSManish V Badarkhe 
251cf48f49fSManish V Badarkhe 	case LFA_GET_INFO:
252b9dee50cSManish V Badarkhe 		/**
253b9dee50cSManish V Badarkhe 		 * The current specification limits this input parameter to be zero for
254b9dee50cSManish V Badarkhe 		 * version 1.0 of LFA
255b9dee50cSManish V Badarkhe 		 */
256b9dee50cSManish V Badarkhe 		if (x1 == 0ULL) {
257b9dee50cSManish V Badarkhe 			SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0);
258b9dee50cSManish V Badarkhe 		} else {
259b9dee50cSManish V Badarkhe 			SMC_RET1(handle, LFA_INVALID_PARAMETERS);
260b9dee50cSManish V Badarkhe 		}
261cf48f49fSManish V Badarkhe 		break;
262cf48f49fSManish V Badarkhe 
263cf48f49fSManish V Badarkhe 	case LFA_GET_INVENTORY:
26406a6f296SManish V Badarkhe 		if (lfa_component_count == 0U) {
26506a6f296SManish V Badarkhe 			SMC_RET1(handle, LFA_WRONG_STATE);
26606a6f296SManish V Badarkhe 		}
26706a6f296SManish V Badarkhe 
26806a6f296SManish V Badarkhe 		/*
26906a6f296SManish V Badarkhe 		 * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan
27006a6f296SManish V Badarkhe 		 * platform firmware and create a valid number of firmware components.
27106a6f296SManish V Badarkhe 		 */
27206a6f296SManish V Badarkhe 		if (fw_seq_id >= lfa_component_count) {
27306a6f296SManish V Badarkhe 			SMC_RET1(handle, LFA_INVALID_PARAMETERS);
27406a6f296SManish V Badarkhe 		}
27506a6f296SManish V Badarkhe 
27606a6f296SManish V Badarkhe 		/*
27706a6f296SManish V Badarkhe 		 * grab the UUID of asked fw_seq_id and set the return UUID
27806a6f296SManish V Badarkhe 		 * variables
27906a6f296SManish V Badarkhe 		 */
28006a6f296SManish V Badarkhe 		uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid;
28106a6f296SManish V Badarkhe 		memcpy(&retx1, uuid_p, sizeof(uint64_t));
28206a6f296SManish V Badarkhe 		memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t));
28306a6f296SManish V Badarkhe 
28406a6f296SManish V Badarkhe 		/*
28506a6f296SManish V Badarkhe 		 * check the given fw_seq_id's update available
28606a6f296SManish V Badarkhe 		 * and accordingly set the active_pending flag
28706a6f296SManish V Badarkhe 		 */
28806a6f296SManish V Badarkhe 		lfa_components[fw_seq_id].activation_pending =
28906a6f296SManish V Badarkhe 				is_plat_lfa_activation_pending(fw_seq_id);
29006a6f296SManish V Badarkhe 
29106a6f296SManish V Badarkhe 		INFO("Component %lu %s live activation:\n", x1,
29206a6f296SManish V Badarkhe 		      lfa_components[fw_seq_id].activator ? "supports" :
29306a6f296SManish V Badarkhe 		      "does not support");
29406a6f296SManish V Badarkhe 
29506a6f296SManish V Badarkhe 		if (lfa_components[fw_seq_id].activator != NULL) {
29606a6f296SManish V Badarkhe 			INFO("Activation pending: %s\n",
29706a6f296SManish V Badarkhe 			      lfa_components[fw_seq_id].activation_pending ? "true" : "false");
29806a6f296SManish V Badarkhe 		}
29906a6f296SManish V Badarkhe 
30006a6f296SManish V Badarkhe 		INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2);
30106a6f296SManish V Badarkhe 
30206a6f296SManish V Badarkhe 		SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id));
30306a6f296SManish V Badarkhe 
304cf48f49fSManish V Badarkhe 		break;
305cf48f49fSManish V Badarkhe 
306cf48f49fSManish V Badarkhe 	case LFA_PRIME:
30767fa182fSManish V Badarkhe 		ret = lfa_prime(x1, &lfa_flags);
30867fa182fSManish V Badarkhe 		if (ret != LFA_SUCCESS) {
30967fa182fSManish V Badarkhe 			SMC_RET1(handle, ret);
31067fa182fSManish V Badarkhe 		} else {
31167fa182fSManish V Badarkhe 			SMC_RET2(handle, ret, lfa_flags);
31267fa182fSManish V Badarkhe 		}
313cf48f49fSManish V Badarkhe 		break;
314cf48f49fSManish V Badarkhe 
315cf48f49fSManish V Badarkhe 	case LFA_ACTIVATE:
316*07de22d2SManish V Badarkhe 		ret = lfa_activate(fw_seq_id, x2, x3, x4);
317*07de22d2SManish V Badarkhe 		/* TODO: implement activate again */
318*07de22d2SManish V Badarkhe 		SMC_RET2(handle, ret, 0ULL);
319*07de22d2SManish V Badarkhe 
320cf48f49fSManish V Badarkhe 		break;
321cf48f49fSManish V Badarkhe 
322cf48f49fSManish V Badarkhe 	case LFA_CANCEL:
3233f7b2862SManish V Badarkhe 		ret = lfa_cancel(x1);
3243f7b2862SManish V Badarkhe 		SMC_RET1(handle, ret);
325cf48f49fSManish V Badarkhe 		break;
326cf48f49fSManish V Badarkhe 
327cf48f49fSManish V Badarkhe 	default:
328cf48f49fSManish V Badarkhe 		WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid);
329cf48f49fSManish V Badarkhe 		SMC_RET1(handle, SMC_UNK);
330cf48f49fSManish V Badarkhe 		break; /* unreachable */
331cf48f49fSManish V Badarkhe 
332cf48f49fSManish V Badarkhe 	}
333cf48f49fSManish V Badarkhe 
334cf48f49fSManish V Badarkhe 	SMC_RET1(handle, SMC_UNK);
335cf48f49fSManish V Badarkhe 
336cf48f49fSManish V Badarkhe 	return 0;
337cf48f49fSManish V Badarkhe }
338