Merge "docs: update PSCI reference" into integration
diff --git a/changelog.yaml b/changelog.yaml
index 4703979..f21aa16 100644
--- a/changelog.yaml
+++ b/changelog.yaml
@@ -244,6 +244,13 @@
           - title: Corstone-1000
             scope: corstone-1000
 
+      - title: Aspeed
+        scope: aspeed
+
+        subsections:
+          - title: AST2700
+            scope: ast2700
+
       - title: Broadcom
         scope: brcm
 
diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst
index b591f2a..663859f 100644
--- a/docs/about/maintainers.rst
+++ b/docs/about/maintainers.rst
@@ -527,6 +527,15 @@
 :|G|: `rupsin01`_
 :|F|: plat/arm/board/tc
 
+Aspeed platform port
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Chia-Wei Wang <chiawei_wang@aspeedtech.com>
+:|G|: `ChiaweiW`_
+:|M|: Neal Liu <neal_liu@aspeedtech.com>
+:|G|: `Neal-liu`_
+:|F|: docs/plat/ast2700.rst
+:|F|: plat/aspeed/
+
 HiSilicon HiKey and HiKey960 platform ports
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 :|M|: Haojian Zhuang <haojian.zhuang@linaro.org>
@@ -983,3 +992,5 @@
 .. _bytefire: https://github.com/bytefire
 .. _rupsin01: https://github.com/rupsin01
 .. _jimmy-brisson: https://github.com/theotherjimmy
+.. _ChiaweiW: https://github.com/chiaweiw
+.. _Neal-liu: https://github.com/neal-liu
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
index 758d62b..ecbefdd 100644
--- a/docs/design/cpu-specific-build-macros.rst
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -53,7 +53,7 @@
 errata workaround is ``ERRATA_<Processor name>_<ID>``, where the ``Processor name``
 is for example ``A57`` for the ``Cortex_A57`` CPU.
 
-Refer to :ref:`firmware_design_cpu_errata_reporting` for information on how to
+Refer to :ref:`firmware_design_cpu_errata_implementation` for information on how to
 write errata workaround functions.
 
 All workarounds are disabled by default. The platform is responsible for
diff --git a/docs/design/firmware-design.rst b/docs/design/firmware-design.rst
index 48084f5..131cca1 100644
--- a/docs/design/firmware-design.rst
+++ b/docs/design/firmware-design.rst
@@ -1244,8 +1244,9 @@
 handling functions.
 
 Details for implementing a CPU specific reset handler can be found in
-Section 8. Details for implementing a platform specific reset handler can be
-found in the :ref:`Porting Guide` (see the ``plat_reset_handler()`` function).
+:ref:`firmware_design_cpu_specific_reset_handling`. Details for implementing a
+platform specific reset handler can be found in the :ref:`Porting Guide` (see
+the``plat_reset_handler()`` function).
 
 When adding functionality to a reset handler, keep in mind that if a different
 reset handling behavior is required between the first and the subsequent
@@ -1339,12 +1340,38 @@
 the platform makefile. The generic CPU specific operations framework code exists
 in ``lib/cpus/aarch64/cpu_helpers.S``.
 
+CPU PCS
+~~~~~~~
+
+All assembly functions in CPU files are asked to follow a modified version of
+the Procedure Call Standard (PCS) in their internals. This is done to ensure
+calling these functions from outside the file doesn't unexpectedly corrupt
+registers in the very early environment and to help the internals to be easier
+to understand. Please see the :ref:`firmware_design_cpu_errata_implementation`
+for any function specific restrictions.
+
++--------------+---------------------------------+
+|   register   | use                             |
++==============+=================================+
+|   x0 - x15   | scratch                         |
++--------------+---------------------------------+
+|   x16, x17   | do not use (used by the linker) |
++--------------+---------------------------------+
+|     x18      | do not use (platform register)  |
++--------------+---------------------------------+
+|   x19 - x28  | callee saved                    |
++--------------+---------------------------------+
+|   x29, x30   | FP, LR                          |
++--------------+---------------------------------+
+
+.. _firmware_design_cpu_specific_reset_handling:
+
 CPU specific Reset Handling
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 After a reset, the state of the CPU when it calls generic reset handler is:
-MMU turned off, both instruction and data caches turned off and not part
-of any coherency domain.
+MMU turned off, both instruction and data caches turned off, not part
+of any coherency domain and no stack.
 
 The BL entrypoint code first invokes the ``plat_reset_handler()`` to allow
 the platform to perform any system initialization required and any system
@@ -1354,10 +1381,9 @@
 in midr are used to find the matching ``cpu_ops`` entry. The ``reset_func()`` in
 the returned ``cpu_ops`` is then invoked which executes the required reset
 handling for that CPU and also any errata workarounds enabled by the platform.
-This function must preserve the values of general purpose registers x20 to x29.
 
-Refer to Section "Guidelines for Reset Handlers" for general guidelines
-regarding placement of code in a reset handler.
+It should be defined using the ``cpu_reset_func_{start,end}`` macros and its
+body may only clobber x0 to x14 with x14 being the cpu_rev parameter.
 
 CPU specific power down sequence
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1390,10 +1416,10 @@
 be reported and a pointer to the ASCII list of register names in a format
 expected by the crash reporting framework.
 
-.. _firmware_design_cpu_errata_reporting:
+.. _firmware_design_cpu_errata_implementation:
 
-CPU errata status reporting
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+CPU errata implementation
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Errata workarounds for CPUs supported in TF-A are applied during both cold and
 warm boots, shortly after reset. Individual Errata workarounds are enabled as
@@ -1401,59 +1427,92 @@
 therefore some are enabled by default, others not. Platform ports shall
 override build options to enable or disable errata as appropriate. The CPU
 drivers take care of applying errata workarounds that are enabled and applicable
-to a given CPU. Refer to :ref:`arm_cpu_macros_errata_workarounds` for more
-information.
+to a given CPU.
 
-Functions in CPU drivers that apply errata workaround must follow the
-conventions listed below.
+Each erratum has a build flag in ``lib/cpus/cpu-ops.mk`` of the form:
+``ERRATA_<cpu_num>_<erratum_id>``. It also has a short description in
+:ref:`arm_cpu_macros_errata_workarounds` on when it should apply.
 
-The errata workaround must be authored as two separate functions:
+Errata framework
+^^^^^^^^^^^^^^^^
 
--  One that checks for errata. This function must determine whether that errata
-   applies to the current CPU. Typically this involves matching the current
-   CPUs revision and variant against a value that's known to be affected by the
-   errata. If the function determines that the errata applies to this CPU, it
-   must return ``ERRATA_APPLIES``; otherwise, it must return
-   ``ERRATA_NOT_APPLIES``. The utility functions ``cpu_get_rev_var`` and
-   ``cpu_rev_var_ls`` functions may come in handy for this purpose.
+The errata framework is a convention and a small library to allow errata to be
+automatically discovered. It enables compliant errata to be automatically
+applied and reported at runtime (either by status reporting or the errata ABI).
 
-For an errata identified as ``E``, the check function must be named
-``check_errata_E``.
+To write a compliant mitigation for erratum number ``erratum_id`` on a cpu that
+declared itself (with ``declare_cpu_ops``) as ``cpu_name`` one needs 3 things:
 
-This function will be invoked at different times, both from assembly and from
-C run time. Therefore it must follow AAPCS, and must not use stack.
+#. A CPU revision checker function: ``check_erratum_<cpu_name>_<erratum_id>``
 
--  Another one that applies the errata workaround. This function would call the
-   check function described above, and applies errata workaround if required.
+   It should check whether this erratum applies on this revision of this CPU.
+   It will be called with the CPU revision as its first parameter (x0) and
+   should return one of ``ERRATA_APPLIES`` or ``ERRATA_NOT_APPLIES``.
 
-CPU drivers that apply errata workaround can optionally implement an assembly
-function that report the status of errata workarounds pertaining to that CPU.
-For a driver that registers the CPU, for example, ``cpux`` via ``declare_cpu_ops``
-macro, the errata reporting function, if it exists, must be named
-``cpux_errata_report``. This function will always be called with MMU enabled; it
-must follow AAPCS and may use stack.
+   It may only clobber x0 to x4. The rest should be treated as callee-saved.
 
-In a debug build of TF-A, on a CPU that comes out of reset, both BL1 and the
-runtime firmware (BL31 in AArch64, and BL32 in AArch32) will invoke errata
-status reporting function, if one exists, for that type of CPU.
+#. A workaround function: ``erratum_<cpu_name>_<erratum_id>_wa``
+
+   It should obtain the cpu revision (with ``cpu_get_rev_var``), call its
+   revision checker, and perform the mitigation, should the erratum apply.
+
+   It may only clobber x0 to x8. The rest should be treated as callee-saved.
 
-To report the status of each errata workaround, the function shall use the
-assembler macro ``report_errata``, passing it:
+#. Register itself to the framework
 
--  The build option that enables the errata;
+   Do this with
+   ``add_erratum_entry <cpu_name>, ERRATUM(<erratum_id>), <errata_flag>``
+   where the ``errata_flag`` is the enable flag in ``cpu-ops.mk`` described
+   above.
 
--  The name of the CPU: this must be the same identifier that CPU driver
-   registered itself with, using ``declare_cpu_ops``;
+See the next section on how to do this easily.
 
--  And the errata identifier: the identifier must match what's used in the
-   errata's check function described above.
+.. note::
 
-The errata status reporting function will be called once per CPU type/errata
-combination during the software's active life time.
+ CVEs have the format ``CVE_<year>_<number>``. To fit them in the framework, the
+ ``erratum_id`` for the checker and the workaround functions become the
+ ``number`` part of its name and the ``ERRATUM(<number>)`` part of the
+ registration should instead be ``CVE(<year>, <number>)``. In the extremely
+ unlikely scenario where a CVE and an erratum numbers clash, the CVE number
+ should be prefixed with a zero.
 
-It's expected that whenever an errata workaround is submitted to TF-A, the
-errata reporting function is appropriately extended to report its status as
-well.
+ Also, their build flag should be ``WORKAROUND_CVE_<year>_<number>``.
+
+.. note::
+
+ AArch32 uses the legacy convention. The checker function has the format
+ ``check_errata_<erratum_id>`` and the workaround has the format
+ ``errata_<cpu_number>_<erratum_id>_wa`` where ``cpu_number`` is the shortform
+ letter and number name of the CPU.
+
+ For CVEs the ``erratum_id`` also becomes ``cve_<year>_<number>``.
+
+Errata framework helpers
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Writing these errata involves lots of boilerplate and repetitive code. On
+AArch64 there are helpers to omit most of this. They are located in
+``include/lib/cpus/aarch64/cpu_macros.S`` and the preferred way to implement
+errata. Please see their comments on how to use them.
+
+The most common type of erratum workaround, one that just sets a "chicken" bit
+in some arbitrary register, would have an implementation for the Cortex-A77,
+erratum #1925769 like::
+
+    workaround_reset_start cortex_a77, ERRATUM(1925769), ERRATA_A77_1925769
+        sysreg_bit_set CORTEX_A77_CPUECTLR_EL1, CORTEX_A77_CPUECTLR_EL1_BIT_8
+    workaround_reset_end cortex_a77, ERRATUM(1925769)
+
+    check_erratum_ls cortex_a77, ERRATUM(1925769), CPU_REV(1, 1)
+
+Status reporting
+^^^^^^^^^^^^^^^^
+
+In a debug build of TF-A, on a CPU that comes out of reset, both BL1 and the
+runtime firmware (BL31 in AArch64, and BL32 in AArch32) will invoke a generic
+errata status reporting function. It will read the ``errata_entries`` list of
+that cpu and will report whether each known erratum was applied and, if not,
+whether it should have been.
 
 Reporting the status of errata workaround is for informational purpose only; it
 has no functional significance.
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 4eafb39..c8ff7d5 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -531,7 +531,8 @@
    through feature specific build flags are supported by the PE or not by
    validating them either at boot phase or at runtime based on the value
    possessed by the feature flag (0 to 2) and report error messages at an early
-   stage.
+   stage. This flag will also enable errata ordering checking for ``DEBUG``
+   builds.
 
    This prevents and benefits us from EL3 runtime exceptions during context save
    and restore routines guarded by these build flags. Henceforth validating them
diff --git a/docs/plat/ast2700.rst b/docs/plat/ast2700.rst
new file mode 100644
index 0000000..0352aea
--- /dev/null
+++ b/docs/plat/ast2700.rst
@@ -0,0 +1,17 @@
+Aspeed AST2700
+==============
+
+Aspeed AST2700 is a 64-bit ARM SoC with 4-cores Cortex-A35 integrated.
+Each core operates at 1.6GHz.
+
+Boot Flow
+---------
+
+    BootRom --> BL1/BL2 --> TF-A BL31 --> BL32 (optional) --> BL33 --> Linux Kernel
+
+How to build
+------------
+
+.. code:: shell
+
+    make CROSS_COMPILE=aarch64-linux-gnu- PLAT=ast2700
diff --git a/docs/plat/index.rst b/docs/plat/index.rst
index 57c7303..188c986 100644
--- a/docs/plat/index.rst
+++ b/docs/plat/index.rst
@@ -8,6 +8,7 @@
 
    allwinner
    arm/index
+   ast2700
    meson-axg
    meson-gxbb
    meson-gxl
diff --git a/include/lib/cpus/aarch64/cpu_macros.S b/include/lib/cpus/aarch64/cpu_macros.S
index 724624c..404b7f9 100644
--- a/include/lib/cpus/aarch64/cpu_macros.S
+++ b/include/lib/cpus/aarch64/cpu_macros.S
@@ -427,6 +427,23 @@
 .endm
 
 /*
+ * Clear a bit in a system register. Can clear multiple bits but is limited by
+ *  the way the BIC instrucion encodes them.
+ *
+ * see sysreg_bit_set for usage
+ */
+.macro sysreg_bit_clear _reg:req, _bit:req
+	mrs	x1, \_reg
+	bic	x1, x1, #\_bit
+	msr	\_reg, x1
+.endm
+
+.macro override_vector_table _table:req
+	adr	x1, \_table
+	msr	vbar_el3, x1
+.endm
+
+/*
  * Apply erratum
  *
  * _cpu:
@@ -497,6 +514,27 @@
 	endfunc check_erratum_\_cpu\()_\_id
 .endm
 
+.macro check_erratum_chosen _cpu:req, _cve:req, _id:req, _chosen:req
+	func check_erratum_\_cpu\()_\_id
+		.if \_chosen
+			mov	x0, #ERRATA_APPLIES
+		.else
+			mov	x0, #ERRATA_MISSING
+		.endif
+		ret
+	endfunc check_erratum_\_cpu\()_\_id
+.endm
+
+/* provide a shorthand for the name format for annoying errata */
+.macro check_erratum_custom_start _cpu:req, _cve:req, _id:req
+	func check_erratum_\_cpu\()_\_id
+.endm
+
+.macro check_erratum_custom_end _cpu:req, _cve:req, _id:req
+	endfunc check_erratum_\_cpu\()_\_id
+.endm
+
+
 /*******************************************************************************
  * CPU reset function wrapper
  ******************************************************************************/
diff --git a/include/lib/cpus/errata.h b/include/lib/cpus/errata.h
index f8f9555..b280435 100644
--- a/include/lib/cpus/errata.h
+++ b/include/lib/cpus/errata.h
@@ -64,6 +64,10 @@
 #define CVE(year, id)		year, id
 #define NO_ISB			1
 #define NO_ASSERT		0
+#define NO_APPLY_AT_RESET	0
+#define APPLY_AT_RESET		1
+/* useful for errata that end up always being worked around */
+#define ERRATUM_ALWAYS_CHOSEN	1
 
 #endif /* __ASSEMBLER__ */
 
diff --git a/lib/cpus/errata_report.c b/lib/cpus/errata_report.c
index a37ba81..4e9bdfc 100644
--- a/lib/cpus/errata_report.c
+++ b/lib/cpus/errata_report.c
@@ -34,38 +34,51 @@
 #define CVE_FORMAT	"%s: %s: CPU workaround for CVE %u_%u was %s\n"
 #define ERRATUM_FORMAT	"%s: %s: CPU workaround for erratum %u was %s\n"
 
-#define PRINT_STATUS_DISPATCH(status, ...)					\
-	do {									\
-		assert(status <= ERRATA_MISSING);				\
-		switch (status) {						\
-		case ERRATA_NOT_APPLIES:					\
-			VERBOSE(__VA_ARGS__, "not applied");			\
-			break;							\
-		case ERRATA_APPLIES:						\
-			INFO(__VA_ARGS__, "applied");				\
-			break;							\
-		case ERRATA_MISSING:						\
-			WARN(__VA_ARGS__, "missing!");				\
-			break;							\
-		}								\
-	} while (0)
 
+static __unused void print_status(int status, char *cpu_str, uint16_t cve, uint32_t id)
+{
+	if (status == ERRATA_MISSING) {
+		if (cve) {
+			WARN(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "missing!");
+		} else {
+			WARN(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "missing!");
+		}
+	} else if (status == ERRATA_APPLIES) {
+		if (cve) {
+			INFO(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "applied");
+		}  else {
+			INFO(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "applied");
+		}
+	} else {
+		if (cve) {
+			VERBOSE(CVE_FORMAT, BL_STRING, cpu_str, cve, id, "not applied");
+		}  else {
+			VERBOSE(ERRATUM_FORMAT, BL_STRING, cpu_str, id, "not applied");
+		}
+	}
+}
 
 #if !REPORT_ERRATA
 void print_errata_status(void) {}
 #else /* !REPORT_ERRATA */
-/* New errata status message printer */
+/*
+ * New errata status message printer
+ * The order checking function is hidden behind the FEATURE_DETECTION flag to
+ * save space. This functionality is only useful on development and platform
+ * bringup builds, when FEATURE_DETECTION should be used anyway
+ */
 void __unused generic_errata_report(void)
 {
 	struct cpu_ops *cpu_ops = get_cpu_ops_ptr();
 	struct erratum_entry *entry = cpu_ops->errata_list_start;
 	struct erratum_entry *end = cpu_ops->errata_list_end;
 	long rev_var = cpu_get_rev_var();
+#if FEATURE_DETECTION
 	uint32_t last_erratum_id = 0;
 	uint16_t last_cve_yr = 0;
 	bool check_cve = false;
-	/* unused because assert goes away on release */
-	bool failed __unused = false;
+	bool failed = false;
+#endif /* FEATURE_DETECTION */
 
 	for (; entry != end; entry += 1) {
 		uint64_t status = entry->check_func(rev_var);
@@ -81,10 +94,10 @@
 			status = ERRATA_MISSING;
 		}
 
-		if (entry->cve) {
-			PRINT_STATUS_DISPATCH(status, CVE_FORMAT, BL_STRING,
-				cpu_ops->cpu_str, entry->cve, entry->id);
+		print_status(status, cpu_ops->cpu_str, entry->cve, entry->id);
 
+#if FEATURE_DETECTION
+		if (entry->cve) {
 			if (last_cve_yr > entry->cve ||
 			   (last_cve_yr == entry->cve && last_erratum_id >= entry->id)) {
 				ERROR("CVE %u_%u was out of order!\n",
@@ -94,9 +107,6 @@
 			check_cve = true;
 			last_cve_yr = entry->cve;
 		} else {
-			PRINT_STATUS_DISPATCH(status, ERRATUM_FORMAT, BL_STRING,
-				cpu_ops->cpu_str, entry->id);
-
 			if (last_erratum_id >= entry->id || check_cve) {
 				ERROR("Erratum %u was out of order!\n",
 				      entry->id);
@@ -104,13 +114,16 @@
 			}
 		}
 		last_erratum_id = entry->id;
+#endif /* FEATURE_DETECTION */
 	}
 
+#if FEATURE_DETECTION
 	/*
 	 * enforce errata and CVEs are in ascending order and that CVEs are
 	 * after errata
 	 */
 	assert(!failed);
+#endif /* FEATURE_DETECTION */
 }
 
 /*
diff --git a/plat/aspeed/ast2700/include/plat_macros.S b/plat/aspeed/ast2700/include/plat_macros.S
new file mode 100644
index 0000000..a58fd74
--- /dev/null
+++ b/plat/aspeed/ast2700/include/plat_macros.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2023, Aspeed Technology Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant platform registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/aspeed/ast2700/include/platform_def.h b/plat/aspeed/ast2700/include/platform_def.h
new file mode 100644
index 0000000..3f2468f
--- /dev/null
+++ b/plat/aspeed/ast2700/include/platform_def.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2023, Aspeed Technology Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <plat/common/common_def.h>
+#include <platform_reg.h>
+
+#define PLATFORM_STACK_SIZE		UL(0x1000)
+
+/* cpu topology */
+#define PLATFORM_SYSTEM_COUNT		U(1)
+#define PLATFORM_CLUSTER_COUNT		U(1)
+#define PLATFORM_CORE_PRIMARY		U(0)
+#define PLATFORM_CORE_COUNT_PER_CLUSTER U(4)
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER_COUNT * \
+					 PLATFORM_CORE_COUNT_PER_CLUSTER)
+
+/* arch timer */
+#define PLAT_SYSCNT_CLKIN_HZ		U(1600000000)
+
+/* power domain */
+#define PLAT_MAX_PWR_LVL		U(1)
+#define PLAT_NUM_PWR_DOMAINS		U(5)
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/* cache line size */
+#define CACHE_WRITEBACK_SHIFT		U(6)
+#define CACHE_WRITEBACK_GRANULE		(U(1) << CACHE_WRITEBACK_SHIFT)
+
+/* translation tables */
+#define PLAT_PHY_ADDR_SPACE_SIZE	(ULL(1) << 36)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(ULL(1) << 40)
+#define MAX_XLAT_TABLES			U(8)
+#define MAX_MMAP_REGIONS		U(32)
+
+/* BL31 region */
+#define BL31_BASE			ULL(0x400000000)
+#define BL31_SIZE			ULL(0x400000)
+#define BL31_LIMIT			(BL31_BASE + BL31_SIZE)
+
+/* BL32 region */
+#define BL32_BASE			BL31_LIMIT
+#define BL32_SIZE			ULL(0x400000)
+#define BL32_LIMIT			(BL32_BASE + BL32_SIZE)
+
+/* console */
+#define CONSOLE_UART_BASE		UART12_BASE
+#define CONSOLE_UART_CLKIN_HZ		U(1846153)
+#define CONSOLE_UART_BAUDRATE		U(115200)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/aspeed/ast2700/include/platform_reg.h b/plat/aspeed/ast2700/include/platform_reg.h
new file mode 100644
index 0000000..20ae32a
--- /dev/null
+++ b/plat/aspeed/ast2700/include/platform_reg.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2023, Aspeed Technology Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_REG_H
+#define PLATFORM_REG_H
+
+/* GIC */
+#define GICD_BASE	U(0x12200000)
+#define GICD_SIZE	U(0x10000)
+#define GICR_BASE	U(0x12280000)
+#define GICR_SIZE	U(0x100000)
+
+/* UART */
+#define UART_BASE	U(0x14c33000)
+#define UART12_BASE	(UART_BASE + 0xb00)
+
+/* CPU-die SCU */
+#define SCU_CPU_BASE		U(0x12c02000)
+#define SCU_CPU_SMP_READY	(SCU_CPU_BASE + 0x780)
+#define SCU_CPU_SMP_EP1		(SCU_CPU_BASE + 0x788)
+#define SCU_CPU_SMP_EP2		(SCU_CPU_BASE + 0x790)
+#define SCU_CPU_SMP_EP3		(SCU_CPU_BASE + 0x798)
+#define SCU_CPU_SMP_POLLINSN	(SCU_CPU_BASE + 0x7a0)
+
+#endif /* PLATFORM_REG_H */
diff --git a/plat/aspeed/ast2700/plat_bl31_setup.c b/plat/aspeed/ast2700/plat_bl31_setup.c
new file mode 100644
index 0000000..36e7338
--- /dev/null
+++ b/plat/aspeed/ast2700/plat_bl31_setup.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2023, Aspeed Technology Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/console.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+static console_t console;
+
+static entry_point_info_t bl32_ep_info;
+static entry_point_info_t bl33_ep_info;
+
+static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static unsigned int plat_mpidr_to_core_pos(u_register_t mpidr)
+{
+	/* to workaround the return type mismatch */
+	return plat_core_pos_by_mpidr(mpidr);
+}
+
+static const gicv3_driver_data_t plat_gic_data = {
+	.gicd_base = GICD_BASE,
+	.gicr_base = GICR_BASE,
+	.rdistif_num = PLATFORM_CORE_COUNT,
+	.rdistif_base_addrs = rdistif_base_addrs,
+	.mpidr_to_core_pos = plat_mpidr_to_core_pos,
+};
+
+static const mmap_region_t plat_mmap[] = {
+	MAP_REGION_FLAT(GICD_BASE, GICD_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(GICR_BASE, GICR_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(UART_BASE, PAGE_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(SCU_CPU_BASE, PAGE_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	{ 0 }
+};
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	console_16550_register(CONSOLE_UART_BASE, CONSOLE_UART_CLKIN_HZ,
+			       CONSOLE_UART_BAUDRATE, &console);
+
+	console_set_scope(&console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
+
+	bl31_params_parse_helper(arg0, &bl32_ep_info, &bl33_ep_info);
+}
+
+void bl31_plat_arch_setup(void)
+{
+	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
+			BL_CODE_END - BL_CODE_BASE,
+			MT_CODE | MT_SECURE);
+
+	mmap_add_region(BL_CODE_END, BL_CODE_END,
+			BL_END - BL_CODE_END,
+			MT_RW_DATA | MT_SECURE);
+
+	mmap_add_region(BL32_BASE, BL32_BASE, BL32_SIZE,
+			MT_MEMORY | MT_RW);
+
+	mmap_add(plat_mmap);
+
+	init_xlat_tables();
+
+	enable_mmu_el3(0);
+}
+
+void bl31_platform_setup(void)
+{
+	gicv3_driver_init(&plat_gic_data);
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *ep_info;
+
+	ep_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info;
+
+	if (!ep_info->pc) {
+		return NULL;
+	}
+
+	return ep_info;
+}
diff --git a/plat/aspeed/ast2700/plat_helpers.S b/plat/aspeed/ast2700/plat_helpers.S
new file mode 100644
index 0000000..1457692
--- /dev/null
+++ b/plat/aspeed/ast2700/plat_helpers.S
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2023, Aspeed Technology Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <arch.h>
+#include <cortex_a35.h>
+#include <platform_def.h>
+
+	.globl	plat_is_my_cpu_primary
+	.globl	plat_my_core_pos
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_get_syscnt_freq2
+	.globl	plat_crash_console_init
+	.globl	plat_crash_console_putc
+	.globl	plat_crash_console_flush
+
+/* unsigned int plat_is_my_cpu_primary(void); */
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #PLATFORM_CORE_PRIMARY
+	cset	w0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+/* unsigned int plat_my_core_pos(void); */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	mov	x2, #PLATFORM_CORE_COUNT_PER_CLUSTER
+	and	x1, x0, #MPIDR_CPU_MASK
+	and	x0, x0, #MPIDR_CLUSTER_MASK
+	madd	x0, x0, x2, x1
+	ret
+endfunc plat_my_core_pos
+
+/* unsigned int plat_get_syscnt_freq2(void); */
+func plat_get_syscnt_freq2
+	mov_imm	w0, PLAT_SYSCNT_CLKIN_HZ
+	ret
+endfunc plat_get_syscnt_freq2
+
+/* int plat_crash_console_init(void); */
+func plat_crash_console_init
+	mov_imm	x0, CONSOLE_UART_BASE
+	mov_imm	x1, CONSOLE_UART_CLKIN_HZ
+	mov_imm	x2, CONSOLE_UART_BAUDRATE
+	b	console_16550_core_init
+endfunc plat_crash_console_init
+
+/* int plat_crash_console_putc(int); */
+func plat_crash_console_putc
+	mov_imm	x1, CONSOLE_UART_BASE
+	b	console_16550_core_putc
+endfunc plat_crash_console_putc
+
+/* void plat_crash_console_flush(void); */
+func plat_crash_console_flush
+	mov_imm	x0, CONSOLE_UART_BASE
+	b	console_16550_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/aspeed/ast2700/plat_pm.c b/plat/aspeed/ast2700/plat_pm.c
new file mode 100644
index 0000000..8e69243
--- /dev/null
+++ b/plat/aspeed/ast2700/plat_pm.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2023, Aspeed Technology Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+
+static uintptr_t sec_ep;
+
+static int plat_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int cpu = plat_core_pos_by_mpidr(mpidr);
+	uintptr_t ep_reg;
+
+	switch (cpu) {
+	case 1U:
+		ep_reg = SCU_CPU_SMP_EP1;
+		break;
+	case 2U:
+		ep_reg = SCU_CPU_SMP_EP2;
+		break;
+	case 3U:
+		ep_reg = SCU_CPU_SMP_EP3;
+		break;
+	default:
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	mmio_write_64(ep_reg, sec_ep);
+
+	dsbsy();
+
+	sev();
+
+	return PSCI_E_SUCCESS;
+}
+
+static void plat_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+static const plat_psci_ops_t plat_psci_ops = {
+	.pwr_domain_on = plat_pwr_domain_on,
+	.pwr_domain_on_finish = plat_pwr_domain_on_finish,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	sec_ep = sec_entrypoint;
+	*psci_ops = &plat_psci_ops;
+
+	return 0;
+}
diff --git a/plat/aspeed/ast2700/plat_topology.c b/plat/aspeed/ast2700/plat_topology.c
new file mode 100644
index 0000000..1476fba
--- /dev/null
+++ b/plat/aspeed/ast2700/plat_topology.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2023, Aspeed Technology Inc.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+#include <platform_def.h>
+
+static const unsigned char ast2700_power_domain_tree_desc[] = {
+	PLATFORM_SYSTEM_COUNT,
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+};
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return ast2700_power_domain_tree_desc;
+}
+
+unsigned int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) {
+		return -1;
+	}
+
+	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT) {
+		return -1;
+	}
+
+	if (cpu_id >= PLATFORM_CORE_COUNT_PER_CLUSTER) {
+		return -1;
+	}
+
+	return (cluster_id * PLATFORM_CORE_COUNT_PER_CLUSTER) + cpu_id;
+}
diff --git a/plat/aspeed/ast2700/platform.mk b/plat/aspeed/ast2700/platform.mk
new file mode 100644
index 0000000..16ecf0a
--- /dev/null
+++ b/plat/aspeed/ast2700/platform.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (c) 2023, Aspeed Technology Inc.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include drivers/arm/gic/v3/gicv3.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_AST2700 := plat/aspeed/ast2700
+
+PLAT_INCLUDES := \
+	-I${PLAT_AST2700}/include
+
+BL31_SOURCES += \
+	common/desc_image_load.c		\
+	lib/cpus/aarch64/cortex_a35.S		\
+	plat/common/plat_gicv3.c		\
+	plat/common/plat_psci_common.c		\
+	drivers/ti/uart/aarch64/16550_console.S	\
+	${PLAT_AST2700}/plat_helpers.S		\
+	${PLAT_AST2700}/plat_topology.c		\
+	${PLAT_AST2700}/plat_bl31_setup.c	\
+	${PLAT_AST2700}/plat_pm.c		\
+	${GICV3_SOURCES}			\
+	${XLAT_TABLES_LIB_SRCS}
+
+PROGRAMMABLE_RESET_ADDRESS := 1
+
+COLD_BOOT_SINGLE_CPU := 1
+
+ENABLE_SVE_FOR_NS := 0