Merge "fix(cpus): reduce generic_errata_report()'s size" into integration
diff --git a/.versionrc.js b/.versionrc.js
index 4e9c71f..3a21ded 100644
--- a/.versionrc.js
+++ b/.versionrc.js
@@ -101,6 +101,25 @@
             "type": "json"
         },
         {
+            "filename": "docs/conf.py",
+            "updater": {
+                "readVersion": function (contents) {
+                    const _ver = contents.match(/version\s=.*"(\d)\.(\d)\.(\d)/);
+
+                    return `${_ver[1]}.${_ver[2]}.${_ver[2]}`;
+                },
+
+                "writeVersion": function (contents, version) {
+                    const _ver = 'version = "' + version + '"'
+                    const _rel = 'release = "' + version + '"'
+
+                    contents = contents.replace(/^(version\s=\s")((\d).?)*$/m, _ver)
+                    contents = contents.replace(/^(release\s=\s")((\d).?)*$/m, _rel)
+                    return contents
+                }
+            },
+        },
+        {
             "filename": "tools/conventional-changelog-tf-a/package.json",
             "type": "json"
         },
diff --git a/bl1/bl1.ld.S b/bl1/bl1.ld.S
index a2527e6..49dda85 100644
--- a/bl1/bl1.ld.S
+++ b/bl1/bl1.ld.S
@@ -41,6 +41,7 @@
         *bl1_entrypoint.o(.text*)
         *(SORT_BY_ALIGNMENT(.text*))
         *(.vectors)
+        __TEXT_END_UNALIGNED__ = .;
 
         . = ALIGN(PAGE_SIZE);
 
@@ -72,6 +73,7 @@
          * aligned and lld does not align the LMA to the alignment specified
          * on the .data section.
          */
+        __RODATA_END_UNALIGNED__ = .;
         __RODATA_END__ = .;
 
         . = ALIGN(16);
diff --git a/bl2/bl2.ld.S b/bl2/bl2.ld.S
index 5f689d5..db83a0c 100644
--- a/bl2/bl2.ld.S
+++ b/bl2/bl2.ld.S
@@ -35,6 +35,7 @@
 
         *(SORT_BY_ALIGNMENT(.text*))
         *(.vectors)
+        __TEXT_END_UNALIGNED__ = .;
 
         . = ALIGN(PAGE_SIZE);
 
@@ -57,6 +58,7 @@
 
         RODATA_COMMON
 
+        __RODATA_END_UNALIGNED__ = .;
         . = ALIGN(PAGE_SIZE);
 
         __RODATA_END__ = .;
diff --git a/bl2/bl2_el3.ld.S b/bl2/bl2_el3.ld.S
index 5da631c..4aa5cb0 100644
--- a/bl2/bl2_el3.ld.S
+++ b/bl2/bl2_el3.ld.S
@@ -65,6 +65,7 @@
 
         *(SORT_BY_ALIGNMENT(.text*))
         *(.vectors)
+        __TEXT_END_UNALIGNED__ = .;
 
         . = ALIGN(PAGE_SIZE);
 
@@ -78,6 +79,7 @@
 
         RODATA_COMMON
 
+        __RODATA_END_UNALIGNED__ = .;
         . = ALIGN(PAGE_SIZE);
 
         __RODATA_END__ = .;
diff --git a/bl2u/bl2u.ld.S b/bl2u/bl2u.ld.S
index 21c91b4..7b1a101 100644
--- a/bl2u/bl2u.ld.S
+++ b/bl2u/bl2u.ld.S
@@ -32,6 +32,7 @@
         *bl2u_entrypoint.o(.text*)
         *(SORT_BY_ALIGNMENT(.text*))
         *(.vectors)
+        __TEXT_END_UNALIGNED__ = .;
 
         . = ALIGN(PAGE_SIZE);
 
@@ -53,6 +54,7 @@
 
         RODATA_COMMON
 
+        __RODATA_END_UNALIGNED__ = .;
         . = ALIGN(PAGE_SIZE);
         __RODATA_END__ = .;
     } >RAM
diff --git a/bl31/bl31.ld.S b/bl31/bl31.ld.S
index abcae0c..7a8c41a 100644
--- a/bl31/bl31.ld.S
+++ b/bl31/bl31.ld.S
@@ -42,6 +42,7 @@
         *bl31_entrypoint.o(.text*)
         *(SORT_BY_ALIGNMENT(SORT(.text*)))
         *(.vectors)
+        __TEXT_END_UNALIGNED__ = .;
 
         . = ALIGN(PAGE_SIZE);
 
@@ -62,6 +63,7 @@
         . = ALIGN(8);
 
 #   include <lib/el3_runtime/pubsub_events.h>
+        __RODATA_END_UNALIGNED__ = .;
 
         . = ALIGN(PAGE_SIZE);
 
diff --git a/bl32/sp_min/sp_min.ld.S b/bl32/sp_min/sp_min.ld.S
index 0a2bad0..dd81973 100644
--- a/bl32/sp_min/sp_min.ld.S
+++ b/bl32/sp_min/sp_min.ld.S
@@ -34,6 +34,7 @@
         *entrypoint.o(.text*)
         *(SORT_BY_ALIGNMENT(.text*))
         *(.vectors)
+        __TEXT_END_UNALIGNED__ = .;
 
         . = ALIGN(PAGE_SIZE);
 
@@ -58,6 +59,7 @@
         . = ALIGN(8);
 
 #   include <lib/el3_runtime/pubsub_events.h>
+        __RODATA_END_UNALIGNED__ = .;
 
         . = ALIGN(PAGE_SIZE);
 
diff --git a/bl32/tsp/tsp.ld.S b/bl32/tsp/tsp.ld.S
index b735f45..22bf11d 100644
--- a/bl32/tsp/tsp.ld.S
+++ b/bl32/tsp/tsp.ld.S
@@ -30,6 +30,7 @@
         *tsp_entrypoint.o(.text*)
         *(.text*)
         *(.vectors)
+        __TEXT_END_UNALIGNED__ = .;
 
         . = ALIGN(PAGE_SIZE);
 
@@ -43,6 +44,7 @@
 
         RODATA_COMMON
 
+        __RODATA_END_UNALIGNED__ = .;
         . = ALIGN(PAGE_SIZE);
 
         __RODATA_END__ = .;
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/conf.py b/docs/conf.py
index 371632a..345f53b 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+# Copyright (c) 2019-2023, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -9,27 +9,34 @@
 #
 # See the options documentation at http://www.sphinx-doc.org/en/master/config
 
-import os
 
 # -- Project information -----------------------------------------------------
 
-project = 'Trusted Firmware-A'
+project = "Trusted Firmware-A"
+author = "Trusted Firmware-A contributors"
+version = "2.9.0"
+release = "2.9.0"
 
 # -- General configuration ---------------------------------------------------
 
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = ['myst_parser', 'sphinx.ext.autosectionlabel', 'sphinxcontrib.plantuml']
+extensions = [
+    "myst_parser",
+    "sphinx.ext.autosectionlabel",
+    "sphinxcontrib.plantuml",
+    "sphinxcontrib.inkscapeconverter",
+]
 
 # Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
 
 # The suffix(es) of source filenames.
-source_suffix = ['.md', '.rst']
+source_suffix = [".md", ".rst"]
 
 # The master toctree document.
-master_doc = 'index'
+master_doc = "index"
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -45,15 +52,16 @@
 exclude_patterns = [".env", "env", ".venv", "venv"]
 
 # The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = "sphinx"
 
 # Load the contents of the global substitutions file into the 'rst_prolog'
-# variable. This ensures that the substitutions are all inserted into each page.
-with open('global_substitutions.txt', 'r') as subs:
-  rst_prolog = subs.read()
+# variable. This ensures that the substitutions are all inserted into each
+# page.
+with open("global_substitutions.txt", "r") as subs:
+    rst_prolog = subs.read()
 
 # Minimum version of sphinx required
-needs_sphinx = '2.0'
+needs_sphinx = "2.0"
 
 # -- Options for HTML output -------------------------------------------------
 
@@ -68,21 +76,21 @@
 html_theme = "sphinx_rtd_theme"
 
 # The logo to display in the sidebar
-html_logo = 'resources/TrustedFirmware-Logo_standard-white.png'
+html_logo = "resources/TrustedFirmware-Logo_standard-white.png"
 
 # Options for the "sphinx-rtd-theme" theme
 html_theme_options = {
-    'collapse_navigation': False, # Can expand and collapse sidebar entries
-    'prev_next_buttons_location': 'both', # Top and bottom of the page
-    'style_external_links': True # Display an icon next to external links
+    "collapse_navigation": False,  # Can expand and collapse sidebar entries
+    "prev_next_buttons_location": "both",  # Top and bottom of the page
+    "style_external_links": True,  # Display an icon next to external links
 }
 
 # Path to _static directory
-html_static_path = ['_static']
+html_static_path = ["_static"]
 
 # Path to css file relative to html_static_path
 html_css_files = [
-    'css/custom.css',
+    "css/custom.css",
 ]
 
 # -- Options for autosectionlabel --------------------------------------------
@@ -92,4 +100,12 @@
 
 # -- Options for plantuml ----------------------------------------------------
 
+plantuml_output_format = "svg_img"
+
-plantuml_output_format = 'svg_img'
+# -- Options for latexmk  ----------------------------------------------------
+
+latex_engine = "xelatex"
+latex_elements = {
+    "maxlistdepth": "10",
+    "pointsize": "11pt",
+}
diff --git a/docs/design/firmware-design.rst b/docs/design/firmware-design.rst
index 94f8656..56bedd4 100644
--- a/docs/design/firmware-design.rst
+++ b/docs/design/firmware-design.rst
@@ -1618,8 +1618,10 @@
 -  ``__RO_START__``
 -  ``__RO_END__``
 -  ``__TEXT_START__``
+-  ``__TEXT_END_UNALIGNED__``
 -  ``__TEXT_END__``
 -  ``__RODATA_START__``
+-  ``__RODATA_END_UNALIGNED__``
 -  ``__RODATA_END__``
 
 BL1's linker symbols
diff --git a/docs/design_documents/measured_boot_poc.rst b/docs/design_documents/measured_boot_poc.rst
index 7f73d7e..7f9519e 100644
--- a/docs/design_documents/measured_boot_poc.rst
+++ b/docs/design_documents/measured_boot_poc.rst
@@ -5,10 +5,10 @@
 critical data used at boot time, for example using a TPM, so that the
 security state can be attested later.
 
-The current implementation of the driver included in Trusted Firmware-A
-(TF-A) stores the measurements into a `TCG event log`_ in secure
-memory. No other means of recording measurements (such as a discrete TPM) is
-supported right now.
+The current implementation of the driver included in |TF-A| supports several
+backends and each has a different means to store the measurements.
+This section focuses on the `TCG event log`_ backend, which stores measurements
+in secure memory.
 
 The driver also provides mechanisms to pass the Event Log to normal world if
 needed.
diff --git a/docs/design_documents/psci_osi_mode.rst b/docs/design_documents/psci_osi_mode.rst
index 3296e27..a6e1bdf 100644
--- a/docs/design_documents/psci_osi_mode.rst
+++ b/docs/design_documents/psci_osi_mode.rst
@@ -4,7 +4,7 @@
 :Author: Maulik Shah & Wing Li
 :Organization: Qualcomm Innovation Center, Inc. & Google LLC
 :Contact: Maulik Shah <quic_mkshah@quicinc.com> & Wing Li <wingers@google.com>
-:Status: RFC
+:Status: Accepted
 
 .. contents:: Table of Contents
 
@@ -367,9 +367,11 @@
     ``psci_validate_state_coordination``. If validation fails, propagate the
     error up the call stack.
 
-* Update the return type of the platform specific ``pwr_domain_suspend``
-  handler from ``void`` to ``int``, to allow the platform to optionally perform
-  validations based on hardware states.
+* Add a new optional member ``pwr_domain_validate_suspend`` to
+  ``plat_psci_ops_t`` to allow the platform to optionally perform validations
+  based on hardware states.
+
+* The platform specific ``pwr_domain_suspend`` handler remains unchanged.
 
 .. image:: ../resources/diagrams/psci-osi-mode.png
 
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/docs/porting-guide.rst b/docs/porting-guide.rst
index 1250071..8182f91 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -2818,6 +2818,17 @@
 for the higher power domain levels depending on the result of state
 coordination. The generic code expects the handler to succeed.
 
+plat_psci_ops.pwr_domain_validate_suspend() [optional]
+......................................................
+
+This is an optional function that is only compiled into the build if the build
+option ``PSCI_OS_INIT_MODE`` is enabled.
+
+If implemented, this function allows the platform to perform platform specific
+validations based on hardware states. The generic code expects this function to
+return PSCI_E_SUCCESS on success, or either PSCI_E_DENIED or
+PSCI_E_INVALID_PARAMS as appropriate for any invalid requests.
+
 plat_psci_ops.pwr_domain_suspend_pwrdown_early() [optional]
 ...........................................................
 
@@ -2876,10 +2887,6 @@
 data, for example in DRAM. The Distributor can then be powered down using an
 implementation-defined sequence.
 
-If the build option ``PSCI_OS_INIT_MODE`` is enabled, the generic code expects
-the platform to return PSCI_E_SUCCESS on success, or either PSCI_E_DENIED or
-PSCI_E_INVALID_PARAMS as appropriate for any invalid requests.
-
 plat_psci_ops.pwr_domain_pwr_down_wfi()
 .......................................
 
diff --git a/docs/resources/diagrams/psci-osi-mode.png b/docs/resources/diagrams/psci-osi-mode.png
index d322953..09175e5 100644
--- a/docs/resources/diagrams/psci-osi-mode.png
+++ b/docs/resources/diagrams/psci-osi-mode.png
Binary files differ
diff --git a/include/lib/psci/psci.h b/include/lib/psci/psci.h
index 4d7e58e..01dc3cb 100644
--- a/include/lib/psci/psci.h
+++ b/include/lib/psci/psci.h
@@ -319,13 +319,13 @@
 	int (*pwr_domain_on)(u_register_t mpidr);
 	void (*pwr_domain_off)(const psci_power_state_t *target_state);
 	int (*pwr_domain_off_early)(const psci_power_state_t *target_state);
+#if PSCI_OS_INIT_MODE
+	int (*pwr_domain_validate_suspend)(
+				const psci_power_state_t *target_state);
+#endif
 	void (*pwr_domain_suspend_pwrdown_early)(
 				const psci_power_state_t *target_state);
-#if PSCI_OS_INIT_MODE
-	int (*pwr_domain_suspend)(const psci_power_state_t *target_state);
-#else
 	void (*pwr_domain_suspend)(const psci_power_state_t *target_state);
-#endif
 	void (*pwr_domain_on_finish)(const psci_power_state_t *target_state);
 	void (*pwr_domain_on_finish_late)(
 				const psci_power_state_t *target_state);
diff --git a/include/services/el3_spmc_logical_sp.h b/include/services/el3_spmc_logical_sp.h
index 5ce33ed..dccd362 100644
--- a/include/services/el3_spmc_logical_sp.h
+++ b/include/services/el3_spmc_logical_sp.h
@@ -49,8 +49,7 @@
  * Function & variable prototypes.
  ******************************************************************************/
 int el3_sp_desc_validate(void);
-uintptr_t handle_el3_sp(uint32_t smc_fid, void *cookie, void *handle,
-						unsigned int flags);
+
 IMPORT_SYM(uintptr_t, __EL3_LP_DESCS_START__,	EL3_LP_DESCS_START);
 IMPORT_SYM(uintptr_t, __EL3_LP_DESCS_END__,	EL3_LP_DESCS_END);
 
diff --git a/lib/psci/psci_common.c b/lib/psci/psci_common.c
index c893476..bfc09cc 100644
--- a/lib/psci/psci_common.c
+++ b/lib/psci/psci_common.c
@@ -451,8 +451,8 @@
  * enter. This function will be called after coordination of requested power
  * states has been done for each power level.
  *****************************************************************************/
-static void psci_set_target_local_pwr_states(unsigned int end_pwrlvl,
-					const psci_power_state_t *target_state)
+void psci_set_target_local_pwr_states(unsigned int end_pwrlvl,
+				      const psci_power_state_t *target_state)
 {
 	unsigned int parent_idx, lvl;
 	const plat_local_state_t *pd_state = target_state->pwr_domain_state;
@@ -474,7 +474,6 @@
 	}
 }
 
-
 /*******************************************************************************
  * PSCI helper function to get the parent nodes corresponding to a cpu_index.
  ******************************************************************************/
@@ -595,9 +594,6 @@
 		state_info->pwr_domain_state[lvl] = PSCI_LOCAL_STATE_RUN;
 
 	}
-
-	/* Update the target state in the power domain nodes */
-	psci_set_target_local_pwr_states(end_pwrlvl, state_info);
 }
 
 #if PSCI_OS_INIT_MODE
@@ -684,9 +680,6 @@
 		return rc;
 	}
 
-	/* Update the target state in the power domain nodes */
-	psci_set_target_local_pwr_states(end_pwrlvl, state_info);
-
 	return rc;
 }
 #endif
diff --git a/lib/psci/psci_off.c b/lib/psci/psci_off.c
index 9f36ac7..f83753f 100644
--- a/lib/psci/psci_off.c
+++ b/lib/psci/psci_off.c
@@ -104,6 +104,9 @@
 	 */
 	psci_do_state_coordination(end_pwrlvl, &state_info);
 
+	/* Update the target state in the power domain nodes */
+	psci_set_target_local_pwr_states(end_pwrlvl, &state_info);
+
 #if ENABLE_PSCI_STAT
 	/* Update the last cpu for each level till end_pwrlvl */
 	psci_stats_update_pwr_down(end_pwrlvl, &state_info);
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
index b9987fe..04f93bd 100644
--- a/lib/psci/psci_private.h
+++ b/lib/psci/psci_private.h
@@ -298,6 +298,8 @@
 #endif
 void psci_get_target_local_pwr_states(unsigned int end_pwrlvl,
 				      psci_power_state_t *target_state);
+void psci_set_target_local_pwr_states(unsigned int end_pwrlvl,
+				      const psci_power_state_t *target_state);
 int psci_validate_entry_point(entry_point_info_t *ep,
 			uintptr_t entrypoint, u_register_t context_id);
 void psci_get_parent_pwr_domain_nodes(unsigned int cpu_idx,
diff --git a/lib/psci/psci_suspend.c b/lib/psci/psci_suspend.c
index 861b875..d93e60d 100644
--- a/lib/psci/psci_suspend.c
+++ b/lib/psci/psci_suspend.c
@@ -219,6 +219,19 @@
 	}
 #endif
 
+#if PSCI_OS_INIT_MODE
+	if (psci_plat_pm_ops->pwr_domain_validate_suspend != NULL) {
+		rc = psci_plat_pm_ops->pwr_domain_validate_suspend(state_info);
+		if (rc != PSCI_E_SUCCESS) {
+			skip_wfi = true;
+			goto exit;
+		}
+	}
+#endif
+
+	/* Update the target state in the power domain nodes */
+	psci_set_target_local_pwr_states(end_pwrlvl, state_info);
+
 #if ENABLE_PSCI_STAT
 	/* Update the last cpu for each level till end_pwrlvl */
 	psci_stats_update_pwr_down(end_pwrlvl, state_info);
@@ -234,15 +247,7 @@
 	 * program the power controller etc.
 	 */
 
-#if PSCI_OS_INIT_MODE
-	rc = psci_plat_pm_ops->pwr_domain_suspend(state_info);
-	if (rc != PSCI_E_SUCCESS) {
-		skip_wfi = true;
-		goto exit;
-	}
-#else
 	psci_plat_pm_ops->pwr_domain_suspend(state_info);
-#endif
 
 #if ENABLE_PSCI_STAT
 	plat_psci_stat_accounting_start(state_info);
diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c
index a3289b6..b8c97f8 100644
--- a/plat/arm/board/fvp/fvp_pm.c
+++ b/plat/arm/board/fvp/fvp_pm.c
@@ -228,11 +228,7 @@
  * FVP handler called when a power domain is about to be suspended. The
  * target_state encodes the power state that each level should transition to.
  ******************************************************************************/
-#if PSCI_OS_INIT_MODE
-static int fvp_pwr_domain_suspend(const psci_power_state_t *target_state)
-#else
 static void fvp_pwr_domain_suspend(const psci_power_state_t *target_state)
-#endif
 {
 	unsigned long mpidr;
 
@@ -242,11 +238,7 @@
 	 */
 	if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
 					ARM_LOCAL_STATE_RET)
-#if PSCI_OS_INIT_MODE
-		return PSCI_E_SUCCESS;
-#else
 		return;
-#endif
 
 	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
 					ARM_LOCAL_STATE_OFF);
@@ -279,11 +271,7 @@
 	/* Program the power controller to power off this cpu. */
 	fvp_pwrc_write_ppoffr(read_mpidr_el1());
 
-#if PSCI_OS_INIT_MODE
-	return PSCI_E_SUCCESS;
-#else
 	return;
-#endif
 }
 
 /*******************************************************************************
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
diff --git a/plat/qti/common/src/qti_pm.c b/plat/qti/common/src/qti_pm.c
index 1405ca6..487a56e 100644
--- a/plat/qti/common/src/qti_pm.c
+++ b/plat/qti/common/src/qti_pm.c
@@ -191,18 +191,6 @@
 	}
 }
 
-#if PSCI_OS_INIT_MODE
-static int qti_node_suspend(const psci_power_state_t *target_state)
-{
-	qtiseclib_psci_node_suspend((const uint8_t *)target_state->
-				    pwr_domain_state);
-	if (is_cpu_off(target_state)) {
-		plat_qti_gic_cpuif_disable();
-		qti_set_cpupwrctlr_val();
-	}
-	return PSCI_E_SUCCESS;
-}
-#else
 static void qti_node_suspend(const psci_power_state_t *target_state)
 {
 	qtiseclib_psci_node_suspend((const uint8_t *)target_state->
@@ -212,7 +200,6 @@
 		qti_set_cpupwrctlr_val();
 	}
 }
-#endif
 
 static void qti_node_suspend_finish(const psci_power_state_t *target_state)
 {
diff --git a/plat/xilinx/versal/pm_service/pm_client.c b/plat/xilinx/versal/pm_service/pm_client.c
index 81a5445..af5263d 100644
--- a/plat/xilinx/versal/pm_service/pm_client.c
+++ b/plat/xilinx/versal/pm_service/pm_client.c
@@ -121,6 +121,48 @@
 	case 57:
 		dev_idx = XPM_NODEIDX_DEV_GEM_0;
 		break;
+	case 58:
+	case 59:
+		dev_idx = XPM_NODEIDX_DEV_GEM_1;
+		break;
+	case 60:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_0;
+		break;
+	case 61:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_1;
+		break;
+	case 62:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_2;
+		break;
+	case 63:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_3;
+		break;
+	case 64:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_4;
+		break;
+	case 65:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_5;
+		break;
+	case 66:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_6;
+		break;
+	case 67:
+		dev_idx = XPM_NODEIDX_DEV_ADMA_7;
+		break;
+	case 74:
+		dev_idx = XPM_NODEIDX_DEV_USB_0;
+		break;
+	case 126:
+	case 127:
+		dev_idx = XPM_NODEIDX_DEV_SDIO_0;
+		break;
+	case 128:
+	case 129:
+		dev_idx = XPM_NODEIDX_DEV_SDIO_1;
+		break;
+	case 142:
+		dev_idx = XPM_NODEIDX_DEV_RTC;
+		break;
 	default:
 		dev_idx = XPM_NODEIDX_DEV_MIN;
 		break;
diff --git a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
index 6cadaab..b00513e 100644
--- a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
+++ b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
@@ -212,7 +212,7 @@
 
 	/* Reserve memory used by Trusted Firmware. */
 	if (fdt_add_reserved_memory(dtb, "tf-a", BL31_BASE,
-				    BL31_LIMIT - BL31_BASE + 1)) {
+				   (size_t) (BL31_LIMIT - BL31_BASE))) {
 		WARN("Failed to add reserved memory nodes for BL31 to DT.\n");
 	}
 
diff --git a/poetry.lock b/poetry.lock
index 92b38da..07cd572 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,10 +1,9 @@
-# This file is automatically @generated by Poetry and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.5.0 and should not be changed by hand.
 
 [[package]]
 name = "alabaster"
 version = "0.7.13"
 description = "A configurable sidebar-enabled Sphinx theme"
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -16,7 +15,6 @@
 name = "anytree"
 version = "2.8.0"
 description = "Powerful and Lightweight Python Tree Data Structure.."
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -35,7 +33,6 @@
 name = "babel"
 version = "2.12.1"
 description = "Internationalization utilities"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -50,7 +47,6 @@
 name = "build"
 version = "0.10.0"
 description = "A simple, correct Python build frontend"
-category = "dev"
 optional = false
 python-versions = ">= 3.7"
 files = [
@@ -74,7 +70,6 @@
 name = "certifi"
 version = "2022.12.7"
 description = "Python package for providing Mozilla's CA Bundle."
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -86,7 +81,6 @@
 name = "charset-normalizer"
 version = "3.1.0"
 description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-category = "dev"
 optional = false
 python-versions = ">=3.7.0"
 files = [
@@ -171,7 +165,6 @@
 name = "click"
 version = "8.1.3"
 description = "Composable command line interface toolkit"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -186,7 +179,6 @@
 name = "colorama"
 version = "0.4.6"
 description = "Cross-platform colored terminal text."
-category = "dev"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
 files = [
@@ -198,7 +190,6 @@
 name = "docutils"
 version = "0.18.1"
 description = "Docutils -- Python Documentation Utilities"
-category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 files = [
@@ -210,7 +201,6 @@
 name = "idna"
 version = "3.4"
 description = "Internationalized Domain Names in Applications (IDNA)"
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -222,7 +212,6 @@
 name = "imagesize"
 version = "1.4.1"
 description = "Getting image size from png/jpeg/jpeg2000/gif file"
-category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 files = [
@@ -234,7 +223,6 @@
 name = "importlib-metadata"
 version = "6.6.0"
 description = "Read metadata from Python packages"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -254,7 +242,6 @@
 name = "jinja2"
 version = "3.1.2"
 description = "A very fast and expressive template engine."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -272,7 +259,6 @@
 name = "markdown-it-py"
 version = "2.2.0"
 description = "Python port of markdown-it. Markdown parsing, done right!"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -297,7 +283,6 @@
 name = "markupsafe"
 version = "2.1.2"
 description = "Safely add untrusted strings to HTML/XML markup."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -357,7 +342,6 @@
 name = "mdit-py-plugins"
 version = "0.3.5"
 description = "Collection of plugins for markdown-it-py"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -377,7 +361,6 @@
 name = "mdurl"
 version = "0.1.2"
 description = "Markdown URL utilities"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -389,7 +372,6 @@
 name = "myst-parser"
 version = "0.18.1"
 description = "An extended commonmark compliant parser, with bridges to docutils & sphinx."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -416,7 +398,6 @@
 name = "packaging"
 version = "23.1"
 description = "Core utilities for Python packages"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -428,7 +409,6 @@
 name = "pip"
 version = "23.1.2"
 description = "The PyPA recommended tool for installing Python packages."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -440,7 +420,6 @@
 name = "pip-tools"
 version = "6.13.0"
 description = "pip-tools keeps your pinned dependencies fresh."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -463,7 +442,6 @@
 name = "prettytable"
 version = "3.7.0"
 description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -481,7 +459,6 @@
 name = "pyelftools"
 version = "0.29"
 description = "Library for analyzing ELF files and DWARF debugging information"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -493,7 +470,6 @@
 name = "pygments"
 version = "2.15.1"
 description = "Pygments is a syntax highlighting package written in Python."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -508,7 +484,6 @@
 name = "pyproject-hooks"
 version = "1.0.0"
 description = "Wrappers to call pyproject.toml-based build backend hooks."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -523,7 +498,6 @@
 name = "pytz"
 version = "2023.3"
 description = "World timezone definitions, modern and historical"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -535,7 +509,6 @@
 name = "pyyaml"
 version = "6.0"
 description = "YAML parser and emitter for Python"
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -585,7 +558,6 @@
 name = "requests"
 version = "2.30.0"
 description = "Python HTTP for Humans."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -607,7 +579,6 @@
 name = "setuptools"
 version = "67.7.2"
 description = "Easily download, build, install, upgrade, and uninstall Python packages"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -624,7 +595,6 @@
 name = "six"
 version = "1.16.0"
 description = "Python 2 and 3 compatibility utilities"
-category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
 files = [
@@ -636,7 +606,6 @@
 name = "snowballstemmer"
 version = "2.2.0"
 description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -648,7 +617,6 @@
 name = "sphinx"
 version = "5.3.0"
 description = "Python documentation generator"
-category = "dev"
 optional = false
 python-versions = ">=3.6"
 files = [
@@ -684,7 +652,6 @@
 name = "sphinx-rtd-theme"
 version = "1.2.0"
 description = "Read the Docs theme for Sphinx"
-category = "dev"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
 files = [
@@ -704,7 +671,6 @@
 name = "sphinxcontrib-applehelp"
 version = "1.0.4"
 description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books"
-category = "dev"
 optional = false
 python-versions = ">=3.8"
 files = [
@@ -720,7 +686,6 @@
 name = "sphinxcontrib-devhelp"
 version = "1.0.2"
 description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document."
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -736,7 +701,6 @@
 name = "sphinxcontrib-htmlhelp"
 version = "2.0.1"
 description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
-category = "dev"
 optional = false
 python-versions = ">=3.8"
 files = [
@@ -752,7 +716,6 @@
 name = "sphinxcontrib-jquery"
 version = "4.1"
 description = "Extension to include jQuery on newer Sphinx releases"
-category = "dev"
 optional = false
 python-versions = ">=2.7"
 files = [
@@ -767,7 +730,6 @@
 name = "sphinxcontrib-jsmath"
 version = "1.0.1"
 description = "A sphinx extension which renders display math in HTML via JavaScript"
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -782,7 +744,6 @@
 name = "sphinxcontrib-plantuml"
 version = "0.24.1"
 description = "Sphinx \"plantuml\" extension"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -799,7 +760,6 @@
 name = "sphinxcontrib-qthelp"
 version = "1.0.3"
 description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document."
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -815,7 +775,6 @@
 name = "sphinxcontrib-serializinghtml"
 version = "1.1.5"
 description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)."
-category = "dev"
 optional = false
 python-versions = ">=3.5"
 files = [
@@ -828,10 +787,26 @@
 test = ["pytest"]
 
 [[package]]
+name = "sphinxcontrib-svg2pdfconverter"
+version = "1.2.2"
+description = "Sphinx SVG to PDF converter extension"
+optional = false
+python-versions = "~=3.4"
+files = [
+    {file = "sphinxcontrib-svg2pdfconverter-1.2.2.tar.gz", hash = "sha256:80a55ca61f70eae93efc65f3814f2f177c86ba55934a9f6c5022f1778b62146b"},
+    {file = "sphinxcontrib_svg2pdfconverter-1.2.2-py3-none-any.whl", hash = "sha256:04ec767b55780a6b18d89cc1a8ada6d900c6efde9d1683abdb98a49b144465ca"},
+]
+
+[package.dependencies]
+Sphinx = ">=1.6.3"
+
+[package.extras]
+cairosvg = ["cairosvg (>=1.0)"]
+
+[[package]]
 name = "tomli"
 version = "2.0.1"
 description = "A lil' TOML parser"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -843,7 +818,6 @@
 name = "typing-extensions"
 version = "4.5.0"
 description = "Backported and Experimental Type Hints for Python 3.7+"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -855,7 +829,6 @@
 name = "urllib3"
 version = "2.0.2"
 description = "HTTP library with thread-safe connection pooling, file post, and more."
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -873,7 +846,6 @@
 name = "wcwidth"
 version = "0.2.6"
 description = "Measures the displayed width of unicode strings in a terminal"
-category = "dev"
 optional = false
 python-versions = "*"
 files = [
@@ -885,7 +857,6 @@
 name = "wheel"
 version = "0.40.0"
 description = "A built-package format for Python"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -900,7 +871,6 @@
 name = "zipp"
 version = "3.15.0"
 description = "Backport of pathlib-compatible object wrapper for zip files"
-category = "dev"
 optional = false
 python-versions = ">=3.7"
 files = [
@@ -915,4 +885,4 @@
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.8"
-content-hash = "9c25ef33612d10c7caafa551a3cf6a12753167c6400f49cc261fddd18c7eaf6e"
+content-hash = "62d9ce9ca1c9f4669c7b40724acfc93968cde31c0460d1d7515d289739dc9464"
diff --git a/pyproject.toml b/pyproject.toml
index 44e78d3..19ba4d8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -21,6 +21,7 @@
 sphinxcontrib-plantuml = "^0.24.1"
 sphinx-rtd-theme = "^1.1.1"
 pip-tools = "^6.4.0"
+sphinxcontrib-svg2pdfconverter = "^1.2.2"
 
 [tool.poetry.group.ci.dependencies]
 click = "^8.1.3"
diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c
index 80b506b..6b16373 100644
--- a/services/std_svc/spmd/spmd_main.c
+++ b/services/std_svc/spmd/spmd_main.c
@@ -249,6 +249,7 @@
 	SMC_RET0(&ctx->cpu_ctx);
 }
 
+#if (EL3_EXCEPTION_HANDLING == 0)
 /*******************************************************************************
  * spmd_group0_interrupt_handler_nwd
  * Group0 secure interrupt in the normal world are trapped to EL3. Delegate the
@@ -281,6 +282,7 @@
 
 	return 0U;
 }
+#endif
 
 /*******************************************************************************
  * spmd_handle_group0_intr_swd
@@ -561,6 +563,18 @@
 	}
 
 	/*
+	 * Permit configurations where the SPM resides at S-EL1/2 and upon a
+	 * Group0 interrupt triggering while the normal world runs, the
+	 * interrupt is routed either through the EHF or directly to the SPMD:
+	 *
+	 * EL3_EXCEPTION_HANDLING=0: the Group0 interrupt is routed to the SPMD
+	 *                   for handling by spmd_group0_interrupt_handler_nwd.
+	 *
+	 * EL3_EXCEPTION_HANDLING=1: the Group0 interrupt is routed to the EHF.
+	 *
+	 */
+#if (EL3_EXCEPTION_HANDLING == 0)
+	/*
 	 * Register an interrupt handler routing Group0 interrupts to SPMD
 	 * while the NWd is running.
 	 */
@@ -570,6 +584,8 @@
 	if (rc != 0) {
 		panic();
 	}
+#endif
+
 	return 0;
 }
 
diff --git a/tools/memory/memory/buildparser.py b/tools/memory/memory/buildparser.py
index c128c36..dedff79 100755
--- a/tools/memory/memory/buildparser.py
+++ b/tools/memory/memory/buildparser.py
@@ -8,14 +8,16 @@
 from pathlib import Path
 
 from memory.elfparser import TfaElfParser
+from memory.mapparser import TfaMapParser
 
 
 class TfaBuildParser:
     """A class for performing analysis on the memory layout of a TF-A build."""
 
-    def __init__(self, path: Path):
+    def __init__(self, path: Path, map_backend=False):
         self._modules = dict()
         self._path = path
+        self.map_backend = map_backend
         self._parse_modules()
 
     def __getitem__(self, module: str):
@@ -23,15 +25,24 @@
         return self._modules[module]
 
     def _parse_modules(self):
-        """Parse ELF files in the build path."""
-        for elf_file in self._path.glob("**/*.elf"):
-            module_name = elf_file.name.split("/")[-1].split(".")[0]
-            with open(elf_file, "rb") as file:
-                self._modules[module_name] = TfaElfParser(file)
+        """Parse the build files using the selected backend."""
+        backend = TfaElfParser
+        files = list(self._path.glob("**/*.elf"))
+        io_perms = "rb"
+
+        if self.map_backend or len(files) == 0:
+            backend = TfaMapParser
+            files = self._path.glob("**/*.map")
+            io_perms = "r"
+
+        for file in files:
+            module_name = file.name.split("/")[-1].split(".")[0]
+            with open(file, io_perms) as f:
+                self._modules[module_name] = backend(f)
 
         if not len(self._modules):
             raise FileNotFoundError(
-                f"failed to find ELF files in path {self._path}!"
+                f"failed to find files to analyse in path {self._path}!"
             )
 
     @property
@@ -54,7 +65,7 @@
         """Returns map of memory usage per memory type for each module."""
         mem_map = {}
         for k, v in self._modules.items():
-            mod_mem_map = v.get_elf_memory_layout()
+            mod_mem_map = v.get_memory_layout()
             if len(mod_mem_map):
                 mem_map[k] = mod_mem_map
         return mem_map
diff --git a/tools/memory/memory/elfparser.py b/tools/memory/memory/elfparser.py
index 1bd68b1..2dd2513 100644
--- a/tools/memory/memory/elfparser.py
+++ b/tools/memory/memory/elfparser.py
@@ -131,7 +131,7 @@
         """Get a dictionary of segments and their section mappings."""
         return [asdict(v) for k, v in self._segments.items()]
 
-    def get_elf_memory_layout(self):
+    def get_memory_layout(self):
         """Get the total memory consumed by this module from the memory
         configuration.
             {"rom": {"start": 0x0, "end": 0xFF, "length": ... }
diff --git a/tools/memory/memory/mapparser.py b/tools/memory/memory/mapparser.py
new file mode 100644
index 0000000..b1a4b4c
--- /dev/null
+++ b/tools/memory/memory/mapparser.py
@@ -0,0 +1,75 @@
+#
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+from re import match, search
+from typing import TextIO
+
+
+class TfaMapParser:
+    """A class representing a map file built for TF-A.
+
+    Provides a basic interface for reading the symbol table. The constructor
+    accepts a file-like object with the contents a Map file. Only GNU map files
+    are supported at this stage.
+    """
+
+    def __init__(self, map_file: TextIO):
+        self._symbols = self.read_symbols(map_file)
+
+    @property
+    def symbols(self):
+        return self._symbols.items()
+
+    @staticmethod
+    def read_symbols(file: TextIO, pattern: str = None) -> dict:
+        pattern = r"\b(0x\w*)\s*(\w*)\s=" if not pattern else pattern
+        symbols = {}
+
+        for line in file.readlines():
+            match = search(pattern, line)
+
+            if match is not None:
+                value, name = match.groups()
+                symbols[name] = int(value, 16)
+
+        return symbols
+
+    def get_memory_layout(self) -> dict:
+        """Get the total memory consumed by this module from the memory
+        configuration.
+            {"rom": {"start": 0x0, "end": 0xFF, "length": ... }
+        """
+        assert len(self._symbols), "Symbol table is empty!"
+        expr = r".*(.?R.M)_REGION.*(START|END|LENGTH)"
+        memory_layout = {}
+
+        region_symbols = filter(lambda s: match(expr, s), self._symbols)
+
+        for symbol in region_symbols:
+            region, _, attr = tuple(symbol.lower().strip("__").split("_"))
+            if region not in memory_layout:
+                memory_layout[region] = {}
+
+            memory_layout[region][attr] = self._symbols[symbol]
+
+            if "start" and "length" and "end" in memory_layout[region]:
+                memory_layout[region]["limit"] = (
+                    memory_layout[region]["end"]
+                    + memory_layout[region]["length"]
+                )
+                memory_layout[region]["free"] = (
+                    memory_layout[region]["limit"]
+                    - memory_layout[region]["end"]
+                )
+                memory_layout[region]["total"] = memory_layout[region][
+                    "length"
+                ]
+                memory_layout[region]["size"] = (
+                    memory_layout[region]["end"]
+                    - memory_layout[region]["start"]
+                )
+
+        return memory_layout
diff --git a/tools/memory/memory/memmap.py b/tools/memory/memory/memmap.py
index 6d6f39d..99149b5 100755
--- a/tools/memory/memory/memmap.py
+++ b/tools/memory/memory/memmap.py
@@ -66,6 +66,11 @@
     default=False,
     help="Display numbers in decimal base.",
 )
+@click.option(
+    "--no-elf-images",
+    is_flag=True,
+    help="Analyse the build's map files instead of ELF images.",
+)
 def main(
     root: Path,
     platform: str,
@@ -76,11 +81,12 @@
     depth: int,
     width: int,
     d: bool,
+    no_elf_images: bool,
 ):
     build_path = root if root else Path("build/", platform, build_type)
     click.echo(f"build-path: {build_path.resolve()}")
 
-    parser = TfaBuildParser(build_path)
+    parser = TfaBuildParser(build_path, map_backend=no_elf_images)
     printer = TfaPrettyPrinter(columns=width, as_decimal=d)
 
     if footprint or not (tree or symbols):
@@ -94,7 +100,7 @@
     if symbols:
         expr = (
             r"(.*)(TEXT|BSS|RODATA|STACKS|_OPS|PMF|XLAT|GOT|FCONF"
-            r"|R.M)(.*)(START|END)__$"
+            r"|R.M)(.*)(START|UNALIGNED|END)__$"
         )
         printer.print_symbol_table(
             parser.filter_symbols(parser.symbols, expr), parser.module_names
diff --git a/tools/memory/memory/printer.py b/tools/memory/memory/printer.py
index 6bc6bff..4b18560 100755
--- a/tools/memory/memory/printer.py
+++ b/tools/memory/memory/printer.py
@@ -95,13 +95,16 @@
         self,
         symbols: list,
         modules: list,
-        start: int = 11,
+        start: int = 12,
     ):
         assert len(symbols), "Empty symbol list!"
         modules = sorted(modules)
         col_width = int((self.term_size - start) / len(modules))
+        address_fixed_width = 11
 
-        num_fmt = "0=#010x" if not self.as_decimal else ">10"
+        num_fmt = (
+            f"0=#0{address_fixed_width}x" if not self.as_decimal else ">10"
+        )
 
         _symbol_map = [
             " " * start