Implement late binding for runtime hooks

At present SPD power management hooks and BL3-2 entry are implemented
using weak references. This would have the handlers bound and registered
with the core framework at build time, but leaves them dangling if a
service fails to initialize at runtime.

This patch replaces implementation by requiring runtime handlers to
register power management and deferred initialization hooks with the
core framework at runtime. The runtime services are to register the
hooks only as the last step, after having all states successfully
initialized.

Change-Id: Ibe788a2a381ef39aec1d4af5ba02376e67269782
diff --git a/services/psci/psci_afflvl_off.c b/services/psci/psci_afflvl_off.c
index 24c212f..3763f6f 100644
--- a/services/psci/psci_afflvl_off.c
+++ b/services/psci/psci_afflvl_off.c
@@ -65,8 +65,8 @@
 	 * to let it do any bookeeping. Assume that the SPD always reports an
 	 * E_DENIED error if SP refuse to power down
 	 */
-	if (spd_pm.svc_off) {
-		rc = spd_pm.svc_off(0);
+	if (psci_spd_pm && psci_spd_pm->svc_off) {
+		rc = psci_spd_pm->svc_off(0);
 		if (rc)
 			return rc;
 	}
diff --git a/services/psci/psci_afflvl_on.c b/services/psci/psci_afflvl_on.c
index ee16c73..0878f21 100644
--- a/services/psci/psci_afflvl_on.c
+++ b/services/psci/psci_afflvl_on.c
@@ -95,8 +95,8 @@
 	 * to let it do any bookeeping. If the handler encounters an error, it's
 	 * expected to assert within
 	 */
-	if (spd_pm.svc_on)
-		spd_pm.svc_on(target_cpu);
+	if (psci_spd_pm && psci_spd_pm->svc_on)
+		psci_spd_pm->svc_on(target_cpu);
 
 	/*
 	 * Arch. management: Derive the re-entry information for
@@ -387,8 +387,8 @@
 	 * Dispatcher to let it do any bookeeping. If the handler encounters an
 	 * error, it's expected to assert within
 	 */
-	if (spd_pm.svc_on_finish)
-		spd_pm.svc_on_finish(0);
+	if (psci_spd_pm && psci_spd_pm->svc_on_finish)
+		psci_spd_pm->svc_on_finish(0);
 
 	/*
 	 * Generic management: Now we just need to retrieve the
diff --git a/services/psci/psci_afflvl_suspend.c b/services/psci/psci_afflvl_suspend.c
index 62d270f..138d033 100644
--- a/services/psci/psci_afflvl_suspend.c
+++ b/services/psci/psci_afflvl_suspend.c
@@ -104,8 +104,8 @@
 	 * Dispatcher to let it do any bookeeping. If the handler encounters an
 	 * error, it's expected to assert within
 	 */
-	if (spd_pm.svc_suspend)
-		spd_pm.svc_suspend(power_state);
+	if (psci_spd_pm && psci_spd_pm->svc_suspend)
+		psci_spd_pm->svc_suspend(power_state);
 
 	/* State management: mark this cpu as suspended */
 	psci_set_state(cpu_node, PSCI_STATE_SUSPEND);
@@ -459,9 +459,9 @@
 	 * Dispatcher to let it do any bookeeping. If the handler encounters an
 	 * error, it's expected to assert within
 	 */
-	if (spd_pm.svc_suspend) {
+	if (psci_spd_pm && psci_spd_pm->svc_suspend) {
 		suspend_level = psci_get_suspend_afflvl(cpu_node);
-		spd_pm.svc_suspend_finish(suspend_level);
+		psci_spd_pm->svc_suspend_finish(suspend_level);
 	}
 
 	/*
diff --git a/services/psci/psci_common.c b/services/psci/psci_common.c
index cacd97e..236309c 100644
--- a/services/psci/psci_common.c
+++ b/services/psci/psci_common.c
@@ -41,10 +41,10 @@
 #include "debug.h"
 
 /*
- * Provide a null weak instantiation for SPD power management operations. An SPD
- * can define its own instance overriding this one
+ * SPD power management operations, expected to be supplied by the registered
+ * SPD on successful SP initialization
  */
-const spd_pm_ops __attribute__((weak)) spd_pm = {0};
+const spd_pm_ops *psci_spd_pm;
 
 /*******************************************************************************
  * Arrays that contains information needs to resume a cpu's execution when woken
@@ -556,3 +556,13 @@
 				  end_afflvl,
 				  mpidr_nodes);
 }
+
+/*******************************************************************************
+ * This function initializes the set of hooks that PSCI invokes as part of power
+ * management operation. The power management hooks are expected to be provided
+ * by the SPD, after it finishes all its initialization
+ ******************************************************************************/
+void psci_register_spd_pm_hook(const spd_pm_ops *pm)
+{
+	psci_spd_pm = pm;
+}
diff --git a/services/psci/psci_private.h b/services/psci/psci_private.h
index 351cbe8..4f47ca5 100644
--- a/services/psci/psci_private.h
+++ b/services/psci/psci_private.h
@@ -96,10 +96,9 @@
 extern afflvl_power_on_finisher psci_afflvl_sus_finish_handlers[];
 
 /*******************************************************************************
- * Weak declarations to allow PSCI to cope on a system where the Secure Payload
- * Dispatcher is missing. An SPD will define this structure when present.
+ * SPD's power management hooks registered with PSCI
  ******************************************************************************/
-extern const spd_pm_ops spd_pm;
+extern const spd_pm_ops *psci_spd_pm;
 
 /*******************************************************************************
  * Function prototypes