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 24b9dee50cSManish V Badarkhe static bool lfa_initialize_components(void) 25b9dee50cSManish V Badarkhe { 26b9dee50cSManish V Badarkhe lfa_component_count = plat_lfa_get_components(&lfa_components); 27b9dee50cSManish V Badarkhe 28b9dee50cSManish V Badarkhe if (lfa_component_count == 0U || lfa_components == NULL) { 29b9dee50cSManish V Badarkhe /* unlikely to reach here */ 30b9dee50cSManish V Badarkhe ERROR("Invalid LFA component setup: count = 0 or components are NULL"); 31b9dee50cSManish V Badarkhe return false; 32b9dee50cSManish V Badarkhe } 33b9dee50cSManish V Badarkhe 34b9dee50cSManish V Badarkhe return true; 35b9dee50cSManish V Badarkhe } 36b9dee50cSManish V Badarkhe 3706a6f296SManish V Badarkhe static uint64_t get_fw_activation_flags(uint32_t fw_seq_id) 3806a6f296SManish V Badarkhe { 3906a6f296SManish V Badarkhe const plat_lfa_component_info_t *comp = 4006a6f296SManish V Badarkhe &lfa_components[fw_seq_id]; 4106a6f296SManish V Badarkhe uint64_t flags = 0ULL; 4206a6f296SManish V Badarkhe 4306a6f296SManish V Badarkhe flags |= ((comp->activator == NULL ? 0ULL : 1ULL) 4406a6f296SManish V Badarkhe << LFA_ACTIVATION_CAPABLE_SHIFT); 4506a6f296SManish V Badarkhe flags |= (uint64_t)(comp->activation_pending) 4606a6f296SManish V Badarkhe << LFA_ACTIVATION_PENDING_SHIFT; 4706a6f296SManish V Badarkhe 4806a6f296SManish V Badarkhe if (comp->activator != NULL) { 4906a6f296SManish V Badarkhe flags |= ((comp->activator->may_reset_cpu ? 1ULL : 0ULL) 5006a6f296SManish V Badarkhe << LFA_MAY_RESET_CPU_SHIFT); 5106a6f296SManish V Badarkhe flags |= ((comp->activator->cpu_rendezvous_required ? 0ULL : 1ULL) 5206a6f296SManish V Badarkhe << LFA_CPU_RENDEZVOUS_OPTIONAL_SHIFT); 5306a6f296SManish V Badarkhe } 5406a6f296SManish V Badarkhe 5506a6f296SManish V Badarkhe return flags; 5606a6f296SManish V Badarkhe } 5706a6f296SManish V Badarkhe 58*3f7b2862SManish V Badarkhe static int lfa_cancel(uint32_t component_id) 59*3f7b2862SManish V Badarkhe { 60*3f7b2862SManish V Badarkhe int ret = LFA_SUCCESS; 61*3f7b2862SManish V Badarkhe 62*3f7b2862SManish V Badarkhe if (lfa_component_count == 0U) { 63*3f7b2862SManish V Badarkhe return LFA_WRONG_STATE; 64*3f7b2862SManish V Badarkhe } 65*3f7b2862SManish V Badarkhe 66*3f7b2862SManish V Badarkhe /* Check if component ID is in range. */ 67*3f7b2862SManish V Badarkhe if ((component_id >= lfa_component_count) || 68*3f7b2862SManish V Badarkhe (component_id != current_activation.component_id)) { 69*3f7b2862SManish V Badarkhe return LFA_INVALID_PARAMETERS; 70*3f7b2862SManish V Badarkhe } 71*3f7b2862SManish V Badarkhe 72*3f7b2862SManish V Badarkhe ret = plat_lfa_cancel(component_id); 73*3f7b2862SManish V Badarkhe if (ret != LFA_SUCCESS) { 74*3f7b2862SManish V Badarkhe return LFA_BUSY; 75*3f7b2862SManish V Badarkhe } 76*3f7b2862SManish V Badarkhe 77*3f7b2862SManish V Badarkhe /* TODO: add proper termination prime and activate phases */ 78*3f7b2862SManish V Badarkhe lfa_reset_activation(); 79*3f7b2862SManish V Badarkhe 80*3f7b2862SManish V Badarkhe return ret; 81*3f7b2862SManish V Badarkhe } 82*3f7b2862SManish V Badarkhe 83cf48f49fSManish V Badarkhe int lfa_setup(void) 84cf48f49fSManish V Badarkhe { 85b9dee50cSManish V Badarkhe is_lfa_initialized = lfa_initialize_components(); 86b9dee50cSManish V Badarkhe if (!is_lfa_initialized) { 87b9dee50cSManish V Badarkhe return -1; 88b9dee50cSManish V Badarkhe } 89b9dee50cSManish V Badarkhe 90b9dee50cSManish V Badarkhe lfa_reset_activation(); 91b9dee50cSManish V Badarkhe 92b9dee50cSManish V Badarkhe return 0; 93cf48f49fSManish V Badarkhe } 94cf48f49fSManish V Badarkhe 95cf48f49fSManish V Badarkhe uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, 96cf48f49fSManish V Badarkhe u_register_t x3, u_register_t x4, void *cookie, 97cf48f49fSManish V Badarkhe void *handle, u_register_t flags) 98cf48f49fSManish V Badarkhe { 9906a6f296SManish V Badarkhe uint64_t retx1, retx2; 10006a6f296SManish V Badarkhe uint8_t *uuid_p; 10106a6f296SManish V Badarkhe uint32_t fw_seq_id = (uint32_t)x1; 102*3f7b2862SManish V Badarkhe int ret; 10306a6f296SManish V Badarkhe 104cf48f49fSManish V Badarkhe /** 105cf48f49fSManish V Badarkhe * TODO: Acquire serialization lock. 106cf48f49fSManish V Badarkhe */ 107b9dee50cSManish V Badarkhe 108b9dee50cSManish V Badarkhe if (!is_lfa_initialized) { 109b9dee50cSManish V Badarkhe return LFA_NOT_SUPPORTED; 110b9dee50cSManish V Badarkhe } 111b9dee50cSManish V Badarkhe 112cf48f49fSManish V Badarkhe switch (smc_fid) { 113cf48f49fSManish V Badarkhe case LFA_VERSION: 114cf48f49fSManish V Badarkhe SMC_RET1(handle, LFA_VERSION_VAL); 115cf48f49fSManish V Badarkhe break; 116cf48f49fSManish V Badarkhe 117cf48f49fSManish V Badarkhe case LFA_FEATURES: 118cf48f49fSManish V Badarkhe SMC_RET1(handle, is_lfa_fid(x1) ? LFA_SUCCESS : LFA_NOT_SUPPORTED); 119cf48f49fSManish V Badarkhe break; 120cf48f49fSManish V Badarkhe 121cf48f49fSManish V Badarkhe case LFA_GET_INFO: 122b9dee50cSManish V Badarkhe /** 123b9dee50cSManish V Badarkhe * The current specification limits this input parameter to be zero for 124b9dee50cSManish V Badarkhe * version 1.0 of LFA 125b9dee50cSManish V Badarkhe */ 126b9dee50cSManish V Badarkhe if (x1 == 0ULL) { 127b9dee50cSManish V Badarkhe SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0); 128b9dee50cSManish V Badarkhe } else { 129b9dee50cSManish V Badarkhe SMC_RET1(handle, LFA_INVALID_PARAMETERS); 130b9dee50cSManish V Badarkhe } 131cf48f49fSManish V Badarkhe break; 132cf48f49fSManish V Badarkhe 133cf48f49fSManish V Badarkhe case LFA_GET_INVENTORY: 13406a6f296SManish V Badarkhe if (lfa_component_count == 0U) { 13506a6f296SManish V Badarkhe SMC_RET1(handle, LFA_WRONG_STATE); 13606a6f296SManish V Badarkhe } 13706a6f296SManish V Badarkhe 13806a6f296SManish V Badarkhe /* 13906a6f296SManish V Badarkhe * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan 14006a6f296SManish V Badarkhe * platform firmware and create a valid number of firmware components. 14106a6f296SManish V Badarkhe */ 14206a6f296SManish V Badarkhe if (fw_seq_id >= lfa_component_count) { 14306a6f296SManish V Badarkhe SMC_RET1(handle, LFA_INVALID_PARAMETERS); 14406a6f296SManish V Badarkhe } 14506a6f296SManish V Badarkhe 14606a6f296SManish V Badarkhe /* 14706a6f296SManish V Badarkhe * grab the UUID of asked fw_seq_id and set the return UUID 14806a6f296SManish V Badarkhe * variables 14906a6f296SManish V Badarkhe */ 15006a6f296SManish V Badarkhe uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid; 15106a6f296SManish V Badarkhe memcpy(&retx1, uuid_p, sizeof(uint64_t)); 15206a6f296SManish V Badarkhe memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t)); 15306a6f296SManish V Badarkhe 15406a6f296SManish V Badarkhe /* 15506a6f296SManish V Badarkhe * check the given fw_seq_id's update available 15606a6f296SManish V Badarkhe * and accordingly set the active_pending flag 15706a6f296SManish V Badarkhe */ 15806a6f296SManish V Badarkhe lfa_components[fw_seq_id].activation_pending = 15906a6f296SManish V Badarkhe is_plat_lfa_activation_pending(fw_seq_id); 16006a6f296SManish V Badarkhe 16106a6f296SManish V Badarkhe INFO("Component %lu %s live activation:\n", x1, 16206a6f296SManish V Badarkhe lfa_components[fw_seq_id].activator ? "supports" : 16306a6f296SManish V Badarkhe "does not support"); 16406a6f296SManish V Badarkhe 16506a6f296SManish V Badarkhe if (lfa_components[fw_seq_id].activator != NULL) { 16606a6f296SManish V Badarkhe INFO("Activation pending: %s\n", 16706a6f296SManish V Badarkhe lfa_components[fw_seq_id].activation_pending ? "true" : "false"); 16806a6f296SManish V Badarkhe } 16906a6f296SManish V Badarkhe 17006a6f296SManish V Badarkhe INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2); 17106a6f296SManish V Badarkhe 17206a6f296SManish V Badarkhe SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id)); 17306a6f296SManish V Badarkhe 174cf48f49fSManish V Badarkhe break; 175cf48f49fSManish V Badarkhe 176cf48f49fSManish V Badarkhe case LFA_PRIME: 177cf48f49fSManish V Badarkhe break; 178cf48f49fSManish V Badarkhe 179cf48f49fSManish V Badarkhe case LFA_ACTIVATE: 180cf48f49fSManish V Badarkhe break; 181cf48f49fSManish V Badarkhe 182cf48f49fSManish V Badarkhe case LFA_CANCEL: 183*3f7b2862SManish V Badarkhe ret = lfa_cancel(x1); 184*3f7b2862SManish V Badarkhe SMC_RET1(handle, ret); 185cf48f49fSManish V Badarkhe break; 186cf48f49fSManish V Badarkhe 187cf48f49fSManish V Badarkhe default: 188cf48f49fSManish V Badarkhe WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid); 189cf48f49fSManish V Badarkhe SMC_RET1(handle, SMC_UNK); 190cf48f49fSManish V Badarkhe break; /* unreachable */ 191cf48f49fSManish V Badarkhe 192cf48f49fSManish V Badarkhe } 193cf48f49fSManish V Badarkhe 194cf48f49fSManish V Badarkhe SMC_RET1(handle, SMC_UNK); 195cf48f49fSManish V Badarkhe 196cf48f49fSManish V Badarkhe return 0; 197cf48f49fSManish V Badarkhe } 198