PSCI: Introduce new platform interface to describe topology

This patch removes the assumption in the current PSCI implementation that MPIDR
based affinity levels map directly to levels in a power domain tree. This
enables PSCI generic code to support complex power domain topologies as
envisaged by PSCIv1.0 specification. The platform interface for querying
the power domain topology has been changed such that:

1. The generic PSCI code does not generate MPIDRs and use them to query the
   platform about the number of power domains at a particular power level. The
   platform now provides a description of the power domain tree on the SoC
   through a data structure. The existing platform APIs to provide the same
   information have been removed.

2. The linear indices returned by plat_core_pos_by_mpidr() and
   plat_my_core_pos() are used to retrieve core power domain nodes from the
   power domain tree. Power domains above the core level are accessed using a
   'parent' field in the tree node descriptors.

The platform describes the power domain tree in an array of 'unsigned
char's. The first entry in the array specifies the number of power domains at
the highest power level implemented in the system. Each susbsequent entry
corresponds to a power domain and contains the number of power domains that are
its direct children. This array is exported to the generic PSCI implementation
via the new `plat_get_power_domain_tree_desc()` platform API.

The PSCI generic code uses this array to populate its internal power domain tree
using the Breadth First Search like algorithm. The tree is split into two
arrays:

1. An array that contains all the core power domain nodes

2. An array that contains all the other power domain nodes

A separate array for core nodes allows certain core specific optimisations to
be implemented e.g. remove the bakery lock, re-use per-cpu data framework for
storing some information.

Entries in the core power domain array are allocated such that the
array index of the domain is equal to the linear index returned by
plat_core_pos_by_mpidr() and plat_my_core_pos() for the MPIDR
corresponding to that domain. This relationship is key to be able to use
an MPIDR to find the corresponding core power domain node, traverse to higher
power domain nodes and index into arrays that contain core specific
information.

An introductory document has been added to briefly describe the new interface.

Change-Id: I4b444719e8e927ba391cae48a23558308447da13
diff --git a/services/std_svc/psci1.0/psci_suspend.c b/services/std_svc/psci1.0/psci_suspend.c
index 3d1bf09..c402937 100644
--- a/services/std_svc/psci1.0/psci_suspend.c
+++ b/services/std_svc/psci1.0/psci_suspend.c
@@ -82,15 +82,15 @@
 }
 
 /*******************************************************************************
- * This function gets the state id of the cpu specified by the 'mpidr' parameter
+ * This function gets the state id of the cpu specified by the cpu index
  * from the power state parameter saved in the per-cpu data array. Returns
  * PSCI_INVALID_DATA if the power state saved is invalid.
  ******************************************************************************/
-int psci_get_suspend_stateid_by_mpidr(unsigned long mpidr)
+int psci_get_suspend_stateid_by_idx(unsigned long cpu_idx)
 {
 	unsigned int power_state;
 
-	power_state = get_cpu_data_by_index(plat_core_pos_by_mpidr(mpidr),
+	power_state = get_cpu_data_by_index(cpu_idx,
 					    psci_svc_cpu_data.power_state);
 
 	return ((power_state == PSCI_INVALID_DATA) ?
@@ -114,12 +114,10 @@
  * the state transition has been done, no further error is expected and it is
  * not possible to undo any of the actions taken beyond that point.
  ******************************************************************************/
-void psci_cpu_suspend_start(entry_point_info_t *ep,
-			int end_pwrlvl)
+void psci_cpu_suspend_start(entry_point_info_t *ep, int end_pwrlvl)
 {
 	int skip_wfi = 0;
-	mpidr_pwr_map_nodes_t mpidr_nodes;
-	unsigned int max_phys_off_pwrlvl;
+	unsigned int max_phys_off_pwrlvl, idx = plat_my_core_pos();
 	unsigned long psci_entrypoint;
 
 	/*
@@ -130,24 +128,12 @@
 			psci_plat_pm_ops->pwr_domain_suspend_finish);
 
 	/*
-	 * Collect the pointers to the nodes in the topology tree for
-	 * each power domain instance in the mpidr. If this function does
-	 * not return successfully then either the mpidr or the power
-	 * levels are incorrect. Either way, this an internal TF error
-	 * therefore assert.
-	 */
-	if (psci_get_pwr_map_nodes(read_mpidr_el1() & MPIDR_AFFINITY_MASK,
-		   MPIDR_AFFLVL0, end_pwrlvl, mpidr_nodes) != PSCI_E_SUCCESS)
-		assert(0);
-
-	/*
 	 * This function acquires the lock corresponding to each power
 	 * level so that by the time all locks are taken, the system topology
 	 * is snapshot and state management can be done safely.
 	 */
-	psci_acquire_pwr_domain_locks(MPIDR_AFFLVL0,
-				  end_pwrlvl,
-				  mpidr_nodes);
+	psci_acquire_pwr_domain_locks(end_pwrlvl,
+				      idx);
 
 	/*
 	 * We check if there are any pending interrupts after the delay
@@ -169,17 +155,15 @@
 
 	/*
 	 * This function updates the state of each power domain instance
-	 * corresponding to the mpidr in the range of power levels
+	 * corresponding to the cpu index in the range of power levels
 	 * specified.
 	 */
-	psci_do_state_coordination(MPIDR_AFFLVL0,
-				  end_pwrlvl,
-				  mpidr_nodes,
-				  PSCI_STATE_SUSPEND);
+	psci_do_state_coordination(end_pwrlvl,
+				   idx,
+				   PSCI_STATE_SUSPEND);
 
-	max_phys_off_pwrlvl = psci_find_max_phys_off_pwrlvl(MPIDR_AFFLVL0,
-							    end_pwrlvl,
-							    mpidr_nodes);
+	max_phys_off_pwrlvl = psci_find_max_phys_off_pwrlvl(end_pwrlvl,
+							    idx);
 	assert(max_phys_off_pwrlvl != PSCI_INVALID_DATA);
 
 	/*
@@ -210,9 +194,8 @@
 	 * Release the locks corresponding to each power level in the
 	 * reverse order to which they were acquired.
 	 */
-	psci_release_pwr_domain_locks(MPIDR_AFFLVL0,
-				  end_pwrlvl,
-				  mpidr_nodes);
+	psci_release_pwr_domain_locks(end_pwrlvl,
+				      idx);
 	if (!skip_wfi)
 		psci_power_down_wfi();
 }
@@ -221,15 +204,14 @@
  * The following functions finish an earlier suspend request. They
  * are called by the common finisher routine in psci_common.c.
  ******************************************************************************/
-void psci_cpu_suspend_finish(pwr_map_node_t *node[], int pwrlvl)
+void psci_cpu_suspend_finish(unsigned int cpu_idx, int max_off_pwrlvl)
 {
 	int32_t suspend_level;
 	uint64_t counter_freq;
 
-	assert(node[pwrlvl]->level == pwrlvl);
-
 	/* Ensure we have been woken up from a suspended state */
-	assert(psci_get_state(node[MPIDR_AFFLVL0]) == PSCI_STATE_SUSPEND);
+	assert(psci_get_state(cpu_idx, PSCI_CPU_PWR_LVL)
+				== PSCI_STATE_SUSPEND);
 
 	/*
 	 * Plat. management: Perform the platform specific actions
@@ -238,7 +220,7 @@
 	 * wrong then assert as there is no way to recover from this
 	 * situation.
 	 */
-	psci_plat_pm_ops->pwr_domain_suspend_finish(pwrlvl);
+	psci_plat_pm_ops->pwr_domain_suspend_finish(max_off_pwrlvl);
 
 	/*
 	 * Arch. management: Enable the data cache, manage stack memory and
@@ -275,4 +257,3 @@
 	/* Clean caches before re-entering normal world */
 	dcsw_op_louis(DCCSW);
 }
-