xref: /rk3399_ARM-atf/services/std_svc/lfa/lfa_main.c (revision 67fa182fc4c460ebf6d7abe3366f9ecbbe393dc6)
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 
7b9dee50cSManish V Badarkhe #include <plat/common/platform.h>
8b9dee50cSManish V Badarkhe #include <services/bl31_lfa.h>
9cf48f49fSManish V Badarkhe #include <services/lfa_svc.h>
10b9dee50cSManish V Badarkhe #include <services/rmmd_rmm_lfa.h>
11cf48f49fSManish V Badarkhe #include <smccc_helpers.h>
12cf48f49fSManish V Badarkhe 
13b9dee50cSManish V Badarkhe static uint32_t lfa_component_count;
14b9dee50cSManish V Badarkhe static plat_lfa_component_info_t *lfa_components;
15b9dee50cSManish V Badarkhe static struct lfa_component_status current_activation;
16b9dee50cSManish V Badarkhe static bool is_lfa_initialized;
17b9dee50cSManish V Badarkhe 
18b9dee50cSManish V Badarkhe void lfa_reset_activation(void)
19b9dee50cSManish V Badarkhe {
20b9dee50cSManish V Badarkhe 	current_activation.component_id = LFA_INVALID_COMPONENT;
21b9dee50cSManish V Badarkhe 	current_activation.prime_status = PRIME_NONE;
22b9dee50cSManish V Badarkhe }
23b9dee50cSManish V Badarkhe 
24*67fa182fSManish V Badarkhe static int convert_to_lfa_error(int ret)
25*67fa182fSManish V Badarkhe {
26*67fa182fSManish V Badarkhe 	switch (ret) {
27*67fa182fSManish V Badarkhe 	case 0:
28*67fa182fSManish V Badarkhe 		return LFA_SUCCESS;
29*67fa182fSManish V Badarkhe 	case -EAUTH:
30*67fa182fSManish V Badarkhe 		return LFA_AUTH_ERROR;
31*67fa182fSManish V Badarkhe 	case -ENOMEM:
32*67fa182fSManish V Badarkhe 		return LFA_NO_MEMORY;
33*67fa182fSManish V Badarkhe 	default:
34*67fa182fSManish V Badarkhe 		return LFA_DEVICE_ERROR;
35*67fa182fSManish V Badarkhe 	}
36*67fa182fSManish V Badarkhe }
37*67fa182fSManish V Badarkhe 
38b9dee50cSManish V Badarkhe static bool lfa_initialize_components(void)
39b9dee50cSManish V Badarkhe {
40b9dee50cSManish V Badarkhe 	lfa_component_count = plat_lfa_get_components(&lfa_components);
41b9dee50cSManish V Badarkhe 
42b9dee50cSManish V Badarkhe 	if (lfa_component_count == 0U || lfa_components == NULL) {
43b9dee50cSManish V Badarkhe 		/* unlikely to reach here */
44b9dee50cSManish V Badarkhe 		ERROR("Invalid LFA component setup: count = 0 or components are NULL");
45b9dee50cSManish V Badarkhe 		return false;
46b9dee50cSManish V Badarkhe 	}
47b9dee50cSManish V Badarkhe 
48b9dee50cSManish V Badarkhe 	return true;
49b9dee50cSManish V Badarkhe }
50b9dee50cSManish V Badarkhe 
5106a6f296SManish V Badarkhe static uint64_t get_fw_activation_flags(uint32_t fw_seq_id)
5206a6f296SManish V Badarkhe {
5306a6f296SManish V Badarkhe 	const plat_lfa_component_info_t *comp =
5406a6f296SManish V Badarkhe 				&lfa_components[fw_seq_id];
5506a6f296SManish V Badarkhe 	uint64_t flags = 0ULL;
5606a6f296SManish V Badarkhe 
5706a6f296SManish V Badarkhe 	flags |= ((comp->activator == NULL ? 0ULL : 1ULL)
5806a6f296SManish V Badarkhe 		 << LFA_ACTIVATION_CAPABLE_SHIFT);
5906a6f296SManish V Badarkhe 	flags |= (uint64_t)(comp->activation_pending)
6006a6f296SManish V Badarkhe 		 << LFA_ACTIVATION_PENDING_SHIFT;
6106a6f296SManish V Badarkhe 
6206a6f296SManish V Badarkhe 	if (comp->activator != NULL) {
6306a6f296SManish V Badarkhe 		flags |= ((comp->activator->may_reset_cpu ? 1ULL : 0ULL)
6406a6f296SManish V Badarkhe 			 << LFA_MAY_RESET_CPU_SHIFT);
6506a6f296SManish V Badarkhe 		flags |= ((comp->activator->cpu_rendezvous_required ? 0ULL : 1ULL)
6606a6f296SManish V Badarkhe 			 << LFA_CPU_RENDEZVOUS_OPTIONAL_SHIFT);
6706a6f296SManish V Badarkhe 	}
6806a6f296SManish V Badarkhe 
6906a6f296SManish V Badarkhe 	return flags;
7006a6f296SManish V Badarkhe }
7106a6f296SManish V Badarkhe 
723f7b2862SManish V Badarkhe static int lfa_cancel(uint32_t component_id)
733f7b2862SManish V Badarkhe {
743f7b2862SManish V Badarkhe 	int ret = LFA_SUCCESS;
753f7b2862SManish V Badarkhe 
763f7b2862SManish V Badarkhe 	if (lfa_component_count == 0U) {
773f7b2862SManish V Badarkhe 		return LFA_WRONG_STATE;
783f7b2862SManish V Badarkhe 	}
793f7b2862SManish V Badarkhe 
803f7b2862SManish V Badarkhe 	/* Check if component ID is in range. */
813f7b2862SManish V Badarkhe 	if ((component_id >= lfa_component_count) ||
823f7b2862SManish V Badarkhe 	    (component_id != current_activation.component_id)) {
833f7b2862SManish V Badarkhe 		return LFA_INVALID_PARAMETERS;
843f7b2862SManish V Badarkhe 	}
853f7b2862SManish V Badarkhe 
863f7b2862SManish V Badarkhe 	ret = plat_lfa_cancel(component_id);
873f7b2862SManish V Badarkhe 	if (ret != LFA_SUCCESS) {
883f7b2862SManish V Badarkhe 		return LFA_BUSY;
893f7b2862SManish V Badarkhe 	}
903f7b2862SManish V Badarkhe 
913f7b2862SManish V Badarkhe 	/* TODO: add proper termination prime and activate phases */
923f7b2862SManish V Badarkhe 	lfa_reset_activation();
933f7b2862SManish V Badarkhe 
943f7b2862SManish V Badarkhe 	return ret;
953f7b2862SManish V Badarkhe }
963f7b2862SManish V Badarkhe 
97*67fa182fSManish V Badarkhe static int lfa_prime(uint32_t component_id, uint64_t *flags)
98*67fa182fSManish V Badarkhe {
99*67fa182fSManish V Badarkhe 	int ret = LFA_SUCCESS;
100*67fa182fSManish V Badarkhe 	struct lfa_component_ops *activator;
101*67fa182fSManish V Badarkhe 
102*67fa182fSManish V Badarkhe 	if (lfa_component_count == 0U ||
103*67fa182fSManish V Badarkhe 	    !lfa_components[component_id].activation_pending) {
104*67fa182fSManish V Badarkhe 		return LFA_WRONG_STATE;
105*67fa182fSManish V Badarkhe 	}
106*67fa182fSManish V Badarkhe 
107*67fa182fSManish V Badarkhe 	/* Check if fw_seq_id is in range. */
108*67fa182fSManish V Badarkhe 	if (component_id >= lfa_component_count) {
109*67fa182fSManish V Badarkhe 		return LFA_INVALID_PARAMETERS;
110*67fa182fSManish V Badarkhe 	}
111*67fa182fSManish V Badarkhe 
112*67fa182fSManish V Badarkhe 	if (lfa_components[component_id].activator == NULL) {
113*67fa182fSManish V Badarkhe 		return LFA_NOT_SUPPORTED;
114*67fa182fSManish V Badarkhe 	}
115*67fa182fSManish V Badarkhe 
116*67fa182fSManish V Badarkhe 	switch (current_activation.prime_status) {
117*67fa182fSManish V Badarkhe 	case PRIME_NONE:
118*67fa182fSManish V Badarkhe 		current_activation.component_id = component_id;
119*67fa182fSManish V Badarkhe 		current_activation.prime_status = PRIME_STARTED;
120*67fa182fSManish V Badarkhe 		break;
121*67fa182fSManish V Badarkhe 
122*67fa182fSManish V Badarkhe 	case PRIME_STARTED:
123*67fa182fSManish V Badarkhe 		if (current_activation.component_id != component_id) {
124*67fa182fSManish V Badarkhe 			/* Mismatched component trying to continue PRIME - error */
125*67fa182fSManish V Badarkhe 			return LFA_WRONG_STATE;
126*67fa182fSManish V Badarkhe 		}
127*67fa182fSManish V Badarkhe 		break;
128*67fa182fSManish V Badarkhe 
129*67fa182fSManish V Badarkhe 	case PRIME_COMPLETE:
130*67fa182fSManish V Badarkhe 	default:
131*67fa182fSManish V Badarkhe 		break;
132*67fa182fSManish V Badarkhe 	}
133*67fa182fSManish V Badarkhe 
134*67fa182fSManish V Badarkhe 	ret = plat_lfa_load_auth_image(component_id);
135*67fa182fSManish V Badarkhe 	ret = convert_to_lfa_error(ret);
136*67fa182fSManish V Badarkhe 
137*67fa182fSManish V Badarkhe 	activator = lfa_components[component_id].activator;
138*67fa182fSManish V Badarkhe 	if (activator->prime != NULL) {
139*67fa182fSManish V Badarkhe 		ret = activator->prime(&current_activation);
140*67fa182fSManish V Badarkhe 		if (ret != LFA_SUCCESS) {
141*67fa182fSManish V Badarkhe 			/*
142*67fa182fSManish V Badarkhe 			 * TODO: it should be LFA_PRIME_FAILED but specification
143*67fa182fSManish V Badarkhe 			 * has not define this error yet
144*67fa182fSManish V Badarkhe 			 */
145*67fa182fSManish V Badarkhe 			return ret;
146*67fa182fSManish V Badarkhe 		}
147*67fa182fSManish V Badarkhe 	}
148*67fa182fSManish V Badarkhe 
149*67fa182fSManish V Badarkhe 	current_activation.prime_status = PRIME_COMPLETE;
150*67fa182fSManish V Badarkhe 
151*67fa182fSManish V Badarkhe 	/* TODO: split this into multiple PRIME calls */
152*67fa182fSManish V Badarkhe 	*flags = 0ULL;
153*67fa182fSManish V Badarkhe 
154*67fa182fSManish V Badarkhe 	return ret;
155*67fa182fSManish V Badarkhe }
156*67fa182fSManish V Badarkhe 
157cf48f49fSManish V Badarkhe int lfa_setup(void)
158cf48f49fSManish V Badarkhe {
159b9dee50cSManish V Badarkhe 	is_lfa_initialized = lfa_initialize_components();
160b9dee50cSManish V Badarkhe 	if (!is_lfa_initialized) {
161b9dee50cSManish V Badarkhe 		return -1;
162b9dee50cSManish V Badarkhe 	}
163b9dee50cSManish V Badarkhe 
164b9dee50cSManish V Badarkhe 	lfa_reset_activation();
165b9dee50cSManish V Badarkhe 
166b9dee50cSManish V Badarkhe 	return 0;
167cf48f49fSManish V Badarkhe }
168cf48f49fSManish V Badarkhe 
169cf48f49fSManish V Badarkhe uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
170cf48f49fSManish V Badarkhe 			 u_register_t x3, u_register_t x4, void *cookie,
171cf48f49fSManish V Badarkhe 			 void *handle, u_register_t flags)
172cf48f49fSManish V Badarkhe {
17306a6f296SManish V Badarkhe 	uint64_t retx1, retx2;
174*67fa182fSManish V Badarkhe 	uint64_t lfa_flags;
17506a6f296SManish V Badarkhe 	uint8_t *uuid_p;
17606a6f296SManish V Badarkhe 	uint32_t fw_seq_id = (uint32_t)x1;
1773f7b2862SManish V Badarkhe 	int ret;
17806a6f296SManish V Badarkhe 
179cf48f49fSManish V Badarkhe 	/**
180cf48f49fSManish V Badarkhe 	 * TODO: Acquire serialization lock.
181cf48f49fSManish V Badarkhe 	 */
182b9dee50cSManish V Badarkhe 
183b9dee50cSManish V Badarkhe 	if (!is_lfa_initialized) {
184b9dee50cSManish V Badarkhe 		return LFA_NOT_SUPPORTED;
185b9dee50cSManish V Badarkhe 	}
186b9dee50cSManish V Badarkhe 
187cf48f49fSManish V Badarkhe 	switch (smc_fid) {
188cf48f49fSManish V Badarkhe 	case LFA_VERSION:
189cf48f49fSManish V Badarkhe 		SMC_RET1(handle, LFA_VERSION_VAL);
190cf48f49fSManish V Badarkhe 		break;
191cf48f49fSManish V Badarkhe 
192cf48f49fSManish V Badarkhe 	case LFA_FEATURES:
193cf48f49fSManish V Badarkhe 		SMC_RET1(handle, is_lfa_fid(x1) ? LFA_SUCCESS : LFA_NOT_SUPPORTED);
194cf48f49fSManish V Badarkhe 		break;
195cf48f49fSManish V Badarkhe 
196cf48f49fSManish V Badarkhe 	case LFA_GET_INFO:
197b9dee50cSManish V Badarkhe 		/**
198b9dee50cSManish V Badarkhe 		 * The current specification limits this input parameter to be zero for
199b9dee50cSManish V Badarkhe 		 * version 1.0 of LFA
200b9dee50cSManish V Badarkhe 		 */
201b9dee50cSManish V Badarkhe 		if (x1 == 0ULL) {
202b9dee50cSManish V Badarkhe 			SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0);
203b9dee50cSManish V Badarkhe 		} else {
204b9dee50cSManish V Badarkhe 			SMC_RET1(handle, LFA_INVALID_PARAMETERS);
205b9dee50cSManish V Badarkhe 		}
206cf48f49fSManish V Badarkhe 		break;
207cf48f49fSManish V Badarkhe 
208cf48f49fSManish V Badarkhe 	case LFA_GET_INVENTORY:
20906a6f296SManish V Badarkhe 		if (lfa_component_count == 0U) {
21006a6f296SManish V Badarkhe 			SMC_RET1(handle, LFA_WRONG_STATE);
21106a6f296SManish V Badarkhe 		}
21206a6f296SManish V Badarkhe 
21306a6f296SManish V Badarkhe 		/*
21406a6f296SManish V Badarkhe 		 * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan
21506a6f296SManish V Badarkhe 		 * platform firmware and create a valid number of firmware components.
21606a6f296SManish V Badarkhe 		 */
21706a6f296SManish V Badarkhe 		if (fw_seq_id >= lfa_component_count) {
21806a6f296SManish V Badarkhe 			SMC_RET1(handle, LFA_INVALID_PARAMETERS);
21906a6f296SManish V Badarkhe 		}
22006a6f296SManish V Badarkhe 
22106a6f296SManish V Badarkhe 		/*
22206a6f296SManish V Badarkhe 		 * grab the UUID of asked fw_seq_id and set the return UUID
22306a6f296SManish V Badarkhe 		 * variables
22406a6f296SManish V Badarkhe 		 */
22506a6f296SManish V Badarkhe 		uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid;
22606a6f296SManish V Badarkhe 		memcpy(&retx1, uuid_p, sizeof(uint64_t));
22706a6f296SManish V Badarkhe 		memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t));
22806a6f296SManish V Badarkhe 
22906a6f296SManish V Badarkhe 		/*
23006a6f296SManish V Badarkhe 		 * check the given fw_seq_id's update available
23106a6f296SManish V Badarkhe 		 * and accordingly set the active_pending flag
23206a6f296SManish V Badarkhe 		 */
23306a6f296SManish V Badarkhe 		lfa_components[fw_seq_id].activation_pending =
23406a6f296SManish V Badarkhe 				is_plat_lfa_activation_pending(fw_seq_id);
23506a6f296SManish V Badarkhe 
23606a6f296SManish V Badarkhe 		INFO("Component %lu %s live activation:\n", x1,
23706a6f296SManish V Badarkhe 		      lfa_components[fw_seq_id].activator ? "supports" :
23806a6f296SManish V Badarkhe 		      "does not support");
23906a6f296SManish V Badarkhe 
24006a6f296SManish V Badarkhe 		if (lfa_components[fw_seq_id].activator != NULL) {
24106a6f296SManish V Badarkhe 			INFO("Activation pending: %s\n",
24206a6f296SManish V Badarkhe 			      lfa_components[fw_seq_id].activation_pending ? "true" : "false");
24306a6f296SManish V Badarkhe 		}
24406a6f296SManish V Badarkhe 
24506a6f296SManish V Badarkhe 		INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2);
24606a6f296SManish V Badarkhe 
24706a6f296SManish V Badarkhe 		SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id));
24806a6f296SManish V Badarkhe 
249cf48f49fSManish V Badarkhe 		break;
250cf48f49fSManish V Badarkhe 
251cf48f49fSManish V Badarkhe 	case LFA_PRIME:
252*67fa182fSManish V Badarkhe 		ret = lfa_prime(x1, &lfa_flags);
253*67fa182fSManish V Badarkhe 		if (ret != LFA_SUCCESS) {
254*67fa182fSManish V Badarkhe 			SMC_RET1(handle, ret);
255*67fa182fSManish V Badarkhe 		} else {
256*67fa182fSManish V Badarkhe 			SMC_RET2(handle, ret, lfa_flags);
257*67fa182fSManish V Badarkhe 		}
258cf48f49fSManish V Badarkhe 		break;
259cf48f49fSManish V Badarkhe 
260cf48f49fSManish V Badarkhe 	case LFA_ACTIVATE:
261cf48f49fSManish V Badarkhe 		break;
262cf48f49fSManish V Badarkhe 
263cf48f49fSManish V Badarkhe 	case LFA_CANCEL:
2643f7b2862SManish V Badarkhe 		ret = lfa_cancel(x1);
2653f7b2862SManish V Badarkhe 		SMC_RET1(handle, ret);
266cf48f49fSManish V Badarkhe 		break;
267cf48f49fSManish V Badarkhe 
268cf48f49fSManish V Badarkhe 	default:
269cf48f49fSManish V Badarkhe 		WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid);
270cf48f49fSManish V Badarkhe 		SMC_RET1(handle, SMC_UNK);
271cf48f49fSManish V Badarkhe 		break; /* unreachable */
272cf48f49fSManish V Badarkhe 
273cf48f49fSManish V Badarkhe 	}
274cf48f49fSManish V Badarkhe 
275cf48f49fSManish V Badarkhe 	SMC_RET1(handle, SMC_UNK);
276cf48f49fSManish V Badarkhe 
277cf48f49fSManish V Badarkhe 	return 0;
278cf48f49fSManish V Badarkhe }
279