Plaform: AN521: Introduce platform binding HAL

This API (tfm_hal_bind_boundaries) binds partition with platform by
a p_boundaries handle, to let platform records partition info and
apply specific settings. Check the API comment for details.

The patch also:

- Updates the boundary update HAL API.
- Updates the HAL design document.
- Removes the FIH on AN521.

Change-Id: I77bba50d16fc6bb034aff3f4a7a8dfefecf345ec
Signed-off-by: Ken Liu <Ken.Liu@arm.com>
Co-authored-by: Mingyang Sun <mingyang.sun@arm.com>
diff --git a/docs/technical_references/design_docs/hardware_abstraction_layer.rst b/docs/technical_references/design_docs/hardware_abstraction_layer.rst
index b574a3d..16db247 100644
--- a/docs/technical_references/design_docs/hardware_abstraction_layer.rst
+++ b/docs/technical_references/design_docs/hardware_abstraction_layer.rst
@@ -252,56 +252,56 @@
 ------------------------
 The memory access attributes are encoded as bit fields, you can logic OR them to
 have a combination of the atrributes, for example
-``TFM_HAL_MEM_ATTR_UNPRIVILEGED | TFM_HAL_MEM_ATTR_READABLE`` is unprivileged
+``TFM_HAL_ACCESS_UNPRIVILEGED | TFM_HAL_ACCESS_READABLE`` is unprivileged
 readable. The data type is `uint32_t`.
 
-TFM_HAL_MEM_ATTR_EXECUTABLE
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
+TFM_HAL_ACCESS_EXECUTABLE
+^^^^^^^^^^^^^^^^^^^^^^^^^
 The memory is executable.
 
 .. code-block:: c
 
-  #define TFM_HAL_MEM_ATTR_EXECUTABLE (1UL << 0)
+  #define TFM_HAL_ACCESS_EXECUTABLE (1UL << 0)
 
-TFM_HAL_MEM_ATTR_READABLE
-^^^^^^^^^^^^^^^^^^^^^^^^^
+TFM_HAL_ACCESS_READABLE
+^^^^^^^^^^^^^^^^^^^^^^^
 The memory is readable.
 
 .. code-block:: c
 
-  #define TFM_HAL_MEM_ATTR_READABLE (1UL << 1)
+  #define TFM_HAL_ACCESS_READABLE (1UL << 1)
 
-TFM_HAL_MEM_ATTR_WRITABLE
-^^^^^^^^^^^^^^^^^^^^^^^^^
+TFM_HAL_ACCESS_WRITABLE
+^^^^^^^^^^^^^^^^^^^^^^^
 The memory is writable.
 
 .. code-block:: c
 
-  #define TFM_HAL_MEM_ATTR_WRITABLE (1UL << 2)
+  #define TFM_HAL_ACCESS_WRITABLE (1UL << 2)
 
-TFM_HAL_MEM_ATTR_UNPRIVILEGED
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+TFM_HAL_ACCESS_UNPRIVILEGED
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 The memory is unprivileged mode accessible.
 
 .. code-block:: c
 
-  #define TFM_HAL_MEM_ATTR_UNPRIVILEGED (1UL << 3)
+  #define TFM_HAL_ACCESS_UNPRIVILEGED (1UL << 3)
 
-TFM_HAL_MEM_ATTR_DEVICE
-^^^^^^^^^^^^^^^^^^^^^^^
+TFM_HAL_ACCESS_DEVICE
+^^^^^^^^^^^^^^^^^^^^^
 The memory is a MMIO device.
 
 .. code-block:: c
 
-  #define TFM_HAL_MEM_ATTR_DEVICE (1UL << 4)
+  #define TFM_HAL_ACCESS_DEVICE (1UL << 4)
 
-TFM_HAL_MEM_ATTR_NS
-^^^^^^^^^^^^^^^^^^^
+TFM_HAL_ACCESS_NS
+^^^^^^^^^^^^^^^^^
 The memory is accessible from :term:`NSPE`
 
 .. code-block:: c
 
-  #define TFM_HAL_MEM_ATTR_NS (1UL << 5)
+  #define TFM_HAL_ACCESS_NS (1UL << 5)
 
 APIs
 ----
@@ -311,7 +311,7 @@
 
 .. code-block:: c
 
-  tfm_hal_status_t tfm_hal_set_up_static_boundaries(void)
+  enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(void)
 
 **Description**
 
@@ -332,31 +332,31 @@
 - ``TFM_HAL_SUCCESS`` - the isolation boundaries have been set up.
 - ``TFM_HAL_ERROR_GENERIC`` - failed to set up the isolation boundaries.
 
-tfm_hal_mpu_update_partition_boundary
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+tfm_hal_update_boundaries()
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 **Prototype**
 
 .. code-block:: c
 
-  enum tfm_hal_status_t tfm_hal_mpu_update_partition_boundary(uintptr_t start,
-                                                              uintptr_t end);
+  enum tfm_hal_status_t tfm_hal_update_boundaries(
+                              const struct partition_load_info_t *p_ldinf,
+                              void *p_boundaries);
 
 **Description**
 
-This API updates the partition isolation boundary for isolation level 3.
-Inside the partition isolation boundary is the private data of the running
-Secure Partition.
-This boundary is updated dynamically when :term:`SPM` switches Partitions in
-isolation level 3.
+This API updates the partition isolation boundary for isolation level 2 and 3.
+The isolation boundary includes the thread privilege and the partition private
+data.
+In isolation level 2, the :term:`SPM` only updates the partition thread
+privilege. In isolation level 3, the :term:`SPM` updates the partition thread
+privilege, and protects each partition's private data.
 
-The access permissions of the boundary is all privileged mode read-write.
-
-Platforms decide which :term:`MPU` region the paritition boundary uses.
+The access permissions outside the boundary is platform-dependent.
 
 **Parameter**
 
-- ``start`` - start address of the partition boundary.
-- ``end`` - end address of the partition boundary.
+- ``p_ldinf`` - Partition load information.
+- ``p_boundaries`` - Platform boundary handle for the partition.
 
 **Return Values**
 
@@ -400,6 +400,40 @@
 - ``TFM_HAL_ERROR_INVALID_INPUT`` - Invalid inputs.
 - ``TFM_HAL_ERROR_GENERIC`` - An error occurred.
 
+tfm_hal_bind_boundaries()
+^^^^^^^^^^^^^^^^^^^^^^^^^
+**Prototype**
+
+.. code-block:: c
+
+  enum tfm_hal_status_t tfm_hal_bind_boundaries(
+                                    const struct partition_load_info_t *p_ldinf,
+                                    void **pp_boundaries);
+
+**Description**
+
+This API binds partition with the platform via a boundary handle.
+
+**Parameter**
+
+- ``p_ldinf`` - Partition load information.
+- ``pp_boundaries`` - Pointer of a the partition's platform boundary handle.
+
+**Return Values**
+
+- ``TFM_HAL_SUCCESS`` - the handle has been binded successfully.
+- ``TFM_HAL_ERROR_GENERIC`` - failed to bind the handle.
+
+.. Note::
+
+  The platform maintains the platform-specific settings for SPM further usage,
+  such as updating partition hardware boundaries or checking resource
+  accessibility. The platform needs to manage the settings with an internal
+  mechanism, and returns a handle to SPM. SPM delivers this handle back to
+  platform when necessary. And SPM checks this handle to decide if the
+  platform-specific settings need to be updated. Hence multiple partitions can
+  have the same handle if they have the same platform-specific settings.
+
 Log API
 =======
 The log API is used by the :term:`TF-M` :doc:`log system <tfm_log_system_design_document>`.
diff --git a/platform/ext/target/arm/mps2/an521/mmio_defs.h b/platform/ext/target/arm/mps2/an521/mmio_defs.h
new file mode 100644
index 0000000..7d3455e
--- /dev/null
+++ b/platform/ext/target/arm/mps2/an521/mmio_defs.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __MMIO_DEFS_H__
+#define __MMIO_DEFS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include "tfm_peripherals_def.h"
+
+/* Boundary handle binding macros. */
+#define HANDLE_PER_ATTR_BITS            (0x4)
+#define HANDLE_ATTR_PRIV_MASK           ((1 << HANDLE_PER_ATTR_BITS) - 1)
+#if TFM_LVL == 3
+#define HANDLE_ATTR_RW_POS              (1 << (HANDLE_PER_ATTR_BITS - 1))
+#define HANDLE_ATTR_INDEX_MASK          (HANDLE_ATTR_RW_POS - 1)
+#define HANDLE_INDEX_BITS               (0x8)
+#define HANDLE_INDEX_MASK               (((1 << HANDLE_INDEX_BITS) -1) << 24)
+#define HANDLE_ENCODE_INDEX(attr, idx)                              \
+    do {                                                            \
+        (attr) |= (((idx) << 24) & HANDLE_INDEX_MASK);              \
+        (idx)++;                                                    \
+    } while (0)
+#endif
+
+/* Allowed named MMIO of this platform */
+const uintptr_t partition_named_mmio_list[] = {
+    (uintptr_t)TFM_PERIPHERAL_TIMER0,
+    (uintptr_t)TFM_PERIPHERAL_STD_UART,
+};
+
+/*
+ * Platform AN521 only has named MMIO.
+ * If the platform has numbered MMIO, define them in another list.
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MMIO_DEFS_H__ */
diff --git a/platform/ext/target/arm/mps2/an521/native_drivers/mpu_armv8m_drv.c b/platform/ext/target/arm/mps2/an521/native_drivers/mpu_armv8m_drv.c
index 8231811..04b0f93 100644
--- a/platform/ext/target/arm/mps2/an521/native_drivers/mpu_armv8m_drv.c
+++ b/platform/ext/target/arm/mps2/an521/native_drivers/mpu_armv8m_drv.c
@@ -7,16 +7,15 @@
 
 #include "mpu_armv8m_drv.h"
 #include "cmsis_cpu.h"
-#include "fih.h"
 
 /*
  * FixMe:
  * This is a beta quality driver for MPU in v8M. To be finalized.
  */
 
-fih_int mpu_armv8m_enable(struct mpu_armv8m_dev_t *dev,
-                          uint32_t privdef_en,
-                          uint32_t hfnmi_en)
+enum mpu_armv8m_error_t mpu_armv8m_enable(struct mpu_armv8m_dev_t *dev,
+                                          uint32_t privdef_en,
+                                          uint32_t hfnmi_en)
 {
     /*No error checking*/
 
@@ -46,32 +45,33 @@
     __DSB();
     __ISB();
 
-    FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
+    return MPU_ARMV8M_OK;
 }
 
-fih_int mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev)
+enum mpu_armv8m_error_t mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev)
 {
     MPU_Type *mpu = (MPU_Type *)dev->base;
 
     /* Reset all fields as enable does full setup */
     mpu->CTRL = 0;
 
-    FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
+    return MPU_ARMV8M_OK;
 }
 
-
-fih_int mpu_armv8m_region_enable(struct mpu_armv8m_dev_t *dev,
-                                 struct mpu_armv8m_region_cfg_t *region_cfg)
+enum mpu_armv8m_error_t mpu_armv8m_region_enable(
+                                struct mpu_armv8m_dev_t *dev,
+                                struct mpu_armv8m_region_cfg_t *region_cfg)
 {
     MPU_Type *mpu = (MPU_Type *)dev->base;
 
+    enum mpu_armv8m_error_t ret_val = MPU_ARMV8M_OK;
     uint32_t ctrl_before;
     uint32_t base_cfg;
     uint32_t limit_cfg;
 
     /*FIXME : Add complete error checking*/
     if ((region_cfg->region_base & ~MPU_RBAR_BASE_Msk) != 0) {
-        FIH_RET(fih_int_encode(MPU_ARMV8M_ERROR));
+        return MPU_ARMV8M_ERROR;
     }
     /* region_limit doesn't need to be aligned but the scatter
      * file needs to be setup to ensure that partitions do not overlap.
@@ -107,12 +107,11 @@
     __DSB();
     __ISB();
 
-    FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
+    return ret_val;
 }
 
-
-fih_int mpu_armv8m_region_disable(struct mpu_armv8m_dev_t *dev,
-                                  uint32_t region_nr)
+enum mpu_armv8m_error_t mpu_armv8m_region_disable(struct mpu_armv8m_dev_t *dev,
+                                                  uint32_t region_nr)
 {
 
     MPU_Type *mpu = (MPU_Type *)dev->base;
@@ -131,25 +130,18 @@
     /*Restore main MPU control*/
     mpu->CTRL = ctrl_before;
 
-    FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
+    return MPU_ARMV8M_OK;
 }
 
-fih_int mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev)
+enum mpu_armv8m_error_t mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev)
 {
     MPU_Type *mpu = (MPU_Type *)dev->base;
     uint32_t i = (mpu->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
-    fih_int fih_rc = fih_int_encode(MPU_ARMV8M_ERROR);
 
     while (i > 0) {
-        FIH_CALL(mpu_armv8m_region_disable, fih_rc, dev, i - 1);
+        mpu_armv8m_region_disable(dev, i - 1);
         i--;
     }
 
-#ifdef TFM_FIH_PROFILE_ON
-    if (i > 0) {
-        FIH_PANIC;
-    }
-#endif
-
-    FIH_RET(fih_int_encode(MPU_ARMV8M_OK));
+    return MPU_ARMV8M_OK;
 }
diff --git a/platform/ext/target/arm/mps2/an521/native_drivers/mpu_armv8m_drv.h b/platform/ext/target/arm/mps2/an521/native_drivers/mpu_armv8m_drv.h
index 78da639..fe0a206 100644
--- a/platform/ext/target/arm/mps2/an521/native_drivers/mpu_armv8m_drv.h
+++ b/platform/ext/target/arm/mps2/an521/native_drivers/mpu_armv8m_drv.h
@@ -11,7 +11,6 @@
 #include <stdint.h>
 
 #include "cmsis.h"
-#include "fih.h"
 
 #define PRIVILEGED_DEFAULT_ENABLE 1
 #define HARDFAULT_NMI_ENABLE      1
@@ -81,9 +80,9 @@
  * \note This function doesn't check if dev is NULL.
  */
 
-fih_int mpu_armv8m_enable(struct mpu_armv8m_dev_t *dev,
-                          uint32_t privdef_en,
-                          uint32_t hfnmi_en);
+enum mpu_armv8m_error_t mpu_armv8m_enable(struct mpu_armv8m_dev_t *dev,
+                                          uint32_t privdef_en,
+                                          uint32_t hfnmi_en);
 
 /**
  * \brief Disable MPU
@@ -94,7 +93,7 @@
  *
  * \note This function doesn't check if dev is NULL.
  */
-fih_int mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev);
+enum mpu_armv8m_error_t mpu_armv8m_disable(struct mpu_armv8m_dev_t *dev);
 
 /**
  * \brief Disable MPU and clean all regions
@@ -105,7 +104,7 @@
  *
  * \note This function doesn't check if dev is NULL.
  */
-fih_int mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev);
+enum mpu_armv8m_error_t mpu_armv8m_clean(struct mpu_armv8m_dev_t *dev);
 
 /**
  * \brief Enable MPU Region
@@ -117,8 +116,9 @@
  *
  * \note This function doesn't check if dev is NULL.
  */
-fih_int mpu_armv8m_region_enable(struct mpu_armv8m_dev_t *dev,
-                                 struct mpu_armv8m_region_cfg_t *region_cfg);
+enum mpu_armv8m_error_t mpu_armv8m_region_enable(
+                                struct mpu_armv8m_dev_t *dev,
+                                struct mpu_armv8m_region_cfg_t *region_cfg);
 
 /**
  * \brief Disable MPU Region
@@ -130,7 +130,7 @@
  *
  * \note This function doesn't check if dev is NULL.
  */
-fih_int mpu_armv8m_region_disable(struct mpu_armv8m_dev_t *dev,
-                                  uint32_t region_nr);
+enum mpu_armv8m_error_t mpu_armv8m_region_disable(struct mpu_armv8m_dev_t *dev,
+                                                  uint32_t region_nr);
 
 #endif /* __MPU_ARMV8M_DRV_H__ */
diff --git a/platform/ext/target/arm/mps2/an521/spm_hal.c b/platform/ext/target/arm/mps2/an521/spm_hal.c
index 33e20b5..045129b 100644
--- a/platform/ext/target/arm/mps2/an521/spm_hal.c
+++ b/platform/ext/target/arm/mps2/an521/spm_hal.c
@@ -5,15 +5,11 @@
  *
  */
 
-#include <stdio.h>
 #include "cmsis.h"
-#include "fih.h"
 #include "tfm_spm_hal.h"
 #include "tfm_platform_core_api.h"
 #include "target_cfg.h"
 #include "Driver_MPC.h"
-#include "mpu_armv8m_drv.h"
-#include "region_defs.h"
 #include "utilities.h"
 
 /* Import MPC driver */
@@ -22,105 +18,6 @@
 /* Get address of memory regions to configure MPU */
 extern const struct memory_region_limits memory_regions;
 
-struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
-
-#ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
-#define PARTITION_REGION_PERIPH_START   5
-#define PARTITION_REGION_PERIPH_MAX_NUM 2
-
-uint32_t periph_num_count = 0;
-#endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
-
-#ifdef TFM_FIH_PROFILE_ON
-fih_int tfm_spm_hal_configure_default_isolation(
-                  bool privileged,
-                  const struct platform_data_t *platform_data)
-#else /* TFM_FIH_PROFILE_ON */
-enum tfm_plat_err_t tfm_spm_hal_configure_default_isolation(
-                  bool privileged,
-                  const struct platform_data_t *platform_data)
-#endif /* TFM_FIH_PROFILE_ON */
-{
-    fih_int fih_rc = FIH_FAILURE;
-#if defined(CONFIG_TFM_ENABLE_MEMORY_PROTECT) && (TFM_LVL != 1)
-    struct mpu_armv8m_region_cfg_t region_cfg;
-#endif
-
-    if (!platform_data) {
-        FIH_RET(fih_int_encode(TFM_PLAT_ERR_INVALID_INPUT));
-    }
-
-#if defined(CONFIG_TFM_ENABLE_MEMORY_PROTECT) && (TFM_LVL != 1)
-    if (!privileged) {
-        region_cfg.region_nr = PARTITION_REGION_PERIPH_START + periph_num_count;
-        periph_num_count++;
-        if (periph_num_count >= PARTITION_REGION_PERIPH_MAX_NUM) {
-            FIH_RET(fih_int_encode(TFM_PLAT_ERR_MAX_VALUE));
-        }
-        region_cfg.region_base = platform_data->periph_start;
-        region_cfg.region_limit = platform_data->periph_limit;
-        region_cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DEVICE_IDX;
-        region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
-        region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
-        region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
-
-#ifdef TFM_FIH_PROFILE_ON
-        FIH_CALL(mpu_armv8m_disable, fih_rc, &dev_mpu_s);
-
-        FIH_CALL(mpu_armv8m_region_enable, fih_rc, &dev_mpu_s, &region_cfg);
-        if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
-            FIH_RET(fih_int_encode(TFM_PLAT_ERR_SYSTEM_ERR));
-        }
-
-        FIH_CALL(mpu_armv8m_enable, fih_rc, &dev_mpu_s,
-                 PRIVILEGED_DEFAULT_ENABLE, HARDFAULT_NMI_ENABLE);
-        if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
-            FIH_RET(fih_int_encode(TFM_PLAT_ERR_SYSTEM_ERR));
-        }
-#else /* TFM_FIH_PROFILE_ON */
-        mpu_armv8m_disable(&dev_mpu_s);
-
-        if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg)
-            != MPU_ARMV8M_OK) {
-            return TFM_PLAT_ERR_SYSTEM_ERR;
-        }
-        mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
-                          HARDFAULT_NMI_ENABLE);
-#endif /* TFM_FIH_PROFILE_ON */
-    }
-#endif /* defined(CONFIG_TFM_ENABLE_MEMORY_PROTECT) && (TFM_LVL != 1) */
-
-    if (platform_data->periph_ppc_bank != PPC_SP_DO_NOT_CONFIGURE) {
-#ifdef TFM_FIH_PROFILE_ON
-        FIH_CALL(ppc_configure_to_secure, fih_rc,
-                 platform_data->periph_ppc_bank,
-                 platform_data->periph_ppc_loc);
-        if (privileged) {
-            FIH_CALL(ppc_clr_secure_unpriv, fih_rc,
-                     platform_data->periph_ppc_bank,
-                     platform_data->periph_ppc_loc);
-        } else {
-            FIH_CALL(ppc_en_secure_unpriv, fih_rc,
-                     platform_data->periph_ppc_bank,
-                     platform_data->periph_ppc_loc);
-        }
-#else /* TFM_FIH_PROFILE_ON */
-        ppc_configure_to_secure(platform_data->periph_ppc_bank,
-                                platform_data->periph_ppc_loc);
-        if (privileged) {
-            ppc_clr_secure_unpriv(platform_data->periph_ppc_bank,
-                                  platform_data->periph_ppc_loc);
-        } else {
-            ppc_en_secure_unpriv(platform_data->periph_ppc_bank,
-                                 platform_data->periph_ppc_loc);
-        }
-#endif /* TFM_FIH_PROFILE_ON */
-    }
-
-    fih_rc = fih_int_encode(TFM_PLAT_ERR_SUCCESS);
-    FIH_RET(fih_rc);
-}
-
 void MPC_Handler(void)
 {
     /* Clear MPC interrupt flag and pending MPC IRQ */
@@ -218,21 +115,10 @@
     return system_reset_cfg();
 }
 
-#ifdef TFM_FIH_PROFILE_ON
-fih_int tfm_spm_hal_init_debug(void)
-{
-    fih_int fih_rc = FIH_FAILURE;
-
-    FIH_CALL(init_debug, fih_rc);
-
-    FIH_RET(fih_rc);
-}
-#else /* TFM_FIH_PROFILE_ON */
 enum tfm_plat_err_t tfm_spm_hal_init_debug(void)
 {
     return init_debug();
 }
-#endif /* TFM_FIH_PROFILE_ON */
 
 enum tfm_plat_err_t tfm_spm_hal_nvic_interrupt_target_state_cfg(void)
 {
@@ -244,16 +130,69 @@
     return nvic_interrupt_enable();
 }
 
-#ifdef TFM_FIH_PROFILE_ON
-fih_int tfm_spm_hal_verify_isolation_hw(void)
-{
-    fih_int fih_rc = FIH_INT_INIT(TFM_PLAT_ERR_SYSTEM_ERR);
+#ifndef TFM_PSA_API
 
-    FIH_CALL(verify_isolation_hw, fih_rc);
-    if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
-        FIH_PANIC;
+#include "mpu_armv8m_drv.h"
+#include "region_defs.h"
+
+struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
+
+#ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
+#define PARTITION_REGION_PERIPH_START   5
+#define PARTITION_REGION_PERIPH_MAX_NUM 2
+
+uint32_t periph_num_count = 0;
+#endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
+
+enum tfm_plat_err_t tfm_spm_hal_configure_default_isolation(
+                  bool privileged,
+                  const struct platform_data_t *platform_data)
+{
+#if defined(CONFIG_TFM_ENABLE_MEMORY_PROTECT) && (TFM_LVL != 1)
+    struct mpu_armv8m_region_cfg_t region_cfg;
+#endif
+
+    if (!platform_data) {
+        return TFM_PLAT_ERR_INVALID_INPUT;
     }
 
-    FIH_RET(fih_int_encode(TFM_PLAT_ERR_SUCCESS));
+#if defined(CONFIG_TFM_ENABLE_MEMORY_PROTECT) && (TFM_LVL != 1)
+    if (!privileged) {
+        region_cfg.region_nr = PARTITION_REGION_PERIPH_START + periph_num_count;
+        periph_num_count++;
+        if (periph_num_count >= PARTITION_REGION_PERIPH_MAX_NUM) {
+            return TFM_PLAT_ERR_MAX_VALUE;
+        }
+        region_cfg.region_base = platform_data->periph_start;
+        region_cfg.region_limit = platform_data->periph_limit;
+        region_cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DEVICE_IDX;
+        region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+        region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+        region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+
+        mpu_armv8m_disable(&dev_mpu_s);
+
+        if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg)
+            != MPU_ARMV8M_OK) {
+            return TFM_PLAT_ERR_SYSTEM_ERR;
+        }
+        mpu_armv8m_enable(&dev_mpu_s, PRIVILEGED_DEFAULT_ENABLE,
+                          HARDFAULT_NMI_ENABLE);
+    }
+#endif /* defined(CONFIG_TFM_ENABLE_MEMORY_PROTECT) && (TFM_LVL != 1) */
+
+    if (platform_data->periph_ppc_bank != PPC_SP_DO_NOT_CONFIGURE) {
+        ppc_configure_to_secure(platform_data->periph_ppc_bank,
+                                platform_data->periph_ppc_loc);
+        if (privileged) {
+            ppc_clr_secure_unpriv(platform_data->periph_ppc_bank,
+                                  platform_data->periph_ppc_loc);
+        } else {
+            ppc_en_secure_unpriv(platform_data->periph_ppc_bank,
+                                 platform_data->periph_ppc_loc);
+        }
+    }
+
+    return TFM_PLAT_ERR_SUCCESS;
 }
-#endif /* TFM_FIH_PROFILE_ON */
+#endif
diff --git a/platform/ext/target/arm/mps2/an521/target_cfg.c b/platform/ext/target/arm/mps2/an521/target_cfg.c
index 8849ab3..c5432ca 100644
--- a/platform/ext/target/arm/mps2/an521/target_cfg.c
+++ b/platform/ext/target/arm/mps2/an521/target_cfg.c
@@ -21,10 +21,6 @@
 #include "region_defs.h"
 #include "tfm_plat_defs.h"
 #include "region.h"
-#include "fih.h"
-#ifdef TFM_FIH_PROFILE_ON
-#include "mpc_sie200_drv.h"
-#endif
 
 #ifdef PSA_API_TEST_IPC
 #define PSA_FF_TEST_SECURE_UART2
@@ -206,7 +202,7 @@
     return TFM_PLAT_ERR_SUCCESS;
 }
 
-fih_int init_debug(void)
+enum tfm_plat_err_t init_debug(void)
 {
     volatile struct sysctrl_t *sys_ctrl =
                                        (struct sysctrl_t *)CMSDK_SYSCTRL_BASE_S;
@@ -243,7 +239,7 @@
      */
 #endif
 
-    FIH_RET(fih_int_encode(TFM_PLAT_ERR_SUCCESS));
+    return TFM_PLAT_ERR_SUCCESS;
 }
 
 /*----------------- NVIC interrupt target state to NS configuration ----------*/
@@ -371,21 +367,13 @@
 
 #define NR_SAU_INIT_STEP                 3
 
-fih_int sau_and_idau_cfg(void)
+void sau_and_idau_cfg(void)
 {
     struct spctrl_def *spctrl = CMSDK_SPCTRL;
     uint32_t i;
 
-    FIH_CFI_STEP_INIT(NR_SAU_INIT_STEP);
-
     /* Enables SAU */
-#ifdef TFM_FIH_PROFILE_ON
     TZ_SAU_Enable();
-    TZ_SAU_Enable();
-#endif
-    TZ_SAU_Enable();
-
-    FIH_CFI_STEP_DECREMENT();
 
     for (i = 0; i < ARRAY_SIZE(sau_cfg); i++) {
         SAU->RNR = i;
@@ -395,20 +383,8 @@
                     SAU_RLAR_ENABLE_Msk;
     }
 
-    FIH_CFI_STEP_DECREMENT();
-
     /* Allows SAU to define the code region as a NSC */
     spctrl->nsccfg |= NSCCFG_CODENSC;
-
-    FIH_CFI_STEP_DECREMENT();
-
-    FIH_RET(fih_int_encode(TFM_PLAT_ERR_SUCCESS));
-
-    /*
-     * Dummy operation to avoid unused variable warning of the saved FIH counter
-     * variable.
-     */
-    FIH_CFI_STEP_ERR_RESET();
 }
 
 /*------------------- Memory configuration functions -------------------------*/
@@ -418,30 +394,21 @@
 #define NR_MPC_INIT_STEP                 6
 #endif
 
-fih_int mpc_init_cfg(void)
+int32_t mpc_init_cfg(void)
 {
-    int32_t ret = ARM_DRIVER_ERROR;
-    fih_int fih_rc = FIH_FAILURE;
-
-    FIH_CFI_STEP_INIT(NR_MPC_INIT_STEP);
+    int32_t ret = ARM_DRIVER_OK;
 
     ret = Driver_SRAM1_MPC.Initialize();
-    FIH_CFI_STEP_DECREMENT();
     if (ret != ARM_DRIVER_OK) {
-        fih_rc = fih_int_encode(ret);
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
+        return ret;
     }
 
     ret = Driver_SRAM1_MPC.ConfigRegion(
                                       memory_regions.non_secure_partition_base,
                                       memory_regions.non_secure_partition_limit,
                                       ARM_MPC_ATTR_NONSECURE);
-    FIH_CFI_STEP_DECREMENT();
     if (ret != ARM_DRIVER_OK) {
-        fih_rc = fih_int_encode(ret);
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
+        return ret;
     }
 
 #ifdef BL2
@@ -449,46 +416,31 @@
     ret = Driver_SRAM1_MPC.ConfigRegion(memory_regions.secondary_partition_base,
                                   memory_regions.secondary_partition_limit,
                                   ARM_MPC_ATTR_NONSECURE);
-    FIH_CFI_STEP_DECREMENT();
     if (ret != ARM_DRIVER_OK) {
-        fih_rc = fih_int_encode(ret);
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
+        return ret;
     }
 #endif /* BL2 */
 
     ret = Driver_SRAM2_MPC.Initialize();
-    FIH_CFI_STEP_DECREMENT();
     if (ret != ARM_DRIVER_OK) {
-        fih_rc = fih_int_encode(ret);
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
+        return ret;
     }
 
     ret = Driver_SRAM2_MPC.ConfigRegion(NS_DATA_START, NS_DATA_LIMIT,
                                         ARM_MPC_ATTR_NONSECURE);
-    FIH_CFI_STEP_DECREMENT();
     if (ret != ARM_DRIVER_OK) {
-        fih_rc = fih_int_encode(ret);
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
+        return ret;
     }
 
     /* Lock down the MPC configuration */
     ret = Driver_SRAM1_MPC.LockDown();
-    FIH_CFI_STEP_DECREMENT();
     if (ret != ARM_DRIVER_OK) {
-        fih_rc = fih_int_encode(ret);
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
+        return ret;
     }
 
     ret = Driver_SRAM2_MPC.LockDown();
-    FIH_CFI_STEP_DECREMENT();
     if (ret != ARM_DRIVER_OK) {
-        fih_rc = fih_int_encode(ret);
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
+        return ret;
     }
 
     /* Add barriers to assure the MPC configuration is done before continue
@@ -497,22 +449,17 @@
     __DSB();
     __ISB();
 
-    fih_rc = fih_int_encode(ARM_DRIVER_OK);
-
-Done:
-    FIH_RET(fih_rc);
+    return ARM_DRIVER_OK;
 }
 
 /*---------------------- PPC configuration functions -------------------------*/
 #define NR_PPC_INIT_STEP                 4
 
-fih_int ppc_init_cfg(void)
+void ppc_init_cfg(void)
 {
     struct spctrl_def* spctrl = CMSDK_SPCTRL;
     struct nspctrl_def* nspctrl = CMSDK_NSPCTRL;
 
-    FIH_CFI_STEP_INIT(NR_PPC_INIT_STEP);
-
     /* Grant non-secure access to peripherals in the PPC0
      * (timer0 and 1, dualtimer, watchdog, mhu 0 and 1)
      */
@@ -552,8 +499,6 @@
                             (1U << CMSDK_FPGA_AUDIO_PPC_POS) |
                             (1U << CMSDK_FPGA_IO_PPC_POS);
 
-    FIH_CFI_STEP_DECREMENT();
-
     /* Grant non-secure access to all peripherals on AHB EXP:
      * Make sure that all possible peripherals are enabled by default
      */
@@ -569,8 +514,6 @@
                             (1U << CMSDK_DMA2_PPC_POS) |
                             (1U << CMSDK_DMA3_PPC_POS);
 
-    FIH_CFI_STEP_DECREMENT();
-
     /* in NS, grant un-privileged for UART0 */
     nspctrl->apbnspppcexp1 |= (1U << CMSDK_UART0_APB_PPC_POS);
 
@@ -578,56 +521,36 @@
     nspctrl->apbnspppcexp2 |= (1U << CMSDK_FPGA_SCC_PPC_POS) |
                               (1U << CMSDK_FPGA_IO_PPC_POS);
 
-    FIH_CFI_STEP_DECREMENT();
-
     /* Configure the response to a security violation as a
      * bus error instead of RAZ/WI
      */
     spctrl->secrespcfg |= 1U;
-
-    FIH_CFI_STEP_DECREMENT();
-
-    FIH_RET(fih_int_encode(TFM_PLAT_ERR_SUCCESS));
-
-    /*
-     * Dummy operation to avoid unused variable warning of the saved FIH counter
-     * variable.
-     */
-    FIH_CFI_STEP_ERR_RESET();
 }
 
-fih_int ppc_configure_to_non_secure(enum ppc_bank_e bank, uint16_t pos)
+void ppc_configure_to_non_secure(enum ppc_bank_e bank, uint16_t pos)
 {
     /* Setting NS flag for peripheral to enable NS access */
     struct spctrl_def* spctrl = CMSDK_SPCTRL;
     ((uint32_t*)&(spctrl->ahbnsppc0))[bank] |= (1U << pos);
-
-    FIH_RET(fih_int_encode(TFM_PLAT_ERR_SUCCESS));
 }
 
-fih_int ppc_configure_to_secure(enum ppc_bank_e bank, uint16_t pos)
+void ppc_configure_to_secure(enum ppc_bank_e bank, uint16_t pos)
 {
     /* Clear NS flag for peripheral to prevent NS access */
     struct spctrl_def* spctrl = CMSDK_SPCTRL;
     ((uint32_t*)&(spctrl->ahbnsppc0))[bank] &= ~(1U << pos);
-
-    FIH_RET(fih_int_encode(TFM_PLAT_ERR_SUCCESS));
 }
 
-fih_int ppc_en_secure_unpriv(enum ppc_bank_e bank, uint16_t pos)
+void ppc_en_secure_unpriv(enum ppc_bank_e bank, uint16_t pos)
 {
     struct spctrl_def* spctrl = CMSDK_SPCTRL;
     ((uint32_t*)&(spctrl->ahbspppc0))[bank] |= (1U << pos);
-
-    FIH_RET(fih_int_encode(TFM_PLAT_ERR_SUCCESS));
 }
 
-fih_int ppc_clr_secure_unpriv(enum ppc_bank_e bank, uint16_t pos)
+void ppc_clr_secure_unpriv(enum ppc_bank_e bank, uint16_t pos)
 {
     struct spctrl_def* spctrl = CMSDK_SPCTRL;
     ((uint32_t*)&(spctrl->ahbspppc0))[bank] &= ~(1U << pos);
-
-    FIH_RET(fih_int_encode(TFM_PLAT_ERR_SUCCESS));
 }
 
 void ppc_clear_irq(void)
@@ -636,88 +559,3 @@
     /* Clear APB PPC EXP2 IRQ */
     spctrl->secppcintclr = CMSDK_APB_PPCEXP2_INT_POS_MASK;
 }
-
-#ifdef TFM_FIH_PROFILE_ON
-#ifdef BL2
-#define NR_VERIFY_STEP                 4
-#else
-#define NR_VERIFY_STEP                 3
-#endif
-
-fih_int verify_isolation_hw(void)
-{
-    enum tfm_plat_err_t ret = ARM_DRIVER_ERROR;
-    ARM_MPC_SEC_ATTR attr;
-    fih_int fih_rc = FIH_FAILURE;
-
-    FIH_CFI_STEP_INIT(NR_VERIFY_STEP);
-
-    /* Check SAU config */
-    if (!(SAU->CTRL & SAU_CTRL_ENABLE_Msk ||
-          SAU->CTRL | SAU_CTRL_ALLNS_Msk)) {
-        FIH_PANIC;
-    }
-
-    FIH_CFI_STEP_DECREMENT();
-
-    /* Check MPC config */
-    ret = Driver_SRAM1_MPC.GetRegionConfig(
-                                  memory_regions.non_secure_partition_base,
-                                  memory_regions.non_secure_partition_limit,
-                                  &attr);
-    FIH_CFI_STEP_DECREMENT();
-    if (ret != ARM_DRIVER_OK) {
-        fih_rc = FIH_FAILURE;
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
-    }
-
-    if (attr != ARM_MPC_ATTR_NONSECURE) {
-        fih_rc = FIH_FAILURE;
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
-    }
-
-#ifdef BL2
-    ret = Driver_SRAM1_MPC.GetRegionConfig(
-                                  memory_regions.secondary_partition_base,
-                                  memory_regions.secondary_partition_limit,
-                                  &attr);
-    FIH_CFI_STEP_DECREMENT();
-    if (ret != ARM_DRIVER_OK) {
-        fih_rc = FIH_FAILURE;
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
-    }
-
-    if (attr != ARM_MPC_ATTR_NONSECURE) {
-        fih_rc = FIH_FAILURE;
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
-    }
-#endif
-
-    ret = Driver_SRAM2_MPC.GetRegionConfig(NS_DATA_START, NS_DATA_LIMIT, &attr);
-    FIH_CFI_STEP_DECREMENT();
-    if (ret != ARM_DRIVER_OK) {
-        fih_rc = FIH_FAILURE;
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
-    }
-
-    if (attr != ARM_MPC_ATTR_NONSECURE) {
-        fih_rc = FIH_FAILURE;
-        FIH_CFI_STEP_ERR_RESET();
-        goto Done;
-    }
-
-    /* Todo: Check PPC config */
-
-    /* Todo: Check static MPU config */
-
-    fih_rc = FIH_SUCCESS;
-
-Done:
-    FIH_RET(fih_rc);
-}
-#endif /* TFM_FIH_PROFILE_ON */
diff --git a/platform/ext/target/arm/mps2/an521/target_cfg.h b/platform/ext/target/arm/mps2/an521/target_cfg.h
index 25cc28a..32f9721 100644
--- a/platform/ext/target/arm/mps2/an521/target_cfg.h
+++ b/platform/ext/target/arm/mps2/an521/target_cfg.h
@@ -21,7 +21,6 @@
 #include "tfm_peripherals_def.h"
 #include "tfm_plat_defs.h"
 #include "arm_uart_drv.h"
-#include "fih.h"
 
 #define TFM_DRIVER_STDIO    Driver_USART0
 #define NS_DRIVER_STDIO     Driver_USART0
@@ -82,32 +81,32 @@
  *
  * \return  Returns error code.
  */
-fih_int mpc_init_cfg(void);
+int32_t mpc_init_cfg(void);
 
 /**
  * \brief Configures the Peripheral Protection Controller.
  */
-fih_int ppc_init_cfg(void);
+void ppc_init_cfg(void);
 
 /**
  * \brief Restict access to peripheral to secure
  */
-fih_int ppc_configure_to_secure(enum ppc_bank_e bank, uint16_t loc);
+void ppc_configure_to_secure(enum ppc_bank_e bank, uint16_t loc);
 
 /**
  * \brief Allow non-secure access to peripheral
  */
-fih_int ppc_configure_to_non_secure(enum ppc_bank_e bank, uint16_t loc);
+void ppc_configure_to_non_secure(enum ppc_bank_e bank, uint16_t loc);
 
 /**
  * \brief Enable secure unprivileged access to peripheral
  */
-fih_int ppc_en_secure_unpriv(enum ppc_bank_e bank, uint16_t pos);
+void ppc_en_secure_unpriv(enum ppc_bank_e bank, uint16_t pos);
 
 /**
  * \brief Clear secure unprivileged access to peripheral
  */
-fih_int ppc_clr_secure_unpriv(enum ppc_bank_e bank, uint16_t pos);
+void ppc_clr_secure_unpriv(enum ppc_bank_e bank, uint16_t pos);
 
 /**
  * \brief Clears PPC interrupt.
@@ -117,7 +116,7 @@
 /**
  * \brief Configures SAU and IDAU.
  */
-fih_int sau_and_idau_cfg(void);
+void sau_and_idau_cfg(void);
 
 /**
  * \brief Enables the fault handlers and sets priorities.
@@ -138,7 +137,7 @@
  *
  * \return Returns values as specified by the \ref fih_int
  */
-fih_int init_debug(void);
+enum tfm_plat_err_t init_debug(void);
 
 /**
  * \brief Configures all external interrupts to target the
@@ -158,18 +157,4 @@
  */
 enum tfm_plat_err_t nvic_interrupt_enable(void);
 
-#ifdef TFM_FIH_PROFILE_ON
-/**
- * \brief This function verifies the settings of HW used for memory isolation,
- *        to make sure that important settings was not skipped due to fault
- *        injection attacks.
- *
- * This function is called during TF-M core late startup, before passing
- * execution to non-secure code.
- *
- * \return Returns values as specified by the \ref fih_int.
- */
-fih_int verify_isolation_hw(void);
-#endif /* TFM_FIH_PROFILE_ON */
-
 #endif /* __TARGET_CFG_H__ */
diff --git a/platform/ext/target/arm/mps2/an521/tfm_hal_isolation.c b/platform/ext/target/arm/mps2/an521/tfm_hal_isolation.c
index 77ece5f..3027402 100644
--- a/platform/ext/target/arm/mps2/an521/tfm_hal_isolation.c
+++ b/platform/ext/target/arm/mps2/an521/tfm_hal_isolation.c
@@ -5,16 +5,28 @@
  *
  */
 
+#include "array.h"
 #include "cmsis.h"
 #include "Driver_Common.h"
-#include "fih.h"
+#include "mmio_defs.h"
 #include "mpu_armv8m_drv.h"
 #include "region.h"
 #include "target_cfg.h"
 #include "tfm_hal_isolation.h"
+#include "tfm_peripherals_def.h"
+#include "tfm_core_utils.h"
+#include "load/partition_defs.h"
+#include "load/asset_defs.h"
+#include "load/spm_load_api.h"
+
+/* It can be retrieved from the MPU_TYPE register. */
+#define MPU_REGION_NUM                  16
 
 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
+static uint32_t n_configured_regions = 0;
+struct mpu_armv8m_dev_t dev_mpu_s = {MPU_BASE};
 #if TFM_LVL == 3
+static uint32_t idx_boundary_handle = 0;
 REGION_DECLARE(Load$$LR$$, LR_VENEER, $$Base);
 REGION_DECLARE(Load$$LR$$, LR_VENEER, $$Limit);
 REGION_DECLARE(Image$$, PT_RO_START, $$Base);
@@ -22,9 +34,7 @@
 REGION_DECLARE(Image$$, PT_PRIV_RWZI_START, $$Base);
 REGION_DECLARE(Image$$, PT_PRIV_RWZI_END, $$Base);
 
-static uint32_t g_static_region_cnt;
-
-static struct mpu_armv8m_region_cfg_t isolation_regions[] = {
+const static struct mpu_armv8m_region_cfg_t isolation_regions[] = {
     {
         0, /* will be updated before using */
         (uint32_t)&REGION_NAME(Load$$LR$$, LR_VENEER, $$Base),
@@ -44,7 +54,7 @@
         MPU_ARMV8M_SH_NONE,
     },
     /* For isolation Level 3, set up static isolation for privileged data.
-     * Unprivileged data is dynamically set during Partition sheduling.
+     * Unprivileged data is dynamically set during Partition scheduling.
      */
     {
         0, /* will be updated before using */
@@ -57,16 +67,6 @@
     },
 };
 #else /* TFM_LVL == 3 */
-#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
-
-#define MPU_REGION_VENEERS              0
-#define MPU_REGION_TFM_UNPRIV_CODE      1
-#define MPU_REGION_NS_STACK             2
-#define PARTITION_REGION_RO             3
-#define PARTITION_REGION_RW_STACK       4
-#ifdef TFM_SP_META_PTR_ENABLE
-#define MPU_REGION_SP_META_PTR          7
-#endif /* TFM_SP_META_PTR_ENABLE */
 
 REGION_DECLARE(Load$$LR$$, LR_VENEER, $$Base);
 REGION_DECLARE(Load$$LR$$, LR_VENEER, $$Limit);
@@ -86,7 +86,7 @@
 const struct mpu_armv8m_region_cfg_t region_cfg[] = {
     /* Veneer region */
     {
-        MPU_REGION_VENEERS,
+        0, /* will be updated before using */
         (uint32_t)&REGION_NAME(Load$$LR$$, LR_VENEER, $$Base),
         (uint32_t)&REGION_NAME(Load$$LR$$, LR_VENEER, $$Limit),
         MPU_ARMV8M_MAIR_ATTR_CODE_IDX,
@@ -96,7 +96,7 @@
     },
     /* TFM Core unprivileged code region */
     {
-        MPU_REGION_TFM_UNPRIV_CODE,
+        0, /* will be updated before using */
         (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Base),
         (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit),
         MPU_ARMV8M_MAIR_ATTR_CODE_IDX,
@@ -106,7 +106,7 @@
     },
     /* NSPM PSP */
     {
-        MPU_REGION_NS_STACK,
+        0, /* will be updated before using */
         (uint32_t)&REGION_NAME(Image$$, ER_INITIAL_PSP, $$ZI$$Base),
         (uint32_t)&REGION_NAME(Image$$, ER_INITIAL_PSP, $$ZI$$Limit),
         MPU_ARMV8M_MAIR_ATTR_DATA_IDX,
@@ -116,7 +116,7 @@
     },
     /* RO region */
     {
-        PARTITION_REGION_RO,
+        0, /* will be updated before using */
         (uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_START, $$Base),
         (uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_END, $$Base),
         MPU_ARMV8M_MAIR_ATTR_CODE_IDX,
@@ -126,7 +126,7 @@
     },
     /* RW, ZI and stack as one region */
     {
-        PARTITION_REGION_RW_STACK,
+        0, /* will be updated before using */
         (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base),
         (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base),
         MPU_ARMV8M_MAIR_ATTR_DATA_IDX,
@@ -137,7 +137,7 @@
 #ifdef TFM_SP_META_PTR_ENABLE
     /* TFM partition metadata pointer region */
     {
-        MPU_REGION_SP_META_PTR,
+        0, /* will be updated before using */
         (uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$RW$$Base),
         (uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$RW$$Limit),
         MPU_ARMV8M_MAIR_ATTR_DATA_IDX,
@@ -150,103 +150,6 @@
 #endif /* TFM_LVL == 3 */
 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
 
-#ifdef TFM_FIH_PROFILE_ON
-fih_int tfm_hal_set_up_static_boundaries(void)
-{
-    fih_int fih_rc = fih_int_encode(TFM_HAL_ERROR_GENERIC);
-
-    /* Set up isolation boundaries between SPE and NSPE */
-    FIH_CALL(sau_and_idau_cfg, fih_rc);
-    if (fih_not_eq(fih_rc, fih_int_encode(TFM_PLAT_ERR_SUCCESS))) {
-        FIH_PANIC;
-    }
-
-    FIH_CALL(mpc_init_cfg, fih_rc);
-    if (fih_not_eq(fih_rc, fih_int_encode(TFM_PLAT_ERR_SUCCESS))) {
-        FIH_PANIC;
-    }
-
-    FIH_CALL(ppc_init_cfg, fih_rc);
-    if (fih_not_eq(fih_rc, fih_int_encode(TFM_PLAT_ERR_SUCCESS))) {
-        FIH_PANIC;
-    }
-
-    /* Set up static isolation boundaries inside SPE */
-#ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
-    int32_t i;
-    struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
-
-    FIH_CALL(mpu_armv8m_clean, fih_rc, &dev_mpu_s);
-    if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
-        FIH_PANIC;
-    }
-
-#if TFM_LVL == 3
-    uint32_t cnt;
-
-    /* Update MPU region numbers. The numbers start from 0 and are continuous */
-    cnt = sizeof(isolation_regions) / sizeof(isolation_regions[0]);
-    g_static_region_cnt = cnt;
-    for (i = 0; i < cnt; i++) {
-        /* Update region number */
-        isolation_regions[i].region_nr = i;
-        /* Enable regions */
-        FIH_CALL(mpu_armv8m_region_enable, fih_rc, &dev_mpu_s,
-                 &isolation_regions[i]);
-        if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
-            FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
-        }
-    }
-#else /* TFM_LVL == 3 */
-    for (i = 0; i < ARRAY_SIZE(region_cfg); i++) {
-
-        FIH_CALL(mpu_armv8m_region_enable, fih_rc, &dev_mpu_s,
-                 (struct mpu_armv8m_region_cfg_t *)&region_cfg[i]);
-        if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
-            FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
-        }
-    }
-#endif /* TFM_LVL == 3 */
-
-    /* Enable MPU */
-    FIH_CALL(mpu_armv8m_enable, fih_rc, &dev_mpu_s,
-             PRIVILEGED_DEFAULT_ENABLE, HARDFAULT_NMI_ENABLE);
-    if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
-        FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
-    }
-#endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
-
-    fih_rc = fih_int_encode(TFM_HAL_SUCCESS);
-    FIH_RET(fih_rc);
-}
-
-#if TFM_LVL == 3
-fih_int tfm_hal_mpu_update_partition_boundary(uintptr_t start,
-                                              uintptr_t end)
-{
-    fih_int fih_rc = fih_int_encode(TFM_HAL_ERROR_GENERIC);
-    struct mpu_armv8m_region_cfg_t cfg;
-    struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
-
-    /* Partition boundary regions is right after static regions */
-    cfg.region_nr = g_static_region_cnt;
-    cfg.region_base = start;
-    cfg.region_limit = end;
-    cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DATA_IDX;
-    cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
-    cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
-    cfg.attr_sh = MPU_ARMV8M_SH_NONE;
-
-    FIH_CALL(mpu_armv8m_region_enable, fih_rc, &dev_mpu_s, &cfg);
-    if (fih_not_eq(fih_rc, fih_int_encode(MPU_ARMV8M_OK))) {
-        FIH_RET(fih_int_encode(TFM_HAL_ERROR_GENERIC));
-    }
-
-    fih_rc = fih_int_encode(TFM_HAL_SUCCESS);
-    FIH_RET(fih_rc);
-}
-#endif /* TFM_LVL == 3 */
-#else /* TFM_FIH_PROFILE_ON */
 enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(void)
 {
     /* Set up isolation boundaries between SPE and NSPE */
@@ -258,34 +161,44 @@
 
     /* Set up static isolation boundaries inside SPE */
 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
+    struct mpu_armv8m_region_cfg_t localcfg;
     int32_t i;
-    struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
 
     mpu_armv8m_clean(&dev_mpu_s);
 
 #if TFM_LVL == 3
-    uint32_t cnt;
-
-    /* Update MPU region numbers. The numbers start from 0 and are continuous */
-    cnt = sizeof(isolation_regions) / sizeof(isolation_regions[0]);
-    g_static_region_cnt = cnt;
-    for (i = 0; i < cnt; i++) {
+    /*
+     * Update MPU region numbers. The numbers start from 0 and are continuous.
+     * Under isolation level3, at lease one MPU region is reserved for private
+     * data asset.
+     */
+    if (ARRAY_SIZE(isolation_regions) >= MPU_REGION_NUM) {
+        return TFM_HAL_ERROR_GENERIC;
+    }
+    for (i = 0; i < ARRAY_SIZE(isolation_regions); i++) {
+        spm_memcpy(&localcfg, &isolation_regions[i], sizeof(localcfg));
         /* Update region number */
-        isolation_regions[i].region_nr = i;
+        localcfg.region_nr = i;
         /* Enable regions */
-        if (mpu_armv8m_region_enable(&dev_mpu_s, &isolation_regions[i])
-                                                             != MPU_ARMV8M_OK) {
+        if (mpu_armv8m_region_enable(&dev_mpu_s, &localcfg) != MPU_ARMV8M_OK) {
             return TFM_HAL_ERROR_GENERIC;
         }
     }
+    n_configured_regions = i;
 #else /* TFM_LVL == 3 */
+    if (ARRAY_SIZE(region_cfg) > MPU_REGION_NUM) {
+        return TFM_HAL_ERROR_GENERIC;
+    }
     for (i = 0; i < ARRAY_SIZE(region_cfg); i++) {
+        spm_memcpy(&localcfg, &region_cfg[i], sizeof(localcfg));
+        localcfg.region_nr = i;
         if (mpu_armv8m_region_enable(&dev_mpu_s,
-            (struct mpu_armv8m_region_cfg_t *)&region_cfg[i])
+            (struct mpu_armv8m_region_cfg_t *)&localcfg)
             != MPU_ARMV8M_OK) {
             return TFM_HAL_ERROR_GENERIC;
         }
     }
+    n_configured_regions = i;
 #endif /* TFM_LVL == 3 */
 
     /* Enable MPU */
@@ -299,27 +212,227 @@
     return TFM_HAL_SUCCESS;
 }
 
-#if TFM_LVL == 3
-enum tfm_hal_status_t tfm_hal_mpu_update_partition_boundary(uintptr_t start,
-                                                            uintptr_t end)
+/*
+ * Implementation of tfm_hal_bind_boundaries() on AN521:
+ *
+ * The API encodes some attributes into a handle and returns it to SPM.
+ * The attributes include isolation boundaries, privilege, and mmio information.
+ * When scheduler switches running partitions, SPM compares the handle between
+ * partitions to know if boundary update is necessary. If update is required,
+ * SPM passes the handle to platform to do platform settings and update
+ * isolation boundaries.
+ *
+ * The handle should be unique under isolation level 3. The implementation
+ * encodes an index at the highest 8 bits to assure handle uniqueness. While
+ * under isolation level 1/2, handles may not be unique.
+ *
+ * The encoding format assignment:
+ * - For isolation level 3
+ *      BIT | 31        24 | 23         20 | ... | 7           4 | 3        0 |
+ *          | Unique Index | Region Attr 5 | ... | Region Attr 1 | Privileged |
+ *
+ *      In which the "Region Attr i" is:
+ *      BIT |       3      | 2        0 |
+ *          | 1: RW, 0: RO | MMIO Index |
+ *
+ * - For isolation level 1/2
+ *      BIT | 31                           0 |
+ *          | 1: privileged, 0: unprivileged |
+ *
+ * This is a reference implementation on AN521, and may have some limitations.
+ * 1. The maximum number of allowed MMIO regions is 5.
+ * 2. Highest 8 bits are for index. It supports 256 unique handles at most.
+ */
+enum tfm_hal_status_t tfm_hal_bind_boundaries(
+                                    const struct partition_load_info_t *p_ldinf,
+                                    void **pp_boundaries)
 {
-    struct mpu_armv8m_region_cfg_t cfg;
-    enum mpu_armv8m_error_t mpu_err;
-    struct mpu_armv8m_dev_t dev_mpu_s = { MPU_BASE };
+    uint32_t i, j;
+    bool privileged;
+    const struct asset_desc_t *p_asset;
+    struct platform_data_t *plat_data_ptr;
+#if TFM_LVL == 2
+    struct mpu_armv8m_region_cfg_t localcfg;
+#elif TFM_LVL == 3
+    uint32_t partition_attrs = 0;
+#endif
 
-    /* Partition boundary regions is right after static regions */
-    cfg.region_nr = g_static_region_cnt;
-    cfg.region_base = start;
-    cfg.region_limit = end;
-    cfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DATA_IDX;
-    cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
-    cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
-    cfg.attr_sh = MPU_ARMV8M_SH_NONE;
-    mpu_err = mpu_armv8m_region_enable(&dev_mpu_s, &cfg);
-    if (mpu_err != MPU_ARMV8M_OK) {
+    if (!p_ldinf || !pp_boundaries) {
         return TFM_HAL_ERROR_GENERIC;
     }
+
+#if TFM_LVL == 1
+    privileged = true;
+#else
+    privileged = !!(p_ldinf->flags & SPM_PART_FLAG_PSA_ROT);
+#endif
+
+    p_asset = (const struct asset_desc_t *)LOAD_INFO_ASSET(p_ldinf);
+
+    /*
+     * Validate if the named MMIO of partition is allowed by the platform.
+     * Otherwise, skip validation.
+     *
+     * NOTE: Need to add validation of numbered MMIO if platform requires.
+     */
+    for (i = 0; i < p_ldinf->nassets; i++) {
+        if (!(p_asset[i].attr & ASSET_ATTR_NAMED_MMIO)) {
+            continue;
+        }
+        for (j = 0; j < ARRAY_SIZE(partition_named_mmio_list); j++) {
+            if (p_asset[i].dev.dev_ref == partition_named_mmio_list[j]) {
+                break;
+            }
+        }
+
+        if (j == ARRAY_SIZE(partition_named_mmio_list)) {
+            /* The MMIO asset is not in the allowed list of platform. */
+            return TFM_HAL_ERROR_GENERIC;
+        }
+        /* Assume PPC & MPC settings are required even under level 1 */
+        plat_data_ptr = REFERENCE_TO_PTR(p_asset[i].dev.dev_ref,
+                                         struct platform_data_t *);
+
+        ppc_configure_to_secure(plat_data_ptr->periph_ppc_bank,
+                                plat_data_ptr->periph_ppc_loc);
+        if (privileged) {
+            ppc_clr_secure_unpriv(plat_data_ptr->periph_ppc_bank,
+                                  plat_data_ptr->periph_ppc_loc);
+        } else {
+            ppc_en_secure_unpriv(plat_data_ptr->periph_ppc_bank,
+                                 plat_data_ptr->periph_ppc_loc);
+        }
+#if TFM_LVL == 2
+        /*
+         * Static boundaries are set. Set up MPU region for MMIO.
+         * Setup regions for unprivileged assets only.
+         */
+        if (!privileged) {
+            localcfg.region_base = plat_data_ptr->periph_start;
+            localcfg.region_limit = plat_data_ptr->periph_limit;
+            localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DEVICE_IDX;
+            localcfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+            localcfg.attr_sh = MPU_ARMV8M_SH_NONE;
+            localcfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+            localcfg.region_nr = n_configured_regions++;
+
+            if (mpu_armv8m_region_enable(&dev_mpu_s, &localcfg)
+                != MPU_ARMV8M_OK) {
+                return TFM_HAL_ERROR_GENERIC;
+            }
+        }
+#elif TFM_LVL == 3
+        /* Encode MMIO attributes into the "partition_attrs". */
+        partition_attrs <<= HANDLE_PER_ATTR_BITS;
+        partition_attrs |= ((j + 1) & HANDLE_ATTR_INDEX_MASK);
+        if (p_asset[i].attr & ASSET_ATTR_READ_WRITE) {
+            partition_attrs |= HANDLE_ATTR_RW_POS;
+        }
+#endif
+    }
+
+#if TFM_LVL == 3
+    partition_attrs <<= HANDLE_PER_ATTR_BITS;
+    partition_attrs |= ((uint8_t)privileged) & HANDLE_ATTR_PRIV_MASK;
+    /*
+     * Highest 8 bits are reserved for index, if they are non-zero, MMIO numbers
+     * must have exceeded the limit of 5.
+     */
+    if (partition_attrs & HANDLE_INDEX_MASK) {
+        return TFM_HAL_ERROR_GENERIC;
+    }
+    HANDLE_ENCODE_INDEX(partition_attrs, idx_boundary_handle);
+    *pp_boundaries = (void *)partition_attrs;
+#else
+    *pp_boundaries = (void *)(((uint32_t)privileged) & HANDLE_ATTR_PRIV_MASK);
+#endif
+
     return TFM_HAL_SUCCESS;
 }
-#endif /* TFM_LVL == 3 */
-#endif /* TFM_FIH_PROFILE_ON */
+
+enum tfm_hal_status_t tfm_hal_update_boundaries(
+                             const struct partition_load_info_t *p_ldinf,
+                             void *p_boundaries)
+{
+    CONTROL_Type ctrl;
+    uint32_t local_handle = (uint32_t)p_boundaries;
+    bool privileged = !!(local_handle & HANDLE_ATTR_PRIV_MASK);
+#if TFM_LVL == 3
+    struct mpu_armv8m_region_cfg_t localcfg;
+    uint32_t i, mmio_index;
+    struct platform_data_t *plat_data_ptr;
+    struct asset_desc_t *rt_mem;
+#endif
+
+    /* Privileged level is required to be set always */
+    ctrl.w = __get_CONTROL();
+    ctrl.b.nPRIV = privileged ? 0 : 1;
+    __set_CONTROL(ctrl.w);
+
+#if TFM_LVL == 3
+    if (!p_ldinf) {
+        return TFM_HAL_ERROR_GENERIC;
+    }
+
+    /* Update regions, for unprivileged partitions only */
+    if (privileged) {
+        return TFM_HAL_SUCCESS;
+    }
+
+    /* Setup runtime memory first */
+    localcfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
+    localcfg.attr_sh = MPU_ARMV8M_SH_NONE;
+    localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DATA_IDX;
+    localcfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
+    rt_mem = (struct asset_desc_t *)LOAD_INFO_ASSET(p_ldinf);
+    /*
+     * AN521 shortcut: The first item is the only runtime memory asset.
+     * Platforms with many memory assets please check this part.
+     */
+    for (i = 0;
+         i < p_ldinf->nassets && !(rt_mem[i].attr & ASSET_ATTR_MMIO);
+         i++) {
+        localcfg.region_nr = n_configured_regions + i;
+        localcfg.region_base = rt_mem[i].mem.start;
+        localcfg.region_limit = rt_mem[i].mem.limit;
+
+        if (mpu_armv8m_region_enable(&dev_mpu_s, &localcfg) != MPU_ARMV8M_OK) {
+            return TFM_HAL_ERROR_GENERIC;
+        }
+    }
+
+    /* Named MMIO part */
+    local_handle = local_handle & (~HANDLE_INDEX_MASK);
+    local_handle >>= HANDLE_PER_ATTR_BITS;
+    mmio_index = local_handle & HANDLE_ATTR_INDEX_MASK;
+
+    localcfg.region_attridx = MPU_ARMV8M_MAIR_ATTR_DEVICE_IDX;
+
+    i = n_configured_regions + i;
+    while (mmio_index && i < MPU_REGION_NUM) {
+        plat_data_ptr =
+          (struct platform_data_t *)partition_named_mmio_list[mmio_index - 1];
+        localcfg.region_nr = i++;
+        localcfg.attr_access = (local_handle & HANDLE_ATTR_RW_POS)?
+                            MPU_ARMV8M_AP_RW_PRIV_UNPRIV :
+                            MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+        localcfg.region_base = plat_data_ptr->periph_start;
+        localcfg.region_limit = plat_data_ptr->periph_limit;
+
+        if (mpu_armv8m_region_enable(&dev_mpu_s, &localcfg) != MPU_ARMV8M_OK) {
+            return TFM_HAL_ERROR_GENERIC;
+        }
+
+        local_handle >>= HANDLE_PER_ATTR_BITS;
+        mmio_index = local_handle & HANDLE_ATTR_INDEX_MASK;
+    }
+
+    /* Disable unused regions */
+    while (i < MPU_REGION_NUM) {
+        if (mpu_armv8m_region_disable(&dev_mpu_s, i++)!= MPU_ARMV8M_OK) {
+            return TFM_HAL_ERROR_GENERIC;
+        }
+    }
+#endif
+    return TFM_HAL_SUCCESS;
+}
diff --git a/platform/include/tfm_hal_isolation.h b/platform/include/tfm_hal_isolation.h
index 18a8c50..120cdf5 100644
--- a/platform/include/tfm_hal_isolation.h
+++ b/platform/include/tfm_hal_isolation.h
@@ -10,8 +10,9 @@
 
 #include <stddef.h>
 #include <stdint.h>
-#include "fih.h"
 #include "tfm_hal_defs.h"
+#include "load/partition_defs.h"
+#include "load/asset_defs.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -26,6 +27,7 @@
 #define TFM_HAL_ACCESS_NS               (1UL << 5)
 
 #ifdef TFM_FIH_PROFILE_ON
+#include "fih.h"
 /**
  * \brief  Sets up the static isolation boundaries which are constant throughout
  *         the runtime of the system, including the SPE/NSPE and partition
@@ -36,24 +38,20 @@
  */
 fih_int tfm_hal_set_up_static_boundaries(void);
 
-#if TFM_LVL == 3
 /**
- * \brief  Updates the partition isolation boundary for isolation level 3.
- *         The boundary protects the private data of the running partition.
- *         The boundary is updated with SPM switching partition in level 3.
+ * \brief  Update the isolation boundaries.
  *
- * \param[in] start     start address of the partition boundary.
- * \param[in] end       end address of the partition boundary.
+ * \param[in]   p_ldinf         Partition load information.
+ * \param[in]   p_boundaries    Platform boundary handle for partition.
  *
- * \return TFM_HAL_SUCCESS - the isolation boundary has been set up.
- *         TFM_HAL_ERROR_GENERIC - failed to set up the isolation boundary.
+ * \return TFM_HAL_SUCCESS          The isolation boundaries update succeeded.
+ *         TFM_HAL_ERROR_GENERIC    Failed to update the isolation boundaries.
  *
  * \note   When FIH_ENABLE_DOUBLE_VARS is enabled, the return code will be
  *         wrapped and protected in \ref fih_int structure.
  */
-fih_int tfm_hal_mpu_update_partition_boundary(uintptr_t start,
-                                              uintptr_t end);
-#endif
+fih_int tfm_hal_update_boundaries(const struct partition_load_info_t *p_ldinf,
+                                  void *p_boundaries);
 #else /* TFM_FIH_PROFILE_ON */
 /**
  * \brief  Sets up the static isolation boundaries which are constant throughout
@@ -62,30 +60,21 @@
  *
  * \return TFM_HAL_SUCCESS - the isolation boundaries have been set up.
  *         TFM_HAL_ERROR_GENERIC - failed to set up the isolation boundaries.
- *
- * \note   When FIH_ENABLE_DOUBLE_VARS is enabled, the return code will be
- *         wrapped and protected in \ref fih_int structure.
  */
 enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(void);
 
-#if TFM_LVL == 3
 /**
- * \brief  Updates the partition isolation boundary for isolation level 3.
- *         The boundary protects the private data of the running partition.
- *         The boundary is updated with SPM switching partition in level 3.
+ * \brief  Update the isolation boundaries.
  *
- * \param[in] start     start address of the partition boundary.
- * \param[in] end       end address of the partition boundary.
+ * \param[in]   p_ldinf         Partition load information.
+ * \param[in]   p_boundaries    Platform boundary handle for partition.
  *
- * \return TFM_HAL_SUCCESS - the isolation boundary has been set up.
- *         TFM_HAL_ERROR_GENERIC - failed to set up the isolation boundary.
- *
- * \note   When FIH_ENABLE_DOUBLE_VARS is enabled, the return code will be
- *         wrapped and protected in \ref fih_int structure.
+ * \return TFM_HAL_SUCCESS          The isolation boundaries update succeeded.
+ *         TFM_HAL_ERROR_GENERIC    Failed to update the isolation boundaries.
  */
-enum tfm_hal_status_t tfm_hal_mpu_update_partition_boundary(uintptr_t start,
-                                                            uintptr_t end);
-#endif
+enum tfm_hal_status_t tfm_hal_update_boundaries(
+                            const struct partition_load_info_t *p_ldinf,
+                            void *p_boundaries);
 #endif /* TFM_FIH_PROFILE_ON */
 
 /**
@@ -108,6 +97,28 @@
                                                 size_t size,
                                                 uint32_t attr);
 
+/**
+ * \brief  This API binds partition boundaries with the platform. The platform
+ *         maintains the platform-specific settings for SPM further
+ *         usage, such as update partition hardware boundaries or
+ *         check resource accessibility. The platform needs to manage
+ *         the settings with internal mechanism, and return a handle
+ *         to SPM. SPM delivers this handle back to platform when
+ *         necessary. And SPM checks this handle to decide if the
+ *         platform-specific settings need to be updated. Hence
+ *         multiple partitions can have the same handle if they have
+ *         the same platform-specific settings, depending on isolation level.
+ *
+ * \param[in]   p_ldinf           Partition load information.
+ * \param[in]   pp_boundaries     Pointer of the boundary handle
+ *
+ * \return TFM_HAL_SUCCESS          - A platform handle binding success.
+ *         TFM_HAL_ERROR_GENERIC    - Error occured while binding.
+ */
+enum tfm_hal_status_t tfm_hal_bind_boundaries(
+                                    const struct partition_load_info_t *p_ldinf,
+                                    void **pp_boundaries);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/platform/include/tfm_spm_hal.h b/platform/include/tfm_spm_hal.h
index 91e9807..3ea57aa 100644
--- a/platform/include/tfm_spm_hal.h
+++ b/platform/include/tfm_spm_hal.h
@@ -322,8 +322,7 @@
  *
  * \return True if the access is granted, false otherwise.
  */
-bool tfm_spm_hal_has_access_to_region(const void *p, size_t s,
-                                              int flags);
+bool tfm_spm_hal_has_access_to_region(const void *p, size_t s, int flags);
 #endif /* !defined(__SAUREGION_PRESENT) || (__SAUREGION_PRESENT == 0) */
 
 #endif /* __TFM_SPM_HAL_H__ */
diff --git a/secure_fw/spm/cmsis_psa/spm_ipc.c b/secure_fw/spm/cmsis_psa/spm_ipc.c
index 12f65a0..a578a18 100644
--- a/secure_fw/spm/cmsis_psa/spm_ipc.c
+++ b/secure_fw/spm/cmsis_psa/spm_ipc.c
@@ -266,34 +266,6 @@
     return msg;
 }
 
-#if TFM_LVL != 1
-/**
- * \brief Change the privilege mode for partition thread mode.
- *
- * \param[in] privileged        Privileged mode,
- *                                \ref TFM_PARTITION_PRIVILEGED_MODE
- *                                and \ref TFM_PARTITION_UNPRIVILEGED_MODE
- *
- * \note Barrier instructions are not called by this function, and if
- *       it is called in thread mode, it might be necessary to call
- *       them after this function returns.
- */
-static void tfm_spm_partition_change_privilege(uint32_t privileged)
-{
-    CONTROL_Type ctrl;
-
-    ctrl.w = __get_CONTROL();
-
-    if (privileged == TFM_PARTITION_PRIVILEGED_MODE) {
-        ctrl.b.nPRIV = 0;
-    } else {
-        ctrl.b.nPRIV = 1;
-    }
-
-    __set_CONTROL(ctrl.w);
-}
-#endif /* if(TFM_LVL != 1) */
-
 uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_flags)
 {
 #if TFM_LVL == 1
@@ -666,13 +638,11 @@
 
 uint32_t tfm_spm_init(void)
 {
-    uint32_t i;
-    bool privileged;
     struct partition_t *partition;
     struct tfm_core_thread_t *pth, *p_ns_entry_thread = NULL;
-    const struct platform_data_t *platform_data_p;
     const struct partition_load_info_t *p_ldinf;
-    struct asset_desc_t *p_asset_load;
+    void *p_boundaries = NULL;
+
 #ifdef TFM_FIH_PROFILE_ON
     fih_int fih_rc = FIH_FAILURE;
 #endif
@@ -703,54 +673,21 @@
             load_irqs_assuredly(partition);
         }
 
-        /* Init mmio assets */
-        if (p_ldinf->nassets > 0) {
-            if (tfm_spm_partition_get_privileged_mode(p_ldinf->flags) ==
-                TFM_PARTITION_PRIVILEGED_MODE) {
-                privileged = true;
-            } else {
-                privileged = false;
-            }
+        /* Bind the partition with plaform. */
+#if TFM_FIH_PROFILE_ON
+        FIH_CALL(tfm_hal_bind_boundaries, fih_rc, partition->p_ldinf,
+                 &p_boundaries);
+        if (fih_not_eq(fih_rc, fih_int_encode(TFM_HAL_SUCCESS))) {
+            tfm_core_panic();
         }
-
-        p_asset_load = (struct asset_desc_t *)LOAD_INFO_ASSET(p_ldinf);
-        for (i = 0; i < p_ldinf->nassets; i++) {
-            /* Skip the memory-based asset */
-            if (!(p_asset_load[i].attr & ASSET_ATTR_NAMED_MMIO)) {
-                continue;
-            }
-
-            platform_data_p = REFERENCE_TO_PTR(p_asset_load[i].dev.dev_ref,
-                                               struct platform_data_t *);
-
-            /*
-             * TODO: some partitions declare MMIO not exist on specific
-             * platforms, and the platform defines a dummy NULL reference
-             * for these MMIO items, which cause 'nassets' to contain several
-             * NULL items. Skip these NULL items initialization temporarily to
-             * avoid HAL API panic.
-             * Eventually, these platform-specific partitions need to be moved
-             * into a platform-specific folder. Then this workaround can be
-             * removed.
-             */
-            if (!platform_data_p) {
-                continue;
-            }
-
-#ifdef TFM_FIH_PROFILE_ON
-            FIH_CALL(tfm_spm_hal_configure_default_isolation, fih_rc,
-                     privileged, platform_data_p);
-            if (fih_not_eq(fih_rc, fih_int_encode(TFM_PLAT_ERR_SUCCESS))) {
-                tfm_core_panic();
-            }
 #else /* TFM_FIH_PROFILE_ON */
-            if (tfm_spm_hal_configure_default_isolation(privileged,
-                platform_data_p) != TFM_PLAT_ERR_SUCCESS) {
-                tfm_core_panic();
-            }
-#endif /* TFM_FIH_PROFILE_ON */
+        if (tfm_hal_bind_boundaries(partition->p_ldinf,
+                                    &p_boundaries) != TFM_HAL_SUCCESS) {
+            tfm_core_panic();
         }
+#endif /* TFM_FIH_PROFILE_ON */
 
+        partition->p_boundaries = p_boundaries;
         partition->signals_allowed |= PSA_DOORBELL;
 
         tfm_event_init(&partition->event);
@@ -795,80 +732,27 @@
     return p_ns_entry_thread->arch_ctx.lr;
 }
 
-#if TFM_LVL != 1
-static void set_up_boundary(const struct partition_load_info_t *p_ldinf)
-{
-#if TFM_LVL == 3
-#if defined(TFM_FIH_PROFILE_ON) && (TFM_LVL == 3)
-    fih_int fih_rc = FIH_FAILURE;
-#endif
-    /*
-     * FIXME: To implement isolations among partitions in isolation level 3,
-     * each partition needs to run in unprivileged mode. Currently some
-     * PRoTs cannot work in unprivileged mode, make them privileged now.
-     */
-    if (!(p_ldinf->flags & SPM_PART_FLAG_PSA_ROT)) {
-        struct asset_desc_t *p_asset =
-            (struct asset_desc_t *)LOAD_INFO_ASSET(p_ldinf);
-        /* Partition must have private data as the first asset in LVL3 */
-        if (p_ldinf->nassets == 0) {
-            tfm_core_panic();
-        }
-        if (p_asset->attr & ASSET_ATTR_NAMED_MMIO) {
-            tfm_core_panic();
-        }
-        /* FIXME: only MPU-based implementations are supported currently */
-#ifdef TFM_FIH_PROFILE_ON
-        FIH_CALL(tfm_hal_mpu_update_partition_boundary, fih_rc,
-                    p_asset->mem.start, p_asset->mem.limit);
-        if (fih_not_eq(fih_rc, fih_int_encode(TFM_HAL_SUCCESS))) {
-            tfm_core_panic();
-        }
-#else /* TFM_FIH_PROFILE_ON */
-        if (tfm_hal_mpu_update_partition_boundary(p_asset->mem.start,
-                                                  p_asset->mem.limit)
-                                                           != TFM_HAL_SUCCESS) {
-            tfm_core_panic();
-        }
-#endif /* TFM_FIH_PROFILE_ON */
-    }
-#else /* TFM_LVL == 3 */
-    (void)p_ldinf;
-#endif /* TFM_LVL == 3 */
-}
-#endif /* TFM_LVL != 1 */
-
-void tfm_set_up_isolation_boundary(const struct partition_t *partition)
-{
-#if TFM_LVL != 1
-    const struct partition_load_info_t *p_ldinf;
-    uint32_t is_privileged;
-
-    p_ldinf = partition->p_ldinf;
-    is_privileged = p_ldinf->flags & SPM_PART_FLAG_PSA_ROT ?
-                                                TFM_PARTITION_PRIVILEGED_MODE :
-                                                TFM_PARTITION_UNPRIVILEGED_MODE;
-
-    tfm_spm_partition_change_privilege(is_privileged);
-
-    set_up_boundary(p_ldinf);
-#else /* TFM_LVL != 1 */
-    (void)partition;
-#endif /* TFM_LVL != 1 */
-}
-
 void tfm_pendsv_do_schedule(struct tfm_arch_ctx_t *p_actx)
 {
-    struct partition_t *p_next_partition;
+    struct partition_t *p_part_curr, *p_part_next;
     struct tfm_core_thread_t *pth_next = tfm_core_thrd_get_next();
     struct tfm_core_thread_t *pth_curr = tfm_core_thrd_get_curr();
 
     if (pth_next != NULL && pth_curr != pth_next) {
-        p_next_partition = TO_CONTAINER(pth_next,
-                                        struct partition_t,
-                                        sp_thread);
-        tfm_set_up_isolation_boundary(p_next_partition);
+        p_part_curr = TO_CONTAINER(pth_curr, struct partition_t, sp_thread);
+        p_part_next = TO_CONTAINER(pth_next, struct partition_t, sp_thread);
 
+        /*
+         * If required, let the platform update boundary based on its
+         * implementation. Change privilege, MPU or other configurations.
+         */
+        if (p_part_curr->p_boundaries != p_part_next->p_boundaries) {
+            if (tfm_hal_update_boundaries(p_part_next->p_ldinf,
+                                          p_part_next->p_boundaries)
+                                                        != TFM_HAL_SUCCESS) {
+                tfm_core_panic();
+            }
+        }
         tfm_core_thrd_switch_context(p_actx, pth_curr, pth_next);
     }
 
diff --git a/secure_fw/spm/cmsis_psa/spm_ipc.h b/secure_fw/spm/cmsis_psa/spm_ipc.h
index 1c28475..64d8cac 100644
--- a/secure_fw/spm/cmsis_psa/spm_ipc.h
+++ b/secure_fw/spm/cmsis_psa/spm_ipc.h
@@ -85,7 +85,7 @@
  */
 struct partition_t {
     const struct partition_load_info_t *p_ldinf;
-    void *p_platform;
+    void *p_boundaries;
     void *p_interrupts;
     void *p_metadata;
     struct tfm_core_thread_t sp_thread;
@@ -376,13 +376,6 @@
  */
 int32_t tfm_spm_get_client_id(bool ns_caller);
 
-/**
- * \brief               Set up the isolation boundary of the given partition.
- *
- * \param[in] partition The partition of which the boundary is set up.
- */
-void tfm_set_up_isolation_boundary(const struct partition_t *partition);
-
 /*
  * PendSV specified function.
  *
diff --git a/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c b/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
index 0987f07..60a0124 100644
--- a/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
+++ b/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
@@ -15,8 +15,10 @@
 #include "tfm_core_utils.h"
 #include "tfm_svcalls.h"
 #include "utilities.h"
+#include "load/spm_load_api.h"
 #include "ffm/tfm_boot_data.h"
 #include "ffm/psa_api.h"
+#include "tfm_hal_isolation.h"
 #include "tfm_hal_spm_logdev.h"
 #include "load/partition_defs.h"
 #include "psa/client.h"
@@ -151,7 +153,10 @@
     } else {
         p_stat_ctx = (struct tfm_state_context_t *)irq_sp_thread->arch_ctx.sp;
         tfm_core_thrd_set_curr(irq_sp_thread);
-        tfm_set_up_isolation_boundary(irq_sp);
+        if (curr_sp->p_boundaries != irq_sp->p_boundaries) {
+            tfm_hal_update_boundaries(irq_sp->p_ldinf,
+                                      irq_sp->p_boundaries);
+        }
         tfm_arch_set_psplim(irq_sp_thread->stk_btm);
     }
 
@@ -195,7 +200,10 @@
     }
 
     if (curr_sp != prev_sp) {
-        tfm_set_up_isolation_boundary(prev_sp);
+        if (prev_sp->p_boundaries != curr_sp->p_boundaries) {
+            tfm_hal_update_boundaries(prev_sp->p_ldinf,
+                                      prev_sp->p_boundaries);
+        }
         tfm_core_thrd_set_curr(&(prev_sp->sp_thread));
         tfm_arch_set_psplim(prev_sp->sp_thread.stk_btm);
     }
diff --git a/secure_fw/spm/include/load/asset_defs.h b/secure_fw/spm/include/load/asset_defs.h
index e88e2d1..b5af2c5 100644
--- a/secure_fw/spm/include/load/asset_defs.h
+++ b/secure_fw/spm/include/load/asset_defs.h
@@ -24,7 +24,7 @@
 
 struct asset_desc_t {
     union {
-        struct {                            /* Memory asset type        */
+        struct {                            /* Memory-based asset type  */
             uintptr_t start;
             uintptr_t limit;
         } mem;
diff --git a/secure_fw/spm/include/load/spm_load_api.h b/secure_fw/spm/include/load/spm_load_api.h
index 26597b2..d8fbc16 100644
--- a/secure_fw/spm/include/load/spm_load_api.h
+++ b/secure_fw/spm/include/load/spm_load_api.h
@@ -19,7 +19,7 @@
 #define NO_MORE_PARTITION        NULL
 
 /* Length of extendable variables in partition load type */
-#define LOAD_INFO_EXT_LENGTH                2
+#define LOAD_INFO_EXT_LENGTH                        (2)
 /* Argument "pldinf" must be a "struct partition_load_info_t *". */
 #define LOAD_INFSZ_BYTES(pldinf)                                       \
     (sizeof(*(pldinf)) + LOAD_INFO_EXT_LENGTH * sizeof(uintptr_t) +    \