Merge "fix(docs): add LTS maintainers" into integration
diff --git a/Makefile b/Makefile
index f574130..afb610f 100644
--- a/Makefile
+++ b/Makefile
@@ -1080,6 +1080,7 @@
         SIMICS_BUILD \
         FEATURE_DETECTION \
 	TRNG_SUPPORT \
+	CONDITIONAL_CMO \
 )))
 
 $(eval $(call assert_numerics,\
@@ -1241,6 +1242,7 @@
         FEATURE_DETECTION \
         TWED_DELAY \
         ENABLE_FEAT_TWED \
+	CONDITIONAL_CMO \
 )))
 
 ifeq (${SANITIZE_UB},trap)
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index eba31da..0b42a79 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -1032,6 +1032,12 @@
   functionalities). When enabled (``1``), a mocked version of the APIs are used.
   The default value is 0.
 
+- ``CONDITIONAL_CMO``: Boolean option to enable call to platform-defined routine
+  ``plat_can_cmo`` which will return zero if cache management operations should
+  be skipped and non-zero otherwise. By default, this option is disabled which
+  means platform hook won't be checked and CMOs will always be performed when
+  related functions are called.
+
 GICv3 driver options
 --------------------
 
diff --git a/docs/getting_started/porting-guide.rst b/docs/getting_started/porting-guide.rst
index d216d81..9019e83 100644
--- a/docs/getting_started/porting-guide.rst
+++ b/docs/getting_started/porting-guide.rst
@@ -1461,6 +1461,22 @@
 
 When the MEASURED_BOOT flag is disabled, this function doesn't do anything.
 
+Function : plat_can_cmo()
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : uint64_t
+
+When CONDITIONAL_CMO flag is enabled:
+
+- This function indicates whether cache management operations should be
+  performed. It returns 0 if CMOs should be skipped and non-zero
+  otherwise.
+- The function must not clobber x2 and x3. It's also not safe to rely on stack.
+  Otherwise obey AAPCS.
+
 Modifications specific to a Boot Loader stage
 ---------------------------------------------
 
diff --git a/lib/aarch32/cache_helpers.S b/lib/aarch32/cache_helpers.S
index 13d1872..fd9b33f 100644
--- a/lib/aarch32/cache_helpers.S
+++ b/lib/aarch32/cache_helpers.S
@@ -37,12 +37,27 @@
 	bx	lr
 .endm
 
+.macro check_plat_can_cmo
+#if CONDITIONAL_CMO
+	mov	r3, lr
+	mov	r2, r0
+	bl	plat_can_cmo
+	mov	lr, r3
+	cmp	r0, #0
+	bne	1f
+	bx	lr
+1:
+	mov	r0, r2
+#endif
+.endm
+
 	/* ------------------------------------------
 	 * Clean+Invalidate from base address till
 	 * size. 'r0' = addr, 'r1' = size
 	 * ------------------------------------------
 	 */
 func flush_dcache_range
+	check_plat_can_cmo
 	do_dcache_maintenance_by_mva cimvac, DCCIMVAC
 endfunc flush_dcache_range
 
@@ -52,6 +67,7 @@
 	 * ------------------------------------------
 	 */
 func clean_dcache_range
+	check_plat_can_cmo
 	do_dcache_maintenance_by_mva cmvac, DCCMVAC
 endfunc clean_dcache_range
 
@@ -61,6 +77,7 @@
 	 * ------------------------------------------
 	 */
 func inv_dcache_range
+	check_plat_can_cmo
 	do_dcache_maintenance_by_mva imvac, DCIMVAC
 endfunc inv_dcache_range
 
@@ -168,6 +185,7 @@
 	 * ---------------------------------------------------------------
 	 */
 func dcsw_op_louis
+	check_plat_can_cmo
 	dcsw_op #LOUIS_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
 endfunc	dcsw_op_louis
 
@@ -180,6 +198,7 @@
 	 * ---------------------------------------------------------------
 	 */
 func dcsw_op_all
+	check_plat_can_cmo
 	dcsw_op #LOC_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
 endfunc	dcsw_op_all
 
@@ -205,6 +224,7 @@
 	 * ---------------------------------------------------------------
 	 */
 func dcsw_op_level1
+	check_plat_can_cmo
 	dcsw_op_level #(1 << LEVEL_SHIFT)
 endfunc dcsw_op_level1
 
@@ -217,6 +237,7 @@
 	 * ---------------------------------------------------------------
 	 */
 func dcsw_op_level2
+	check_plat_can_cmo
 	dcsw_op_level #(2 << LEVEL_SHIFT)
 endfunc dcsw_op_level2
 
@@ -229,5 +250,6 @@
 	 * ---------------------------------------------------------------
 	 */
 func dcsw_op_level3
+	check_plat_can_cmo
 	dcsw_op_level #(3 << LEVEL_SHIFT)
 endfunc dcsw_op_level3
diff --git a/lib/aarch64/cache_helpers.S b/lib/aarch64/cache_helpers.S
index 6faf545..67fafb1 100644
--- a/lib/aarch64/cache_helpers.S
+++ b/lib/aarch64/cache_helpers.S
@@ -36,12 +36,26 @@
 exit_loop_\op:
 	ret
 .endm
+
+.macro check_plat_can_cmo
+#if CONDITIONAL_CMO
+	mov	x3, x30
+	mov	x2, x0
+	bl	plat_can_cmo
+	mov	x30, x3
+	cbnz	x0, 1f
+	ret
+1:
+	mov	 x0, x2
+#endif
+.endm
 	/* ------------------------------------------
 	 * Clean+Invalidate from base address till
 	 * size. 'x0' = addr, 'x1' = size
 	 * ------------------------------------------
 	 */
 func flush_dcache_range
+	check_plat_can_cmo
 	do_dcache_maintenance_by_mva civac
 endfunc flush_dcache_range
 
@@ -51,6 +65,7 @@
 	 * ------------------------------------------
 	 */
 func clean_dcache_range
+	check_plat_can_cmo
 	do_dcache_maintenance_by_mva cvac
 endfunc clean_dcache_range
 
@@ -60,6 +75,7 @@
 	 * ------------------------------------------
 	 */
 func inv_dcache_range
+	check_plat_can_cmo
 	do_dcache_maintenance_by_mva ivac
 endfunc inv_dcache_range
 
@@ -79,6 +95,7 @@
 func flush_dcache_to_popa_range
 	/* Exit early if size is zero */
 	cbz	x1, exit_loop_dc_cipapa
+	check_plat_can_cmo
 	dcache_line_size x2, x3
 	sub	x3, x2, #1
 	bic	x0, x0, x3
@@ -205,6 +222,7 @@
 
 
 func dcsw_op_all
+	check_plat_can_cmo
 	dcsw_op #LOC_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
 endfunc dcsw_op_all
 
@@ -228,6 +246,7 @@
 	 * ---------------------------------------------------------------
 	 */
 func dcsw_op_level1
+	check_plat_can_cmo
 	dcsw_op_level #(1 << LEVEL_SHIFT)
 endfunc dcsw_op_level1
 
@@ -239,6 +258,7 @@
 	 * ---------------------------------------------------------------
 	 */
 func dcsw_op_level2
+	check_plat_can_cmo
 	dcsw_op_level #(2 << LEVEL_SHIFT)
 endfunc dcsw_op_level2
 
@@ -250,5 +270,6 @@
 	 * ---------------------------------------------------------------
 	 */
 func dcsw_op_level3
+	check_plat_can_cmo
 	dcsw_op_level #(3 << LEVEL_SHIFT)
 endfunc dcsw_op_level3
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 8c6798b..866ac41 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -254,6 +254,16 @@
 				   ICC_SRE_EN_BIT | ICC_SRE_SRE_BIT;
 	write_ctx_reg(get_el2_sysregs_ctx(ctx), CTX_ICC_SRE_EL2,
 			icc_sre_el2);
+
+	/*
+	 * Initialize MDCR_EL2.HPMN to its hardware reset value so we don't
+	 * throw anyone off who expects this to be sensible.
+	 * TODO: A similar thing happens in cm_prepare_el3_exit. They should be
+	 * unified with the proper PMU implementation
+	 */
+	u_register_t mdcr_el2 = ((read_pmcr_el0() >> PMCR_EL0_N_SHIFT) &
+			PMCR_EL0_N_MASK);
+	write_ctx_reg(get_el2_sysregs_ctx(ctx), CTX_MDCR_EL2, mdcr_el2);
 #endif /* CTX_INCLUDE_EL2_REGS */
 }
 
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 2aa84ff..52a7a39 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -480,3 +480,7 @@
 
 # Dynamic Root of Trust for Measurement support
 DRTM_SUPPORT			:= 0
+
+# Check platform if cache management operations should be performed.
+# Disabled by default.
+CONDITIONAL_CMO			:= 0