Add provision to extend CPU operations at more levels

Various CPU drivers in ARM Trusted Firmware register functions to handle
power-down operations. At present, separate functions are registered to
power down individual cores and clusters.

This scheme operates on the basis of core and cluster, and doesn't cater
for extending the hierarchy for power-down operations. For example,
future CPUs might support multiple threads which might need powering
down individually.

This patch therefore reworks the CPU operations framework to allow for
registering power down handlers on specific level basis. Henceforth:

  - Generic code invokes CPU power down operations by the level
    required.

  - CPU drivers explicitly mention CPU_NO_RESET_FUNC when the CPU has no
    reset function.

  - CPU drivers register power down handlers as a list: a mandatory
    handler for level 0, and optional handlers for higher levels.

All existing CPU drivers are adapted to the new CPU operations framework
without needing any functional changes within.

Also update firmware design guide.

Change-Id: I1826842d37a9e60a9e85fdcee7b4b8f6bc1ad043
Signed-off-by: Jeenu Viswambharan <jeenu.viswambharan@arm.com>
diff --git a/lib/cpus/aarch64/aem_generic.S b/lib/cpus/aarch64/aem_generic.S
index 0ab5253..0cedd85 100644
--- a/lib/cpus/aarch64/aem_generic.S
+++ b/lib/cpus/aarch64/aem_generic.S
@@ -90,7 +90,11 @@
 
 
 /* cpu_ops for Base AEM FVP */
-declare_cpu_ops aem_generic, BASE_AEM_MIDR, 1
+declare_cpu_ops aem_generic, BASE_AEM_MIDR, CPU_NO_RESET_FUNC, \
+	aem_generic_core_pwr_dwn, \
+	aem_generic_cluster_pwr_dwn
 
 /* cpu_ops for Foundation FVP */
-declare_cpu_ops aem_generic, FOUNDATION_AEM_MIDR, 1
+declare_cpu_ops aem_generic, FOUNDATION_AEM_MIDR, CPU_NO_RESET_FUNC, \
+	aem_generic_core_pwr_dwn, \
+	aem_generic_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a35.S b/lib/cpus/aarch64/cortex_a35.S
index ba29d6d..c17c8f1 100644
--- a/lib/cpus/aarch64/cortex_a35.S
+++ b/lib/cpus/aarch64/cortex_a35.S
@@ -157,4 +157,7 @@
 	ret
 endfunc cortex_a35_cpu_reg_dump
 
-declare_cpu_ops cortex_a35, CORTEX_A35_MIDR
+declare_cpu_ops cortex_a35, CORTEX_A35_MIDR, \
+	cortex_a35_reset_func, \
+	cortex_a35_core_pwr_dwn, \
+	cortex_a35_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a53.S b/lib/cpus/aarch64/cortex_a53.S
index ed546e7..06be9ce 100644
--- a/lib/cpus/aarch64/cortex_a53.S
+++ b/lib/cpus/aarch64/cortex_a53.S
@@ -244,4 +244,7 @@
 	ret
 endfunc cortex_a53_cpu_reg_dump
 
-declare_cpu_ops cortex_a53, CORTEX_A53_MIDR
+declare_cpu_ops cortex_a53, CORTEX_A53_MIDR, \
+	cortex_a53_reset_func, \
+	cortex_a53_core_pwr_dwn, \
+	cortex_a53_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a57.S b/lib/cpus/aarch64/cortex_a57.S
index d6b181d..e531b1e 100644
--- a/lib/cpus/aarch64/cortex_a57.S
+++ b/lib/cpus/aarch64/cortex_a57.S
@@ -488,4 +488,7 @@
 endfunc cortex_a57_cpu_reg_dump
 
 
-declare_cpu_ops cortex_a57, CORTEX_A57_MIDR
+declare_cpu_ops cortex_a57, CORTEX_A57_MIDR, \
+	cortex_a57_reset_func, \
+	cortex_a57_core_pwr_dwn, \
+	cortex_a57_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a72.S b/lib/cpus/aarch64/cortex_a72.S
index 9f04fb7..fffc99f 100644
--- a/lib/cpus/aarch64/cortex_a72.S
+++ b/lib/cpus/aarch64/cortex_a72.S
@@ -242,4 +242,7 @@
 endfunc cortex_a72_cpu_reg_dump
 
 
-declare_cpu_ops cortex_a72, CORTEX_A72_MIDR
+declare_cpu_ops cortex_a72, CORTEX_A72_MIDR, \
+	cortex_a72_reset_func, \
+	cortex_a72_core_pwr_dwn, \
+	cortex_a72_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cortex_a73.S b/lib/cpus/aarch64/cortex_a73.S
index e1615db..49d5449 100644
--- a/lib/cpus/aarch64/cortex_a73.S
+++ b/lib/cpus/aarch64/cortex_a73.S
@@ -153,4 +153,7 @@
 	ret
 endfunc cortex_a73_cpu_reg_dump
 
-declare_cpu_ops cortex_a73, CORTEX_A73_MIDR
+declare_cpu_ops cortex_a73, CORTEX_A73_MIDR, \
+	cortex_a73_reset_func, \
+	cortex_a73_core_pwr_dwn, \
+	cortex_a73_cluster_pwr_dwn
diff --git a/lib/cpus/aarch64/cpu_helpers.S b/lib/cpus/aarch64/cpu_helpers.S
index dab933c..ec7f1dd 100644
--- a/lib/cpus/aarch64/cpu_helpers.S
+++ b/lib/cpus/aarch64/cpu_helpers.S
@@ -74,31 +74,23 @@
 
 #if IMAGE_BL31 /* The power down core and cluster is needed only in  BL31 */
 	/*
-	 * The prepare core power down function for all platforms.  After
-	 * the cpu_ops pointer is retrieved from cpu_data, the corresponding
-	 * pwr_dwn_core in the cpu_ops is invoked.
+	 * void prepare_cpu_pwr_dwn(unsigned int power_level)
+	 *
+	 * Prepare CPU power down function for all platforms. The function takes
+	 * a domain level to be powered down as its parameter. After the cpu_ops
+	 * pointer is retrieved from cpu_data, the handler for requested power
+	 * level is called.
 	 */
-	.globl	prepare_core_pwr_dwn
-func prepare_core_pwr_dwn
-	mrs	x1, tpidr_el3
-	ldr	x0, [x1, #CPU_DATA_CPU_OPS_PTR]
-#if ASM_ASSERTION
-	cmp	x0, #0
-	ASM_ASSERT(ne)
-#endif
-
-	/* Get the cpu_ops core_pwr_dwn handler */
-	ldr	x1, [x0, #CPU_PWR_DWN_CORE]
-	br	x1
-endfunc prepare_core_pwr_dwn
-
+	.globl	prepare_cpu_pwr_dwn
+func prepare_cpu_pwr_dwn
 	/*
-	 * The prepare cluster power down function for all platforms.  After
-	 * the cpu_ops pointer is retrieved from cpu_data, the corresponding
-	 * pwr_dwn_cluster in the cpu_ops is invoked.
+	 * If the given power level exceeds CPU_MAX_PWR_DWN_OPS, we call the
+	 * power down handler for the last power level
 	 */
-	.globl	prepare_cluster_pwr_dwn
-func prepare_cluster_pwr_dwn
+	mov_imm	x2, (CPU_MAX_PWR_DWN_OPS - 1)
+	cmp	x0, x2
+	csel	x2, x2, x0, hi
+
 	mrs	x1, tpidr_el3
 	ldr	x0, [x1, #CPU_DATA_CPU_OPS_PTR]
 #if ASM_ASSERTION
@@ -106,10 +98,12 @@
 	ASM_ASSERT(ne)
 #endif
 
-	/* Get the cpu_ops cluster_pwr_dwn handler */
-	ldr	x1, [x0, #CPU_PWR_DWN_CLUSTER]
+	/* Get the appropriate power down handler */
+	mov	x1, #CPU_PWR_DWN_OPS
+	add	x1, x1, x2, lsl #3
+	ldr	x1, [x0, x1]
 	br	x1
-endfunc prepare_cluster_pwr_dwn
+endfunc prepare_cpu_pwr_dwn
 
 
 	/*
diff --git a/lib/cpus/aarch64/denver.S b/lib/cpus/aarch64/denver.S
index bce0573..0b61440 100644
--- a/lib/cpus/aarch64/denver.S
+++ b/lib/cpus/aarch64/denver.S
@@ -163,4 +163,7 @@
 	ret
 endfunc denver_cpu_reg_dump
 
-declare_cpu_ops denver, DENVER_1_0_MIDR
+declare_cpu_ops denver, DENVER_1_0_MIDR, \
+	denver_reset_func, \
+	denver_core_pwr_dwn, \
+	denver_cluster_pwr_dwn