Merge "`requested_irq_received` must be initialized for all tests"
diff --git a/Makefile b/Makefile
index c200119..1269b6d 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@
 
 # TFTF Version
 VERSION_MAJOR		:= 2
-VERSION_MINOR		:= 1
+VERSION_MINOR		:= 2
 
 ################################################################################
 # Default values for build configurations, and their dependencies
diff --git a/docs/change-log.rst b/docs/change-log.rst
index da74923..29de0ed 100644
--- a/docs/change-log.rst
+++ b/docs/change-log.rst
@@ -10,6 +10,114 @@
 Tests are not guaranteed to be compatible. This also means that a version
 upgrade on the TF-A-Tests side might not necessarily introduce any new feature.
 
+Trusted Firmware-A Tests - version 2.2
+======================================
+
+New features
+------------
+
+-  A wide range of tests are made available in this release to help validate
+   the functionality of TF-A.
+
+-  Various improvements to test framework and test suite.
+
+TFTF
+````
+
+-  Enhancement to xlat table library synchronous to TF-A code base.
+
+-  Enabled strict alignment checks (SCTLR.A & SCTLR.SA) in all images.
+
+-  Support for a simple console driver. Currently it serves as a placeholder
+   with empty functions.
+
+-  A topology helper API is added in the framework to get parent node info.
+
+-  Support for FVP with clusters having upto 8 CPUs.
+
+-  Enhanced linker script to separate code and RO data sections.
+
+-  Relax SMC calls tests. The SMCCC specification recommends Trusted OSes to
+   mitigate the risk of leaking information by either preserving the register
+   state over the call, or returning a constant value, such as zero, in each
+   register. Tests only allowed the former behaviour and have been extended to
+   allow the latter as well.
+
+-  Pointer Authentication enabled on warm boot path with individual APIAKey
+   generation for each CPU.
+
+-  New tests:
+
+   -  Basic unit tests for xlat table library v2.
+
+   -  Tests for validating SVE support in TF-A.
+
+   -  Stress tests for dynamic xlat table library.
+
+   -  PSCI test to measure latencies when turning ON a cluster.
+
+   -  Series of AArch64 tests that stress the secure world to leak sensitive
+      counter values.
+
+   -  Test to validate PSCI SYSTEM_RESET call.
+
+   -  Basic tests to validate Memory Tagging Extensions are being enabled and
+      ensuring no undesired leak of sensitive data occurs.
+
+-  Enhanced tests:
+
+   -  Improved tests for Pointer Authentication support. Checks are performed
+      to see if pointer authentication keys are accessible as well as validate
+      if secure keys are being leaked after a PSCI version call or TSP call.
+
+   -  Improved AMU test to remove unexecuted code iterating over Group1 counters
+      and fix the conditional check of AMU Group0 counter value.
+
+Secure partitions
+`````````````````
+
+A new Secure Partition Quark is introduced in this release.
+
+Quark
+'''''''''
+
+The Quark test secure partition provided is a simple service which returns a
+magic number. Further, a simple test is added to test if Quark is functional.
+
+Issues resolved since last release
+----------------------------------
+
+-  Bug fix in libc memchr implementation.
+
+-  Bug fix in calculation of number of CPUs.
+
+-  Streamlined SMC WORKAROUND_2 test and fixed a false fail on Cortex-A76 CPU.
+
+-  Pointer Authentication support is now available for secondary CPUs and the
+   corresponding tests are stable in this release.
+
+Known issues and limitations
+----------------------------
+
+The sections below list the known issues and limitations of each test image
+provided in this repository. Unless and otherwise stated, issues and limitations
+stated in previous release continue to exist in this release.
+
+TFTF
+````
+
+Tests
+'''''
+
+-  Multicore spurious interrupt test is observed to have unstable behavior. As a
+   temporary solution, this test is skipped for AArch64 Juno configurations.
+
+-  Generating SVE instructions requires `O3` compilation optimization. Since the
+   current build structure does not allow compilation flag modification for
+   specific files, the function which tests support for SVE has been pre-compiled
+   and added as an assembly file.
+
+
 
 Trusted Firmware-A Tests - version 2.1
 ======================================
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index 77cf7fd..205d203 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -166,13 +166,12 @@
 
 #define SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(version)			\
 	do {									\
-		uint32_t debug_ver = read_id_aa64dfr0_el1() &			\
-			(ID_AA64DFR0_DEBUG_MASK << ID_AA64DFR0_DEBUG_SHIFT);	\
+		uint32_t debug_ver = arch_get_debug_version();			\
 										\
-		if ((debug_ver >> ID_AA64DFR0_DEBUG_SHIFT) < version) {		\
+		if (debug_ver < version) {					\
 			tftf_testcase_printf("Debug version returned %d\n"	\
 					     "The required version is %d\n",	\
-					     debug_ver >> ID_AA64DFR0_DEBUG_SHIFT,\
+					     debug_ver,				\
 					     version);				\
 			return TEST_RESULT_SKIPPED;				\
 		}								\
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h
index 3c2a517..dcc4243 100644
--- a/include/lib/aarch32/arch.h
+++ b/include/lib/aarch32/arch.h
@@ -405,11 +405,45 @@
 #define MAX_CACHE_LINE_SIZE	U(0x800) /* 2KB */
 
 /* PMCR definitions */
-#define PMCR_N_SHIFT		U(11)
-#define PMCR_N_MASK		U(0x1f)
-#define PMCR_N_BITS		(PMCR_N_MASK << PMCR_N_SHIFT)
-#define PMCR_LC_BIT		(U(1) << 6)
-#define PMCR_DP_BIT		(U(1) << 5)
+#define PMCR_EL0_N_SHIFT	U(11)
+#define PMCR_EL0_N_MASK		U(0x1f)
+#define PMCR_EL0_N_BITS		(PMCR_EL0_N_MASK << PMCR_EL0_N_SHIFT)
+#define PMCR_EL0_LC_BIT		(U(1) << 6)
+#define PMCR_EL0_DP_BIT		(U(1) << 5)
+#define PMCR_EL0_E_BIT		(U(1) << 0)
+
+/* PMCNTENSET definitions */
+#define PMCNTENSET_EL0_C_BIT		(U(1) << 31)
+#define PMCNTENSET_EL0_P_BIT(x)		(U(1) << x)
+
+/* PMEVTYPER<n> definitions */
+#define PMEVTYPER_EL0_P_BIT		(U(1) << 31)
+#define PMEVTYPER_EL0_NSK_BIT		(U(1) << 29)
+#define PMEVTYPER_EL0_NSH_BIT		(U(1) << 27)
+#define PMEVTYPER_EL0_M_BIT		(U(1) << 26)
+#define PMEVTYPER_EL0_MT_BIT		(U(1) << 25)
+#define PMEVTYPER_EL0_SH_BIT		(U(1) << 24)
+#define PMEVTYPER_EL0_EVTCOUNT_BITS	U(0x000003FF)
+
+/* PMCCFILTR definitions */
+#define PMCCFILTR_EL0_P_BIT		(U(1) << 31)
+#define PMCCFILTR_EL0_NSK_BIT		(U(1) << 29)
+#define PMCCFILTR_EL0_NSH_BIT		(U(1) << 27)
+#define PMCCFILTR_EL0_M_BIT		(U(1) << 26)
+#define PMCCFILTR_EL0_MT_BIT		(U(1) << 25)
+#define PMCCFILTR_EL0_SH_BIT		(U(1) << 24)
+
+/* PMU event counter ID definitions */
+#define PMU_EV_PC_WRITE_RETIRED		U(0x000C)
+
+/* DBGDIDR definitions */
+#define DBGDIDR_VERSION_SHIFT	U(16)
+#define DBGDIDR_VERSION_MASK	U(0xf)
+#define DBGDIDR_VERSION_BITS	(DBGDIDR_VERSION_MASK << DBGDIDR_VERSION_SHIFT)
+#define DBGDIDR_V8_DEBUG_ARCH_SUPPORTED		U(6)
+#define DBGDIDR_V8_DEBUG_ARCH_VHE_SUPPORTED	U(7)
+#define DBGDIDR_V8_2_DEBUG_ARCH_SUPPORTED	U(8)
+#define DBGDIDR_V8_4_DEBUG_ARCH_SUPPORTED	U(9)
 
 /*******************************************************************************
  * Definitions of register offsets, fields and macros for CPU system
@@ -522,6 +556,12 @@
 /* Debug register defines. The format is: coproc, opt1, CRn, CRm, opt2 */
 #define HDCR		p15, 4, c1, c1, 1
 #define PMCR		p15, 0, c9, c12, 0
+#define PMCNTENSET	p15, 0, c9, c12, 1
+#define PMCCFILTR	p15, 0, c14, c15, 7
+#define PMCCNTR		p15, 0, c9, c13, 0
+#define PMEVTYPER0	p15, 0, c14, c12, 0
+#define PMEVCNTR0	p15, 0, c14, c8, 0
+#define DBGDIDR		p14, 0, c0, c0, 0
 #define CNTHP_TVAL	p15, 4, c14, c2, 0
 #define CNTHP_CTL	p15, 4, c14, c2, 1
 
diff --git a/include/lib/aarch32/arch_features.h b/include/lib/aarch32/arch_features.h
index b953db7..e2c2f2c 100644
--- a/include/lib/aarch32/arch_features.h
+++ b/include/lib/aarch32/arch_features.h
@@ -29,4 +29,10 @@
 		ID_MMFR4_CNP_MASK) != 0U;
 }
 
+static inline uint32_t arch_get_debug_version(void)
+{
+	return ((read_dbgdidr() & DBGDIDR_VERSION_BITS) >>
+		DBGDIDR_VERSION_SHIFT);
+}
+
 #endif /* ARCH_FEATURES_H */
diff --git a/include/lib/aarch32/arch_helpers.h b/include/lib/aarch32/arch_helpers.h
index e983554..f2e3e00 100644
--- a/include/lib/aarch32/arch_helpers.h
+++ b/include/lib/aarch32/arch_helpers.h
@@ -277,7 +277,13 @@
 
 DEFINE_COPROCR_RW_FUNCS(hdcr, HDCR)
 DEFINE_COPROCR_RW_FUNCS(cnthp_ctl, CNTHP_CTL)
-DEFINE_COPROCR_READ_FUNC(pmcr, PMCR)
+DEFINE_COPROCR_RW_FUNCS(pmcr, PMCR)
+DEFINE_COPROCR_RW_FUNCS(pmcntenset, PMCNTENSET)
+DEFINE_COPROCR_RW_FUNCS(pmccfiltr, PMCCFILTR)
+DEFINE_COPROCR_READ_FUNC(pmccntr, PMCCNTR)
+DEFINE_COPROCR_RW_FUNCS(pmevtyper0, PMEVTYPER0)
+DEFINE_COPROCR_READ_FUNC(pmevcntr0, PMEVCNTR0)
+DEFINE_COPROCR_READ_FUNC(dbgdidr, DBGDIDR)
 
 /*
  * Address translation
@@ -377,6 +383,22 @@
 
 #define read_ctr_el0()		read_ctr()
 
+#define read_pmcr_el0()			read_pmcr()
+#define write_pmcr_el0(_v)		write_pmcr(_v)
+
+#define read_pmcntenset_el0()		read_pmcntenset()
+#define write_pmcntenset_el0(_v)	write_pmcntenset(_v)
+
+#define read_pmccfiltr_el0()		read_pmccfiltr()
+#define write_pmccfiltr_el0(_v)		write_pmccfiltr(_v)
+
+#define read_pmevtyper0_el0()		read_pmevtyper0()
+#define write_pmevtyper0_el0(_v)	write_pmevtyper0(_v)
+
+#define read_pmccntr_el0		read_pmccntr
+
+#define read_pmevcntr0_el0		read_pmevcntr0
+
 #define write_icc_sgi0r_el1(_v)	write64_icc_sgi0r_el1(_v)
 
 #define read_daif()		read_cpsr()
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 1d5cc11..4e9c03b 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -152,6 +152,8 @@
 #define ID_AA64DFR0_DEBUG_SHIFT			U(0)
 #define ID_AA64DFR0_DEBUG_LENGTH		U(4)
 #define ID_AA64DFR0_DEBUG_MASK			ULL(0xf)
+#define ID_AA64DFR0_DEBUG_BITS			(ID_AA64DFR0_DEBUG_MASK << \
+						 ID_AA64DFR0_DEBUG_SHIFT)
 #define ID_AA64DFR0_V8_DEBUG_ARCH_SUPPORTED	U(6)
 #define ID_AA64DFR0_V8_DEBUG_ARCH_VHE_SUPPORTED	U(7)
 #define ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED	U(8)
diff --git a/include/lib/aarch64/arch_features.h b/include/lib/aarch64/arch_features.h
index 86c0763..20433fd 100644
--- a/include/lib/aarch64/arch_features.h
+++ b/include/lib/aarch64/arch_features.h
@@ -68,4 +68,10 @@
 		ID_AA64PFR1_EL1_MTE_MASK);
 }
 
+static inline uint32_t arch_get_debug_version(void)
+{
+	return ((read_id_aa64dfr0_el1() & ID_AA64DFR0_DEBUG_BITS) >>
+		ID_AA64DFR0_DEBUG_SHIFT);
+}
+
 #endif /* ARCH_FEATURES_H */
diff --git a/readme.rst b/readme.rst
index 1500ccc..9c024c2 100644
--- a/readme.rst
+++ b/readme.rst
@@ -1,4 +1,4 @@
-Trusted Firmware-A Tests - version 2.1
+Trusted Firmware-A Tests - version 2.2
 ======================================
 
 The Trusted Firmware-A Tests (TF-A-Tests) is a suite of baremetal tests to
@@ -54,12 +54,11 @@
 This release
 ------------
 
-This release provides a starting point for exercising some of the TF-A features
-on the Arm FVP and Juno platforms, porting the tests to new platforms, enhancing
-existing tests or implementing new ones.
+This release makes a wide range of tests available for validating the functionality
+of TF-A as well as several improvements to test framework and test suite.
 
-Please note that this code is not mature yet and suffers from some stability
-issues. Refer to the known issues in the `change log`_ for more details.
+Please refer to the `change log`_ for more details of the features, known issues and
+limitations in the current release.
 
 
 Platforms
@@ -89,7 +88,7 @@
 -  ``FVP_Base_Cortex-A32x4``
 -  ``FVP_Base_RevC-2xAEMv8A``
 
-NOTE: Unless otherwise stated, the model version is version 11.5, build 33.
+NOTE: Unless otherwise stated, the model version is version 11.6, build 45.
 
 System Guidance for Infrastructure Fixed Virtual Platforms
 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
@@ -102,8 +101,8 @@
 
 NOTE:
 
--  For ``FVP_CSS_SGI-575``, the model version is 11.4, build 40
--  For ``FVP_RD_N1Edge``, the model version is 11.6, build 29
+-  For ``FVP_CSS_SGI-575`` and ``FVP_RD_N1Edge``, internal version of the
+   models were used.
 
 Still to come
 `````````````
diff --git a/tftf/tests/misc_tests/test_pmu_leakage.c b/tftf/tests/misc_tests/test_pmu_leakage.c
index a0ac82d..da28999 100644
--- a/tftf/tests/misc_tests/test_pmu_leakage.c
+++ b/tftf/tests/misc_tests/test_pmu_leakage.c
@@ -37,6 +37,11 @@
  *	-v8.5 implemented:
  *	    |-- Prohibit general event counters: as in v8.2 Debug.
  *	    |-- Prohibit cycle counter: MDCR_EL3.SCCD == 1
+ *
+ * In Aarch32 state the PMU registers have identical names (apart from the
+ * '_EL0' suffix) and bit fields. As far as the PMU is concerned, the Aarch32
+ * counterpart of MDCR_EL3 is the SDCR register, which has both the SCCD and
+ * SPME bits.
  */
 
 #include <drivers/arm/arm_gic.h>
@@ -47,7 +52,6 @@
 #include <string.h>
 #include <test_helpers.h>
 
-#ifdef AARCH64
 #define ITERATIONS_CNT 1000
 
 /*
@@ -71,6 +75,12 @@
 	unsigned long long avg;
 };
 
+#ifdef AARCH64
+#define V8_2_DEBUG_ARCH_SUPPORTED ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED
+#else
+#define V8_2_DEBUG_ARCH_SUPPORTED DBGDIDR_V8_2_DEBUG_ARCH_SUPPORTED
+#endif
+
 static inline void configure_pmu_cntr0(const uint32_t event)
 {
 	/*
@@ -249,16 +259,34 @@
 }
 
 /*
+ * Checks that when requesting an SMC call after getting a baseline PMU event
+ * count the number of PMU events counted is either not greater than the
+ * baseline or it has increased by no more than ALLOWED_DEVIATION%. The first
+ * comparison is required because of underflow on unsigned types.
+ * This is used to determine if PMU timing information has been leaked from the
+ * secure world.
+ */
+static bool results_within_allowed_margin(unsigned long long baseline_cnt,
+					  unsigned long long smc_cnt)
+{
+	return (smc_cnt <= baseline_cnt) ||
+	       (smc_cnt - baseline_cnt <= baseline_cnt / ALLOWED_DEVIATION);
+}
+
+/*
  * Measure the number of retired writes to the PC in the PSCI_SUSPEND SMC.
  * This test only succeeds if no useful information about the PMU counters has
  * been leaked.
  */
 test_result_t smc_psci_suspend_pc_write_retired(void)
 {
+#if ARM_ARCH_MAJOR < 8
+	INFO("%s skipped on ARMv7 and earlier\n", __func__);
+	return TEST_RESULT_SKIPPED;
+#else
 	struct pmu_event_info baseline, cpu_suspend;
 
-	SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(
-		ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED);
+	SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(V8_2_DEBUG_ARCH_SUPPORTED);
 
 	configure_pmu_cntr0(PMU_EV_PC_WRITE_RETIRED);
 	pmu_enable_counting();
@@ -268,9 +296,10 @@
 	tftf_testcase_printf("Profiling PSCI_SUSPEND_PC:\n");
 	measure_event(read_pmevcntr0_el0, profile_cpu_suspend, &cpu_suspend);
 
-	if (cpu_suspend.avg - baseline.avg > baseline.avg / ALLOWED_DEVIATION)
+	if (!results_within_allowed_margin(baseline.avg, cpu_suspend.avg))
 		return TEST_RESULT_FAIL;
 	return TEST_RESULT_SUCCESS;
+#endif
 }
 
 /*
@@ -280,10 +309,13 @@
  */
 test_result_t smc_psci_suspend_cycles(void)
 {
+#if ARM_ARCH_MAJOR < 8
+	INFO("%s skipped on ARMv7 and earlier\n", __func__);
+	return TEST_RESULT_SKIPPED;
+#else
 	struct pmu_event_info baseline, cpu_suspend;
 
-	SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(
-		ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED);
+	SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(V8_2_DEBUG_ARCH_SUPPORTED);
 
 	configure_pmu_cycle_cntr();
 	pmu_enable_counting();
@@ -293,9 +325,10 @@
 	tftf_testcase_printf("Profiling PSCI_SUSPEND_PC:\n");
 	measure_event(read_pmccntr_el0, profile_cpu_suspend, &cpu_suspend);
 
-	if (cpu_suspend.avg - baseline.avg > baseline.avg / ALLOWED_DEVIATION)
+	if (!results_within_allowed_margin(baseline.avg, cpu_suspend.avg))
 		return TEST_RESULT_FAIL;
 	return TEST_RESULT_SUCCESS;
+#endif
 }
 
 /*
@@ -305,10 +338,13 @@
  */
 test_result_t fast_smc_add_pc_write_retired(void)
 {
+#if ARM_ARCH_MAJOR < 8
+	INFO("%s skipped on ARMv7 and earlier\n", __func__);
+	return TEST_RESULT_SKIPPED;
+#else
 	struct pmu_event_info baseline, fast_smc_add;
 
-	SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(
-		ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED);
+	SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(V8_2_DEBUG_ARCH_SUPPORTED);
 
 	SKIP_TEST_IF_TSP_NOT_PRESENT();
 
@@ -320,9 +356,10 @@
 	tftf_testcase_printf("Profiling Fast Add SMC:\n");
 	measure_event(read_pmevcntr0_el0, profile_fast_smc_add, &fast_smc_add);
 
-	if (fast_smc_add.avg - baseline.avg > baseline.avg / ALLOWED_DEVIATION)
+	if (!results_within_allowed_margin(baseline.avg, fast_smc_add.avg))
 		return TEST_RESULT_FAIL;
 	return TEST_RESULT_SUCCESS;
+#endif
 }
 
 /*
@@ -332,10 +369,13 @@
  */
 test_result_t fast_smc_add_cycles(void)
 {
+#if ARM_ARCH_MAJOR < 8
+	INFO("%s skipped on ARMv7 and earlier\n", __func__);
+	return TEST_RESULT_SKIPPED;
+#else
 	struct pmu_event_info baseline, fast_smc_add;
 
-	SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(
-		ID_AA64DFR0_V8_2_DEBUG_ARCH_SUPPORTED);
+	SKIP_TEST_IF_ARCH_DEBUG_VERSION_LESS_THAN(V8_2_DEBUG_ARCH_SUPPORTED);
 
 	SKIP_TEST_IF_TSP_NOT_PRESENT();
 
@@ -347,32 +387,8 @@
 	tftf_testcase_printf("Profiling Fast Add SMC:\n");
 	measure_event(read_pmccntr_el0, profile_fast_smc_add, &fast_smc_add);
 
-	if (fast_smc_add.avg - baseline.avg > baseline.avg / ALLOWED_DEVIATION)
+	if (!results_within_allowed_margin(baseline.avg, fast_smc_add.avg))
 		return TEST_RESULT_FAIL;
 	return TEST_RESULT_SUCCESS;
-}
-#else
-test_result_t smc_psci_suspend_pc_write_retired(void)
-{
-	INFO("%s skipped on AArch32\n", __func__);
-	return TEST_RESULT_SKIPPED;
-}
-
-test_result_t smc_psci_suspend_cycles(void)
-{
-	INFO("%s skipped on AArch32\n", __func__);
-	return TEST_RESULT_SKIPPED;
-}
-
-test_result_t fast_smc_add_pc_write_retired(void)
-{
-	INFO("%s skipped on AArch32\n", __func__);
-	return TEST_RESULT_SKIPPED;
-}
-
-test_result_t fast_smc_add_cycles(void)
-{
-	INFO("%s skipped on AArch32\n", __func__);
-	return TEST_RESULT_SKIPPED;
-}
 #endif
+}
diff --git a/tftf/tests/runtime_services/standard_service/psci/api_tests/system_off/test_system_off.c b/tftf/tests/runtime_services/standard_service/psci/api_tests/system_off/test_system_off.c
index 2ac6550..a6d6914 100644
--- a/tftf/tests/runtime_services/standard_service/psci/api_tests/system_off/test_system_off.c
+++ b/tftf/tests/runtime_services/standard_service/psci/api_tests/system_off/test_system_off.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,6 +7,37 @@
 #include <psci.h>
 #include <smccc.h>
 #include <tftf_lib.h>
+#include <test_helpers.h>
+#include <power_management.h>
+
+/* Generic function to call System OFF SMC */
+static test_result_t test_cpu_system_off(void)
+{
+	u_register_t curr_mpid = read_mpidr_el1() & MPID_MASK;
+	u_register_t mpid;
+	unsigned int cpu_node;
+	smc_args args = { SMC_PSCI_SYSTEM_OFF };
+
+	/* Wait for all other CPU's to turn off */
+	for_each_cpu(cpu_node) {
+		mpid = tftf_get_mpidr_from_node(cpu_node);
+		/* Skip current CPU */
+		if (mpid == curr_mpid)
+			continue;
+
+		while (tftf_psci_affinity_info(mpid,
+			MPIDR_AFFLVL0) != PSCI_STATE_OFF) {
+		}
+	}
+
+	INFO("System off from CPU MPID 0x%lx\n", curr_mpid);
+	tftf_notify_reboot();
+	tftf_smc(&args);
+
+	/* The PSCI SYSTEM_OFF call is not supposed to return */
+	tftf_testcase_printf("System didn't shutdown properly\n");
+	return TEST_RESULT_FAIL;
+}
 
 /*
  * @Test_Aim@ Validate the SYSTEM_OFF call.
@@ -15,17 +46,49 @@
  */
 test_result_t test_system_off(void)
 {
-	smc_args args = { SMC_PSCI_SYSTEM_OFF };
-
-	if (tftf_is_rebooted()) {
-		/* Successfully resumed from system off */
+	if (tftf_is_rebooted() == 1) {
+		/* Successfully resumed from SYSTEM_OFF */
 		return TEST_RESULT_SUCCESS;
 	}
 
-	tftf_notify_reboot();
-	tftf_smc(&args);
+	return test_cpu_system_off();
+}
 
-	/* The PSCI SYSTEM_OFF call is not supposed to return */
-	tftf_testcase_printf("System didn't shutdown properly\n");
+/*
+ * @Test_Aim@ Validate the SYSTEM_OFF call on CPU other than lead CPU
+ * Test SUCCESS in case of system shutdown.
+ * Test FAIL in case of execution not terminated.
+ */
+test_result_t test_system_off_cpu_other_than_lead(void)
+{
+	u_register_t lead_mpid = read_mpidr_el1() & MPID_MASK;
+	u_register_t cpu_mpid;
+	int psci_ret;
+
+	SKIP_TEST_IF_LESS_THAN_N_CPUS(2);
+
+	if (tftf_is_rebooted() == 1) {
+		/* Successfully resumed from SYSTEM_OFF */
+		return TEST_RESULT_SUCCESS;
+	}
+
+	/* Power ON another CPU, other than the lead CPU */
+	cpu_mpid = tftf_find_random_cpu_other_than(lead_mpid);
+	VERBOSE("CPU to be turned on MPID: 0x%lx\n", cpu_mpid);
+	psci_ret = tftf_cpu_on(cpu_mpid,
+			   (uintptr_t)test_cpu_system_off,
+			   0);
+
+	if (psci_ret != PSCI_E_SUCCESS) {
+		tftf_testcase_printf("Failed to power on CPU 0x%lx (%d)\n",
+				cpu_mpid, psci_ret);
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Power down the lead CPU */
+	INFO("Lead CPU to be turned off MPID: 0x%lx\n", lead_mpid);
+	tftf_cpu_off();
+
+	/* Test should not reach here */
 	return TEST_RESULT_FAIL;
 }
diff --git a/tftf/tests/tests-manual.xml b/tftf/tests/tests-manual.xml
index e7c29e0..f718fab 100644
--- a/tftf/tests/tests-manual.xml
+++ b/tftf/tests/tests-manual.xml
@@ -19,7 +19,8 @@
   </testsuite>
 
   <testsuite name="System off test" description="Validate SYSTEM_OFF PSCI call">
-     <testcase name="System Off" function="test_system_off" />
+    <testcase name="System Off" function="test_system_off" />
+    <testcase name="System Off Secondary CPU" function="test_system_off_cpu_other_than_lead" />
   </testsuite>
 
   <testsuite name="PSCI mem_protect" description="Check the mem_protect feature">