xref: /rk3399_ARM-atf/services/std_svc/lfa/lfa_main.c (revision 67fa182fc4c460ebf6d7abe3366f9ecbbe393dc6)
1 /*
2  * Copyright (c) 2025, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <plat/common/platform.h>
8 #include <services/bl31_lfa.h>
9 #include <services/lfa_svc.h>
10 #include <services/rmmd_rmm_lfa.h>
11 #include <smccc_helpers.h>
12 
13 static uint32_t lfa_component_count;
14 static plat_lfa_component_info_t *lfa_components;
15 static struct lfa_component_status current_activation;
16 static bool is_lfa_initialized;
17 
18 void lfa_reset_activation(void)
19 {
20 	current_activation.component_id = LFA_INVALID_COMPONENT;
21 	current_activation.prime_status = PRIME_NONE;
22 }
23 
24 static int convert_to_lfa_error(int ret)
25 {
26 	switch (ret) {
27 	case 0:
28 		return LFA_SUCCESS;
29 	case -EAUTH:
30 		return LFA_AUTH_ERROR;
31 	case -ENOMEM:
32 		return LFA_NO_MEMORY;
33 	default:
34 		return LFA_DEVICE_ERROR;
35 	}
36 }
37 
38 static bool lfa_initialize_components(void)
39 {
40 	lfa_component_count = plat_lfa_get_components(&lfa_components);
41 
42 	if (lfa_component_count == 0U || lfa_components == NULL) {
43 		/* unlikely to reach here */
44 		ERROR("Invalid LFA component setup: count = 0 or components are NULL");
45 		return false;
46 	}
47 
48 	return true;
49 }
50 
51 static uint64_t get_fw_activation_flags(uint32_t fw_seq_id)
52 {
53 	const plat_lfa_component_info_t *comp =
54 				&lfa_components[fw_seq_id];
55 	uint64_t flags = 0ULL;
56 
57 	flags |= ((comp->activator == NULL ? 0ULL : 1ULL)
58 		 << LFA_ACTIVATION_CAPABLE_SHIFT);
59 	flags |= (uint64_t)(comp->activation_pending)
60 		 << LFA_ACTIVATION_PENDING_SHIFT;
61 
62 	if (comp->activator != NULL) {
63 		flags |= ((comp->activator->may_reset_cpu ? 1ULL : 0ULL)
64 			 << LFA_MAY_RESET_CPU_SHIFT);
65 		flags |= ((comp->activator->cpu_rendezvous_required ? 0ULL : 1ULL)
66 			 << LFA_CPU_RENDEZVOUS_OPTIONAL_SHIFT);
67 	}
68 
69 	return flags;
70 }
71 
72 static int lfa_cancel(uint32_t component_id)
73 {
74 	int ret = LFA_SUCCESS;
75 
76 	if (lfa_component_count == 0U) {
77 		return LFA_WRONG_STATE;
78 	}
79 
80 	/* Check if component ID is in range. */
81 	if ((component_id >= lfa_component_count) ||
82 	    (component_id != current_activation.component_id)) {
83 		return LFA_INVALID_PARAMETERS;
84 	}
85 
86 	ret = plat_lfa_cancel(component_id);
87 	if (ret != LFA_SUCCESS) {
88 		return LFA_BUSY;
89 	}
90 
91 	/* TODO: add proper termination prime and activate phases */
92 	lfa_reset_activation();
93 
94 	return ret;
95 }
96 
97 static int lfa_prime(uint32_t component_id, uint64_t *flags)
98 {
99 	int ret = LFA_SUCCESS;
100 	struct lfa_component_ops *activator;
101 
102 	if (lfa_component_count == 0U ||
103 	    !lfa_components[component_id].activation_pending) {
104 		return LFA_WRONG_STATE;
105 	}
106 
107 	/* Check if fw_seq_id is in range. */
108 	if (component_id >= lfa_component_count) {
109 		return LFA_INVALID_PARAMETERS;
110 	}
111 
112 	if (lfa_components[component_id].activator == NULL) {
113 		return LFA_NOT_SUPPORTED;
114 	}
115 
116 	switch (current_activation.prime_status) {
117 	case PRIME_NONE:
118 		current_activation.component_id = component_id;
119 		current_activation.prime_status = PRIME_STARTED;
120 		break;
121 
122 	case PRIME_STARTED:
123 		if (current_activation.component_id != component_id) {
124 			/* Mismatched component trying to continue PRIME - error */
125 			return LFA_WRONG_STATE;
126 		}
127 		break;
128 
129 	case PRIME_COMPLETE:
130 	default:
131 		break;
132 	}
133 
134 	ret = plat_lfa_load_auth_image(component_id);
135 	ret = convert_to_lfa_error(ret);
136 
137 	activator = lfa_components[component_id].activator;
138 	if (activator->prime != NULL) {
139 		ret = activator->prime(&current_activation);
140 		if (ret != LFA_SUCCESS) {
141 			/*
142 			 * TODO: it should be LFA_PRIME_FAILED but specification
143 			 * has not define this error yet
144 			 */
145 			return ret;
146 		}
147 	}
148 
149 	current_activation.prime_status = PRIME_COMPLETE;
150 
151 	/* TODO: split this into multiple PRIME calls */
152 	*flags = 0ULL;
153 
154 	return ret;
155 }
156 
157 int lfa_setup(void)
158 {
159 	is_lfa_initialized = lfa_initialize_components();
160 	if (!is_lfa_initialized) {
161 		return -1;
162 	}
163 
164 	lfa_reset_activation();
165 
166 	return 0;
167 }
168 
169 uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
170 			 u_register_t x3, u_register_t x4, void *cookie,
171 			 void *handle, u_register_t flags)
172 {
173 	uint64_t retx1, retx2;
174 	uint64_t lfa_flags;
175 	uint8_t *uuid_p;
176 	uint32_t fw_seq_id = (uint32_t)x1;
177 	int ret;
178 
179 	/**
180 	 * TODO: Acquire serialization lock.
181 	 */
182 
183 	if (!is_lfa_initialized) {
184 		return LFA_NOT_SUPPORTED;
185 	}
186 
187 	switch (smc_fid) {
188 	case LFA_VERSION:
189 		SMC_RET1(handle, LFA_VERSION_VAL);
190 		break;
191 
192 	case LFA_FEATURES:
193 		SMC_RET1(handle, is_lfa_fid(x1) ? LFA_SUCCESS : LFA_NOT_SUPPORTED);
194 		break;
195 
196 	case LFA_GET_INFO:
197 		/**
198 		 * The current specification limits this input parameter to be zero for
199 		 * version 1.0 of LFA
200 		 */
201 		if (x1 == 0ULL) {
202 			SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0);
203 		} else {
204 			SMC_RET1(handle, LFA_INVALID_PARAMETERS);
205 		}
206 		break;
207 
208 	case LFA_GET_INVENTORY:
209 		if (lfa_component_count == 0U) {
210 			SMC_RET1(handle, LFA_WRONG_STATE);
211 		}
212 
213 		/*
214 		 * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan
215 		 * platform firmware and create a valid number of firmware components.
216 		 */
217 		if (fw_seq_id >= lfa_component_count) {
218 			SMC_RET1(handle, LFA_INVALID_PARAMETERS);
219 		}
220 
221 		/*
222 		 * grab the UUID of asked fw_seq_id and set the return UUID
223 		 * variables
224 		 */
225 		uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid;
226 		memcpy(&retx1, uuid_p, sizeof(uint64_t));
227 		memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t));
228 
229 		/*
230 		 * check the given fw_seq_id's update available
231 		 * and accordingly set the active_pending flag
232 		 */
233 		lfa_components[fw_seq_id].activation_pending =
234 				is_plat_lfa_activation_pending(fw_seq_id);
235 
236 		INFO("Component %lu %s live activation:\n", x1,
237 		      lfa_components[fw_seq_id].activator ? "supports" :
238 		      "does not support");
239 
240 		if (lfa_components[fw_seq_id].activator != NULL) {
241 			INFO("Activation pending: %s\n",
242 			      lfa_components[fw_seq_id].activation_pending ? "true" : "false");
243 		}
244 
245 		INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2);
246 
247 		SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id));
248 
249 		break;
250 
251 	case LFA_PRIME:
252 		ret = lfa_prime(x1, &lfa_flags);
253 		if (ret != LFA_SUCCESS) {
254 			SMC_RET1(handle, ret);
255 		} else {
256 			SMC_RET2(handle, ret, lfa_flags);
257 		}
258 		break;
259 
260 	case LFA_ACTIVATE:
261 		break;
262 
263 	case LFA_CANCEL:
264 		ret = lfa_cancel(x1);
265 		SMC_RET1(handle, ret);
266 		break;
267 
268 	default:
269 		WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid);
270 		SMC_RET1(handle, SMC_UNK);
271 		break; /* unreachable */
272 
273 	}
274 
275 	SMC_RET1(handle, SMC_UNK);
276 
277 	return 0;
278 }
279