feat(lfa): add initial implementation for LFA_ACTIVATE

This patch introduces the overall handling of the LFA_ACTIVATE 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.

Change-Id: Ie9d4584fc0c0abc9a9faffed62165b4461efed3a
Signed-off-by: Manish V Badarkhe <Manish.Badarkhe@arm.com>
diff --git a/include/services/lfa_component_desc.h b/include/services/lfa_component_desc.h
index ca3b15e..5f198bd 100644
--- a/include/services/lfa_component_desc.h
+++ b/include/services/lfa_component_desc.h
@@ -19,6 +19,7 @@
 struct lfa_component_status {
 	uint32_t component_id;
 	lfa_prime_status_t prime_status;
+	bool cpu_rendezvous_required;
 };
 
 typedef int32_t (*component_prime_fn)(struct lfa_component_status *activation);
diff --git a/include/services/lfa_svc.h b/include/services/lfa_svc.h
index 26dbb7a..69d549c 100644
--- a/include/services/lfa_svc.h
+++ b/include/services/lfa_svc.h
@@ -57,6 +57,8 @@
 #define LFA_MAY_RESET_CPU_SHIFT			2
 #define LFA_CPU_RENDEZVOUS_OPTIONAL_SHIFT	3
 
+#define LFA_SKIP_CPU_RENDEZVOUS_BIT		BIT(0)
+
 /* List of errors as per the specification */
 enum lfa_retc {
 	LFA_SUCCESS			=  0,
diff --git a/services/std_svc/lfa/lfa_main.c b/services/std_svc/lfa/lfa_main.c
index d0d3bf4..1cf65ae 100644
--- a/services/std_svc/lfa/lfa_main.c
+++ b/services/std_svc/lfa/lfa_main.c
@@ -4,6 +4,8 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <errno.h>
+
 #include <plat/common/platform.h>
 #include <services/bl31_lfa.h>
 #include <services/lfa_svc.h>
@@ -19,6 +21,7 @@
 {
 	current_activation.component_id = LFA_INVALID_COMPONENT;
 	current_activation.prime_status = PRIME_NONE;
+	current_activation.cpu_rendezvous_required = false;
 }
 
 static int convert_to_lfa_error(int ret)
@@ -94,6 +97,58 @@
 	return ret;
 }
 
+static int lfa_activate(uint32_t component_id, uint64_t flags,
+			uint64_t ep_address, uint64_t context_id)
+{
+	int ret = LFA_ACTIVATION_FAILED;
+	struct lfa_component_ops *activator;
+
+	if ((lfa_component_count == 0U) ||
+	    (!lfa_components[component_id].activation_pending) ||
+	    (current_activation.prime_status != PRIME_COMPLETE)) {
+		return LFA_COMPONENT_WRONG_STATE;
+	}
+
+	/* Check if fw_seq_id is in range. */
+	if ((component_id >= lfa_component_count) ||
+	    (current_activation.component_id != component_id)) {
+		return LFA_INVALID_PARAMETERS;
+	}
+
+	if (lfa_components[component_id].activator == NULL) {
+		return LFA_NOT_SUPPORTED;
+	}
+
+	activator = lfa_components[component_id].activator;
+	if (activator->activate != NULL) {
+		/*
+		 * Pass skip_cpu_rendezvous (flag[0]) only if flag[0]==1
+		 * & CPU_RENDEZVOUS is not required.
+		 */
+		if (flags & LFA_SKIP_CPU_RENDEZVOUS_BIT) {
+			if (!activator->cpu_rendezvous_required) {
+				INFO("Skipping rendezvous requested by caller.\n");
+				current_activation.cpu_rendezvous_required = false;
+			}
+			/*
+			 * Return error if caller tries to skip rendezvous when
+			 * it is required.
+			 */
+			else {
+				ERROR("CPU Rendezvous is required, can't skip.\n");
+				return LFA_INVALID_PARAMETERS;
+			}
+		}
+
+		ret = activator->activate(&current_activation, ep_address,
+					  context_id);
+	}
+
+	lfa_components[component_id].activation_pending = false;
+
+	return ret;
+}
+
 static int lfa_prime(uint32_t component_id, uint64_t *flags)
 {
 	int ret = LFA_SUCCESS;
@@ -258,6 +313,10 @@
 		break;
 
 	case LFA_ACTIVATE:
+		ret = lfa_activate(fw_seq_id, x2, x3, x4);
+		/* TODO: implement activate again */
+		SMC_RET2(handle, ret, 0ULL);
+
 		break;
 
 	case LFA_CANCEL: