Merge "FVP_Base_AEMv8A platform: Fix cache maintenance operations" into integration
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index fa857fb..2b4ae1a 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -112,6 +112,7 @@
 /* CLIDR definitions */
 #define LOUIS_SHIFT		U(21)
 #define LOC_SHIFT		U(24)
+#define CTYPE_SHIFT(n)		U(3 * (n - 1))
 #define CLIDR_FIELD_WIDTH	U(3)
 
 /* CSSELR definitions */
diff --git a/lib/cpus/aarch64/aem_generic.S b/lib/cpus/aarch64/aem_generic.S
index 51b5ce9..6291e43 100644
--- a/lib/cpus/aarch64/aem_generic.S
+++ b/lib/cpus/aarch64/aem_generic.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -18,15 +18,43 @@
 	msr	sctlr_el3, x1
 	isb
 
-	mov	x0, #DCCISW
-
 	/* ---------------------------------------------
-	 * Flush L1 cache to PoU.
+	 * AEM model supports L3 caches in which case L2
+	 * will be private per core caches and flush
+	 * from L1 to L2 is not sufficient.
 	 * ---------------------------------------------
 	 */
-	b	dcsw_op_louis
-endfunc aem_generic_core_pwr_dwn
+	mrs	x1, clidr_el1
 
+	/* ---------------------------------------------
+	 * Check if L3 cache is implemented.
+	 * ---------------------------------------------
+	 */
+	tst	x1, ((1 << CLIDR_FIELD_WIDTH) - 1) << CTYPE_SHIFT(3)
+
+	/* ---------------------------------------------
+	 * There is no L3 cache, flush L1 to L2 only.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	b.eq	dcsw_op_level1
+
+	mov	x18, x30
+
+	/* ---------------------------------------------
+	 * Flush L1 cache to L2.
+	 * ---------------------------------------------
+	 */
+	bl	dcsw_op_level1
+	mov	x30, x18
+
+	/* ---------------------------------------------
+	 * Flush L2 cache to L3.
+	 * ---------------------------------------------
+	 */
+	mov	x0, #DCCISW
+	b	dcsw_op_level2
+endfunc aem_generic_core_pwr_dwn
 
 func aem_generic_cluster_pwr_dwn
 	/* ---------------------------------------------
@@ -39,7 +67,7 @@
 	isb
 
 	/* ---------------------------------------------
-	 * Flush L1 and L2 caches to PoC.
+	 * Flush all caches to PoC.
 	 * ---------------------------------------------
 	 */
 	mov	x0, #DCCISW