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(¤t_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