xref: /rk3399_ARM-atf/services/std_svc/lfa/lfa_main.c (revision a7fbcccd43a42ad6e1a8069f16bc53bbde961096)
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 bool lfa_initialize_components(void)
25 {
26 	lfa_component_count = plat_lfa_get_components(&lfa_components);
27 
28 	if (lfa_component_count == 0U || lfa_components == NULL) {
29 		/* unlikely to reach here */
30 		ERROR("Invalid LFA component setup: count = 0 or components are NULL");
31 		return false;
32 	}
33 
34 	return true;
35 }
36 
37 static uint64_t get_fw_activation_flags(uint32_t fw_seq_id)
38 {
39 	const plat_lfa_component_info_t *comp =
40 				&lfa_components[fw_seq_id];
41 	uint64_t flags = 0ULL;
42 
43 	flags |= ((comp->activator == NULL ? 0ULL : 1ULL)
44 		 << LFA_ACTIVATION_CAPABLE_SHIFT);
45 	flags |= (uint64_t)(comp->activation_pending)
46 		 << LFA_ACTIVATION_PENDING_SHIFT;
47 
48 	if (comp->activator != NULL) {
49 		flags |= ((comp->activator->may_reset_cpu ? 1ULL : 0ULL)
50 			 << LFA_MAY_RESET_CPU_SHIFT);
51 		flags |= ((comp->activator->cpu_rendezvous_required ? 0ULL : 1ULL)
52 			 << LFA_CPU_RENDEZVOUS_OPTIONAL_SHIFT);
53 	}
54 
55 	return flags;
56 }
57 
58 static int lfa_cancel(uint32_t component_id)
59 {
60 	int ret = LFA_SUCCESS;
61 
62 	if (lfa_component_count == 0U) {
63 		return LFA_WRONG_STATE;
64 	}
65 
66 	/* Check if component ID is in range. */
67 	if ((component_id >= lfa_component_count) ||
68 	    (component_id != current_activation.component_id)) {
69 		return LFA_INVALID_PARAMETERS;
70 	}
71 
72 	ret = plat_lfa_cancel(component_id);
73 	if (ret != LFA_SUCCESS) {
74 		return LFA_BUSY;
75 	}
76 
77 	/* TODO: add proper termination prime and activate phases */
78 	lfa_reset_activation();
79 
80 	return ret;
81 }
82 
83 int lfa_setup(void)
84 {
85 	is_lfa_initialized = lfa_initialize_components();
86 	if (!is_lfa_initialized) {
87 		return -1;
88 	}
89 
90 	lfa_reset_activation();
91 
92 	return 0;
93 }
94 
95 uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
96 			 u_register_t x3, u_register_t x4, void *cookie,
97 			 void *handle, u_register_t flags)
98 {
99 	uint64_t retx1, retx2;
100 	uint8_t *uuid_p;
101 	uint32_t fw_seq_id = (uint32_t)x1;
102 	int ret;
103 
104 	/**
105 	 * TODO: Acquire serialization lock.
106 	 */
107 
108 	if (!is_lfa_initialized) {
109 		return LFA_NOT_SUPPORTED;
110 	}
111 
112 	switch (smc_fid) {
113 	case LFA_VERSION:
114 		SMC_RET1(handle, LFA_VERSION_VAL);
115 		break;
116 
117 	case LFA_FEATURES:
118 		SMC_RET1(handle, is_lfa_fid(x1) ? LFA_SUCCESS : LFA_NOT_SUPPORTED);
119 		break;
120 
121 	case LFA_GET_INFO:
122 		/**
123 		 * The current specification limits this input parameter to be zero for
124 		 * version 1.0 of LFA
125 		 */
126 		if (x1 == 0ULL) {
127 			SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0);
128 		} else {
129 			SMC_RET1(handle, LFA_INVALID_PARAMETERS);
130 		}
131 		break;
132 
133 	case LFA_GET_INVENTORY:
134 		if (lfa_component_count == 0U) {
135 			SMC_RET1(handle, LFA_WRONG_STATE);
136 		}
137 
138 		/*
139 		 * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan
140 		 * platform firmware and create a valid number of firmware components.
141 		 */
142 		if (fw_seq_id >= lfa_component_count) {
143 			SMC_RET1(handle, LFA_INVALID_PARAMETERS);
144 		}
145 
146 		/*
147 		 * grab the UUID of asked fw_seq_id and set the return UUID
148 		 * variables
149 		 */
150 		uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid;
151 		memcpy(&retx1, uuid_p, sizeof(uint64_t));
152 		memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t));
153 
154 		/*
155 		 * check the given fw_seq_id's update available
156 		 * and accordingly set the active_pending flag
157 		 */
158 		lfa_components[fw_seq_id].activation_pending =
159 				is_plat_lfa_activation_pending(fw_seq_id);
160 
161 		INFO("Component %lu %s live activation:\n", x1,
162 		      lfa_components[fw_seq_id].activator ? "supports" :
163 		      "does not support");
164 
165 		if (lfa_components[fw_seq_id].activator != NULL) {
166 			INFO("Activation pending: %s\n",
167 			      lfa_components[fw_seq_id].activation_pending ? "true" : "false");
168 		}
169 
170 		INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2);
171 
172 		SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id));
173 
174 		break;
175 
176 	case LFA_PRIME:
177 		break;
178 
179 	case LFA_ACTIVATE:
180 		break;
181 
182 	case LFA_CANCEL:
183 		ret = lfa_cancel(x1);
184 		SMC_RET1(handle, ret);
185 		break;
186 
187 	default:
188 		WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid);
189 		SMC_RET1(handle, SMC_UNK);
190 		break; /* unreachable */
191 
192 	}
193 
194 	SMC_RET1(handle, SMC_UNK);
195 
196 	return 0;
197 }
198