feat(lfa): add initial implementation for LFA_PRIME

This patch introduces the overall handling of the LFA_PRIME call,
including input validation and invocation flow.
While this covers the core implementation, per-component-specific
handling will be developed in a separate patch. The respective
component callbacks are invoked as part of this logic.

Signed-off-by: Manish V Badarkhe <Manish.Badarkhe@arm.com>
Change-Id: Ie13d15d0a060ae5f9704991245d2a65c7d846047
diff --git a/include/services/lfa_component_desc.h b/include/services/lfa_component_desc.h
index 1f3edbc..ca3b15e 100644
--- a/include/services/lfa_component_desc.h
+++ b/include/services/lfa_component_desc.h
@@ -12,6 +12,8 @@
 
 typedef enum {
 	PRIME_NONE = 0,
+	PRIME_STARTED,
+	PRIME_COMPLETE,
 } lfa_prime_status_t;
 
 struct lfa_component_status {
diff --git a/services/std_svc/lfa/lfa_main.c b/services/std_svc/lfa/lfa_main.c
index d518c96..d0d3bf4 100644
--- a/services/std_svc/lfa/lfa_main.c
+++ b/services/std_svc/lfa/lfa_main.c
@@ -21,6 +21,20 @@
 	current_activation.prime_status = PRIME_NONE;
 }
 
+static int convert_to_lfa_error(int ret)
+{
+	switch (ret) {
+	case 0:
+		return LFA_SUCCESS;
+	case -EAUTH:
+		return LFA_AUTH_ERROR;
+	case -ENOMEM:
+		return LFA_NO_MEMORY;
+	default:
+		return LFA_DEVICE_ERROR;
+	}
+}
+
 static bool lfa_initialize_components(void)
 {
 	lfa_component_count = plat_lfa_get_components(&lfa_components);
@@ -80,6 +94,66 @@
 	return ret;
 }
 
+static int lfa_prime(uint32_t component_id, uint64_t *flags)
+{
+	int ret = LFA_SUCCESS;
+	struct lfa_component_ops *activator;
+
+	if (lfa_component_count == 0U ||
+	    !lfa_components[component_id].activation_pending) {
+		return LFA_WRONG_STATE;
+	}
+
+	/* Check if fw_seq_id is in range. */
+	if (component_id >= lfa_component_count) {
+		return LFA_INVALID_PARAMETERS;
+	}
+
+	if (lfa_components[component_id].activator == NULL) {
+		return LFA_NOT_SUPPORTED;
+	}
+
+	switch (current_activation.prime_status) {
+	case PRIME_NONE:
+		current_activation.component_id = component_id;
+		current_activation.prime_status = PRIME_STARTED;
+		break;
+
+	case PRIME_STARTED:
+		if (current_activation.component_id != component_id) {
+			/* Mismatched component trying to continue PRIME - error */
+			return LFA_WRONG_STATE;
+		}
+		break;
+
+	case PRIME_COMPLETE:
+	default:
+		break;
+	}
+
+	ret = plat_lfa_load_auth_image(component_id);
+	ret = convert_to_lfa_error(ret);
+
+	activator = lfa_components[component_id].activator;
+	if (activator->prime != NULL) {
+		ret = activator->prime(&current_activation);
+		if (ret != LFA_SUCCESS) {
+			/*
+			 * TODO: it should be LFA_PRIME_FAILED but specification
+			 * has not define this error yet
+			 */
+			return ret;
+		}
+	}
+
+	current_activation.prime_status = PRIME_COMPLETE;
+
+	/* TODO: split this into multiple PRIME calls */
+	*flags = 0ULL;
+
+	return ret;
+}
+
 int lfa_setup(void)
 {
 	is_lfa_initialized = lfa_initialize_components();
@@ -97,6 +171,7 @@
 			 void *handle, u_register_t flags)
 {
 	uint64_t retx1, retx2;
+	uint64_t lfa_flags;
 	uint8_t *uuid_p;
 	uint32_t fw_seq_id = (uint32_t)x1;
 	int ret;
@@ -174,6 +249,12 @@
 		break;
 
 	case LFA_PRIME:
+		ret = lfa_prime(x1, &lfa_flags);
+		if (ret != LFA_SUCCESS) {
+			SMC_RET1(handle, ret);
+		} else {
+			SMC_RET2(handle, ret, lfa_flags);
+		}
 		break;
 
 	case LFA_ACTIVATE: