Merge "refactor(measured boot): rename a macro INVALID_ID to EVLOG_INVALID_ID" into integration
diff --git a/.commitlintrc.js b/.commitlintrc.js
index 3bd68bb..f970481 100644
--- a/.commitlintrc.js
+++ b/.commitlintrc.js
@@ -46,7 +46,7 @@
         "change-id-exists": [1, "always", "Change-Id:"], /* Warning */
         "signed-off-by-exists": [1, "always", "Signed-off-by:"], /* Warning */
 
-        "scope-case": [2, "always", "kebab-case"], /* Error */
+        "scope-case": [2, "always", "lower-case"], /* Error */
         "scope-enum": [1, "always", scopes] /* Warning */
     },
 };
diff --git a/.cz.json b/.cz.json
index 5447f17..5ac961e 100644
--- a/.cz.json
+++ b/.cz.json
@@ -93,12 +93,16 @@
                     "scopes": ["sve"]
                 },
                 {
+                    "title": "System Register Trace Extensions (FEAT_ETMv4, FEAT_ETE and FEAT_ETEv1.1)",
+                    "scopes": ["sys-reg-trace", "sys_reg_trace"]
+                },
+                {
                     "title": "Trace Buffer Extension (FEAT_TRBE)",
                     "scopes": ["trbe"]
                 },
                 {
-                    "title": "Self-hosted Trace Extensions (FEAT_TRF)",
-                    "scopes": ["trf", "sys_reg_trace"]
+                    "title": "Self-hosted Trace Extension (FEAT_TRF)",
+                    "scopes": ["trf"]
                 }
             ]
         },
@@ -194,6 +198,10 @@
                         {
                             "title": "MT8195",
                             "scopes": ["mt8195", "plat/mediatek/me8195", "plat/mediatek/mt8195", "plat/mdeiatek/mt8195"]
+                        },
+                        {
+                            "title": "MT8186",
+                            "scopes": ["mt8186", "plat/mediatek/mt8186"]
                         }
                     ]
                 },
diff --git a/docs/about/release-information.rst b/docs/about/release-information.rst
index b65571d..a50b033 100644
--- a/docs/about/release-information.rst
+++ b/docs/about/release-information.rst
@@ -61,7 +61,7 @@
 |                                | Date        | after   |                                                         |
 |                                |             | Release |                                                         |
 +================================+=============+=========+=========================================================+
-|                                |             |         |                                                         |
+| STM32MP_USE_STM32IMAGE macro   |   Dec '21   |   2.7   | FIP is the recommended boot method for STM32MP          |
 +--------------------------------+-------------+---------+---------------------------------------------------------+
 
 --------------
diff --git a/docs/change-log.md b/docs/change-log.md
index f0cb352..7f36d01 100644
--- a/docs/change-log.md
+++ b/docs/change-log.md
@@ -63,15 +63,18 @@
 
     - enable SVE for the secure world ([0c5e7d1](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/0c5e7d1ce376cabcebebc43dbf238fe4482ab2dc))
 
+  - **System Register Trace Extensions (FEAT_ETMv4, FEAT_ETE and FEAT_ETEv1.1)**
+
+    - enable trace system registers access from lower NS ELs ([d4582d3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d4582d30885673987240cf01fd4f5d2e6780e84c))
+    - initialize trap settings of trace system registers access ([2031d61](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2031d6166a58623ae59034bc2353fcd2fabe9c30))
+
   - **Trace Buffer Extension (FEAT_TRBE)**
 
     - enable access to trace buffer control registers from lower NS EL ([813524e](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/813524ea9d2e4138246b8f77a772299e52fb33bc))
     - initialize trap settings of trace buffer control registers access ([40ff907](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/40ff90747098ed9d2a09894d1a886c10ca76cee6))
 
-  - **Self-hosted Trace Extensions (FEAT_TRF)**
+  - **Self-hosted Trace Extension (FEAT_TRF)**
 
-    - enable trace system registers access from lower NS ELs ([d4582d3](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/d4582d30885673987240cf01fd4f5d2e6780e84c))
-    - initialize trap settings of trace system registers access ([2031d61](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/2031d6166a58623ae59034bc2353fcd2fabe9c30))
     - enable trace filter control register access from lower NS EL ([8fcd3d9](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8fcd3d9600bb2cb6809c6fc68f945ce3ad89633d))
     - initialize trap settings of trace filter control registers access ([5de20ec](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/5de20ece38f782c8459f546a08c6a97b9e0f5bc5))
 
@@ -324,6 +327,7 @@
 
     - add support for Hayes CPU ([7bd8dfb](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/7bd8dfb85a8bf5c22d6a39f4538b89cc748090d1))
     - add support for Hunter CPU ([fb9e5f7](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/fb9e5f7bb76e9764b3ecd7973668c851015fa1b4))
+    - add support for Demeter CPU ([f4616ef](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/f4616efafbc1004f1330f515b898e7617e338875))
     - workaround for Cortex A78 AE erratum 1941500 ([47d6f5f](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/47d6f5ff16d1f2ad009d630a381054b10fa0a06f))
     - workaround for Cortex A78 AE erratum 1951502 ([8913047](https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/8913047a52e646877812617a2d98cff99494487b))
 
diff --git a/docs/plat/index.rst b/docs/plat/index.rst
index 5848005..eadd946 100644
--- a/docs/plat/index.rst
+++ b/docs/plat/index.rst
@@ -20,6 +20,7 @@
    intel-stratix10
    marvell/index
    mt8183
+   mt8186
    mt8192
    mt8195
    nvidia-tegra
diff --git a/docs/plat/mt8186.rst b/docs/plat/mt8186.rst
new file mode 100644
index 0000000..16b833a
--- /dev/null
+++ b/docs/plat/mt8186.rst
@@ -0,0 +1,21 @@
+MediaTek 8186
+=============
+
+MediaTek 8186 (MT8186) is a 64-bit ARM SoC introduced by MediaTek in 2021.
+The chip incorporates eight cores - six Cortex-A55 little cores and two Cortex-A76.
+Cortex-A76 can operate at up to 2.05 GHz.
+Cortex-A55 can operate at up to 2.0 GHz.
+
+Boot Sequence
+-------------
+
+::
+
+    Boot Rom --> Coreboot --> TF-A BL31 --> Depthcharge --> Linux Kernel
+
+How to Build
+------------
+
+.. code:: shell
+
+    make CROSS_COMPILE=aarch64-linux-gnu- PLAT=mt8186 DEBUG=1 COREBOOT=1
diff --git a/docs/threat_model/threat_model_spm.rst b/docs/threat_model/threat_model_spm.rst
index 82f9916..4db4c66 100644
--- a/docs/threat_model/threat_model_spm.rst
+++ b/docs/threat_model/threat_model_spm.rst
@@ -36,7 +36,8 @@
   running in the secure world of TrustZone (at S-EL2 exception level).
   The threat model is not related to the normal world Hypervisor or VMs.
   The S-EL1 SPMC solution is not covered.
-- The implementation complies with the FF-A v1.0 specification.
+- The implementation complies with the FF-A v1.0 specification, and a few
+  features of FF-A v1.1 specification.
 - Secure partitions are statically provisioned at boot time.
 - Focus on the run-time part of the life-cycle (no specific emphasis on boot
   time, factory firmware provisioning, firmware udpate etc.)
@@ -477,7 +478,7 @@
 +------------------------+------------------+---------------+-----------------+
 | ``Total Risk Rating``  | Medium (6)       | Medium (6)    |                 |
 +------------------------+------------------+---------------+-----------------+
-| ``Mitigations``        | For the specific case of direct requests targetting|
+| ``Mitigations``        | For the specific case of direct requests targeting |
 |                        | the SPMC, the latter is hardened to prevent        |
 |                        | its internal state or the state of an SP to be     |
 |                        | revealed through a direct message response.        |
@@ -572,7 +573,7 @@
 | ID                     | 11                                                 |
 +========================+====================================================+
 | ``Threat``             | **A malicious endpoint may attempt flooding the    |
-|                        | SPMC with requests targetting a service within an  |
+|                        | SPMC with requests targeting a service within an   |
 |                        | endpoint such that it denies another endpoint to   |
 |                        | access this service.**                             |
 |                        | Similarly, the malicious endpoint may target a     |
@@ -607,7 +608,281 @@
 |                        | in a limited timeframe.                            |
 +------------------------+----------------------------------------------------+
 
---------------
++------------------------+----------------------------------------------------+
+| ID                     | 12                                                 |
++========================+====================================================+
+| ``Threat``             | **A malicious endpoint may attempt to allocate     |
+|                        | notifications bitmaps in the SPMC, through the     |
+|                        | FFA_NOTIFICATION_BITMAP_CREATE.**                  |
+|                        | This might be an attempt to exhaust SPMC's memory, |
+|                        | or to allocate a bitmap for a VM that was not      |
+|                        | intended to receive notifications from SPs. Thus   |
+|                        | creating the possibility for a channel that was not|
+|                        | meant to exist.                                    |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements``   | DF1, DF2, DF3                                      |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A        | SPMC                                               |
+| Components``           |                                                    |
++------------------------+----------------------------------------------------+
+| ``Assets``             | SPMC state                                         |
++------------------------+----------------------------------------------------+
+| ``Threat Agent``       | NS-Endpoint, S-Endpoint                            |
++------------------------+----------------------------------------------------+
+| ``Threat Type``        | Denial of service, Spoofing                        |
++------------------------+------------------+-----------------+---------------+
+| ``Application``        |   ``Server``     |   ``Mobile``    |               |
++------------------------+------------------+-----------------+---------------+
+| ``Impact``             | Medium(3)        | Medium(3)       |               |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood``         | Medium(3)        | Medium(3)       |               |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating``  | Medium(9)        | Medium(9)       |               |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations``        | The TF-A SPMC mitigates this threat by defining a  |
+|                        | a fixed size pool for bitmap allocation.           |
+|                        | It also limits the designated FF-A calls to be used|
+|                        | from NWd endpoints.                                |
+|                        | In the NWd the hypervisor is supposed to limit the |
+|                        | access to the designated FF-A call.                |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID                     | 13                                                 |
++========================+====================================================+
+| ``Threat``             | **A malicious endpoint may attempt to destroy the  |
+|                        | notifications bitmaps in the SPMC, through the     |
+|                        | FFA_NOTIFICATION_BITMAP_DESTROY.**                 |
+|                        | This might be an attempt to tamper with the SPMC   |
+|                        | state such that a partition isn't able to receive  |
+|                        | notifications.                                     |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements``   | DF1, DF2, DF3                                      |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A        | SPMC                                               |
+| Components``           |                                                    |
++------------------------+----------------------------------------------------+
+| ``Assets``             | SPMC state                                         |
++------------------------+----------------------------------------------------+
+| ``Threat Agent``       | NS-Endpoint, S-Endpoint                            |
++------------------------+----------------------------------------------------+
+| ``Threat Type``        | Tampering                                          |
++------------------------+------------------+-----------------+---------------+
+| ``Application``        |   ``Server``     |   ``Mobile``    |               |
++------------------------+------------------+-----------------+---------------+
+| ``Impact``             | Low(2)           | Low(2)          |               |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood``         | Low(2)           | Low(2)          |               |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating``  | Low(4)           | Low(4)          |               |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations``        | The TF-A SPMC mitigates this issue by limiting the |
+|                        | designated FF-A call to be issued by the NWd.      |
+|                        | Also, the notifications bitmap can't be destroyed  |
+|                        | if there are pending notifications.                |
+|                        | In the NWd, the hypervisor must restrict the       |
+|                        | NS-endpoints that can issue the designated call.   |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID                     | 14                                                 |
++========================+====================================================+
+| ``Threat``             | **A malicious endpoint might attempt to give       |
+|                        | permissions to an unintended sender to set         |
+|                        | notifications targeting another receiver using the |
+|                        | FF-A call FFA_NOTIFICATION_BIND.**                 |
+|                        | This might be an attempt to tamper with the SPMC   |
+|                        | state such that an unintended, and possibly        |
+|                        | malicious, communication channel is established.   |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements``   | DF1, DF2, DF3                                      |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A        | SPMC                                               |
+| Components``           |                                                    |
++------------------------+----------------------------------------------------+
+| ``Assets``             | SPMC state                                         |
++------------------------+----------------------------------------------------+
+| ``Threat Agent``       | NS-Endpoint, S-Endpoint                            |
++------------------------+----------------------------------------------------+
+| ``Threat Type``        | Tampering, Spoofing                                |
++------------------------+------------------+-----------------+---------------+
+| ``Application``        |   ``Server``     |   ``Mobile``    |               |
++------------------------+------------------+-----------------+---------------+
+| ``Impact``             | Low(2)           | Low(2)          |               |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood``         | Medium(3)        | Medium(3)       |               |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating``  | Medium(6)        | Medium(6)       |               |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations``        | The TF-A SPMC mitigates this by restricting        |
+|                        | designated FFA_NOTIFICATION_BIND call to be issued |
+|                        | by the receiver only. The receiver is responsible  |
+|                        | for allocating the notifications IDs to one        |
+|                        | specific partition.                                |
+|                        | Also, receivers that are not meant to receive      |
+|                        | notifications, must have notifications receipt     |
+|                        | disabled in the respective partition's manifest.   |
+|                        | As for calls coming from NWd, if the NWd VM has had|
+|                        | its bitmap allocated at initialization, the TF-A   |
+|                        | SPMC can't guarantee this threat won't happen.     |
+|                        | The Hypervisor must mitigate in the NWd, similarly |
+|                        | to SPMC for calls in SWd. Though, if the Hypervisor|
+|                        | has been compromised, the SPMC won't be able to    |
+|                        | mitigate it for calls forwarded from NWd.          |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID                     | 15                                                 |
++========================+====================================================+
+| ``Threat``             | **A malicious partition endpoint might attempt to  |
+|                        | set notifications that are not bound to it.**      |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements``   | DF1, DF2, DF3                                      |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A        | SPMC                                               |
+| Components``           |                                                    |
++------------------------+----------------------------------------------------+
+| ``Assets``             | SPMC state                                         |
++------------------------+----------------------------------------------------+
+| ``Threat Agent``       | NS-Endpoint, S-Endpoint                            |
++------------------------+----------------------------------------------------+
+| ``Threat Type``        | Spoofing                                           |
++------------------------+------------------+-----------------+---------------+
+| ``Application``        |   ``Server``     |   ``Mobile``    |               |
++------------------------+------------------+-----------------+---------------+
+| ``Impact``             | Low(2)           | Low(2)          |               |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood``         | Low(2)           | Low(2)          |               |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating``  | Low(4)           | Low(4)          |               |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations``        | The TF-A SPMC mitigates this by checking the       |
+|                        | sender's ID provided in the input to the call      |
+|                        | FFA_NOTIFICATION_SET. The SPMC keeps track of which|
+|                        | notifications are bound to which sender, for a     |
+|                        | given receiver. If the sender is an SP, the        |
+|                        | provided sender ID must match the ID of the        |
+|                        | currently running partition.                       |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID                     | 16                                                 |
++========================+====================================================+
+| ``Threat``             | **A malicious partition endpoint might attempt to  |
+|                        | get notifications that are not targeted to it.**   |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements``   | DF1, DF2, DF3                                      |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A        | SPMC                                               |
+| Components``           |                                                    |
++------------------------+----------------------------------------------------+
+| ``Assets``             | SPMC state                                         |
++------------------------+----------------------------------------------------+
+| ``Threat Agent``       | NS-Endpoint, S-Endpoint                            |
++------------------------+----------------------------------------------------+
+| ``Threat Type``        | Spoofing                                           |
++------------------------+------------------+-----------------+---------------+
+| ``Application``        |   ``Server``     |   ``Mobile``    |               |
++------------------------+------------------+-----------------+---------------+
+| ``Impact``             | Informational(1) | Informational(1)|               |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood``         | Low(2)           | Low(2)          |               |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating``  | Low(2)           | Low(2)          |               |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations``        | The TF-A SPMC mitigates this by checking the       |
+|                        | receiver's ID provided in the input to the call    |
+|                        | FFA_NOTIFICATION_GET. The SPMC keeps track of which|
+|                        | notifications are pending for each receiver.       |
+|                        | The provided receiver ID must match the ID of the  |
+|                        | currently running partition, if it is an SP.       |
+|                        | For calls forwarded from NWd, the SPMC will return |
+|                        | the pending notifications if the receiver had its  |
+|                        | bitmap created, and has pending notifications.     |
+|                        | If Hypervisor or OS kernel are compromised, the    |
+|                        | SPMC won't be able to mitigate calls from rogue NWd|
+|                        | endpoints.                                         |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID                     | 17                                                 |
++========================+====================================================+
+| ``Threat``             | **A malicious partition endpoint might attempt to  |
+|                        | get the information about pending notifications,   |
+|                        | through the FFA_NOTIFICATION_INFO_GET call.**      |
+|                        | This call is meant to be used by the NWd FF-A      |
+|                        | driver.                                            |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements``   | DF1, DF2, DF3                                      |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A        | SPMC                                               |
+| Components``           |                                                    |
++------------------------+----------------------------------------------------+
+| ``Assets``             | SPMC state                                         |
++------------------------+----------------------------------------------------+
+| ``Threat Agent``       | NS-Endpoint, S-Endpoint                            |
++------------------------+----------------------------------------------------+
+| ``Threat Type``        | Information disclosure                             |
++------------------------+------------------+-----------------+---------------+
+| ``Application``        |   ``Server``     |   ``Mobile``    |               |
++------------------------+------------------+-----------------+---------------+
+| ``Impact``             | Low(2)           | Low(2)          |               |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood``         | Medium(3)        | Medium(3)       |               |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating``  | Medium(6)        | Medium(6)       |               |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations``        | The TF-A SPMC mitigates this by returning error to |
+|                        | calls made by SPs to FFA_NOTIFICATION_INFO_GET.    |
+|                        | If Hypervisor or OS kernel are compromised, the    |
+|                        | SPMC won't be able mitigate calls from rogue NWd   |
+|                        | endpoints.                                         |
++------------------------+----------------------------------------------------+
+
++------------------------+----------------------------------------------------+
+| ID                     | 18                                                 |
++========================+====================================================+
+| ``Threat``             | **A malicious partition endpoint might attempt to  |
+|                        | flood another partition endpoint with notifications|
+|                        | hindering its operation.**                         |
+|                        | The intent of the malicious endpoint could be to   |
+|                        | interfere with both the receiver's and/or primary  |
+|                        | endpoint execution, as they can both be preempted  |
+|                        | by the NPI and SRI, respectively.                  |
++------------------------+----------------------------------------------------+
+| ``Diagram Elements``   | DF1, DF2, DF3, DF4                                 |
++------------------------+----------------------------------------------------+
+| ``Affected TF-A        | SPMC                                               |
+| Components``           |                                                    |
++------------------------+----------------------------------------------------+
+| ``Assets``             | SPMC state, SP state, CPU cycles                   |
++------------------------+----------------------------------------------------+
+| ``Threat Agent``       | NS-Endpoint, S-Endpoint                            |
++------------------------+----------------------------------------------------+
+| ``Threat Type``        | DoS                                                |
++------------------------+------------------+-----------------+---------------+
+| ``Application``        |   ``Server``     |   ``Mobile``    |               |
++------------------------+------------------+-----------------+---------------+
+| ``Impact``             | Low(2)           | Low(2)          |               |
++------------------------+------------------+-----------------+---------------+
+| ``Likelihood``         | Medium(3)        | Medium(3)       |               |
++------------------------+------------------+-----------------+---------------+
+| ``Total Risk Rating``  | Medium(6)        | Medium(6)       |               |
++------------------------+------------------+-----------------+---------------+
+| ``Mitigations``        | The TF-A SPMC does not mitigate this threat.       |
+|                        | However, the impact is limited due to the          |
+|                        | architecture:                                      |
+|                        | - Notifications are not queued, one that has been  |
+|                        | signaled needs to be retrieved by the receiver,    |
+|                        | until it can be sent again.                        |
+|                        | - Both SRI and NPI can't be pended until handled   |
+|                        | which limits the amount of spurious interrupts.    |
+|                        | - A given receiver could only bind a maximum number|
+|                        | of notifications to a given sender, within a given |
+|                        | execution context.                                 |
++------------------------+----------------------------------------------------+
+
+---------------
 
 *Copyright (c) 2021, Arm Limited. All rights reserved.*
 
diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h
index 93ee1a1..3af0500 100644
--- a/drivers/arm/gic/v3/gicv3_private.h
+++ b/drivers/arm/gic/v3/gicv3_private.h
@@ -171,7 +171,7 @@
 static inline u_register_t gicd_irouter_val_from_mpidr(u_register_t mpidr,
 						       unsigned int irm)
 {
-	return (mpidr & ~(U(0xff) << 24)) |
+	return (mpidr & MPIDR_AFFINITY_MASK) |
 		((irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT);
 }
 
diff --git a/drivers/marvell/uart/a3700_console.S b/drivers/marvell/uart/a3700_console.S
index 218fd86..c7eb165 100644
--- a/drivers/marvell/uart/a3700_console.S
+++ b/drivers/marvell/uart/a3700_console.S
@@ -34,7 +34,7 @@
 	 *     w1 - Uart clock in Hz
 	 *     w2 - Baud rate
 	 * Out: return 1 on success
-	 * Clobber list : x1, x2, x3
+	 * Clobber list : x1, x2, x3, x4
 	 * -----------------------------------------------
 	 */
 func console_a3700_core_init
@@ -44,24 +44,11 @@
 	cbz	w1, init_fail
 	cbz	w2, init_fail
 
-	/* Program the baudrate */
-	/* Divisor = Round(Uartclock / (16 * baudrate)) */
-	lsl	w2, w2, #4
-	add	w1, w1, w2, lsr #1
-	udiv	w2, w1, w2
-	and	w2, w2, #0x3ff /* clear all other bits to use default clock */
-
-	str	w2, [x0, #UART_BAUD_REG]/* set baud rate divisor */
-
-	/* Set UART to default 16X scheme */
-	mov	w3, #0
-	str	w3, [x0, #UART_POSSR_REG]
-
 	/*
 	 * Wait for the TX (THR and TSR) to be empty. If wait for 3ms, the TX FIFO is
 	 * still not empty, TX FIFO will reset by all means.
 	 */
-	mov	w1, #30				/* max time out 30 * 100 us */
+	mov	w4, #30				/* max time out 30 * 100 us */
 2:
 	/* Check whether TX (THR and TSR) is empty */
 	ldr	w3, [x0, #UART_STATUS_REG]
@@ -70,30 +57,51 @@
 	b.ne	4f
 
 	/* Delay */
-	mov	w2, #60000	/* 60000 cycles of below 3 instructions on 1200 MHz CPU ~~ 100 us */
+	mov	w3, #60000	/* 60000 cycles of below 3 instructions on 1200 MHz CPU ~~ 100 us */
 3:
-	sub     w2, w2, #1
-	cmp	w2, #0
+	sub	w3, w3, #1
+	cmp	w3, #0
 	b.ne	3b
 
 	/* Check whether wait timeout expired */
-	sub     w1, w1, #1
-	cmp	w1, #0
+	sub	w4, w4, #1
+	cmp	w4, #0
 	b.ne	2b
 
 4:
+	/* Reset UART via North Bridge Peripheral */
+	mov_imm	x4, MVEBU_NB_RESET_REG
+	ldr	w3, [x4]
+	bic	w3, w3, #MVEBU_NB_RESET_UART_N
+	str	w3, [x4]
+	orr	w3, w3, #MVEBU_NB_RESET_UART_N
+	str	w3, [x4]
+
 	/* Reset FIFO */
 	mov	w3, #UART_CTRL_RXFIFO_RESET
 	orr	w3, w3, #UART_CTRL_TXFIFO_RESET
 	str	w3, [x0, #UART_CTRL_REG]
 
 	/* Delay */
-	mov	w2, #2000
+	mov	w3, #2000
 1:
-	sub     w2, w2, #1
-	cmp	w2, #0
+	sub	w3, w3, #1
+	cmp	w3, #0
 	b.ne	1b
 
+	/* Program the baudrate */
+	/* Divisor = Round(Uartclock / (16 * baudrate)) */
+	lsl	w2, w2, #4
+	add	w1, w1, w2, lsr #1
+	udiv	w2, w1, w2
+	and	w2, w2, #0x3ff /* clear all other bits to use default clock */
+
+	str	w2, [x0, #UART_BAUD_REG]/* set baud rate divisor */
+
+	/* Set UART to default 16X scheme */
+	mov	w3, #0
+	str	w3, [x0, #UART_POSSR_REG]
+
 	/* No Parity, 1 Stop */
 	mov	w3, #0
 	str	w3, [x0, #UART_CTRL_REG]
@@ -118,7 +126,7 @@
 	 *     w2 - Baud rate
 	 *     x3 - pointer to empty console_t struct
 	 * Out: return 1 on success, 0 on error
-	 * Clobber list : x0, x1, x2, x6, x7, x14
+	 * Clobber list : x0, x1, x2, x3, x4, x6, x7, x14
 	 * -----------------------------------------------
 	 */
 func console_a3700_register
diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c
index d57f120..0db0dee 100644
--- a/drivers/st/clk/stm32mp_clkfunc.c
+++ b/drivers/st/clk/stm32mp_clkfunc.c
@@ -14,6 +14,7 @@
 #include <drivers/st/stm32_gpio.h>
 #include <drivers/st/stm32mp_clkfunc.h>
 
+#define DT_UART_COMPAT		"st,stm32h7-uart"
 /*
  * Get the frequency of an oscillator from its name in device tree.
  * @param name: oscillator name
@@ -297,3 +298,32 @@
 	cuint++;
 	return (int)fdt32_to_cpu(*cuint);
 }
+
+/*
+ * Get the frequency of the specified UART instance.
+ * @param instance: UART interface registers base address.
+ * @return: clock frequency on success, 0 value on failure.
+ */
+unsigned long fdt_get_uart_clock_freq(uintptr_t instance)
+{
+	void *fdt;
+	int node;
+	int clk_id;
+
+	if (fdt_get_address(&fdt) == 0) {
+		return 0UL;
+	}
+
+	/* Check for UART nodes */
+	node = dt_match_instance_by_compatible(DT_UART_COMPAT, instance);
+	if (node < 0) {
+		return 0UL;
+	}
+
+	clk_id = fdt_get_clock_id(node);
+	if (clk_id < 0) {
+		return 0UL;
+	}
+
+	return stm32mp_clk_get_rate((unsigned long)clk_id);
+}
diff --git a/drivers/st/uart/stm32_uart.c b/drivers/st/uart/stm32_uart.c
new file mode 100644
index 0000000..e2e5405
--- /dev/null
+++ b/drivers/st/uart/stm32_uart.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/bl_common.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_uart.h>
+#include <drivers/st/stm32_uart_regs.h>
+#include <drivers/st/stm32mp_clkfunc.h>
+#include <lib/mmio.h>
+
+#include <platform_def.h>
+
+/* UART time-out value */
+#define STM32_UART_TIMEOUT_US	20000U
+
+/* Mask to clear ALL the configuration registers */
+
+#define STM32_UART_CR1_FIELDS \
+		(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | \
+		 USART_CR1_RE | USART_CR1_OVER8 | USART_CR1_FIFOEN)
+
+#define STM32_UART_CR2_FIELDS \
+		(USART_CR2_SLVEN | USART_CR2_DIS_NSS | USART_CR2_ADDM7 | \
+		 USART_CR2_LBDL | USART_CR2_LBDIE | USART_CR2_LBCL | \
+		 USART_CR2_CPHA | USART_CR2_CPOL | USART_CR2_CLKEN | \
+		 USART_CR2_STOP | USART_CR2_LINEN | USART_CR2_SWAP | \
+		 USART_CR2_RXINV | USART_CR2_TXINV | USART_CR2_DATAINV | \
+		 USART_CR2_MSBFIRST | USART_CR2_ABREN | USART_CR2_ABRMODE | \
+		 USART_CR2_RTOEN | USART_CR2_ADD)
+
+#define STM32_UART_CR3_FIELDS \
+		(USART_CR3_EIE | USART_CR3_IREN | USART_CR3_IRLP | \
+		 USART_CR3_HDSEL | USART_CR3_NACK | USART_CR3_SCEN | \
+		 USART_CR3_DMAR | USART_CR3_DMAT | USART_CR3_RTSE | \
+		 USART_CR3_CTSE | USART_CR3_CTSIE | USART_CR3_ONEBIT | \
+		 USART_CR3_OVRDIS | USART_CR3_DDRE | USART_CR3_DEM | \
+		 USART_CR3_DEP | USART_CR3_SCARCNT | USART_CR3_WUS | \
+		 USART_CR3_WUFIE | USART_CR3_TXFTIE | USART_CR3_TCBGTIE | \
+		 USART_CR3_RXFTCFG | USART_CR3_RXFTIE | USART_CR3_TXFTCFG)
+
+#define STM32_UART_ISR_ERRORS	 \
+		(USART_ISR_ORE | USART_ISR_NE |  USART_ISR_FE | USART_ISR_PE)
+
+static const uint16_t presc_table[STM32_UART_PRESCALER_NB] = {
+	1U, 2U, 4U, 6U, 8U, 10U, 12U, 16U, 32U, 64U, 128U, 256U
+};
+
+/* @brief  BRR division operation to set BRR register in 8-bit oversampling
+ * mode.
+ * @param  clockfreq: UART clock.
+ * @param  baud_rate: Baud rate set by the user.
+ * @param  prescaler: UART prescaler value.
+ * @retval Division result.
+ */
+static uint32_t uart_div_sampling8(unsigned long clockfreq,
+				   uint32_t baud_rate,
+				   uint32_t prescaler)
+{
+	uint32_t scaled_freq = clockfreq / presc_table[prescaler];
+
+	return ((scaled_freq * 2) + (baud_rate / 2)) / baud_rate;
+
+}
+
+/* @brief  BRR division operation to set BRR register in 16-bit oversampling
+ * mode.
+ * @param  clockfreq: UART clock.
+ * @param  baud_rate: Baud rate set by the user.
+ * @param  prescaler: UART prescaler value.
+ * @retval Division result.
+ */
+static uint32_t uart_div_sampling16(unsigned long clockfreq,
+				    uint32_t baud_rate,
+				    uint32_t prescaler)
+{
+	uint32_t scaled_freq = clockfreq / presc_table[prescaler];
+
+	return (scaled_freq + (baud_rate / 2)) / baud_rate;
+
+}
+
+/*
+ * @brief  Return the UART clock frequency.
+ * @param  huart: UART handle.
+ * @retval Frequency value in Hz.
+ */
+static unsigned long uart_get_clock_freq(struct stm32_uart_handle_s *huart)
+{
+	return fdt_get_uart_clock_freq((uintptr_t)huart->base);
+}
+
+/*
+ * @brief  Configure the UART peripheral.
+ * @param  huart: UART handle.
+ * @retval UART status.
+ */
+static int uart_set_config(struct stm32_uart_handle_s *huart,
+			   const struct stm32_uart_init_s *init)
+{
+	uint32_t tmpreg;
+	unsigned long clockfreq;
+	uint32_t brrtemp;
+
+	/*
+	 * ---------------------- USART CR1 Configuration --------------------
+	 * Clear M, PCE, PS, TE, RE and OVER8 bits and configure
+	 * the UART word length, parity, mode and oversampling:
+	 * - set the M bits according to init->word_length value,
+	 * - set PCE and PS bits according to init->parity value,
+	 * - set TE and RE bits according to init->mode value,
+	 * - set OVER8 bit according to init->over_sampling value.
+	 */
+	tmpreg = init->word_length |
+		 init->parity |
+		 init->mode |
+		 init->over_sampling |
+		 init->fifo_mode;
+	mmio_clrsetbits_32(huart->base + USART_CR1, STM32_UART_CR1_FIELDS, tmpreg);
+
+	/*
+	 * --------------------- USART CR2 Configuration ---------------------
+	 * Configure the UART Stop Bits: Set STOP[13:12] bits according
+	 * to init->stop_bits value.
+	 */
+	mmio_clrsetbits_32(huart->base + USART_CR2, STM32_UART_CR2_FIELDS,
+			   init->stop_bits);
+
+	/*
+	 * --------------------- USART CR3 Configuration ---------------------
+	 * Configure:
+	 * - UART HardWare Flow Control: set CTSE and RTSE bits according
+	 *   to init->hw_flow_control value,
+	 * - one-bit sampling method versus three samples' majority rule
+	 *   according to init->one_bit_sampling (not applicable to
+	 *   LPUART),
+	 * - set TXFTCFG bit according to init->tx_fifo_threshold value,
+	 * - set RXFTCFG bit according to init->rx_fifo_threshold value.
+	 */
+	tmpreg = init->hw_flow_control | init->one_bit_sampling;
+
+	if (init->fifo_mode == USART_CR1_FIFOEN) {
+		tmpreg |= init->tx_fifo_threshold |
+			  init->rx_fifo_threshold;
+	}
+
+	mmio_clrsetbits_32(huart->base + USART_CR3, STM32_UART_CR3_FIELDS, tmpreg);
+
+	/*
+	 * --------------------- USART PRESC Configuration -------------------
+	 * Configure UART Clock Prescaler : set PRESCALER according to
+	 * init->prescaler value.
+	 */
+	assert(init->prescaler < STM32_UART_PRESCALER_NB);
+	mmio_clrsetbits_32(huart->base + USART_PRESC, USART_PRESC_PRESCALER,
+			   init->prescaler);
+
+	/*---------------------- USART BRR configuration --------------------*/
+	clockfreq = uart_get_clock_freq(huart);
+	if (clockfreq == 0UL) {
+		return -ENODEV;
+	}
+
+	if (init->over_sampling == STM32_UART_OVERSAMPLING_8) {
+		uint32_t usartdiv = uart_div_sampling8(clockfreq,
+						       init->baud_rate,
+						       init->prescaler);
+
+		brrtemp = (usartdiv & USART_BRR_DIV_MANTISSA) |
+			  ((usartdiv & USART_BRR_DIV_FRACTION) >> 1);
+	} else {
+		brrtemp = uart_div_sampling16(clockfreq,
+					      init->baud_rate,
+					      init->prescaler) &
+			  (USART_BRR_DIV_FRACTION | USART_BRR_DIV_MANTISSA);
+	}
+	mmio_write_32(huart->base + USART_BRR, brrtemp);
+
+	return 0;
+}
+
+/*
+ * @brief  Handle UART communication timeout.
+ * @param  huart: UART handle.
+ * @param  flag: Specifies the UART flag to check.
+ * @retval UART status.
+ */
+static int stm32_uart_wait_flag(struct stm32_uart_handle_s *huart, uint32_t flag)
+{
+	uint64_t timeout_ref = timeout_init_us(STM32_UART_TIMEOUT_US);
+
+	while ((mmio_read_32(huart->base + USART_ISR) & flag) == 0U) {
+		if (timeout_elapsed(timeout_ref)) {
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * @brief  Check the UART idle State.
+ * @param  huart: UART handle.
+ * @retval UART status.
+ */
+static int stm32_uart_check_idle(struct stm32_uart_handle_s *huart)
+{
+	int ret;
+
+	/* Check if the transmitter is enabled */
+	if ((mmio_read_32(huart->base + USART_CR1) & USART_CR1_TE) == USART_CR1_TE) {
+		ret = stm32_uart_wait_flag(huart, USART_ISR_TEACK);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	/* Check if the receiver is enabled */
+	if ((mmio_read_32(huart->base + USART_CR1) & USART_CR1_RE) == USART_CR1_RE) {
+		ret = stm32_uart_wait_flag(huart, USART_ISR_REACK);
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * @brief  Compute RDR register mask depending on word length.
+ * @param  huart: UART handle.
+ * @retval Mask value.
+ */
+static unsigned int stm32_uart_rdr_mask(const struct stm32_uart_init_s *init)
+{
+	unsigned int mask = 0U;
+
+	switch (init->word_length) {
+	case STM32_UART_WORDLENGTH_9B:
+		mask = GENMASK(8, 0);
+		break;
+	case STM32_UART_WORDLENGTH_8B:
+		mask = GENMASK(7, 0);
+		break;
+	case STM32_UART_WORDLENGTH_7B:
+		mask = GENMASK(6, 0);
+		break;
+	default:
+		break; /* not reached */
+	}
+
+	if (init->parity != STM32_UART_PARITY_NONE) {
+		mask >>= 1;
+	}
+
+	return mask;
+}
+
+/*
+ * @brief  Check interrupt and status errors.
+ * @retval True if error detected, false otherwise.
+ */
+static bool stm32_uart_error_detected(struct stm32_uart_handle_s *huart)
+{
+	return (mmio_read_32(huart->base + USART_ISR) & STM32_UART_ISR_ERRORS) != 0U;
+}
+
+/*
+ * @brief  Clear status errors.
+ */
+static void stm32_uart_error_clear(struct stm32_uart_handle_s *huart)
+{
+	mmio_write_32(huart->base + USART_ICR, STM32_UART_ISR_ERRORS);
+}
+
+/*
+ * @brief  Stop the UART.
+ * @param  base: UART base address.
+ */
+void stm32_uart_stop(uintptr_t base)
+{
+	mmio_clrbits_32(base + USART_CR1, USART_CR1_UE);
+}
+
+/*
+ * @brief  Initialize UART.
+ * @param  huart: UART handle.
+ * @param  base_addr: base address of UART.
+ * @param  init: UART initialization parameter.
+ * @retval UART status.
+ */
+
+int stm32_uart_init(struct stm32_uart_handle_s *huart,
+		    uintptr_t base_addr,
+		    const struct stm32_uart_init_s *init)
+{
+	int ret;
+
+	if (huart == NULL || init == NULL || base_addr == 0U) {
+		return -EINVAL;
+	}
+
+	huart->base = base_addr;
+
+	/* Disable the peripheral */
+	stm32_uart_stop(huart->base);
+
+	/* Computation of UART mask to apply to RDR register */
+	huart->rdr_mask = stm32_uart_rdr_mask(init);
+
+	/* Init the peripheral */
+	ret = uart_set_config(huart, init);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Enable the peripheral */
+	mmio_setbits_32(huart->base + USART_CR1, USART_CR1_UE);
+
+	/* TEACK and/or REACK to check */
+	return stm32_uart_check_idle(huart);
+}
+
+/*
+ * @brief  Transmit one data in no blocking mode.
+ * @param  huart: UART handle.
+ * @param  c: data to sent.
+ * @retval UART status.
+ */
+int stm32_uart_putc(struct stm32_uart_handle_s *huart, int c)
+{
+	int ret;
+
+	if (huart == NULL) {
+		return -EINVAL;
+	}
+
+	ret = stm32_uart_wait_flag(huart, USART_ISR_TXE);
+	if (ret != 0) {
+		return ret;
+	}
+
+	mmio_write_32(huart->base + USART_TDR, c);
+	if (stm32_uart_error_detected(huart)) {
+		stm32_uart_error_clear(huart);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/*
+ * @brief  Flush TX Transmit fifo
+ * @param  huart: UART handle.
+ * @retval UART status.
+ */
+int stm32_uart_flush(struct stm32_uart_handle_s *huart)
+{
+	int ret;
+
+	if (huart == NULL) {
+		return -EINVAL;
+	}
+
+	ret = stm32_uart_wait_flag(huart, USART_ISR_TXE);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return stm32_uart_wait_flag(huart, USART_ISR_TC);
+}
+
+/*
+ * @brief  Receive a data in no blocking mode.
+ * @retval value if >0 or UART status.
+ */
+int stm32_uart_getc(struct stm32_uart_handle_s *huart)
+{
+	uint32_t data;
+
+	if (huart == NULL) {
+		return -EINVAL;
+	}
+
+	/* Check if data is available */
+	if ((mmio_read_32(huart->base + USART_ISR) & USART_ISR_RXNE) == 0U) {
+		return -EAGAIN;
+	}
+
+	data = mmio_read_32(huart->base + USART_RDR) & huart->rdr_mask;
+
+	if (stm32_uart_error_detected(huart)) {
+		stm32_uart_error_clear(huart);
+		return -EFAULT;
+	}
+
+	return (int)data;
+}
diff --git a/include/drivers/marvell/uart/a3700_console.h b/include/drivers/marvell/uart/a3700_console.h
index 12d2cdc..ce673a1 100644
--- a/include/drivers/marvell/uart/a3700_console.h
+++ b/include/drivers/marvell/uart/a3700_console.h
@@ -9,6 +9,7 @@
 #define A3700_CONSOLE_H
 
 #include <drivers/console.h>
+#include <platform_def.h>
 
 /* MVEBU UART Registers */
 #define UART_RX_REG		0x00
diff --git a/include/drivers/st/stm32_uart.h b/include/drivers/st/stm32_uart.h
new file mode 100644
index 0000000..212968f
--- /dev/null
+++ b/include/drivers/st/stm32_uart.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STM32_UART_H
+#define STM32_UART_H
+
+/* UART word length */
+#define STM32_UART_WORDLENGTH_7B		USART_CR1_M1
+#define STM32_UART_WORDLENGTH_8B		0x00000000U
+#define STM32_UART_WORDLENGTH_9B		USART_CR1_M0
+
+/* UART number of stop bits */
+#define STM32_UART_STOPBITS_0_5			USART_CR2_STOP_0
+#define STM32_UART_STOPBITS_1			0x00000000U
+#define STM32_UART_STOPBITS_1_5			(USART_CR2_STOP_0 | USART_CR2_STOP_1)
+#define STM32_UART_STOPBITS_2			USART_CR2_STOP_1
+
+/* UART parity */
+#define STM32_UART_PARITY_NONE			0x00000000U
+#define STM32_UART_PARITY_EVEN			USART_CR1_PCE
+#define STM32_UART_PARITY_ODD			(USART_CR1_PCE | USART_CR1_PS)
+
+/* UART transfer mode */
+#define STM32_UART_MODE_RX			USART_CR1_RE
+#define STM32_UART_MODE_TX			USART_CR1_TE
+#define STM32_UART_MODE_TX_RX			(USART_CR1_TE | USART_CR1_RE)
+
+/* UART hardware flow control */
+#define STM32_UART_HWCONTROL_NONE		0x00000000U
+#define STM32_UART_HWCONTROL_RTS		USART_CR3_RTSE
+#define STM32_UART_HWCONTROL_CTS		USART_CR3_CTSE
+#define STM32_UART_HWCONTROL_RTS_CTS		(USART_CR3_RTSE | USART_CR3_CTSE)
+
+/* UART over sampling */
+#define STM32_UART_OVERSAMPLING_16		0x00000000U
+#define STM32_UART_OVERSAMPLING_8		USART_CR1_OVER8
+
+/* UART prescaler */
+#define STM32_UART_PRESCALER_DIV1		0x00000000U
+#define STM32_UART_PRESCALER_DIV2		0x00000001U
+#define STM32_UART_PRESCALER_DIV4		0x00000002U
+#define STM32_UART_PRESCALER_DIV6		0x00000003U
+#define STM32_UART_PRESCALER_DIV8		0x00000004U
+#define STM32_UART_PRESCALER_DIV10		0x00000005U
+#define STM32_UART_PRESCALER_DIV12		0x00000006U
+#define STM32_UART_PRESCALER_DIV16		0x00000007U
+#define STM32_UART_PRESCALER_DIV32		0x00000008U
+#define STM32_UART_PRESCALER_DIV64		0x00000009U
+#define STM32_UART_PRESCALER_DIV128		0x0000000AU
+#define STM32_UART_PRESCALER_DIV256		0x0000000BU
+#define STM32_UART_PRESCALER_NB			0x0000000CU
+
+/* UART fifo mode */
+#define STM32_UART_FIFOMODE_EN			USART_CR1_FIFOEN
+#define STM32_UART_FIFOMODE_DIS			0x00000000U
+
+/* UART TXFIFO threshold level */
+#define STM32_UART_TXFIFO_THRESHOLD_1EIGHTHFULL		0x00000000U
+#define STM32_UART_TXFIFO_THRESHOLD_1QUARTERFUL		USART_CR3_TXFTCFG_0
+#define STM32_UART_TXFIFO_THRESHOLD_HALFFULL		USART_CR3_TXFTCFG_1
+#define STM32_UART_TXFIFO_THRESHOLD_3QUARTERSFULL	(USART_CR3_TXFTCFG_0 | USART_CR3_TXFTCFG_1)
+#define STM32_UART_TXFIFO_THRESHOLD_7EIGHTHFULL		USART_CR3_TXFTCFG_2
+#define STM32_UART_TXFIFO_THRESHOLD_EMPTY		(USART_CR3_TXFTCFG_2 | USART_CR3_TXFTCFG_0)
+
+/* UART RXFIFO threshold level */
+#define STM32_UART_RXFIFO_THRESHOLD_1EIGHTHFULL		0x00000000U
+#define STM32_UART_RXFIFO_THRESHOLD_1QUARTERFULL	USART_CR3_RXFTCFG_0
+#define STM32_UART_RXFIFO_THRESHOLD_HALFFULL		USART_CR3_RXFTCFG_1
+#define STM32_UART_RXFIFO_THRESHOLD_3QUARTERSFULL	(USART_CR3_RXFTCFG_0 | USART_CR3_RXFTCFG_1)
+#define STM32_UART_RXFIFO_THRESHOLD_7EIGHTHFULL		USART_CR3_RXFTCFG_2
+#define STM32_UART_RXFIFO_THRESHOLD_FULL		(USART_CR3_RXFTCFG_2 | USART_CR3_RXFTCFG_0)
+
+struct stm32_uart_init_s {
+	uint32_t baud_rate;		/*
+					 * Configures the UART communication
+					 * baud rate.
+					 */
+
+	uint32_t word_length;		/*
+					 * Specifies the number of data bits
+					 * transmitted or received in a frame.
+					 * This parameter can be a value of
+					 * @ref STM32_UART_WORDLENGTH_*.
+					 */
+
+	uint32_t stop_bits;		/*
+					 * Specifies the number of stop bits
+					 * transmitted. This parameter can be
+					 * a value of @ref STM32_UART_STOPBITS_*.
+					 */
+
+	uint32_t parity;		/*
+					 * Specifies the parity mode.
+					 * This parameter can be a value of
+					 * @ref STM32_UART_PARITY_*.
+					 */
+
+	uint32_t mode;			/*
+					 * Specifies whether the receive or
+					 * transmit mode is enabled or
+					 * disabled. This parameter can be a
+					 * value of @ref @ref STM32_UART_MODE_*.
+					 */
+
+	uint32_t hw_flow_control;	/*
+					 * Specifies whether the hardware flow
+					 * control mode is enabled or
+					 * disabled. This parameter can be a
+					 * value of @ref STM32_UARTHWCONTROL_*.
+					 */
+
+	uint32_t over_sampling;		/*
+					 * Specifies whether the over sampling
+					 * 8 is enabled or disabled.
+					 * This parameter can be a value of
+					 * @ref STM32_UART_OVERSAMPLING_*.
+					 */
+
+	uint32_t one_bit_sampling;	/*
+					 * Specifies whether a single sample
+					 * or three samples' majority vote is
+					 * selected. This parameter can be 0
+					 * or USART_CR3_ONEBIT.
+					 */
+
+	uint32_t prescaler;		/*
+					 * Specifies the prescaler value used
+					 * to divide the UART clock source.
+					 * This parameter can be a value of
+					 * @ref STM32_UART_PRESCALER_*.
+					 */
+
+	uint32_t fifo_mode;		/*
+					 * Specifies if the FIFO mode will be
+					 * used. This parameter can be a value
+					 * of @ref STM32_UART_FIFOMODE_*.
+					 */
+
+	uint32_t tx_fifo_threshold;	/*
+					 * Specifies the TXFIFO threshold
+					 * level. This parameter can be a
+					 * value of @ref
+					 * STM32_UART_TXFIFO_THRESHOLD_*.
+					 */
+
+	uint32_t rx_fifo_threshold;	/*
+					 * Specifies the RXFIFO threshold
+					 * level. This parameter can be a
+					 * value of @ref
+					 * STM32_UART_RXFIFO_THRESHOLD_*.
+					 */
+};
+
+struct stm32_uart_handle_s {
+	uint32_t base;
+	uint32_t rdr_mask;
+};
+
+int stm32_uart_init(struct stm32_uart_handle_s *huart,
+		    uintptr_t base_addr,
+		    const struct stm32_uart_init_s *init);
+void stm32_uart_stop(uintptr_t base_addr);
+int stm32_uart_putc(struct stm32_uart_handle_s *huart, int c);
+int stm32_uart_flush(struct stm32_uart_handle_s *huart);
+int stm32_uart_getc(struct stm32_uart_handle_s *huart);
+
+#endif /* STM32_UART_H */
diff --git a/include/drivers/st/stm32mp_clkfunc.h b/include/drivers/st/stm32mp_clkfunc.h
index c3329cc..a282035 100644
--- a/include/drivers/st/stm32mp_clkfunc.h
+++ b/include/drivers/st/stm32mp_clkfunc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -26,5 +26,6 @@
 bool fdt_get_rcc_secure_status(void);
 
 int fdt_get_clock_id(int node);
+unsigned long fdt_get_uart_clock_freq(uintptr_t instance);
 
 #endif /* STM32MP_CLKFUNC_H */
diff --git a/lib/aarch32/misc_helpers.S b/lib/aarch32/misc_helpers.S
index 8b16f93..59e15bd 100644
--- a/lib/aarch32/misc_helpers.S
+++ b/lib/aarch32/misc_helpers.S
@@ -301,9 +301,9 @@
 	cmp	r4, r6
 	blo	2f
 
-	/* Skip adding offset if address is >= upper limit */
+	/* Skip adding offset if address is > upper limit */
 	cmp	r4, r7
-	bhs	2f
+	bhi	2f
 
 	add 	r4, r0, r4
 	str	r4, [r3]
diff --git a/lib/aarch64/misc_helpers.S b/lib/aarch64/misc_helpers.S
index 6e4d1fc..01531ca 100644
--- a/lib/aarch64/misc_helpers.S
+++ b/lib/aarch64/misc_helpers.S
@@ -532,9 +532,9 @@
 	cmp	x3, x6
 	b.lo	2f
 
-	/* Skip adding offset if address is >= upper limit */
+	/* Skip adding offset if address is > upper limit */
 	cmp	x3, x7
-	b.hs	2f
+	b.hi	2f
 	add	x3, x3, x0
 	str	x3, [x1]
 
@@ -582,9 +582,9 @@
 	cmp	x4, x6
 	b.lo	2f
 
-	/* Skip adding offset if r_addend entry is >= upper limit */
+	/* Skip adding offset if r_addend entry is > upper limit */
 	cmp	x4, x7
-	b.hs	2f
+	b.hi	2f
 
 	add	x4, x0, x4	/* Diff(S) + r_addend */
 	str	x4, [x3]
diff --git a/lib/xlat_tables_v2/xlat_tables_utils.c b/lib/xlat_tables_v2/xlat_tables_utils.c
index df17386..38a375e 100644
--- a/lib/xlat_tables_v2/xlat_tables_utils.c
+++ b/lib/xlat_tables_v2/xlat_tables_utils.c
@@ -6,6 +6,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -199,7 +200,7 @@
 					(uint64_t *)addr_inner,
 					XLAT_TABLE_ENTRIES, level + 1U);
 			} else {
-				printf("%sVA:0x%lx PA:0x%llx size:0x%zx ",
+				printf("%sVA:0x%lx PA:0x%" PRIx64 " size:0x%zx ",
 				       level_spacers[level], table_idx_va,
 				       (uint64_t)(desc & TABLE_ADDR_MASK),
 				       level_size);
diff --git a/plat/arm/css/sgi/sgi-common.mk b/plat/arm/css/sgi/sgi-common.mk
index 8baf4ee..f56fe35 100644
--- a/plat/arm/css/sgi/sgi-common.mk
+++ b/plat/arm/css/sgi/sgi-common.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -20,6 +20,9 @@
 
 CSS_SGI_PLATFORM_VARIANT	:=	0
 
+# Do not enable SVE
+ENABLE_SVE_FOR_NS		:=	0
+
 INTERCONNECT_SOURCES	:=	${CSS_ENT_BASE}/sgi_interconnect.c
 
 PLAT_INCLUDES		+=	-I${CSS_ENT_BASE}/include
diff --git a/plat/marvell/armada/a3k/common/include/a3700_plat_def.h b/plat/marvell/armada/a3k/common/include/a3700_plat_def.h
index 83d9561..4d45e15 100644
--- a/plat/marvell/armada/a3k/common/include/a3700_plat_def.h
+++ b/plat/marvell/armada/a3k/common/include/a3700_plat_def.h
@@ -51,6 +51,41 @@
 #define MVEBU_CCI_BASE			0xFE000000
 
 /*****************************************************************************
+ * North and south bridge reset registers
+ *****************************************************************************
+ */
+#define MVEBU_NB_RESET_REG		(MVEBU_REGS_BASE + 0x12400)
+#define   MVEBU_NB_RESET_I2C1_N		(1 << 0)
+#define   MVEBU_NB_RESET_1WIRE_N	(1 << 1)
+#define   MVEBU_NB_RESET_SPI_N		(1 << 2)
+#define   MVEBU_NB_RESET_UART_N		(1 << 3)
+#define   MVEBU_NB_RESET_XTL_N		(1 << 4)
+#define   MVEBU_NB_RESET_I2C2_N		(1 << 5)
+#define   MVEBU_NB_RESET_UART2_N	(1 << 6)
+#define   MVEBU_NB_RESET_AVS_N		(1 << 7)
+#define   MVEBU_NB_RESET_DDR_N		(1 << 10)
+#define   MVEBU_NB_RESET_SETM_N		(1 << 11)
+#define   MVEBU_NB_RESET_DMA_N		(1 << 12)
+#define   MVEBU_NB_RESET_TSECM_N	(1 << 13)
+#define   MVEBU_NB_RESET_SDIO_N		(1 << 14)
+#define   MVEBU_NB_RESET_SATA_N		(1 << 15)
+#define   MVEBU_NB_RESET_PWRMGT_N	(1 << 16)
+#define   MVEBU_NB_RESET_OTP_N		(1 << 17)
+#define   MVEBU_NB_RESET_EIP_N		(1 << 18)
+#define MVEBU_SB_RESET_REG		(MVEBU_REGS_BASE + 0x18600)
+#define   MVEBU_SB_RESET_MCIPHY		(1 << 1)
+#define   MVEBU_SB_RESET_SDIO_N		(1 << 2)
+#define   MVEBU_SB_RESET_PCIE_N		(1 << 3)
+#define   MVEBU_SB_RESET_GBE1_N		(1 << 4)
+#define   MVEBU_SB_RESET_GBE0_N		(1 << 5)
+#define   MVEBU_SB_RESET_USB2PHY	(1 << 6)
+#define   MVEBU_SB_RESET_USB2HPHY	(1 << 7)
+#define   MVEBU_SB_RESET_MCI_N		(1 << 8)
+#define   MVEBU_SB_RESET_PWRMGT_N	(1 << 9)
+#define   MVEBU_SB_RESET_EBM_N		(1 << 10)
+#define   MVEBU_SB_RESET_OTP_N		(1 << 11)
+
+/*****************************************************************************
  * North and south bridge register base
  *****************************************************************************
  */
diff --git a/plat/mediatek/mt8186/aarch64/plat_helpers.S b/plat/mediatek/mt8186/aarch64/plat_helpers.S
new file mode 100644
index 0000000..35b293f
--- /dev/null
+++ b/plat/mediatek/mt8186/aarch64/plat_helpers.S
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <platform_def.h>
+
+	.globl plat_is_my_cpu_primary
+	.globl plat_my_core_pos
+	.globl plat_mediatek_calc_core_pos
+
+func plat_is_my_cpu_primary
+	mrs	x0, mpidr_el1
+	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
+	cmp	x0, #PLAT_PRIMARY_CPU
+	cset	x0, eq
+	ret
+endfunc plat_is_my_cpu_primary
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_my_core_pos(void)
+	 *  This function uses the plat_mediatek_calc_core_pos()
+	 *  definition to get the index of the calling CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	plat_mediatek_calc_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 * unsigned int plat_mediatek_calc_core_pos(u_register_t mpidr);
+	 *
+	 * With this function: CorePos = CoreID (AFF1)
+	 * we do it with x0 = (x0 >> 8) & 0xff
+	 * -----------------------------------------------------
+	 */
+func plat_mediatek_calc_core_pos
+	mov	x1, #MPIDR_AFFLVL_MASK
+	and	x0, x1, x0, lsr #MPIDR_AFF1_SHIFT
+	ret
+endfunc plat_mediatek_calc_core_pos
diff --git a/plat/mediatek/mt8186/aarch64/platform_common.c b/plat/mediatek/mt8186/aarch64/platform_common.c
new file mode 100644
index 0000000..745e547
--- /dev/null
+++ b/plat/mediatek/mt8186/aarch64/platform_common.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <platform_def.h>
+
+/* Table of regions to map using the MMU.  */
+const mmap_region_t plat_mmap[] = {
+	/* for TF text, RO, RW */
+	MAP_REGION_FLAT(MTK_DEV_RNG0_BASE, MTK_DEV_RNG0_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MTK_DEV_RNG1_BASE, MTK_DEV_RNG1_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(MTK_DEV_RNG2_BASE, MTK_DEV_RNG2_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	{ 0 }
+};
+
+/*******************************************************************************
+ * Macro generating the code for the function setting up the pagetables as per
+ * the platform memory map & initialize the mmu, for the given exception level
+ ******************************************************************************/
+void plat_configure_mmu_el3(uintptr_t total_base,
+			    uintptr_t total_size,
+			    uintptr_t ro_start,
+			    uintptr_t ro_limit)
+{
+	mmap_add_region(total_base, total_base, total_size,
+			MT_RW_DATA | MT_SECURE);
+	mmap_add_region(ro_start, ro_start, ro_limit - ro_start,
+			MT_CODE | MT_SECURE);
+	mmap_add(plat_mmap);
+	init_xlat_tables();
+	enable_mmu_el3(0);
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return SYS_COUNTER_FREQ_IN_TICKS;
+}
diff --git a/plat/mediatek/mt8186/bl31_plat_setup.c b/plat/mediatek/mt8186/bl31_plat_setup.c
new file mode 100644
index 0000000..3fd1c71
--- /dev/null
+++ b/plat/mediatek/mt8186/bl31_plat_setup.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* System Includes */
+#include <assert.h>
+
+/* Project Includes */
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <drivers/ti/uart/uart_16550.h>
+#include <lib/coreboot.h>
+
+/* Platform Includes */
+#include <plat_params.h>
+#include <plat_private.h>
+
+static entry_point_info_t bl32_ep_info;
+static entry_point_info_t bl33_ep_info;
+
+/*******************************************************************************
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ ******************************************************************************/
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	entry_point_info_t *next_image_info;
+
+	next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info;
+	assert(next_image_info->h.type == PARAM_EP);
+
+	/* None of the images on this platform can have 0x0 as the entrypoint */
+	if (next_image_info->pc) {
+		return next_image_info;
+	} else {
+		return NULL;
+	}
+}
+
+/*******************************************************************************
+ * Perform any BL31 early platform setup. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ * BL2 has flushed this information to memory, so we are guaranteed to pick up
+ * good data.
+ ******************************************************************************/
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	static console_t console;
+
+	params_early_setup(arg1);
+
+#if COREBOOT
+	if (coreboot_serial.type) {
+		console_16550_register(coreboot_serial.baseaddr,
+				       coreboot_serial.input_hertz,
+				       coreboot_serial.baud,
+				       &console);
+	}
+#else
+	console_16550_register(UART0_BASE, UART_CLOCK, UART_BAUDRATE, &console);
+#endif
+
+	INFO("MT8186 bl31_setup\n");
+
+	bl31_params_parse_helper(arg0, &bl32_ep_info, &bl33_ep_info);
+}
+
+
+/*******************************************************************************
+ * Perform any BL31 platform setup code
+ ******************************************************************************/
+void bl31_platform_setup(void)
+{
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the mmu in a quick and dirty way.
+ ******************************************************************************/
+void bl31_plat_arch_setup(void)
+{
+	plat_configure_mmu_el3(BL31_START,
+			       BL31_END - BL31_START,
+			       BL_CODE_BASE,
+			       BL_CODE_END);
+}
diff --git a/plat/mediatek/mt8186/include/plat_helpers.h b/plat/mediatek/mt8186/include/plat_helpers.h
new file mode 100644
index 0000000..ebc9fa0
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_helpers.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __PLAT_HELPERS_H__
+#define __PLAT_HELPERS_H__
+
+unsigned int plat_mediatek_calc_core_pos(u_register_t mpidr);
+
+#endif /* __PLAT_HELPERS_H__ */
diff --git a/plat/mediatek/mt8186/include/plat_macros.S b/plat/mediatek/mt8186/include/plat_macros.S
new file mode 100644
index 0000000..39727ea
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_macros.S
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <platform_def.h>
+
+.section .rodata.gic_reg_name, "aS"
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n"	\
+		" Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+.section .rodata.cci_reg_name, "aS"
+cci_iface_regs:
+	.asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , ""
+
+	/* ---------------------------------------------
+	 * The below macro prints out relevant GIC
+	 * registers whenever an unhandled exception
+	 * is taken in BL31.
+	 * Clobbers: x0 - x10, x26, x27, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	/* TODO: leave implementation to GIC owner */
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/mediatek/mt8186/include/plat_private.h b/plat/mediatek/mt8186/include/plat_private.h
new file mode 100644
index 0000000..7ef2b85
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_private.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+/*******************************************************************************
+ * Function and variable prototypes
+ ******************************************************************************/
+void plat_configure_mmu_el3(uintptr_t total_base,
+			    uintptr_t total_size,
+			    uintptr_t ro_start,
+			    uintptr_t ro_limit);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/mediatek/mt8186/include/platform_def.h b/plat/mediatek/mt8186/include/platform_def.h
new file mode 100644
index 0000000..bf1bbef
--- /dev/null
+++ b/plat/mediatek/mt8186/include/platform_def.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#define PLAT_PRIMARY_CPU	0x0
+
+#define MT_GIC_BASE		(0x0C000000)
+#define MCUCFG_BASE		(0x0C530000)
+#define IO_PHYS			(0x10000000)
+
+/* Aggregate of all devices for MMU mapping */
+#define MTK_DEV_RNG0_BASE	IO_PHYS
+#define MTK_DEV_RNG0_SIZE	0x400000
+#define MTK_DEV_RNG1_BASE	(IO_PHYS + 0x1000000)
+#define MTK_DEV_RNG1_SIZE	0xa110000
+#define MTK_DEV_RNG2_BASE	MT_GIC_BASE
+#define MTK_DEV_RNG2_SIZE	0x600000
+
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define UART0_BASE			(IO_PHYS + 0x01002000)
+
+#define UART_BAUDRATE			115200
+
+/*******************************************************************************
+ * System counter frequency related constants
+ ******************************************************************************/
+#define SYS_COUNTER_FREQ_IN_TICKS	13000000
+#define SYS_COUNTER_FREQ_IN_MHZ		13
+
+/*******************************************************************************
+ * Platform binary types for linking
+ ******************************************************************************/
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+#define PLATFORM_STACK_SIZE		0x800
+
+#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
+
+#define PLAT_MAX_PWR_LVL		U(3)
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(9)
+
+#define PLATFORM_SYSTEM_COUNT		U(1)
+#define PLATFORM_MCUSYS_COUNT		U(1)
+#define PLATFORM_CLUSTER_COUNT		U(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT	U(8)
+#define PLATFORM_CLUSTER1_CORE_COUNT	U(0)
+
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	U(8)
+
+#define SOC_CHIP_ID			U(0x8186)
+
+/*******************************************************************************
+ * Platform memory map related constants
+ ******************************************************************************/
+#define TZRAM_BASE			0x54600000
+#define TZRAM_SIZE			0x00030000
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL3-1 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL3-1 debug size plus a
+ * little space for growth.
+ */
+#define BL31_BASE			(TZRAM_BASE + 0x1000)
+#define BL31_LIMIT			(TZRAM_BASE + TZRAM_SIZE)
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
+#define MAX_XLAT_TABLES			16
+#define MAX_MMAP_REGIONS		16
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+#define CACHE_WRITEBACK_SHIFT		6
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/mediatek/mt8186/plat_pm.c b/plat/mediatek/mt8186/plat_pm.c
new file mode 100644
index 0000000..61d2cc9
--- /dev/null
+++ b/plat/mediatek/mt8186/plat_pm.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/psci/psci.h>
+
+static const plat_psci_ops_t plat_psci_ops = {
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	*psci_ops = &plat_psci_ops;
+
+	return 0;
+}
diff --git a/plat/mediatek/mt8186/plat_topology.c b/plat/mediatek/mt8186/plat_topology.c
new file mode 100644
index 0000000..bc95c64
--- /dev/null
+++ b/plat/mediatek/mt8186/plat_topology.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+
+#include <plat_helpers.h>
+#include <platform_def.h>
+
+const unsigned char mtk_power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	PLATFORM_SYSTEM_COUNT,
+	/* Number of children for the root node */
+	PLATFORM_MCUSYS_COUNT,
+	/* Number of children for the mcusys node */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first cluster node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return mtk_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	unsigned int cluster_id, cpu_id;
+
+	if ((read_mpidr() & MPIDR_MT_MASK) != 0) {
+		/* ARMv8.2 arch */
+		if ((mpidr & (MPIDR_AFFLVL_MASK << MPIDR_AFF0_SHIFT)) != 0) {
+			return -1;
+		}
+		return plat_mediatek_calc_core_pos(mpidr);
+	}
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	if ((mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) != 0) {
+		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;
+	}
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) {
+		return -1;
+	}
+
+	return (cpu_id + (cluster_id * 8));
+}
diff --git a/plat/mediatek/mt8186/platform.mk b/plat/mediatek/mt8186/platform.mk
new file mode 100644
index 0000000..2d20213
--- /dev/null
+++ b/plat/mediatek/mt8186/platform.mk
@@ -0,0 +1,51 @@
+#
+# Copyright (c) 2021, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+MTK_PLAT     := plat/mediatek
+MTK_PLAT_SOC := ${MTK_PLAT}/${PLAT}
+
+PLAT_INCLUDES := -I${MTK_PLAT}/common/                            \
+                 -I${MTK_PLAT_SOC}/include/
+
+include drivers/arm/gic/v3/gicv3.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+
+PLAT_BL_COMMON_SOURCES := ${GICV3_SOURCES}                              \
+                          ${XLAT_TABLES_LIB_SRCS}                       \
+                          plat/common/aarch64/crash_console_helpers.S   \
+                          plat/common/plat_psci_common.c
+
+
+BL31_SOURCES += common/desc_image_load.c                              \
+                drivers/ti/uart/aarch64/16550_console.S               \
+                lib/bl_aux_params/bl_aux_params.c                     \
+                lib/cpus/aarch64/cortex_a55.S                         \
+                lib/cpus/aarch64/cortex_a76.S                         \
+                plat/common/plat_gicv3.c                              \
+                ${MTK_PLAT}/common/mtk_plat_common.c                  \
+                ${MTK_PLAT}/common/params_setup.c                     \
+                ${MTK_PLAT_SOC}/aarch64/platform_common.c             \
+                ${MTK_PLAT_SOC}/aarch64/plat_helpers.S                \
+                ${MTK_PLAT_SOC}/bl31_plat_setup.c                     \
+                ${MTK_PLAT_SOC}/plat_pm.c                             \
+                ${MTK_PLAT_SOC}/plat_topology.c
+
+# Configs for A76 and A55
+HW_ASSISTED_COHERENCY := 1
+USE_COHERENT_MEM := 0
+CTX_INCLUDE_AARCH32_REGS := 0
+ERRATA_A55_1530923 := 1
+ERRATA_A55_1221012 := 1
+
+# indicate the reset vector address can be programmed
+PROGRAMMABLE_RESET_ADDRESS := 1
+
+COLD_BOOT_SINGLE_CPU := 1
+
+MACH_MT8186 := 1
+$(eval $(call add_define,MACH_MT8186))
+
+include lib/coreboot/coreboot.mk
diff --git a/plat/mediatek/mt8195/aarch64/platform_common.c b/plat/mediatek/mt8195/aarch64/platform_common.c
index 4792746..2b95171 100644
--- a/plat/mediatek/mt8195/aarch64/platform_common.c
+++ b/plat/mediatek/mt8195/aarch64/platform_common.c
@@ -21,6 +21,14 @@
 			MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(eDP_SEC_BASE, eDP_SEC_SIZE,
 			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(APUSYS_SCTRL_REVISER_BASE, APUSYS_SCTRL_REVISER_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(APUSYS_APU_S_S_4_BASE, APUSYS_APU_S_S_4_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(APUSYS_APU_PLL_BASE, APUSYS_APU_PLL_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(APUSYS_APU_ACC_BASE, APUSYS_APU_ACC_SIZE,
+			MT_DEVICE | MT_RW | MT_SECURE),
 	{ 0 }
 };
 
diff --git a/plat/mediatek/mt8195/drivers/apusys/apupll.c b/plat/mediatek/mt8195/drivers/apusys/apupll.c
new file mode 100644
index 0000000..0eb8d4a
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/apusys/apupll.c
@@ -0,0 +1,581 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/spinlock.h>
+
+#include <apupwr_clkctl.h>
+#include <apupwr_clkctl_def.h>
+#include <mtk_plat_common.h>
+#include <platform_def.h>
+
+uint32_t mixed_con0_addr[APUPLL_MAX] = {
+	APU_PLL4H_PLL1_CON0,
+	APU_PLL4H_PLL2_CON0,
+	APU_PLL4H_PLL3_CON0,
+	APU_PLL4H_PLL4_CON0,
+};
+
+uint32_t mixed_con1_addr[APUPLL_MAX] = {
+	APU_PLL4H_PLL1_CON1,
+	APU_PLL4H_PLL2_CON1,
+	APU_PLL4H_PLL3_CON1,
+	APU_PLL4H_PLL4_CON1,
+};
+
+uint32_t mixed_con3_addr[APUPLL_MAX] = {
+	APU_PLL4H_PLL1_CON3,
+	APU_PLL4H_PLL2_CON3,
+	APU_PLL4H_PLL3_CON3,
+	APU_PLL4H_PLL4_CON3,
+};
+
+uint32_t fhctl_dds_addr[APUPLL_MAX] = {
+	APU_PLL4H_FHCTL0_DDS,
+	APU_PLL4H_FHCTL1_DDS,
+	APU_PLL4H_FHCTL2_DDS,
+	APU_PLL4H_FHCTL3_DDS,
+};
+
+uint32_t fhctl_dvfs_addr[APUPLL_MAX] = {
+	APU_PLL4H_FHCTL0_DVFS,
+	APU_PLL4H_FHCTL1_DVFS,
+	APU_PLL4H_FHCTL2_DVFS,
+	APU_PLL4H_FHCTL3_DVFS,
+};
+
+uint32_t fhctl_mon_addr[APUPLL_MAX] = {
+	APU_PLL4H_FHCTL0_MON,
+	APU_PLL4H_FHCTL1_MON,
+	APU_PLL4H_FHCTL2_MON,
+	APU_PLL4H_FHCTL3_MON,
+};
+
+uint32_t fhctl_cfg_addr[APUPLL_MAX] = {
+	APU_PLL4H_FHCTL0_CFG,
+	APU_PLL4H_FHCTL1_CFG,
+	APU_PLL4H_FHCTL2_CFG,
+	APU_PLL4H_FHCTL3_CFG,
+};
+
+static spinlock_t apupll_lock;
+static spinlock_t npupll_lock;
+static spinlock_t apupll_1_lock;
+static spinlock_t apupll_2_lock;
+static uint32_t pll_cnt[APUPLL_MAX];
+/**
+ * vd2pllidx() - voltage domain to pll idx.
+ * @domain: the voltage domain for getting pll index.
+ *
+ * Caller will get correspond pll index by different voltage domain.
+ * pll_idx[0] --> APUPLL (MDLA0/1)
+ * pll_idx[1] --> NPUPLL (VPU0/1)
+ * pll_idx[2] --> APUPLL1(CONN)
+ * pll_idx[3] --> APUPLL2(IOMMU)
+ * The longer description may have multiple paragraphs.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 ~ 3	- return the corresponding pll index
+ * * -EEXIST	- cannot find pll idex of the specific voltage domain
+ *
+ */
+static int32_t vd2pllidx(enum dvfs_voltage_domain domain)
+{
+	int32_t ret;
+
+	switch (domain) {
+	case V_VPU0:
+	case V_VPU1:
+		ret = NPUPLL;
+		break;
+	case V_MDLA0:
+	case V_MDLA1:
+		ret = APUPLL;
+		break;
+	case V_TOP_IOMMU:
+		ret = APUPLL2;
+		break;
+	case V_APU_CONN:
+		ret = APUPLL1;
+		break;
+	default:
+		ERROR("%s wrong voltage domain: %d\n", __func__, domain);
+		ret = -EEXIST; /* non-exist */
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * pllidx2name() - return names of specific pll index.
+ * @pll_idx: input for specific pll index.
+ *
+ * Given pll index, this function will return name of it.
+ *
+ * Context: Any context.
+ * Return: Names of pll_idx, if found, otherwise will return "NULL"
+ */
+static const char *pllidx2name(int32_t pll_idx)
+{
+	static const char *const names[] = {
+		[APUPLL] = "PLL4H_PLL1",
+		[NPUPLL] = "PLL4H_PLL2",
+		[APUPLL1] = "PLL4H_PLL3",
+		[APUPLL2] = "PLL4H_PLL4",
+		[APUPLL_MAX] = "NULL",
+	};
+
+	if (pll_idx >= APUPLL_MAX) {
+		pll_idx = APUPLL_MAX;
+	}
+
+	return names[pll_idx];
+}
+
+/**
+ * _fhctl_mon_done() - poll whether fhctl HW mode is done.
+ * @pll_idx: input for specific pll index.
+ * @tar_dds: target dds for fhctl_mon to be.
+ *
+ * Given pll index, this function will continue to poll whether fhctl_mon
+ * has reached the expected value within 80us.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 - OK for fhctl_mon == tar_dds
+ * * -ETIMEDOUT - fhctl_mon not reach tar_dds
+ */
+static int32_t _fhctl_mon_done(uint32_t pll_idx, unsigned long tar_dds)
+{
+	unsigned long mon_dds;
+	uint64_t timeout = timeout_init_us(PLL_READY_TIME_20US);
+	int32_t ret = 0;
+
+	tar_dds &= DDS_MASK;
+	do {
+		mon_dds = apupwr_readl(fhctl_mon_addr[pll_idx]) & DDS_MASK;
+		if (mon_dds == tar_dds) {
+			break;
+		}
+
+		if (timeout_elapsed(timeout)) {
+			ERROR("%s monitor DDS 0x%08lx != expect 0x%08lx\n",
+				  pllidx2name(pll_idx), mon_dds, tar_dds);
+			ret = -ETIMEDOUT;
+			break;
+		}
+	} while (mon_dds != tar_dds);
+
+	return ret;
+}
+
+/**
+ * _pll_get_postdiv_reg() - return current post dividor of pll_idx
+ * @pll_idx: input for specific pll index.
+ *
+ * Given pll index, this function will return its current post dividor.
+ *
+ * Context: Any context.
+ * Return: post dividor of current pll_idx.
+ *
+ */
+static uint32_t _pll_get_postdiv_reg(uint32_t pll_idx)
+{
+	int32_t pll_postdiv_reg = 0;
+	uint32_t val;
+
+	val = apupwr_readl(mixed_con1_addr[pll_idx]);
+	pll_postdiv_reg = (val >> POSDIV_SHIFT) & POSDIV_MASK;
+	return pll_postdiv_reg;
+}
+
+/**
+ * _set_postdiv_reg() - set pll_idx's post dividor.
+ * @pll_idx: Which PLL to enable/disable
+ * @post_div: the register value of post dividor to be wrtten.
+ *
+ * Below are lists of post dividor register value and its meaning:
+ * [31]     APUPLL_SDM_PCW_CHG
+ * [26:24]  APUPLL_POSDIV
+ * [21:0]   APUPLL_SDM_PCW (8bit integer + 14bit fraction)
+ * expected freq range ----- divider-------post divider in reg:
+ * >1500M   (1500/ 1)         -> 1        -> 0(2 to the zero power)
+ * > 750M   (1500/ 2)         -> 2        -> 1(2 to the 1st  power)
+ * > 375M   (1500/ 4)         -> 4        -> 2(2 to the 2nd  power)
+ * > 187.5M (1500/ 8)         -> 8        -> 3(2 to the 3rd  power)
+ * > 93.75M (1500/16)         -> 16       -> 4(2 to the 4th  power)
+ *
+ * Context: Any context.
+ */
+static void _set_postdiv_reg(uint32_t pll_idx, uint32_t post_div)
+{
+	apupwr_clrbits(POSDIV_MASK << POSDIV_SHIFT, mixed_con1_addr[pll_idx]);
+	apupwr_setbits((post_div & POSDIV_MASK) << POSDIV_SHIFT,
+			mixed_con1_addr[pll_idx]);
+}
+
+/**
+ * _cal_pll_data() - input freq, calculate correspond post dividor and dds.
+ * @pd: address of output post dividor.
+ * @dds: address of output dds.
+ * @freq: input frequency.
+ *
+ * Given freq, this function will calculate correspond post dividor and dds.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 - done for calculating post dividor and dds.
+ */
+static int32_t _cal_pll_data(uint32_t *pd, uint32_t *dds, uint32_t freq)
+{
+	uint32_t vco, postdiv_val = 1, postdiv_reg = 0;
+	uint32_t pcw_val;
+
+	vco = freq;
+	postdiv_val = 1;
+	postdiv_reg = 0;
+	while (vco <= FREQ_VCO_MIN) {
+		postdiv_val = postdiv_val << 1;
+		postdiv_reg = postdiv_reg + 1;
+		vco = vco << 1;
+	}
+
+	pcw_val = vco * (1 << PCW_FRACTIONAL_SHIFT);
+	pcw_val = pcw_val / FREQ_FIN;
+
+	if (postdiv_reg == 0) { /* Fvco * 2 with post_divider = 2 */
+		pcw_val = pcw_val * 2;
+		postdiv_val = postdiv_val << 1;
+		postdiv_reg = postdiv_reg + 1;
+	} /* Post divider is 1 is not available */
+	*pd = postdiv_reg;
+	*dds = pcw_val | RG_PLL_SDM_PCW_CHG;
+
+	return 0;
+}
+
+/**
+ * _pll_en() - enable/disable RG_PLL_EN of CON1 for pll[pll_idx]
+ * @pll_idx: Which PLL to enable/disable
+ * @on: 1 -> enable, 0 -> disable.
+ *
+ * This funciton will only change RG_PLL_EN of CON1 for pll[pll_idx].
+ *
+ * Context: Any context.
+ */
+static void _pll_en(uint32_t pll_idx, bool on)
+{
+	if (on) {
+		apupwr_setbits(RG_PLL_EN, mixed_con0_addr[pll_idx]);
+	} else {
+		apupwr_clrbits(RG_PLL_EN, mixed_con0_addr[pll_idx]);
+	}
+}
+
+/**
+ * _pll_pwr() - enable/disable PLL_SDM_PWR_ON of CON3 for pll[pll_idx]
+ * @pll_idx: Which PLL to enable/disable
+ * @on: 1 -> enable, 0 -> disable.
+ *
+ * This funciton will only change PLL_SDM_PWR_ON of CON3 for pll[pll_idx].
+ *
+ * Context: Any context.
+ */
+static void _pll_pwr(uint32_t pll_idx, bool on)
+{
+	if (on) {
+		apupwr_setbits(DA_PLL_SDM_PWR_ON, mixed_con3_addr[pll_idx]);
+	} else {
+		apupwr_clrbits(DA_PLL_SDM_PWR_ON, mixed_con3_addr[pll_idx]);
+	}
+}
+
+/**
+ * _pll_iso() - enable/disable PLL_SDM_ISO_EN of CON3 for pll[pll_idx]
+ * @pll_idx: Which PLL to enable/disable
+ * @enable: 1 -> turn on isolation, 0 -> turn off isolation.
+ *
+ * This funciton will turn on/off pll isolation by
+ * changing PLL_SDM_PWR_ON of CON3 for pll[pll_idx].
+ *
+ * Context: Any context.
+ */
+static void _pll_iso(uint32_t pll_idx, bool enable)
+{
+	if (enable) {
+		apupwr_setbits(DA_PLL_SDM_ISO_EN, mixed_con3_addr[pll_idx]);
+	} else {
+		apupwr_clrbits(DA_PLL_SDM_ISO_EN, mixed_con3_addr[pll_idx]);
+	}
+}
+
+/**
+ * _pll_switch() - entry point to turn whole PLL on/off
+ * @pll_idx: Which PLL to enable/disable
+ * @on: 1 -> enable, 0 -> disable.
+ * @fhctl_en: enable or disable fhctl function
+ *
+ * This is the entry poing for controlling pll and fhctl funciton on/off.
+ * Caller can chose only enable pll instead of fhctl function.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0		- done for enable pll or fhctl as well.
+ */
+static int32_t _pll_switch(uint32_t pll_idx, bool on, bool fhctl_en)
+{
+	int32_t ret = 0;
+
+	if (pll_idx >= APUPLL_MAX) {
+		ERROR("%s wrong pll_idx: %d\n", __func__, pll_idx);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (on) {
+		_pll_pwr(pll_idx, true);
+		udelay(PLL_CMD_READY_TIME_1US);
+		_pll_iso(pll_idx, false);
+		udelay(PLL_CMD_READY_TIME_1US);
+		_pll_en(pll_idx, true);
+		udelay(PLL_READY_TIME_20US);
+	} else {
+		_pll_en(pll_idx, false);
+		_pll_iso(pll_idx, true);
+		_pll_pwr(pll_idx, false);
+	}
+
+err:
+	return ret;
+}
+
+/**
+ * apu_pll_enable() - API for smc function to enable/disable pll
+ * @pll_idx: Which pll to enable/disable.
+ * @enable: 1 -> enable, 0 -> disable.
+ * @fhctl_en: enable or disable fhctl function
+ *
+ * pll_idx[0] --> APUPLL (MDLA0/1)
+ * pll_idx[1] --> NPUPLL (VPU0/1)
+ * pll_idx[2] --> APUPLL1(CONN)
+ * pll_idx[3] --> APUPLL2(IOMMU)
+ * The differences between _pll_switch are:
+ * 1. Atomic update pll reference cnt to protect double enable pll &
+ * close pll during user is not zero.
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 - done for enable pll or fhctl as well.
+ */
+int32_t apu_pll_enable(int32_t pll_idx, bool enable, bool fhctl_en)
+{
+	int32_t ret = 0;
+
+	if (pll_idx >= APUPLL_MAX) {
+		ERROR("%s wrong pll_idx: %d\n", __func__, pll_idx);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (enable) {
+		switch (pll_idx) {
+		case APUPLL:
+			spin_lock(&apupll_lock);
+			if (pll_cnt[APUPLL] == 0) {
+				_pll_switch(pll_idx, enable, fhctl_en);
+			}
+			pll_cnt[APUPLL]++;
+			spin_unlock(&apupll_lock);
+			break;
+		case NPUPLL:
+			spin_lock(&npupll_lock);
+			if (pll_cnt[NPUPLL] == 0) {
+				_pll_switch(pll_idx, enable, fhctl_en);
+			}
+			pll_cnt[NPUPLL]++;
+			spin_unlock(&npupll_lock);
+			break;
+		case APUPLL1:
+			spin_lock(&apupll_1_lock);
+			if (pll_cnt[APUPLL1] == 0) {
+				_pll_switch(pll_idx, enable, fhctl_en);
+			}
+			pll_cnt[APUPLL1]++;
+			spin_unlock(&apupll_1_lock);
+			break;
+		case APUPLL2:
+			spin_lock(&apupll_2_lock);
+			if (pll_cnt[APUPLL2] == 0) {
+				_pll_switch(pll_idx, enable, fhctl_en);
+			}
+			pll_cnt[APUPLL2]++;
+			spin_unlock(&apupll_2_lock);
+			break;
+		default:
+			ERROR("%s invalid pll_idx: %d\n", __func__, pll_idx);
+			ret = -EINVAL;
+			break;
+		}
+	} else {
+		switch (pll_idx) {
+		case APUPLL:
+			spin_lock(&apupll_lock);
+			if (pll_cnt[APUPLL]) {
+				pll_cnt[APUPLL]--;
+			}
+			if (pll_cnt[APUPLL] == 0) {
+				_pll_switch(pll_idx, enable, fhctl_en);
+			}
+			spin_unlock(&apupll_lock);
+			break;
+		case NPUPLL:
+			spin_lock(&npupll_lock);
+			if (pll_cnt[NPUPLL]) {
+				pll_cnt[NPUPLL]--;
+			}
+			if (pll_cnt[NPUPLL] == 0) {
+				_pll_switch(pll_idx, enable, fhctl_en);
+			}
+			spin_unlock(&npupll_lock);
+			break;
+		case APUPLL1:
+			spin_lock(&apupll_1_lock);
+			if (pll_cnt[APUPLL1]) {
+				pll_cnt[APUPLL1]--;
+			}
+			if (pll_cnt[APUPLL1] == 0) {
+				_pll_switch(pll_idx, enable, fhctl_en);
+			}
+			spin_unlock(&apupll_1_lock);
+			break;
+		case APUPLL2:
+			spin_lock(&apupll_2_lock);
+			if (pll_cnt[APUPLL2]) {
+				pll_cnt[APUPLL2]--;
+			}
+			if (pll_cnt[APUPLL2] == 0) {
+				_pll_switch(pll_idx, enable, fhctl_en);
+			}
+			spin_unlock(&apupll_2_lock);
+			break;
+		default:
+			ERROR("%s invalid pll_idx: %d\n", __func__, pll_idx);
+			ret = -EINVAL;
+			break;
+		}
+	}
+
+err:
+	return ret;
+}
+
+/**
+ * anpu_pll_set_rate() - API for smc function to set rate of voltage domain.
+ * @domain: Which pll of correspond voltage domain to change rate.
+ * @mode: which mode to use when set_rate
+ * @freq: which frequency to set.
+ *
+ * For V_VPU0/1, it will only allow 1 of them to modify NPUPLL
+ * such that there will be no race condition happen.
+ *
+ * For V_MDLA0/1, it will only allow 1 of them to modify APUPLL1
+ * such that there will be no race condition happen.
+ *
+ * There are 3 kinds of modes to set pll's rate.
+ * 1. pure sw mode: (CON0_PCW)
+ *        fhctl function is off and change rate by programming CON1_PCW.
+ * 2. fhctl sw mode: (FHCTL_SW)
+ *        fhctl function is on and change rate by programming fhctl_dds.
+ *        (post dividor is still need to program CON1_PCW)
+ * 3. fhctl hw mode: (FHCTL_HW)
+ *        fhctl function is on and change rate by programming fhctl_dvfs.
+ *        (post dividor is still need to program CON1_PCW)
+ *
+ * Context: Any context.
+ * Return:
+ * * 0 - done for set rate of voltage domain.
+ */
+int32_t anpu_pll_set_rate(enum dvfs_voltage_domain domain,
+		      enum pll_set_rate_mode mode, int32_t freq)
+{
+	uint32_t pd, old_pd, dds;
+	int32_t pll_idx, ret = 0;
+
+	pll_idx = vd2pllidx(domain);
+	if (pll_idx < 0) {
+		ret = pll_idx;
+		goto err;
+	}
+
+	_cal_pll_data(&pd, &dds, freq / 1000);
+
+	INFO("%s %s new post_div=%d, target dds=0x%08x(%dMhz) mode = %d\n",
+	     __func__, pllidx2name(pll_idx), pd, dds, freq / 1000, mode);
+
+	/* spin_lock for NPULL, since vpu0/1 share npupll */
+	if (domain == V_VPU0 || domain == V_VPU1) {
+		spin_lock(&npupll_lock);
+	}
+
+	/* spin_lock for APUPLL, since mdla0/1 shate apupll */
+	if (domain == V_MDLA0 || domain == V_MDLA1) {
+		spin_lock(&apupll_lock);
+	}
+
+	switch (mode) {
+	case CON0_PCW:
+		pd = RG_PLL_SDM_PCW_CHG |
+		     (pd & POSDIV_MASK) << POSDIV_SHIFT | dds;
+		apupwr_writel(pd, mixed_con1_addr[pll_idx]);
+		udelay(PLL_READY_TIME_20US);
+		break;
+	case FHCTL_SW:
+		/* pll con0 disable */
+		_pll_en(pll_idx, false);
+		apupwr_writel(dds, fhctl_dds_addr[pll_idx]);
+		_set_postdiv_reg(pll_idx, pd);
+		apupwr_setbits(PLL_TGL_ORG, fhctl_dds_addr[pll_idx]);
+		udelay(PLL_CMD_READY_TIME_1US);
+		/* pll con0 enable */
+		_pll_en(pll_idx, true);
+		udelay(PLL_READY_TIME_20US);
+		break;
+	case FHCTL_HW:
+		old_pd = _pll_get_postdiv_reg(pll_idx);
+		if (pd > old_pd) {
+			_set_postdiv_reg(pll_idx, pd);
+			apupwr_writel(dds, fhctl_dvfs_addr[pll_idx]);
+		} else {
+			apupwr_writel(dds, fhctl_dvfs_addr[pll_idx]);
+			_set_postdiv_reg(pll_idx, pd);
+		}
+		ret = _fhctl_mon_done(pll_idx, dds);
+		break;
+	default:
+		ERROR("%s input wrong mode: %d\n", __func__, mode);
+		ret = -EINVAL;
+		break;
+	}
+
+	/* spin_lock for NPULL, since vpu0/1 share npupll */
+	if (domain == V_VPU0 || domain == V_VPU1) {
+		spin_unlock(&npupll_lock);
+	}
+
+	/* spin_lock for APUPLL, since mdla0/1 share apupll */
+	if (domain == V_MDLA0 || domain == V_MDLA1) {
+		spin_unlock(&apupll_lock);
+	}
+
+err:
+	return ret;
+}
diff --git a/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.c b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.c
new file mode 100644
index 0000000..465054d
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+
+#include <apupwr_clkctl.h>
+#include <apupwr_clkctl_def.h>
+#include <mtk_plat_common.h>
+#include <platform_def.h>
+
+/* 8195 use PCW mode to change freq directly */
+enum pll_set_rate_mode PLL_MODE = CON0_PCW;
+
+char *buck_domain_str[APUSYS_BUCK_DOMAIN_NUM] = {
+	"V_VPU0",
+	"V_VPU1",
+	"V_MDLA0",
+	"V_MDLA1",
+	"V_APU_CONN",
+	"V_TOP_IOMMU",
+	"V_VCORE",
+};
+
+uint32_t aacc_set[APUSYS_BUCK_DOMAIN_NUM] = {
+	APU_ACC_CONFG_SET1, APU_ACC_CONFG_SET2,
+	APU_ACC_CONFG_SET4, APU_ACC_CONFG_SET5,
+	APU_ACC_CONFG_SET0, APU_ACC_CONFG_SET7
+};
+
+uint32_t aacc_clr[APUSYS_BUCK_DOMAIN_NUM] = {
+	APU_ACC_CONFG_CLR1, APU_ACC_CONFG_CLR2,
+	APU_ACC_CONFG_CLR4, APU_ACC_CONFG_CLR5,
+	APU_ACC_CONFG_CLR0, APU_ACC_CONFG_CLR7
+};
+
+struct reg_seq {
+	uint32_t address;
+	uint32_t val;
+};
+
+static const struct reg_seq init_acc_cfg[] = {
+	{ APU_ACC_CONFG_SET0, BIT(BIT_SEL_APU) },
+	{ APU_ACC_CONFG_CLR0, BIT(BIT_CGEN_SOC) },
+	{ APU_ACC_CONFG_SET0, BIT(BIT_SEL_APU_DIV2) },
+	{ APU_ACC_CONFG_SET7, BIT(BIT_SEL_APU) },
+	{ APU_ACC_CONFG_CLR7, BIT(BIT_CGEN_SOC) },
+	{ APU_ACC_CONFG_SET7, BIT(BIT_SEL_APU_DIV2) },
+	{ APU_ACC_CONFG_SET1, BIT(BIT_SEL_APU) },
+	{ APU_ACC_CONFG_CLR1, BIT(BIT_CGEN_SOC) },
+	{ APU_ACC_CONFG_SET1, BIT(BIT_SEL_APU_DIV2) },
+	{ APU_ACC_CONFG_SET2, BIT(BIT_INVEN_OUT) },
+	{ APU_ACC_CONFG_SET2, BIT(BIT_SEL_APU) },
+	{ APU_ACC_CONFG_CLR2, BIT(BIT_CGEN_SOC) },
+	{ APU_ACC_CONFG_SET2, BIT(BIT_SEL_APU_DIV2) },
+	{ APU_ACC_CONFG_SET4, BIT(BIT_SEL_APU) },
+	{ APU_ACC_CONFG_CLR4, BIT(BIT_CGEN_SOC) },
+	{ APU_ACC_CONFG_SET4, BIT(BIT_SEL_APU_DIV2) },
+	{ APU_ACC_CONFG_SET5, BIT(BIT_INVEN_OUT) },
+	{ APU_ACC_CONFG_SET5, BIT(BIT_SEL_APU) },
+	{ APU_ACC_CONFG_CLR5, BIT(BIT_CGEN_SOC) },
+	{ APU_ACC_CONFG_SET5, BIT(BIT_SEL_APU_DIV2) },
+};
+
+int32_t apupwr_smc_acc_init_all(void)
+{
+	int32_t i;
+
+	for (i = 0; i < ARRAY_SIZE(init_acc_cfg); i++) {
+		apupwr_writel(init_acc_cfg[i].val,
+			      init_acc_cfg[i].address);
+	}
+
+	/* Deault ACC will raise APU_DIV_2 */
+	apupwr_smc_pll_set_rate(BUCK_VCONN_DOMAIN_DEFAULT_FREQ,
+				true, V_APU_CONN);
+
+	apupwr_smc_pll_set_rate(BUCK_VCONN_DOMAIN_DEFAULT_FREQ,
+				true, V_TOP_IOMMU);
+
+	apupwr_smc_pll_set_rate(BUCK_VVPU_DOMAIN_DEFAULT_FREQ,
+				true, V_VPU0);
+
+	apupwr_smc_pll_set_rate(BUCK_VMDLA_DOMAIN_DEFAULT_FREQ,
+				true, V_MDLA0);
+
+	return 0;
+}
+
+void apupwr_smc_acc_top(bool enable)
+{
+	if (enable) {
+		apupwr_writel(BIT(BIT_CGEN_APU), aacc_set[V_APU_CONN]);
+		apupwr_writel(BIT(BIT_CGEN_APU), aacc_set[V_TOP_IOMMU]);
+	} else {
+		apupwr_writel(BIT(BIT_CGEN_APU), aacc_clr[V_APU_CONN]);
+		apupwr_writel(BIT(BIT_CGEN_APU), aacc_clr[V_TOP_IOMMU]);
+	}
+}
+
+/*
+ * acc_clk_set_parent:ACC MUX select
+ * 0. freq parameters here, only ACC clksrc is valid
+ * 1. Switch between APUPLL <=> Parking (F26M, PARK)
+ * 2. Turn on/off CG_F26M, CG_PARK, CG_SOC, but no CG_APU
+ * 3. Clear APU Div2 while Parking
+ * 4. Only use clksrc of APUPLL while ACC CG_APU is on
+ */
+int32_t apupwr_smc_acc_set_parent(uint32_t freq, uint32_t domain)
+{
+	uint32_t acc_set = 0;
+	uint32_t acc_clr = 0;
+	int32_t ret = 0;
+
+	if (freq > DVFS_FREQ_ACC_APUPLL) {
+		ERROR("%s wrong clksrc: %d\n", __func__, freq);
+		ret = -EIO;
+		goto err;
+	}
+
+	switch (domain) {
+	case V_VPU1:
+	case V_VPU0:
+	case V_MDLA1:
+	case V_MDLA0:
+	case V_APU_CONN:
+	case V_TOP_IOMMU:
+		acc_set = aacc_set[domain];
+		acc_clr = aacc_clr[domain];
+		break;
+	default:
+		ret = -EIO;
+		break;
+	}
+
+	/* Select park source */
+	switch (freq) {
+	case DVFS_FREQ_ACC_PARKING:
+		/* Select park source */
+		apupwr_writel(BIT(BIT_SEL_PARK), acc_set);
+		apupwr_writel(BIT(BIT_SEL_F26M), acc_clr);
+		/* Enable park cg */
+		apupwr_writel(BIT(BIT_CGEN_PARK), acc_set);
+		apupwr_writel(BIT(BIT_CGEN_F26M) | BIT(BIT_CGEN_SOC), acc_clr);
+		/* Select park path */
+		apupwr_writel(BIT(BIT_SEL_APU), acc_clr);
+		/* clear apu div 2 */
+		apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr);
+		break;
+
+	case DVFS_FREQ_ACC_APUPLL:
+		/* Select park path */
+		apupwr_writel(BIT(BIT_SEL_APU), acc_set);
+		/* Clear park cg */
+		apupwr_writel(BIT(BIT_CGEN_PARK) | BIT(BIT_CGEN_F26M) |
+			      BIT(BIT_CGEN_SOC), acc_clr);
+		break;
+
+	case DVFS_FREQ_ACC_SOC:
+		/* Select park source */
+		apupwr_writel(BIT(BIT_SEL_PARK), acc_clr);
+		apupwr_writel(BIT(BIT_SEL_F26M), acc_clr);
+		/* Enable park cg */
+		apupwr_writel(BIT(BIT_CGEN_SOC), acc_set);
+		apupwr_writel(BIT(BIT_CGEN_F26M) | BIT(BIT_CGEN_PARK), acc_clr);
+		/* Select park path */
+		apupwr_writel(BIT(BIT_SEL_APU), acc_clr);
+		/* clear apu div 2 */
+		apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr);
+		break;
+
+	case DVFS_FREQ_ACC_26M:
+	case DVFS_FREQ_NOT_SUPPORT:
+	default:
+		/* Select park source */
+		apupwr_writel(BIT(BIT_SEL_F26M), acc_set);
+		apupwr_writel(BIT(BIT_SEL_PARK), acc_clr);
+		/* Enable park cg */
+		apupwr_writel(BIT(BIT_CGEN_F26M), acc_set);
+		apupwr_writel(BIT(BIT_CGEN_PARK) | BIT(BIT_CGEN_SOC), acc_clr);
+		/* Select park path */
+		apupwr_writel(BIT(BIT_SEL_APU), acc_clr);
+		/* clear apu div 2 */
+		apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_clr);
+		ERROR("[APUPWR] %s wrong ACC clksrc : %d, force assign 26M\n",
+		      __func__, freq);
+		break;
+	}
+
+err:
+	return ret;
+}
+
+int32_t apupwr_smc_pll_set_rate(uint32_t freq, bool div2, uint32_t domain)
+{
+	int32_t ret = 0;
+	uint32_t acc_set0 = 0, acc_set1 = 0;
+
+	if (freq > DVFS_FREQ_MAX) {
+		ERROR("%s wrong freq: %d\n", __func__, freq);
+		ret = -EIO;
+		goto err;
+	}
+
+	/*
+	 * Switch to Parking src
+	 * 1. Need to switch out all ACCs sharing the same apupll
+	 */
+	switch (domain) {
+	case V_MDLA0:
+	case V_MDLA1:
+		acc_set0 = APU_ACC_CONFG_SET4;
+		acc_set1 = APU_ACC_CONFG_SET5;
+		ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
+						V_MDLA0);
+		ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
+						V_MDLA1);
+		break;
+	case V_VPU0:
+	case V_VPU1:
+		acc_set0 = APU_ACC_CONFG_SET1;
+		acc_set1 = APU_ACC_CONFG_SET2;
+		ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
+						V_VPU0);
+		ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
+						V_VPU1);
+		break;
+	case V_APU_CONN:
+		acc_set0 = APU_ACC_CONFG_SET0;
+		ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
+						V_APU_CONN);
+		break;
+	case V_TOP_IOMMU:
+		acc_set0 = APU_ACC_CONFG_SET7;
+		ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_PARKING,
+						V_TOP_IOMMU);
+		break;
+	default:
+		ERROR("[APUPWR] %s %d invalid domain (%d)\n",
+		      __func__, __LINE__, domain);
+		ret = -EIO;
+		goto err;
+	}
+
+	anpu_pll_set_rate(domain, PLL_MODE, (div2) ? (freq * 2) : freq);
+
+	if (div2) {
+		apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_set0);
+		if (acc_set1) {
+			apupwr_writel(BIT(BIT_SEL_APU_DIV2), acc_set1);
+		}
+	}
+
+	/*
+	 * Switch back to APUPLL
+	 * Only switch back to APUPLL while CG_APU on
+	 * And clksrc is not APUPLL
+	 */
+	switch (domain) {
+	case V_VPU0:
+	case V_VPU1:
+		if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) &&
+		     !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) {
+			ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
+							V_VPU0);
+		}
+		if ((apupwr_readl(acc_set1) & BIT(BIT_CGEN_APU)) &&
+		     !(apupwr_readl(acc_set1) & BIT(BIT_SEL_APU))) {
+			ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
+							V_VPU1);
+		}
+		break;
+	case V_MDLA0:
+	case V_MDLA1:
+		if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) &&
+		     !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) {
+			ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
+							V_MDLA0);
+		}
+		if ((apupwr_readl(acc_set1) & BIT(BIT_CGEN_APU)) &&
+		     !(apupwr_readl(acc_set1) & BIT(BIT_SEL_APU))) {
+			ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
+							V_MDLA1);
+		}
+		break;
+	case V_APU_CONN:
+	case V_TOP_IOMMU:
+		if ((apupwr_readl(acc_set0) & BIT(BIT_CGEN_APU)) &&
+		    !(apupwr_readl(acc_set0) & BIT(BIT_SEL_APU))) {
+			ret = apupwr_smc_acc_set_parent(DVFS_FREQ_ACC_APUPLL,
+							domain);
+		}
+		break;
+	default:
+		ERROR("[APUPWR] %s %d invalid domain (%d)\n",
+		      __func__, __LINE__, domain);
+		ret = -EIO;
+		break;
+	}
+	INFO("[%s][%d] set domain %d to freq %d\n",
+	     __func__, __LINE__, domain, (div2) ? (freq * 2) : freq);
+
+err:
+	return ret;
+}
+
+int32_t apupwr_smc_bulk_pll(bool enable)
+{
+	int32_t ret = 0;
+	int32_t pll_idx;
+
+	if (enable) {
+		for (pll_idx = APUPLL; pll_idx < APUPLL_MAX; pll_idx++) {
+			ret = apu_pll_enable(pll_idx, enable, false);
+			if (ret != 0) {
+				goto err;
+			}
+		}
+	} else {
+		for (pll_idx = APUPLL2; pll_idx >= APUPLL; pll_idx--) {
+			ret = apu_pll_enable(pll_idx, enable, false);
+			if (ret != 0) {
+				goto err;
+			}
+		}
+	}
+
+err:
+	return ret;
+}
+
+void apupwr_smc_bus_prot_cg_on(void)
+{
+	apupwr_clrbits(AO_MD32_MNOC_MASK, APU_CSR_DUMMY_0);
+}
diff --git a/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.h b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.h
new file mode 100644
index 0000000..3b27c1b
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUPWR_CLKCTL_H
+#define APUPWR_CLKCTL_H
+
+#include <arch_helpers.h>
+#include <apupwr_clkctl_def.h>
+
+int32_t apupwr_smc_acc_init_all(void);
+void apupwr_smc_acc_top(bool enable);
+int32_t apupwr_smc_acc_set_parent(uint32_t freq, uint32_t domain);
+int32_t apupwr_smc_pll_set_rate(uint32_t pll, bool div2, uint32_t domain);
+int32_t apupwr_smc_bulk_pll(bool enable);
+void apupwr_smc_bus_prot_cg_on(void);
+
+int32_t apu_pll_enable(int32_t pll_idx, bool enable, bool fhctl_en);
+int32_t anpu_pll_set_rate(enum dvfs_voltage_domain domain,
+			  enum pll_set_rate_mode mode, int32_t freq);
+#endif /* APUPWR_CLKCTL_H */
diff --git a/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl_def.h b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl_def.h
new file mode 100644
index 0000000..6663ad9
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/apusys/apupwr_clkctl_def.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef APUPWR_CLKCTL_DEF_H
+#define APUPWR_CLKCTL_DEF_H
+
+#include <lib/mmio.h>
+
+enum dvfs_voltage_domain {
+	V_VPU0			= 0,
+	V_VPU1			= 1,
+	V_MDLA0			= 2,
+	V_MDLA1			= 3,
+	V_APU_CONN		= 4,
+	V_TOP_IOMMU		= 5,
+	V_VCORE			= 6,
+	APUSYS_BUCK_DOMAIN_NUM	= 7,
+};
+
+enum dvfs_freq {
+	DVFS_FREQ_NOT_SUPPORT	= 0,
+	DVFS_FREQ_ACC_26M	= 1,
+	DVFS_FREQ_ACC_PARKING	= 2,
+	DVFS_FREQ_ACC_SOC	= 3,
+	DVFS_FREQ_ACC_APUPLL	= 4,
+	DVFS_FREQ_00_026000_F	= 26000,
+	DVFS_FREQ_00_208000_F	= 208000,
+	DVFS_FREQ_00_238000_F	= 238000,
+	DVFS_FREQ_00_273000_F	= 273000,
+	DVFS_FREQ_00_312000_F	= 312000,
+	DVFS_FREQ_00_358000_F	= 358000,
+	DVFS_FREQ_00_385000_F	= 385000,
+	DVFS_FREQ_00_499200_F	= 499200,
+	DVFS_FREQ_00_500000_F	= 500000,
+	DVFS_FREQ_00_525000_F	= 525000,
+	DVFS_FREQ_00_546000_F	= 546000,
+	DVFS_FREQ_00_594000_F	= 594000,
+	DVFS_FREQ_00_624000_F	= 624000,
+	DVFS_FREQ_00_688000_F	= 688000,
+	DVFS_FREQ_00_687500_F	= 687500,
+	DVFS_FREQ_00_728000_F	= 728000,
+	DVFS_FREQ_00_800000_F	= 800000,
+	DVFS_FREQ_00_832000_F	= 832000,
+	DVFS_FREQ_00_960000_F	= 960000,
+	DVFS_FREQ_00_1100000_F	= 1100000,
+};
+#define DVFS_FREQ_MAX (DVFS_FREQ_00_1100000_F)
+
+enum pll_set_rate_mode {
+	CON0_PCW		= 0,
+	FHCTL_SW		= 1,
+	FHCTL_HW		= 2,
+	PLL_SET_RATE_MODE_MAX	= 3,
+};
+
+enum apupll {
+	APUPLL		= 0,
+	NPUPLL		= 1,
+	APUPLL1		= 2,
+	APUPLL2		= 3,
+	APUPLL_MAX	= 4,
+};
+
+#define BUCK_VVPU_DOMAIN_DEFAULT_FREQ	(DVFS_FREQ_00_273000_F)
+#define BUCK_VMDLA_DOMAIN_DEFAULT_FREQ	(DVFS_FREQ_00_312000_F)
+#define BUCK_VCONN_DOMAIN_DEFAULT_FREQ	(DVFS_FREQ_00_208000_F)
+
+#define apupwr_writel(VAL, REG)		mmio_write_32((uintptr_t)REG, VAL)
+#define apupwr_writel_relax(VAL, REG)	mmio_write_32_relax((uintptr_t)REG, VAL)
+#define apupwr_readl(REG)		mmio_read_32((uintptr_t)REG)
+#define apupwr_clrbits(VAL, REG)	mmio_clrbits_32((uintptr_t)REG, VAL)
+#define apupwr_setbits(VAL, REG)	mmio_setbits_32((uintptr_t)REG, VAL)
+#define apupwr_clrsetbits(CLR_VAL, SET_VAL, REG)	\
+			  mmio_clrsetbits_32((uintptr_t)REG, CLR_VAL, SET_VAL)
+
+/* PLL and related register */
+#define APU_PLL_BASE		(APUSYS_APU_PLL_BASE)
+#define APU_PLL4H_PLL1_CON0	(APU_PLL_BASE + 0x008)
+#define APU_PLL4H_PLL1_CON1	(APU_PLL_BASE + 0x00C)
+#define APU_PLL4H_PLL1_CON3	(APU_PLL_BASE + 0x014)
+
+#define APU_PLL4H_PLL2_CON0	(APU_PLL_BASE + 0x018)
+#define APU_PLL4H_PLL2_CON1	(APU_PLL_BASE + 0x01C)
+#define APU_PLL4H_PLL2_CON3	(APU_PLL_BASE + 0x024)
+
+#define APU_PLL4H_PLL3_CON0	(APU_PLL_BASE + 0x028)
+#define APU_PLL4H_PLL3_CON1	(APU_PLL_BASE + 0x02C)
+#define APU_PLL4H_PLL3_CON3	(APU_PLL_BASE + 0x034)
+
+#define APU_PLL4H_PLL4_CON0	(APU_PLL_BASE + 0x038)
+#define APU_PLL4H_PLL4_CON1	(APU_PLL_BASE + 0x03C)
+#define APU_PLL4H_PLL4_CON3	(APU_PLL_BASE + 0x044)
+
+#define APU_PLL4H_FHCTL_HP_EN		(APU_PLL_BASE + 0x0E00)
+#define APU_PLL4H_FHCTL_UNITSLOPE_EN	(APU_PLL_BASE + 0x0E04)
+#define APU_PLL4H_FHCTL_CLK_CON		(APU_PLL_BASE + 0x0E08)
+#define APU_PLL4H_FHCTL_RST_CON		(APU_PLL_BASE + 0x0E0C)
+#define APU_PLL4H_FHCTL_SLOPE0		(APU_PLL_BASE + 0x0E10)
+#define APU_PLL4H_FHCTL_SLOPE1		(APU_PLL_BASE + 0x0E14)
+#define APU_PLL4H_FHCTL_DSSC_CFG	(APU_PLL_BASE + 0x0E18)
+#define APU_PLL4H_FHCTL_DSSC0_CON	(APU_PLL_BASE + 0x0E1C)
+#define APU_PLL4H_FHCTL_DSSC1_CON	(APU_PLL_BASE + 0x0E20)
+#define APU_PLL4H_FHCTL_DSSC2_CON	(APU_PLL_BASE + 0x0E24)
+#define APU_PLL4H_FHCTL_DSSC3_CON	(APU_PLL_BASE + 0x0E28)
+#define APU_PLL4H_FHCTL_DSSC4_CON	(APU_PLL_BASE + 0x0E2C)
+#define APU_PLL4H_FHCTL_DSSC5_CON	(APU_PLL_BASE + 0x0E30)
+#define APU_PLL4H_FHCTL_DSSC6_CON	(APU_PLL_BASE + 0x0E34)
+#define APU_PLL4H_FHCTL_DSSC7_CON	(APU_PLL_BASE + 0x0E38)
+#define APU_PLL4H_FHCTL0_CFG		(APU_PLL_BASE + 0x0E3C)
+#define APU_PLL4H_FHCTL0_UPDNLMT	(APU_PLL_BASE + 0x0E40)
+#define APU_PLL4H_FHCTL0_DDS		(APU_PLL_BASE + 0x0E44)
+#define APU_PLL4H_FHCTL0_DVFS		(APU_PLL_BASE + 0x0E48)
+#define APU_PLL4H_FHCTL0_MON		(APU_PLL_BASE + 0x0E4C)
+#define APU_PLL4H_FHCTL1_CFG		(APU_PLL_BASE + 0x0E50)
+#define APU_PLL4H_FHCTL1_UPDNLMT	(APU_PLL_BASE + 0x0E54)
+#define APU_PLL4H_FHCTL1_DDS		(APU_PLL_BASE + 0x0E58)
+#define APU_PLL4H_FHCTL1_DVFS		(APU_PLL_BASE + 0x0E5C)
+#define APU_PLL4H_FHCTL1_MON		(APU_PLL_BASE + 0x0E60)
+#define APU_PLL4H_FHCTL2_CFG		(APU_PLL_BASE + 0x0E64)
+#define APU_PLL4H_FHCTL2_UPDNLMT	(APU_PLL_BASE + 0x0E68)
+#define APU_PLL4H_FHCTL2_DDS		(APU_PLL_BASE + 0x0E6C)
+#define APU_PLL4H_FHCTL2_DVFS		(APU_PLL_BASE + 0x0E70)
+#define APU_PLL4H_FHCTL2_MON		(APU_PLL_BASE + 0x0E74)
+#define APU_PLL4H_FHCTL3_CFG		(APU_PLL_BASE + 0x0E78)
+#define APU_PLL4H_FHCTL3_UPDNLMT	(APU_PLL_BASE + 0x0E7C)
+#define APU_PLL4H_FHCTL3_DDS		(APU_PLL_BASE + 0x0E80)
+#define APU_PLL4H_FHCTL3_DVFS		(APU_PLL_BASE + 0x0E84)
+#define APU_PLL4H_FHCTL3_MON		(APU_PLL_BASE + 0x0E88)
+
+/* PLL4H_PLLx_CON0 */
+#define RG_PLL_EN		BIT(0)
+
+/* PLL4H_PLLx_CON1 */
+#define RG_PLL_SDM_PCW_CHG	BIT(31)
+#define POSDIV_SHIFT		(24U)
+#define POSDIV_MASK		(0x7)
+
+/* PLL4H_PLLx_CON3 */
+#define DA_PLL_SDM_PWR_ON	BIT(0)
+#define DA_PLL_SDM_ISO_EN	BIT(1)
+
+/* FHCTLx_DDS */
+#define DDS_MASK		GENMASK_32(21, 0)
+#define PCW_FRACTIONAL_SHIFT	14U
+#define PLL_TGL_ORG		BIT(31)
+
+#define PLL_READY_TIME_20US	(20U)
+#define PLL_CMD_READY_TIME_1US	(1U)
+
+#define FREQ_VCO_MIN		(1500U) /* 1500MHz*/
+#define FREQ_FIN		(26U)	/* 26M*/
+
+/* ACC and related register */
+#define APU_ACC_BASE		(APUSYS_APU_ACC_BASE)
+#define APU_ACC_CONFG_SET0	(APU_ACC_BASE + 0x000)
+#define APU_ACC_CONFG_SET1	(APU_ACC_BASE + 0x004)
+#define APU_ACC_CONFG_SET2	(APU_ACC_BASE + 0x008)
+#define APU_ACC_CONFG_SET4	(APU_ACC_BASE + 0x010)
+#define APU_ACC_CONFG_SET5	(APU_ACC_BASE + 0x014)
+#define APU_ACC_CONFG_SET7	(APU_ACC_BASE + 0x01C)
+
+#define APU_ACC_CONFG_CLR0	(APU_ACC_BASE + 0x040)
+#define APU_ACC_CONFG_CLR1	(APU_ACC_BASE + 0x044)
+#define APU_ACC_CONFG_CLR2	(APU_ACC_BASE + 0x048)
+#define APU_ACC_CONFG_CLR4	(APU_ACC_BASE + 0x050)
+#define APU_ACC_CONFG_CLR5	(APU_ACC_BASE + 0x054)
+#define APU_ACC_CONFG_CLR7	(APU_ACC_BASE + 0x05C)
+
+#define APU_ACC_FM_CONFG_SET	(APU_ACC_BASE + 0x0C0)
+#define APU_ACC_FM_CONFG_CLR	(APU_ACC_BASE + 0x0C4)
+#define APU_ACC_FM_SEL		(APU_ACC_BASE + 0x0C8)
+#define APU_ACC_FM_CNT		(APU_ACC_BASE + 0x0CC)
+
+/* APU AO control */
+#define APU_AO_CTRL_BASE	(APUSYS_APU_S_S_4_BASE)
+#define APU_CSR_DUMMY_0		(APU_AO_CTRL_BASE + 0x24)
+
+#define AO_MD32_MNOC_MASK	(BIT(1) | BIT(0))
+
+#define BIT_CGEN_F26M		(0)
+#define BIT_CGEN_PARK		(1)
+#define BIT_CGEN_SOC		(2)
+#define BIT_CGEN_APU		(3)
+#define BIT_CGEN_OUT		(4)
+#define BIT_SEL_PARK		(8)
+#define BIT_SEL_F26M		(9)
+#define BIT_SEL_APU_DIV2	(10)
+#define BIT_SEL_APU		(11)
+#define BIT_SEL_PARK_SRC_OUT	(12)
+#define BIT_INVEN_OUT		(15)
+
+#endif /* APUPWR_CLKCTL_DEF_H*/
diff --git a/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.c b/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.c
new file mode 100644
index 0000000..3ed26a1
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+
+#include <apupwr_clkctl.h>
+#include <mtk_apusys.h>
+#include <plat/common/platform.h>
+
+int32_t apusys_kernel_ctrl(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
+			    uint32_t *ret1)
+{
+	int32_t ret = 0L;
+	uint32_t request_ops;
+
+	request_ops = (uint32_t)x1;
+
+	switch (request_ops) {
+	case MTK_SIP_APU_START_MCU:
+		/* setup addr[33:32] in reviser */
+		mmio_write_32(REVISER_SECUREFW_CTXT, 0U);
+		mmio_write_32(REVISER_USDRFW_CTXT, 0U);
+
+		/* setup secure sideband */
+		mmio_write_32(AO_SEC_FW,
+			      (SEC_FW_NON_SECURE << SEC_FW_SHIFT_NS) |
+			      (0U << SEC_FW_DOMAIN_SHIFT));
+
+		/* setup boot address */
+		mmio_write_32(AO_MD32_BOOT_CTRL, 0U);
+
+		/* setup pre-define region */
+		mmio_write_32(AO_MD32_PRE_DEFINE,
+			      (PRE_DEFINE_CACHE_TCM << PRE_DEFINE_SHIFT_0G) |
+			      (PRE_DEFINE_CACHE << PRE_DEFINE_SHIFT_1G) |
+			      (PRE_DEFINE_CACHE << PRE_DEFINE_SHIFT_2G) |
+			      (PRE_DEFINE_CACHE << PRE_DEFINE_SHIFT_3G));
+
+		/* release runstall */
+		mmio_write_32(AO_MD32_SYS_CTRL, SYS_CTRL_RUN);
+
+		INFO("[APUSYS] rev(0x%08x,0x%08x)\n",
+		     mmio_read_32(REVISER_SECUREFW_CTXT),
+		     mmio_read_32(REVISER_USDRFW_CTXT));
+		INFO("[APUSYS] ao(0x%08x,0x%08x,0x%08x,0x%08x,0x%08x)\n",
+		     mmio_read_32(AO_SEC_FW),
+		     mmio_read_32(AO_SEC_USR_FW),
+		     mmio_read_32(AO_MD32_BOOT_CTRL),
+		     mmio_read_32(AO_MD32_PRE_DEFINE),
+		     mmio_read_32(AO_MD32_SYS_CTRL));
+		break;
+	case MTK_SIP_APU_STOP_MCU:
+		/* hold runstall */
+		mmio_write_32(AO_MD32_SYS_CTRL, SYS_CTRL_STALL);
+
+		INFO("[APUSYS] md32_boot_ctrl=0x%08x,runstall=0x%08x\n",
+		     mmio_read_32(AO_MD32_BOOT_CTRL),
+		     mmio_read_32(AO_MD32_SYS_CTRL));
+		break;
+	case MTK_SIP_APUPWR_BUS_PROT_CG_ON:
+		apupwr_smc_bus_prot_cg_on();
+		break;
+	case MTK_SIP_APUPWR_BULK_PLL:
+		ret = apupwr_smc_bulk_pll((bool)x2);
+		break;
+	case MTK_SIP_APUPWR_ACC_INIT_ALL:
+		ret = apupwr_smc_acc_init_all();
+		break;
+	case MTK_SIP_APUPWR_ACC_TOP:
+		apupwr_smc_acc_top((bool)x2);
+		break;
+	default:
+		ERROR("%s, unknown request_ops=0x%x\n", __func__, request_ops);
+		break;
+	}
+
+	return ret;
+}
diff --git a/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.h b/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.h
new file mode 100644
index 0000000..639abd3
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/apusys/mtk_apusys.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_APUSYS_H
+#define MTK_APUSYS_H
+
+#include <stdint.h>
+
+/* setup the SMC command ops */
+#define MTK_SIP_APU_START_MCU		(0x00U)
+#define MTK_SIP_APU_STOP_MCU		(0x01U)
+#define MTK_SIP_APUPWR_BUS_PROT_CG_ON	(0x02U)
+#define MTK_SIP_APUPWR_BULK_PLL		(0x03U)
+#define MTK_SIP_APUPWR_ACC_INIT_ALL	(0x04U)
+#define MTK_SIP_APUPWR_ACC_TOP		(0x05U)
+
+/* AO Register */
+#define AO_MD32_PRE_DEFINE	(APUSYS_APU_S_S_4_BASE + 0x00)
+#define AO_MD32_BOOT_CTRL	(APUSYS_APU_S_S_4_BASE + 0x04)
+#define AO_MD32_SYS_CTRL	(APUSYS_APU_S_S_4_BASE + 0x08)
+#define AO_SEC_FW		(APUSYS_APU_S_S_4_BASE + 0x10)
+#define AO_SEC_USR_FW		(APUSYS_APU_S_S_4_BASE + 0x14)
+
+#define PRE_DEFINE_CACHE_TCM	(0x3U)
+#define PRE_DEFINE_CACHE	(0x2U)
+#define PRE_DEFINE_SHIFT_0G	(0U)
+#define PRE_DEFINE_SHIFT_1G	(2U)
+#define PRE_DEFINE_SHIFT_2G	(4U)
+#define PRE_DEFINE_SHIFT_3G	(6U)
+
+#define SEC_FW_NON_SECURE	(1U)
+#define SEC_FW_SHIFT_NS		(4U)
+#define SEC_FW_DOMAIN_SHIFT	(0U)
+
+#define SEC_USR_FW_NON_SECURE	(1U)
+#define SEC_USR_FW_SHIFT_NS	(4U)
+#define SEC_USR_FW_DOMAIN_SHIFT	(0U)
+
+#define SYS_CTRL_RUN		(0U)
+#define SYS_CTRL_STALL		(1U)
+
+/* Reviser Register */
+#define REVISER_SECUREFW_CTXT	(APUSYS_SCTRL_REVISER_BASE + 0x100)
+#define REVISER_USDRFW_CTXT	(APUSYS_SCTRL_REVISER_BASE + 0x104)
+
+int32_t apusys_kernel_ctrl(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
+			   uint32_t *ret1);
+#endif /* MTK_APUSYS_H */
diff --git a/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.c b/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.c
index 4330b77..794e21e 100644
--- a/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.c
+++ b/plat/mediatek/mt8195/drivers/emi_mpu/emi_mpu.c
@@ -91,7 +91,61 @@
 	return 0;
 }
 
+void dump_emi_mpu_regions(void)
+{
+	unsigned long apc[EMI_MPU_DGROUP_NUM], sa, ea;
+
+	int region, i;
+
+	/* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
+	for (region = 0; region < 8; ++region) {
+		for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i)
+			apc[i] = mmio_read_32(EMI_MPU_APC(region, i));
+		sa = mmio_read_32(EMI_MPU_SA(region));
+		ea = mmio_read_32(EMI_MPU_EA(region));
+
+		INFO("region %d:\n", region);
+		INFO("\tsa:0x%lx, ea:0x%lx, apc0: 0x%lx apc1: 0x%lx\n",
+		     sa, ea, apc[0], apc[1]);
+	}
+}
+
 void emi_mpu_init(void)
 {
-	/* TODO: more setting for EMI MPU. */
+	struct emi_region_info_t region_info;
+
+	/* SCP DRAM */
+	region_info.start = 0x50000000ULL;
+	region_info.end = 0x51400000ULL;
+	region_info.region = 2;
+	SET_ACCESS_PERMISSION(region_info.apc, 1,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      NO_PROTECTION, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
+	emi_mpu_set_protection(&region_info);
+
+	/* DSP protect address */
+	region_info.start = 0x60000000ULL;	/* dram base addr */
+	region_info.end = 0x610FFFFFULL;
+	region_info.region = 3;
+	SET_ACCESS_PERMISSION(region_info.apc, 1,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
+	emi_mpu_set_protection(&region_info);
+
+	/* Forbidden All */
+	region_info.start = 0x40000000ULL;	/* dram base addr */
+	region_info.end = 0x1FFFF0000ULL;
+	region_info.region = 4;
+	SET_ACCESS_PERMISSION(region_info.apc, 1,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
+	emi_mpu_set_protection(&region_info);
+
+	dump_emi_mpu_regions();
 }
diff --git a/plat/mediatek/mt8195/include/plat_sip_calls.h b/plat/mediatek/mt8195/include/plat_sip_calls.h
index ce25c6f..5562a67 100644
--- a/plat/mediatek/mt8195/include/plat_sip_calls.h
+++ b/plat/mediatek/mt8195/include/plat_sip_calls.h
@@ -10,7 +10,7 @@
 /*******************************************************************************
  * Plat SiP function constants
  ******************************************************************************/
-#define MTK_PLAT_SIP_NUM_CALLS    4
+#define MTK_PLAT_SIP_NUM_CALLS    6
 
 /* DFD */
 #define MTK_SIP_KERNEL_DFD_AARCH32	0x82000205
@@ -20,4 +20,8 @@
 #define MTK_SIP_DP_CONTROL_AARCH32	0x82000523
 #define MTK_SIP_DP_CONTROL_AARCH64	0xC2000523
 
+/* APUSYS SMC call */
+#define MTK_SIP_APUSYS_CONTROL_AARCH32	0x8200051E
+#define MTK_SIP_APUSYS_CONTROL_AARCH64	0xC200051E
+
 #endif /* PLAT_SIP_CALLS_H */
diff --git a/plat/mediatek/mt8195/include/platform_def.h b/plat/mediatek/mt8195/include/platform_def.h
index 68301d6..d4f2f83 100644
--- a/plat/mediatek/mt8195/include/platform_def.h
+++ b/plat/mediatek/mt8195/include/platform_def.h
@@ -21,6 +21,16 @@
 #define MTK_MCDI_SRAM_BASE	0x11B000
 #define MTK_MCDI_SRAM_MAP_SIZE	0x1000
 
+#define APUSYS_BASE			0x19000000
+#define APUSYS_SCTRL_REVISER_BASE	0x19021000
+#define APUSYS_SCTRL_REVISER_SIZE	0x1000
+#define APUSYS_APU_S_S_4_BASE		0x190F2000
+#define APUSYS_APU_S_S_4_SIZE		0x1000
+#define APUSYS_APU_PLL_BASE		0x190F3000
+#define APUSYS_APU_PLL_SIZE		0x1000
+#define APUSYS_APU_ACC_BASE		0x190F4000
+#define APUSYS_APU_ACC_SIZE		0x1000
+
 #define TOPCKGEN_BASE           (IO_PHYS + 0x00000000)
 #define INFRACFG_AO_BASE        (IO_PHYS + 0x00001000)
 #define SPM_BASE		(IO_PHYS + 0x00006000)
diff --git a/plat/mediatek/mt8195/plat_sip_calls.c b/plat/mediatek/mt8195/plat_sip_calls.c
index ddc7502..7d3c512 100644
--- a/plat/mediatek/mt8195/plat_sip_calls.c
+++ b/plat/mediatek/mt8195/plat_sip_calls.c
@@ -9,6 +9,7 @@
 #include <mt_dp.h>
 #include <mt_spm.h>
 #include <mt_spm_vcorefs.h>
+#include <mtk_apusys.h>
 #include <mtk_sip_svc.h>
 #include <plat_dfd.h>
 #include "plat_sip_calls.h"
@@ -41,6 +42,11 @@
 		ret = dfd_smc_dispatcher(x1, x2, x3, x4);
 		SMC_RET1(handle, ret);
 		break;
+	case MTK_SIP_APUSYS_CONTROL_AARCH32:
+	case MTK_SIP_APUSYS_CONTROL_AARCH64:
+		ret = apusys_kernel_ctrl(x1, x2, x3, x4, &ret_val);
+		SMC_RET2(handle, ret, ret_val);
+		break;
 	default:
 		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
 		break;
diff --git a/plat/mediatek/mt8195/platform.mk b/plat/mediatek/mt8195/platform.mk
index ef7ff81..72c71fe 100644
--- a/plat/mediatek/mt8195/platform.mk
+++ b/plat/mediatek/mt8195/platform.mk
@@ -14,6 +14,7 @@
                  -I${MTK_PLAT}/common/drivers/timer/              \
                  -I${MTK_PLAT}/common/drivers/uart/               \
                  -I${MTK_PLAT}/common/lpm/                        \
+                 -I${MTK_PLAT_SOC}/drivers/apusys/                \
                  -I${MTK_PLAT_SOC}/drivers/dcm                    \
                  -I${MTK_PLAT_SOC}/drivers/dfd                    \
                  -I${MTK_PLAT_SOC}/drivers/dp/                    \
@@ -59,6 +60,9 @@
                 ${MTK_PLAT_SOC}/aarch64/platform_common.c             \
                 ${MTK_PLAT_SOC}/aarch64/plat_helpers.S                \
                 ${MTK_PLAT_SOC}/bl31_plat_setup.c                     \
+                ${MTK_PLAT_SOC}/drivers/apusys/apupll.c               \
+                ${MTK_PLAT_SOC}/drivers/apusys/apupwr_clkctl.c        \
+		${MTK_PLAT_SOC}/drivers/apusys/mtk_apusys.c           \
                 ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm.c                 \
                 ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm_utils.c           \
                 ${MTK_PLAT_SOC}/drivers/dfd/plat_dfd.c                \
diff --git a/plat/qemu/common/qemu_bl2_mem_params_desc.c b/plat/qemu/common/qemu_bl2_mem_params_desc.c
index f8b9066..5af3a22 100644
--- a/plat/qemu/common/qemu_bl2_mem_params_desc.c
+++ b/plat/qemu/common/qemu_bl2_mem_params_desc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -116,7 +116,7 @@
 
 	   SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2,
 				 image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
-#if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE)
+#if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE) || defined(SPMC_OPTEE)
 	   .image_info.image_base = QEMU_OPTEE_PAGEABLE_LOAD_BASE,
 	   .image_info.image_max_size = QEMU_OPTEE_PAGEABLE_LOAD_SIZE,
 #endif
diff --git a/plat/qemu/common/qemu_bl2_setup.c b/plat/qemu/common/qemu_bl2_setup.c
index 3e289fc..2c0da15 100644
--- a/plat/qemu/common/qemu_bl2_setup.c
+++ b/plat/qemu/common/qemu_bl2_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -144,16 +144,20 @@
 {
 	int err = 0;
 	bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id);
-#if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE)
+#if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE) || defined(SPMC_OPTEE)
 	bl_mem_params_node_t *pager_mem_params = NULL;
 	bl_mem_params_node_t *paged_mem_params = NULL;
 #endif
+#if defined(SPD_spmd)
+	unsigned int mode_rw = MODE_RW_64;
+	uint64_t pagable_part = 0;
+#endif
 
 	assert(bl_mem_params);
 
 	switch (image_id) {
 	case BL32_IMAGE_ID:
-#if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE)
+#if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE) || defined(SPMC_OPTEE)
 		pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID);
 		assert(pager_mem_params);
 
@@ -166,21 +170,30 @@
 		if (err != 0) {
 			WARN("OPTEE header parse error.\n");
 		}
+#if defined(SPD_spmd)
+		mode_rw = bl_mem_params->ep_info.args.arg0;
+		pagable_part = bl_mem_params->ep_info.args.arg1;
+#endif
+#endif
 
-#if defined(SPD_opteed)
+#if defined(SPD_spmd)
+		bl_mem_params->ep_info.args.arg0 = ARM_PRELOADED_DTB_BASE;
+		bl_mem_params->ep_info.args.arg1 = pagable_part;
+		bl_mem_params->ep_info.args.arg2 = mode_rw;
+		bl_mem_params->ep_info.args.arg3 = 0;
+#elif defined(SPD_opteed)
 		/*
 		 * OP-TEE expect to receive DTB address in x2.
 		 * This will be copied into x2 by dispatcher.
 		 */
 		bl_mem_params->ep_info.args.arg3 = ARM_PRELOADED_DTB_BASE;
-#else /* case AARCH32_SP_OPTEE */
+#elif defined(AARCH32_SP_OPTEE)
 		bl_mem_params->ep_info.args.arg0 =
 					bl_mem_params->ep_info.args.arg1;
 		bl_mem_params->ep_info.args.arg1 = 0;
 		bl_mem_params->ep_info.args.arg2 = ARM_PRELOADED_DTB_BASE;
 		bl_mem_params->ep_info.args.arg3 = 0;
 #endif
-#endif
 		bl_mem_params->ep_info.spsr = qemu_get_spsr_for_bl32_entry();
 		break;
 
diff --git a/plat/qemu/common/qemu_spmd_manifest.c b/plat/qemu/common/qemu_spmd_manifest.c
new file mode 100644
index 0000000..fd46e26
--- /dev/null
+++ b/plat/qemu/common/qemu_spmd_manifest.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <services/spm_core_manifest.h>
+
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+int plat_spm_core_manifest_load(spmc_manifest_attribute_t *manifest,
+				const void *pm_addr)
+{
+	entry_point_info_t *ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+
+	assert(ep_info != NULL);
+	assert(manifest != NULL);
+
+	manifest->major_version = 1;
+	manifest->minor_version = 0;
+	manifest->exec_state = ep_info->args.arg2;
+	manifest->load_address = BL32_BASE;
+	manifest->entrypoint = BL32_BASE;
+	manifest->binary_size = BL32_LIMIT - BL32_BASE;
+	manifest->spmc_id = 0x8000;
+
+	return 0;
+}
diff --git a/plat/qemu/qemu/platform.mk b/plat/qemu/qemu/platform.mk
index a3b353f..a8f978a 100644
--- a/plat/qemu/qemu/platform.mk
+++ b/plat/qemu/qemu/platform.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -26,6 +26,10 @@
 ifeq ($(AARCH32_SP),optee)
 add-lib-optee 		:= 	yes
 endif
+ifeq ($(SPMC_OPTEE),1)
+$(eval $(call add_define,SPMC_OPTEE))
+add-lib-optee 		:= 	yes
+endif
 
 include lib/libfdt/libfdt.mk
 
@@ -175,6 +179,10 @@
 				${PLAT_QEMU_COMMON_PATH}/aarch64/plat_helpers.S	\
 				${PLAT_QEMU_COMMON_PATH}/qemu_bl31_setup.c		\
 				${QEMU_GIC_SOURCES}
+
+ifeq (${SPD},spmd)
+BL31_SOURCES		+=	plat/qemu/common/qemu_spmd_manifest.c
+endif
 endif
 
 # Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images
diff --git a/plat/st/common/bl2_io_storage.c b/plat/st/common/bl2_io_storage.c
index b0314d2..6069e5f 100644
--- a/plat/st/common/bl2_io_storage.c
+++ b/plat/st/common/bl2_io_storage.c
@@ -99,7 +99,7 @@
 static const io_dev_connector_t *spi_dev_con;
 #endif
 
-#if STM32MP_USB_PROGRAMMER
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
 static const io_dev_connector_t *memmap_dev_con;
 #endif
 
@@ -136,6 +136,9 @@
 	case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NAND_QSPI:
 		INFO("Using SPI NAND\n");
 		break;
+	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
+		INFO("Using UART\n");
+		break;
 	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
 		INFO("Using USB\n");
 		break;
@@ -257,7 +260,7 @@
 }
 #endif /* STM32MP_SPI_NAND */
 
-#if STM32MP_USB_PROGRAMMER
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
 static void mmap_io_setup(void)
 {
 	int io_result __unused;
@@ -270,6 +273,21 @@
 	assert(io_result == 0);
 }
 
+#if STM32MP_UART_PROGRAMMER
+static void stm32cubeprogrammer_uart(void)
+{
+	int ret __unused;
+	boot_api_context_t *boot_context =
+		(boot_api_context_t *)stm32mp_get_boot_ctx_address();
+	uintptr_t uart_base;
+
+	uart_base = get_uart_address(boot_context->boot_interface_instance);
+	ret = stm32cubeprog_uart_load(uart_base, DWL_BUFFER_BASE, DWL_BUFFER_SIZE);
+	assert(ret == 0);
+}
+#endif
+
+#if STM32MP_USB_PROGRAMMER
 static void stm32cubeprogrammer_usb(void)
 {
 	int ret __unused;
@@ -282,6 +300,8 @@
 	assert(ret == 0);
 }
 #endif
+#endif /* STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER */
+
 
 void stm32mp_io_setup(void)
 {
@@ -334,8 +354,13 @@
 		boot_spi_nand(boot_context);
 		break;
 #endif
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+#if STM32MP_UART_PROGRAMMER
+	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
+#endif
 #if STM32MP_USB_PROGRAMMER
 	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
+#endif
 		dmbsy();
 		mmap_io_setup();
 		break;
@@ -400,6 +425,16 @@
 		break;
 #endif
 
+#if STM32MP_UART_PROGRAMMER
+	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
+		if (image_id == FW_CONFIG_ID) {
+			stm32cubeprogrammer_uart();
+			/* FIP loaded at DWL address */
+			image_block_spec.offset = DWL_BUFFER_BASE;
+			image_block_spec.length = DWL_BUFFER_SIZE;
+		}
+		break;
+#endif
 #if STM32MP_USB_PROGRAMMER
 	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
 		if (image_id == FW_CONFIG_ID) {
diff --git a/plat/st/common/include/stm32cubeprogrammer.h b/plat/st/common/include/stm32cubeprogrammer.h
index 503d919..0f5a64d 100644
--- a/plat/st/common/include/stm32cubeprogrammer.h
+++ b/plat/st/common/include/stm32cubeprogrammer.h
@@ -24,4 +24,6 @@
 			   uintptr_t ssbl_base,
 			   size_t ssbl_len);
 
+int stm32cubeprog_uart_load(uintptr_t instance, uintptr_t base, size_t len);
+
 #endif /* STM32CUBEPROGRAMMER_H */
diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h
index 8a5fe48..6183964 100644
--- a/plat/st/common/include/stm32mp_common.h
+++ b/plat/st/common/include/stm32mp_common.h
@@ -48,6 +48,11 @@
 uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags);
 #endif
 
+#if STM32MP_UART_PROGRAMMER
+/* Get the UART address from its instance number */
+uintptr_t get_uart_address(uint32_t instance_nb);
+#endif
+
 /*
  * Platform util functions for the GPIO driver
  * @bank: Target GPIO bank ID as per DT bindings
diff --git a/plat/st/common/stm32cubeprogrammer_uart.c b/plat/st/common/stm32cubeprogrammer_uart.c
new file mode 100644
index 0000000..46ac9cf
--- /dev/null
+++ b/plat/st/common/stm32cubeprogrammer_uart.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/st/stm32_iwdg.h>
+#include <drivers/st/stm32_uart.h>
+#include <drivers/st/stm32_uart_regs.h>
+#include <lib/mmio.h>
+#include <tools_share/firmware_image_package.h>
+
+#include <platform_def.h>
+#include <stm32cubeprogrammer.h>
+
+/* USART bootloader protocol version V4.0 */
+#define USART_BL_VERSION	0x40U
+
+/* Command definition */
+#define GET_CMD_COMMAND		0x00U
+#define GET_VER_COMMAND		0x01U
+#define GET_ID_COMMAND		0x02U
+#define PHASE_COMMAND		0x03U
+#define READ_PART_COMMAND	0x12U
+#define START_COMMAND		0x21U
+#define DOWNLOAD_COMMAND	0x31U
+
+/* Answer defines */
+#define INIT_BYTE		0x7FU
+#define ACK_BYTE		0x79U
+#define NACK_BYTE		0x1FU
+#define ABORT			0x5FU
+
+#define UNDEFINED_DOWN_ADDR	U(0xFFFFFFFF)
+#define PROGRAMMER_TIMEOUT_US	20000U
+
+static const uint8_t command_tab[] = {
+	GET_CMD_COMMAND,
+	GET_VER_COMMAND,
+	GET_ID_COMMAND,
+	PHASE_COMMAND,
+	START_COMMAND,
+	DOWNLOAD_COMMAND
+};
+
+/* STM32CubeProgrammer over UART handle */
+struct stm32prog_uart_handle_s {
+	struct stm32_uart_handle_s uart;
+	uint32_t packet;
+	uint8_t *addr;
+	uint32_t len;
+	uint8_t phase;
+	/* Error msg buffer: max 255 in UART protocol, reduced in TF-A */
+	uint8_t error[64];
+} handle;
+
+/* Trace and handle unrecoverable UART protocol error */
+#define STM32PROG_ERROR(...) \
+	{ \
+		ERROR(__VA_ARGS__); \
+		if (handle.phase != PHASE_RESET) { \
+			snprintf((char *)&handle.error, sizeof(handle.error), __VA_ARGS__); \
+			handle.phase = PHASE_RESET; \
+			handle.addr = (uint8_t *)UNDEFINED_DOWN_ADDR; \
+			handle.len = 0U; \
+			handle.packet = 0U; \
+		} \
+	}
+
+static int uart_write(const uint8_t *addr, uint16_t size)
+{
+	while (size != 0U) {
+		if (stm32_uart_putc(&handle.uart, *addr) != 0) {
+			return -EIO;
+		}
+		size--;
+		addr++;
+	}
+
+	return 0;
+}
+
+static int uart_write_8(uint8_t byte)
+{
+	return stm32_uart_putc(&handle.uart, byte);
+}
+
+static int uart_write_32(uint32_t value)
+{
+	return uart_write((uint8_t *)&value, 4U);
+}
+
+static int uart_read_8(uint8_t *byte)
+{
+	int ret;
+	uint64_t timeout_ref = timeout_init_us(PROGRAMMER_TIMEOUT_US);
+
+	do {
+		ret = stm32_uart_getc(&handle.uart);
+		if (ret == -EAGAIN) {
+			if (timeout_elapsed(timeout_ref)) {
+				return -ETIMEDOUT;
+			}
+		} else if (ret < 0) {
+			return ret;
+		}
+	} while (ret == -EAGAIN);
+
+	*byte = (uint8_t)ret;
+
+	return 0;
+}
+
+static int uart_send_result(uint8_t byte)
+{
+	int ret;
+
+	/* Always flush fifo before to send result = read all pending data */
+	do {
+		ret = stm32_uart_getc(&handle.uart);
+	} while (ret >= 0);
+
+	return uart_write_8(byte);
+}
+
+static bool is_valid_header(fip_toc_header_t *header)
+{
+	return (header->name == TOC_HEADER_NAME) &&
+	       (header->serial_number != 0U);
+}
+
+static int uart_receive_command(uint8_t *command)
+{
+	uint8_t byte = 0U;
+	uint8_t xor = 0U;
+	unsigned int count;
+	bool found = false;
+	int ret;
+
+	/* Repeat read until something is received */
+	do {
+		stm32_iwdg_refresh();
+		ret = uart_read_8(&byte);
+	} while (ret == -ETIMEDOUT);
+
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Handle reconnection request */
+	if (byte == INIT_BYTE) {
+		*command = byte;
+		return 0;
+	}
+
+	for (count = 0U; count < ARRAY_SIZE(command_tab); count++) {
+		if (command_tab[count] == byte) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		VERBOSE("UART: Command unknown (byte=0x%x)\n", byte);
+		return -EPROTO;
+	}
+
+	ret = uart_read_8(&xor);
+	if (ret != 0) {
+		return ret;
+	}
+	if ((byte ^ xor) != 0xFF) {
+		VERBOSE("UART: Command XOR check fail (byte=0x%x, xor=0x%x)\n",
+			byte, xor);
+		return -EPROTO;
+	}
+
+	*command = byte;
+
+	return 0;
+}
+
+static int get_cmd_command(void)
+{
+	const uint8_t msg[2] = {
+		sizeof(command_tab), /* Length of data - 1 */
+		USART_BL_VERSION
+	};
+	int ret;
+
+	ret = uart_write(msg, sizeof(msg));
+	if (ret != 0) {
+		return ret;
+	}
+
+	return uart_write(command_tab, sizeof(command_tab));
+}
+
+static int get_version_command(void)
+{
+	return uart_write_8(STM32_TF_VERSION);
+}
+
+static int get_id_command(void)
+{
+	uint8_t msg[3] = {
+		sizeof(msg) - 1 /* Length of data - 1 */
+	};
+	uint32_t chip_id = stm32mp_get_chip_dev_id();
+
+	be16enc(&msg[1], chip_id);
+
+	return uart_write(msg, sizeof(msg));
+}
+
+static int uart_send_phase(uint32_t address)
+{
+	int ret;
+	uint8_t msg_size = 5U; /* Length of data - 1 */
+	uint8_t error_size = 0U;
+
+	/* Additional information only for RESET phase */
+	if (handle.phase == PHASE_RESET) {
+		error_size = strnlen((char *)&handle.error, sizeof(handle.error));
+	}
+	ret = uart_write_8(msg_size + error_size);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Send the ID of next partition */
+	ret = uart_write_8(handle.phase);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Destination address */
+	ret = uart_write_32(address);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = uart_write_8(error_size);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/* Additional information: message error */
+	if (error_size > 0U) {
+		ret = uart_write(handle.error, error_size);
+	}
+
+	return ret;
+}
+
+static int uart_download_part(void)
+{
+	uint8_t operation = 0U;
+	uint8_t xor;
+	uint8_t byte = 0U;
+	uint32_t packet_number = 0U;
+	uint32_t packet_size = 0U;
+	uint32_t i = 0U;
+	int ret;
+
+	/* Get operation number */
+	ret = uart_read_8(&operation);
+	if (ret != 0) {
+		return ret;
+	}
+
+	xor = operation;
+
+	/* Get packet number */
+	for (i = 3U; i != 0U; i--) {
+		ret = uart_read_8(&byte);
+		if (ret != 0) {
+			return ret;
+		}
+
+		xor ^= byte;
+		packet_number = (packet_number << 8) | byte;
+	}
+
+	if (packet_number != handle.packet) {
+		WARN("UART: Bad packet number receive: %u, expected %u\n",
+		     packet_number, handle.packet);
+		return -EPROTO;
+	}
+
+	/* Checksum */
+	ret = uart_read_8(&byte);
+	if (ret != 0) {
+		return ret;
+	}
+	if (xor != byte) {
+		VERBOSE("UART: Download Command checksum xor: %x, received %x\n",
+			xor, byte);
+		return -EPROTO;
+	}
+
+	ret = uart_send_result(ACK_BYTE);
+	if (ret != 0) {
+		return ret;
+	}
+
+	ret = uart_read_8(&byte);
+	if (ret != 0) {
+		return ret;
+	}
+	xor = byte;
+	packet_size = byte + 1U;
+	if (handle.len < packet_size) {
+		STM32PROG_ERROR("Download overflow at %p\n", handle.addr + packet_size);
+		return 0;
+	}
+
+	for (i = 0U; i < packet_size; i++) {
+		ret = uart_read_8(&byte);
+		if (ret != 0) {
+			return ret;
+		}
+
+		*(handle.addr + i) = byte;
+		xor ^= byte;
+	}
+
+	/* Checksum */
+	ret = uart_read_8(&byte) != 0;
+	if (ret != 0) {
+		return ret;
+	}
+	if (xor != byte) {
+		VERBOSE("UART: Download Data checksum xor: %x, received %x\n",
+			xor, byte);
+		return -EPROTO;
+	}
+
+	/* Packet treated */
+	handle.packet++;
+	handle.addr += packet_size;
+	handle.len -= packet_size;
+
+	return 0;
+}
+
+static int uart_start_cmd(uintptr_t buffer)
+{
+	uint8_t byte = 0U;
+	uint8_t xor = 0U;
+	uint32_t i;
+	uint32_t start_address = 0U;
+	int ret;
+
+	/* Get address */
+	for (i = 4U; i != 0U; i--) {
+		ret = uart_read_8(&byte);
+		if (ret != 0U) {
+			return ret;
+		}
+
+		xor ^= byte;
+		start_address = (start_address << 8) | byte;
+	}
+
+	/* Checksum */
+	ret = uart_read_8(&byte);
+	if (ret != 0) {
+		return ret;
+	}
+
+	if (xor != byte) {
+		VERBOSE("UART: Start Command checksum xor: %x, received %x\n",
+			xor, byte);
+		return -EPROTO;
+	}
+
+	if (start_address != UNDEFINED_DOWN_ADDR) {
+		STM32PROG_ERROR("Invalid start at %x, for phase %u\n",
+				start_address, handle.phase);
+		return 0;
+	}
+
+	if (!is_valid_header((fip_toc_header_t *)buffer)) {
+		STM32PROG_ERROR("FIP Header check failed %lx, for phase %u\n",
+				buffer, handle.phase);
+		return -EIO;
+	}
+	VERBOSE("FIP header looks OK.\n");
+
+	return 0;
+}
+
+static int uart_read(uint8_t id, uintptr_t buffer, size_t length)
+{
+	bool start_done = false;
+	int ret;
+	uint8_t command = 0U;
+
+	handle.phase = id;
+	handle.packet = 0U;
+	handle.addr = (uint8_t *)buffer;
+	handle.len = length;
+
+	INFO("UART: read phase %u at 0x%lx size 0x%x\n",
+	     id, buffer, length);
+	while (!start_done) {
+		ret = uart_receive_command(&command);
+		if (ret != 0) {
+			/* Delay to wait STM32CubeProgrammer end of transmission */
+			mdelay(3);
+
+			ret = uart_send_result(NACK_BYTE);
+			if (ret != 0U) {
+				return ret;
+			}
+
+			continue;
+		}
+
+		uart_send_result(ACK_BYTE);
+
+		switch (command) {
+		case INIT_BYTE:
+			INFO("UART: Connected\n");
+			/* Nothing to do */
+			continue;
+
+		case GET_CMD_COMMAND:
+			ret = get_cmd_command();
+			break;
+
+		case GET_VER_COMMAND:
+			ret = get_version_command();
+			break;
+
+		case GET_ID_COMMAND:
+			ret = get_id_command();
+			break;
+
+		case PHASE_COMMAND:
+			ret = uart_send_phase((uint32_t)buffer);
+			if ((ret == 0) && (handle.phase == PHASE_RESET)) {
+				start_done = true;
+				INFO("UART: Reset\n");
+			}
+			break;
+
+		case DOWNLOAD_COMMAND:
+			ret = uart_download_part();
+			break;
+
+		case START_COMMAND:
+			ret = uart_start_cmd(buffer);
+			if ((ret == 0) && (handle.phase == id)) {
+				INFO("UART: Start phase %u\n", handle.phase);
+				start_done = true;
+			}
+			break;
+
+		default:
+			WARN("UART: Unknown command\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		if (ret == 0) {
+			ret = uart_send_result(ACK_BYTE);
+		} else {
+			ret = uart_send_result(NACK_BYTE);
+		}
+		if (ret != 0) {
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/* Init UART: 115200, 8bit 1stop parity even and enable FIFO mode */
+const struct stm32_uart_init_s init = {
+	.baud_rate = U(115200),
+	.word_length = STM32_UART_WORDLENGTH_9B,
+	.stop_bits = STM32_UART_STOPBITS_1,
+	.parity = STM32_UART_PARITY_EVEN,
+	.hw_flow_control = STM32_UART_HWCONTROL_NONE,
+	.mode = STM32_UART_MODE_TX_RX,
+	.over_sampling = STM32_UART_OVERSAMPLING_16,
+	.fifo_mode = STM32_UART_FIFOMODE_EN,
+};
+
+int stm32cubeprog_uart_load(uintptr_t instance, uintptr_t base, size_t len)
+{
+	int ret;
+
+	if (stm32_uart_init(&handle.uart, instance, &init) != 0) {
+		return -EIO;
+	}
+
+	/*
+	 * The following NACK_BYTE is written because STM32CubeProgrammer has
+	 * already sent its command before TF-A has reached this point, and
+	 * because FIFO was not configured by BootROM.
+	 * The byte in the UART_RX register is then the checksum and not the
+	 * command. NACK_BYTE has to be written, so that the programmer will
+	 * re-send the good command.
+	 */
+	ret = uart_send_result(NACK_BYTE);
+	if (ret != 0) {
+		return ret;
+	}
+
+	return uart_read(PHASE_SSBL, base, len);
+}
diff --git a/plat/st/stm32mp1/bl2_plat_setup.c b/plat/st/stm32mp1/bl2_plat_setup.c
index 7eaf0ed..218f28d 100644
--- a/plat/st/stm32mp1/bl2_plat_setup.c
+++ b/plat/st/stm32mp1/bl2_plat_setup.c
@@ -493,12 +493,13 @@
 	uint16_t boot_itf = stm32mp_get_boot_itf_selected();
 
 	switch (boot_itf) {
-#if STM32MP_USB_PROGRAMMER
+#if STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER
+	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART:
 	case BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB:
 		/* Invalidate the downloaded buffer used with io_memmap */
 		inv_dcache_range(DWL_BUFFER_BASE, DWL_BUFFER_SIZE);
 		break;
-#endif
+#endif /* STM32MP_UART_PROGRAMMER || STM32MP_USB_PROGRAMMER */
 	default:
 		/* Do nothing in default case */
 		break;
diff --git a/plat/st/stm32mp1/include/boot_api.h b/plat/st/stm32mp1/include/boot_api.h
index 52b1d1a..198ffa9 100644
--- a/plat/st/stm32mp1/include/boot_api.h
+++ b/plat/st/stm32mp1/include/boot_api.h
@@ -39,6 +39,9 @@
 /* Boot occurred on QSPI NOR */
 #define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_NOR_QSPI		0x4U
 
+/* Boot occurred on UART */
+#define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_UART		0x5U
+
 /* Boot occurred on USB */
 #define BOOT_API_CTX_BOOT_INTERFACE_SEL_SERIAL_USB		0x6U
 
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index badc926..2a4ab78 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -55,6 +55,7 @@
 
 # Serial boot devices
 STM32MP_USB_PROGRAMMER	?=	0
+STM32MP_UART_PROGRAMMER	?=	0
 
 # Device tree
 DTB_FILE_NAME		?=	stm32mp157c-ev1.dtb
@@ -130,6 +131,7 @@
 		STM32MP_SPI_NOR \
 		STM32MP_EMMC_BOOT \
 		PLAT_XLAT_TABLES_DYNAMIC \
+		STM32MP_UART_PROGRAMMER \
 		STM32MP_USB_PROGRAMMER \
 		STM32MP_USE_STM32IMAGE \
 )))
@@ -138,10 +140,12 @@
 	$(sort \
 		STM32_TF_A_COPIES \
 		PLAT_PARTITION_MAX_ENTRIES \
+		STM32_TF_VERSION \
 )))
 
 $(eval $(call add_defines,\
 	$(sort \
+		STM32_TF_VERSION \
 		STM32MP_EMMC \
 		STM32MP_SDMMC \
 		STM32MP_RAW_NAND \
@@ -151,6 +155,7 @@
 		PLAT_XLAT_TABLES_DYNAMIC \
 		STM32_TF_A_COPIES \
 		PLAT_PARTITION_MAX_ENTRIES \
+		STM32MP_UART_PROGRAMMER \
 		STM32MP_USB_PROGRAMMER \
 		STM32MP_USE_STM32IMAGE \
 )))
@@ -260,11 +265,19 @@
 BL2_SOURCES		+=	plat/st/stm32mp1/stm32mp1_boot_device.c
 endif
 
+ifneq ($(filter 1,${STM32MP_UART_PROGRAMMER} ${STM32MP_USB_PROGRAMMER}),)
+BL2_SOURCES		+=	drivers/io/io_memmap.c
+endif
+
+ifeq (${STM32MP_UART_PROGRAMMER},1)
+BL2_SOURCES		+=	drivers/st/uart/stm32_uart.c				\
+				plat/st/common/stm32cubeprogrammer_uart.c
+endif
+
 ifeq (${STM32MP_USB_PROGRAMMER},1)
 #The DFU stack uses only one end point, reduce the USB stack footprint
 $(eval $(call add_define_val,CONFIG_USBD_EP_NB,1U))
-BL2_SOURCES		+=	drivers/io/io_memmap.c					\
-				drivers/st/usb/stm32mp1_usb.c				\
+BL2_SOURCES		+=	drivers/st/usb/stm32mp1_usb.c				\
 				drivers/usb/usb_device.c				\
 				plat/st/common/stm32cubeprogrammer_usb.c		\
 				plat/st/common/usb_dfu.c					\
@@ -295,6 +308,7 @@
 	    [ ${STM32MP_RAW_NAND} != 1 ] && \
 	    [ ${STM32MP_SPI_NAND} != 1 ] && \
 	    [ ${STM32MP_SPI_NOR} != 1 ] && \
+	    [ ${STM32MP_UART_PROGRAMMER} != 1 ] && \
 	    [ ${STM32MP_USB_PROGRAMMER} != 1 ]; then \
 		echo "No boot device driver is enabled"; \
 		false; \
diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c
index e4065c1..0165cfe 100644
--- a/plat/st/stm32mp1/stm32mp1_private.c
+++ b/plat/st/stm32mp1/stm32mp1_private.c
@@ -153,6 +153,32 @@
 	}
 }
 
+#if STM32MP_UART_PROGRAMMER
+/*
+ * UART Management
+ */
+static const uintptr_t stm32mp1_uart_addresses[8] = {
+	USART1_BASE,
+	USART2_BASE,
+	USART3_BASE,
+	UART4_BASE,
+	UART5_BASE,
+	USART6_BASE,
+	UART7_BASE,
+	UART8_BASE,
+};
+
+uintptr_t get_uart_address(uint32_t instance_nb)
+{
+	if ((instance_nb == 0U) ||
+	    (instance_nb > ARRAY_SIZE(stm32mp1_uart_addresses))) {
+		return 0U;
+	}
+
+	return stm32mp1_uart_addresses[instance_nb - 1U];
+}
+#endif
+
 uint32_t stm32mp_get_chip_version(void)
 {
 	uint32_t version = 0U;
diff --git a/plat/xilinx/versal/bl31_versal_setup.c b/plat/xilinx/versal/bl31_versal_setup.c
index 8b8714c..f59859e 100644
--- a/plat/xilinx/versal/bl31_versal_setup.c
+++ b/plat/xilinx/versal/bl31_versal_setup.c
@@ -46,11 +46,11 @@
  */
 static inline void bl31_set_default_config(void)
 {
-	bl32_image_ep_info.pc = BL32_BASE;
-	bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry();
-	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
-	bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
-					DISABLE_ALL_EXCEPTIONS);
+	bl32_image_ep_info.pc = (uintptr_t)BL32_BASE;
+	bl32_image_ep_info.spsr = (uint32_t)arm_get_spsr_for_bl32_entry();
+	bl33_image_ep_info.pc = (uintptr_t)plat_get_ns_image_entrypoint();
+	bl33_image_ep_info.spsr = (uint32_t)SPSR_64(MODE_EL2, MODE_SP_ELX,
+						    DISABLE_ALL_EXCEPTIONS);
 }
 
 /*
@@ -67,23 +67,26 @@
 	if (VERSAL_CONSOLE_IS(pl011)) {
 		static console_t versal_runtime_console;
 		/* Initialize the console to provide early debug support */
-		int rc = console_pl011_register(VERSAL_UART_BASE,
-						VERSAL_UART_CLOCK,
-						VERSAL_UART_BAUDRATE,
+		int rc = console_pl011_register((unsigned long)VERSAL_UART_BASE,
+						(unsigned int)VERSAL_UART_CLOCK,
+						(unsigned int)VERSAL_UART_BAUDRATE,
 						&versal_runtime_console);
 		if (rc == 0) {
 			panic();
 		}
 
-		console_set_scope(&versal_runtime_console, CONSOLE_FLAG_BOOT |
-				  CONSOLE_FLAG_RUNTIME);
+		console_set_scope(&versal_runtime_console, (unsigned int)(CONSOLE_FLAG_BOOT |
+				  CONSOLE_FLAG_RUNTIME));
 	} else if (VERSAL_CONSOLE_IS(dcc)) {
 		/* Initialize the dcc console for debug */
 		int rc = console_dcc_register();
 		if (rc == 0) {
 			panic();
 		}
+	} else {
+		NOTICE("BL31: Did not register for any console.\n");
 	}
+
 	/* Initialize the platform config for future decision making */
 	versal_config_setup();
 	/* There are no parameters from BL2 if BL31 is a reset vector */
@@ -111,6 +114,8 @@
 		bl31_set_default_config();
 	} else if (ret != FSBL_HANDOFF_SUCCESS) {
 		panic();
+	} else {
+		ERROR("BL31: Error during fsbl-atf handover %d.\n", ret);
 	}
 
 	NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
@@ -122,7 +127,7 @@
 int request_intr_type_el3(uint32_t id, interrupt_type_handler_t handler)
 {
 	/* Validate 'handler'*/
-	if (!handler) {
+	if (handler == NULL) {
 		return -EINVAL;
 	}
 
@@ -145,7 +150,7 @@
 	}
 
 	handler = type_el3_interrupt_handler;
-	if (handler) {
+	if (handler != NULL) {
 		return handler(intr_id, flags, handle, cookie);
 	}
 
@@ -161,12 +166,12 @@
 void bl31_plat_runtime_setup(void)
 {
 	uint64_t flags = 0;
-	uint64_t rc;
+	int32_t rc;
 
 	set_interrupt_rm_flag(flags, NON_SECURE);
 	rc = register_interrupt_type_handler(INTR_TYPE_EL3,
 					     rdo_el3_interrupt_handler, flags);
-	if (rc) {
+	if (rc != 0) {
 		panic();
 	}
 }
diff --git a/plat/xilinx/versal/include/platform_def.h b/plat/xilinx/versal/include/platform_def.h
index 8b513ef..83e5083 100644
--- a/plat/xilinx/versal/include/platform_def.h
+++ b/plat/xilinx/versal/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -18,9 +18,9 @@
 #define PLATFORM_STACK_SIZE	0x440
 
 #define PLATFORM_CORE_COUNT		U(2)
-#define PLAT_MAX_PWR_LVL		1
-#define PLAT_MAX_RET_STATE		1
-#define PLAT_MAX_OFF_STATE		2
+#define PLAT_MAX_PWR_LVL		U(1)
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
 
 /*******************************************************************************
  * BL31 specific defines.
@@ -31,8 +31,8 @@
  * little space for growth.
  */
 #ifndef VERSAL_ATF_MEM_BASE
-# define BL31_BASE			0xfffe0000
-# define BL31_LIMIT			0xffffffff
+# define BL31_BASE			U(0xfffe0000)
+# define BL31_LIMIT			U(0xffffffff)
 #else
 # define BL31_BASE			(VERSAL_ATF_MEM_BASE)
 # define BL31_LIMIT			(VERSAL_ATF_MEM_BASE + VERSAL_ATF_MEM_SIZE - 1)
@@ -45,8 +45,8 @@
  * BL32 specific defines.
  ******************************************************************************/
 #ifndef VERSAL_BL32_MEM_BASE
-# define BL32_BASE			0x60000000
-# define BL32_LIMIT			0x7fffffff
+# define BL32_BASE			U(0x60000000)
+# define BL32_LIMIT			U(0x7fffffff)
 #else
 # define BL32_BASE			(VERSAL_BL32_MEM_BASE)
 # define BL32_LIMIT			(VERSAL_BL32_MEM_BASE + VERSAL_BL32_MEM_SIZE - 1)
@@ -56,7 +56,7 @@
  * BL33 specific defines.
  ******************************************************************************/
 #ifndef PRELOADED_BL33_BASE
-# define PLAT_ARM_NS_IMAGE_BASE		0x8000000
+# define PLAT_ARM_NS_IMAGE_BASE		U(0x8000000)
 #else
 # define PLAT_ARM_NS_IMAGE_BASE		PRELOADED_BL33_BASE
 #endif
@@ -81,8 +81,8 @@
 #define CACHE_WRITEBACK_SHIFT	6
 #define CACHE_WRITEBACK_GRANULE	(1 << CACHE_WRITEBACK_SHIFT)
 
-#define PLAT_VERSAL_GICD_BASE	0xF9000000
-#define PLAT_VERSAL_GICR_BASE	0xF9080000
+#define PLAT_VERSAL_GICD_BASE	U(0xF9000000)
+#define PLAT_VERSAL_GICR_BASE	U(0xF9080000)
 
 /*
  * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
@@ -91,7 +91,7 @@
  */
 #define PLAT_VERSAL_G1S_IRQS	VERSAL_IRQ_SEC_PHY_TIMER
 #define PLAT_VERSAL_G0_IRQS	VERSAL_IRQ_SEC_PHY_TIMER
-#define PLAT_VERSAL_IPI_IRQ	62
+#define PLAT_VERSAL_IPI_IRQ	U(62)
 
 #define PLAT_VERSAL_G1S_IRQ_PROPS(grp) \
 	INTR_PROP_DESC(VERSAL_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
diff --git a/plat/xilinx/versal/include/versal_def.h b/plat/xilinx/versal/include/versal_def.h
index 001fb04..9372954 100644
--- a/plat/xilinx/versal/include/versal_def.h
+++ b/plat/xilinx/versal/include/versal_def.h
@@ -52,7 +52,7 @@
 /*******************************************************************************
  * IRQ constants
  ******************************************************************************/
-#define VERSAL_IRQ_SEC_PHY_TIMER		29
+#define VERSAL_IRQ_SEC_PHY_TIMER		U(29)
 
 /*******************************************************************************
  * CCI-400 related constants
@@ -112,33 +112,33 @@
 #define FPD_MAINCCI_SIZE	0x00100000
 
 /* APU registers and bitfields */
-#define FPD_APU_BASE		0xFD5C0000
-#define FPD_APU_CONFIG_0	(FPD_APU_BASE + 0x20)
-#define FPD_APU_RVBAR_L_0	(FPD_APU_BASE + 0x40)
-#define FPD_APU_RVBAR_H_0	(FPD_APU_BASE + 0x44)
-#define FPD_APU_PWRCTL		(FPD_APU_BASE + 0x90)
+#define FPD_APU_BASE		0xFD5C0000U
+#define FPD_APU_CONFIG_0	(FPD_APU_BASE + 0x20U)
+#define FPD_APU_RVBAR_L_0	(FPD_APU_BASE + 0x40U)
+#define FPD_APU_RVBAR_H_0	(FPD_APU_BASE + 0x44U)
+#define FPD_APU_PWRCTL		(FPD_APU_BASE + 0x90U)
 
-#define FPD_APU_CONFIG_0_VINITHI_SHIFT	8
-#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK	1
-#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK	2
+#define FPD_APU_CONFIG_0_VINITHI_SHIFT	8U
+#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK	1U
+#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK	2U
 
 /* PMC registers and bitfields */
-#define PMC_GLOBAL_BASE			0xF1110000
-#define PMC_GLOBAL_GLOB_GEN_STORAGE4	(PMC_GLOBAL_BASE + 0x40)
+#define PMC_GLOBAL_BASE			0xF1110000U
+#define PMC_GLOBAL_GLOB_GEN_STORAGE4	(PMC_GLOBAL_BASE + 0x40U)
 
 /* IPI registers and bitfields */
-#define IPI0_REG_BASE		0xFF330000
-#define IPI0_TRIG_BIT		(1 << 2)
-#define PMC_IPI_TRIG_BIT	(1 << 1)
-#define IPI1_REG_BASE		0xFF340000
-#define IPI1_TRIG_BIT		(1 << 3)
-#define IPI2_REG_BASE		0xFF350000
-#define IPI2_TRIG_BIT		(1 << 4)
-#define IPI3_REG_BASE		0xFF360000
-#define IPI3_TRIG_BIT		(1 << 5)
-#define IPI4_REG_BASE		0xFF370000
-#define IPI4_TRIG_BIT		(1 << 5)
-#define IPI5_REG_BASE		0xFF380000
-#define IPI5_TRIG_BIT		(1 << 6)
+#define IPI0_REG_BASE		U(0xFF330000)
+#define IPI0_TRIG_BIT		(1U << 2U)
+#define PMC_IPI_TRIG_BIT	(1U << 1U)
+#define IPI1_REG_BASE		U(0xFF340000)
+#define IPI1_TRIG_BIT		(1U << 3U)
+#define IPI2_REG_BASE		U(0xFF350000)
+#define IPI2_TRIG_BIT		(1U << 4U)
+#define IPI3_REG_BASE		U(0xFF360000)
+#define IPI3_TRIG_BIT		(1U << 5U)
+#define IPI4_REG_BASE		U(0xFF370000)
+#define IPI4_TRIG_BIT		(1U << 5U)
+#define IPI5_REG_BASE		U(0xFF380000)
+#define IPI5_TRIG_BIT		(1U << 6U)
 
 #endif /* VERSAL_DEF_H */
diff --git a/plat/xilinx/versal/plat_psci.c b/plat/xilinx/versal/plat_psci.c
index fa0284c..eb05e58 100644
--- a/plat/xilinx/versal/plat_psci.c
+++ b/plat/xilinx/versal/plat_psci.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,19 +21,20 @@
 
 static int versal_pwr_domain_on(u_register_t mpidr)
 {
-	unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
+	int cpu_id = plat_core_pos_by_mpidr(mpidr);
 	const struct pm_proc *proc;
 
 	VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
 
-	if (cpu_id == -1)
+	if (cpu_id == -1) {
 		return PSCI_E_INTERN_FAIL;
+	}
 
-	proc = pm_get_proc(cpu_id);
+	proc = pm_get_proc((unsigned int)cpu_id);
 
 	/* Send request to PMC to wake up selected ACPU core */
-	pm_req_wakeup(proc->node_id, (versal_sec_entry & 0xFFFFFFFF) | 0x1,
-		      versal_sec_entry >> 32, 0, SECURE_FLAG);
+	(void)pm_req_wakeup(proc->node_id, (versal_sec_entry & 0xFFFFFFFFU) | 0x1U,
+			    versal_sec_entry >> 32, 0, SECURE_FLAG);
 
 	/* Clear power down request */
 	pm_client_wakeup(proc);
@@ -53,9 +54,10 @@
 	unsigned int cpu_id = plat_my_core_pos();
 	const struct pm_proc *proc = pm_get_proc(cpu_id);
 
-	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+	for (size_t i = 0U; i <= PLAT_MAX_PWR_LVL; i++) {
 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
 			__func__, i, target_state->pwr_domain_state[i]);
+	}
 
 	plat_versal_gic_cpuif_disable();
 
@@ -67,8 +69,8 @@
 		PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
 
 	/* Send request to PMC to suspend this core */
-	pm_self_suspend(proc->node_id, MAX_LATENCY, state, versal_sec_entry,
-			SECURE_FLAG);
+	(void)pm_self_suspend(proc->node_id, MAX_LATENCY, state, versal_sec_entry,
+			      SECURE_FLAG);
 
 	/* APU is to be turned off */
 	if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
@@ -89,9 +91,10 @@
 	unsigned int cpu_id = plat_my_core_pos();
 	const struct pm_proc *proc = pm_get_proc(cpu_id);
 
-	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+	for (size_t i = 0U; i <= PLAT_MAX_PWR_LVL; i++) {
 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
 			__func__, i, target_state->pwr_domain_state[i]);
+	}
 
 	/* Clear the APU power control register for this cpu */
 	pm_client_wakeup(proc);
@@ -123,11 +126,12 @@
 static void __dead2 versal_system_off(void)
 {
 	/* Send the power down request to the PMC */
-	pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
-			  pm_get_shutdown_scope(), SECURE_FLAG);
+	(void)pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
+				 pm_get_shutdown_scope(), SECURE_FLAG);
 
-	while (1)
+	while (1) {
 		wfi();
+	}
 }
 
 /**
@@ -137,11 +141,12 @@
 static void __dead2 versal_system_reset(void)
 {
 	/* Send the system reset request to the PMC */
-	pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
-			  pm_get_shutdown_scope(), SECURE_FLAG);
+	(void)pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
+				 pm_get_shutdown_scope(), SECURE_FLAG);
 
-	while (1)
+	while (1) {
 		wfi();
+	}
 }
 
 /**
@@ -154,9 +159,10 @@
 	unsigned int cpu_id = plat_my_core_pos();
 	const struct pm_proc *proc = pm_get_proc(cpu_id);
 
-	for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+	for (size_t i = 0U; i <= PLAT_MAX_PWR_LVL; i++) {
 		VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
 			__func__, i, target_state->pwr_domain_state[i]);
+	}
 
 	/* Prevent interrupts from spuriously waking up this cpu */
 	plat_versal_gic_cpuif_disable();
@@ -169,8 +175,8 @@
 	 * invoking CPU_on function, during which resume address will
 	 * be set.
 	 */
-	pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0,
-			SECURE_FLAG);
+	(void)pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0,
+			      SECURE_FLAG);
 }
 
 /**
@@ -187,19 +193,21 @@
 {
 	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
 
-	int pstate = psci_get_pstate_type(power_state);
+	unsigned int pstate = psci_get_pstate_type(power_state);
 
 	assert(req_state);
 
 	/* Sanity check the requested state */
-	if (pstate == PSTATE_TYPE_STANDBY)
+	if (pstate == PSTATE_TYPE_STANDBY) {
 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
-	else
+	} else {
 		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+	}
 
 	/* We expect the 'state id' to be zero */
-	if (psci_get_pstate_id(power_state))
+	if (psci_get_pstate_id(power_state) != 0U) {
 		return PSCI_E_INVALID_PARAMS;
+	}
 
 	return PSCI_E_SUCCESS;
 }
diff --git a/plat/xilinx/versal/plat_versal.c b/plat/xilinx/versal/plat_versal.c
index 107eae6..54c35b6 100644
--- a/plat/xilinx/versal/plat_versal.c
+++ b/plat/xilinx/versal/plat_versal.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,7 +9,7 @@
 
 int plat_core_pos_by_mpidr(u_register_t mpidr)
 {
-	if (mpidr & MPIDR_CLUSTER_MASK) {
+	if ((mpidr & MPIDR_CLUSTER_MASK) != 0U) {
 		return -1;
 	}
 
@@ -17,5 +17,5 @@
 		return -1;
 	}
 
-	return versal_calc_core_pos(mpidr);
+	return (int)versal_calc_core_pos(mpidr);
 }
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.c b/plat/xilinx/versal/pm_service/pm_api_sys.c
index 912835a..534d910 100644
--- a/plat/xilinx/versal/pm_service/pm_api_sys.c
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2019-2021, Xilinx, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,10 +21,10 @@
 /*********************************************************************
  * Target module IDs macros
  ********************************************************************/
-#define LIBPM_MODULE_ID		0x2
-#define LOADER_MODULE_ID	0x7
+#define LIBPM_MODULE_ID		0x2U
+#define LOADER_MODULE_ID	0x7U
 
-#define  MODE	0x80000000
+#define  MODE	0x80000000U
 /* default shutdown/reboot scope is system(2) */
 static unsigned int pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM;
 
@@ -42,32 +42,32 @@
  * Assigning of argument values into array elements.
  */
 #define PM_PACK_PAYLOAD1(pl, mid, flag, arg0) {	\
-	pl[0] = (uint32_t)((uint32_t)((arg0) & 0xFF) | (mid << 8) | ((flag) << 24)); \
+	pl[0] = (uint32_t)(((uint32_t)(arg0) & 0xFFU) | ((mid) << 8U) | ((flag) << 24U)); \
 }
 
 #define PM_PACK_PAYLOAD2(pl, mid, flag, arg0, arg1) {		\
 	pl[1] = (uint32_t)(arg1);				\
-	PM_PACK_PAYLOAD1(pl, mid, flag, arg0);			\
+	PM_PACK_PAYLOAD1(pl, (mid), (flag), (arg0));			\
 }
 
 #define PM_PACK_PAYLOAD3(pl, mid, flag, arg0, arg1, arg2) {	\
 	pl[2] = (uint32_t)(arg2);				\
-	PM_PACK_PAYLOAD2(pl, mid, flag, arg0, arg1);		\
+	PM_PACK_PAYLOAD2(pl, (mid), (flag), (arg0), (arg1));		\
 }
 
 #define PM_PACK_PAYLOAD4(pl, mid, flag, arg0, arg1, arg2, arg3) {	\
 	pl[3] = (uint32_t)(arg3);					\
-	PM_PACK_PAYLOAD3(pl, mid, flag, arg0, arg1, arg2);		\
+	PM_PACK_PAYLOAD3(pl, (mid), (flag), (arg0), (arg1), (arg2));		\
 }
 
 #define PM_PACK_PAYLOAD5(pl, mid, flag, arg0, arg1, arg2, arg3, arg4) {	\
 	pl[4] = (uint32_t)(arg4);					\
-	PM_PACK_PAYLOAD4(pl, mid, flag, arg0, arg1, arg2, arg3);	\
+	PM_PACK_PAYLOAD4(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3));	\
 }
 
 #define PM_PACK_PAYLOAD6(pl, mid, flag, arg0, arg1, arg2, arg3, arg4, arg5) {	\
 	pl[5] = (uint32_t)(arg5);						\
-	PM_PACK_PAYLOAD5(pl, mid, flag, arg0, arg1, arg2, arg3, arg4);		\
+	PM_PACK_PAYLOAD5(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3), (arg4));		\
 }
 
 /* PM API functions */
@@ -130,7 +130,7 @@
 	unsigned int cpuid = plat_my_core_pos();
 	const struct pm_proc *proc = pm_get_proc(cpuid);
 
-	if (!proc) {
+	if (proc == NULL) {
 		WARN("Failed to get proc %d\n", cpuid);
 		return PM_RET_ERROR_INTERNAL;
 	}
@@ -197,10 +197,11 @@
 	/* Send request to the PMU */
 	PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_REQ_SUSPEND, target,
 			 latency, state);
-	if (ack == IPI_BLOCKING)
+	if (ack == IPI_BLOCKING) {
 		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
-	else
+	} else {
 		return pm_ipi_send(primary_proc, payload);
+	}
 }
 
 /**
@@ -372,8 +373,9 @@
 void pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag)
 {
 	/* Return if interrupt is not from PMU */
-	if (!pm_ipi_irq_status(primary_proc))
+	if (pm_ipi_irq_status(primary_proc) == 0) {
 		return;
+	}
 
 	pm_ipi_buff_read_callb(data, count);
 	pm_ipi_irq_clear(primary_proc);
@@ -771,10 +773,11 @@
 	PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, PM_FORCE_POWERDOWN,
 			 target, ack);
 
-	if (ack == IPI_BLOCKING)
+	if (ack == IPI_BLOCKING) {
 		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
-	else
+	} else {
 		return pm_ipi_send(primary_proc, payload);
+	}
 }
 
 /**
@@ -830,7 +833,7 @@
 
 	ret = pm_feature_check(PM_QUERY_DATA, &version, flag);
 	if (PM_RET_SUCCESS == ret) {
-		fw_api_version = version & 0xFFFF ;
+		fw_api_version = version & 0xFFFFU;
 		if ((2U == fw_api_version) &&
 		    ((XPM_QID_CLOCK_GET_NAME == qid) ||
 		     (XPM_QID_PINCTRL_GET_FUNCTION_NAME == qid))) {
@@ -864,32 +867,39 @@
 				uint32_t flag)
 {
 	uint32_t payload[PAYLOAD_ARG_CNT];
-	int ret;
+	enum pm_ret_status ret;
 
 	switch (ioctl_id) {
 	case IOCTL_SET_PLL_FRAC_MODE:
-		return pm_pll_set_mode(arg1, arg2, flag);
+		ret =  pm_pll_set_mode(arg1, arg2, flag);
+		break;
 	case IOCTL_GET_PLL_FRAC_MODE:
-		return pm_pll_get_mode(arg1, value, flag);
+		ret =  pm_pll_get_mode(arg1, value, flag);
+		break;
 	case IOCTL_SET_PLL_FRAC_DATA:
-		return pm_pll_set_param(arg1, PM_PLL_PARAM_DATA, arg2, flag);
+		ret =  pm_pll_set_param(arg1, PM_PLL_PARAM_DATA, arg2, flag);
+		break;
 	case IOCTL_GET_PLL_FRAC_DATA:
-		return pm_pll_get_param(arg1, PM_PLL_PARAM_DATA, value, flag);
+		ret =  pm_pll_get_param(arg1, PM_PLL_PARAM_DATA, value, flag);
+		break;
 	case IOCTL_SET_SGI:
 		/* Get the sgi number */
-		ret = pm_register_sgi(arg1);
-		if (ret) {
+		if (pm_register_sgi(arg1) != 0) {
 			return PM_RET_ERROR_ARGS;
 		}
 		gicd_write_irouter(gicv3_driver_data->gicd_base,
-				PLAT_VERSAL_IPI_IRQ, MODE);
-		return PM_RET_SUCCESS;
+				  (unsigned int)PLAT_VERSAL_IPI_IRQ, MODE);
+		ret =  PM_RET_SUCCESS;
+		break;
 	default:
 		/* Send request to the PMC */
 		PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_IOCTL,
 				 device_id, ioctl_id, arg1, arg2);
-		return pm_ipi_send_sync(primary_proc, payload, value, 1);
+		ret =  pm_ipi_send_sync(primary_proc, payload, value, 1);
+		break;
 	}
+
+	return ret;
 }
 
 /**
@@ -944,14 +954,15 @@
 				    uint32_t flag)
 {
 	uint32_t payload[PAYLOAD_ARG_CNT], fw_api_version;
-	uint32_t status;
+	enum pm_ret_status status = PM_RET_ERROR_NOFEATURE;
 
 	switch (api_id) {
 	case PM_GET_CALLBACK_DATA:
 	case PM_GET_TRUSTZONE_VERSION:
 	case PM_LOAD_PDI:
 		*version = (PM_API_BASE_VERSION << 16);
-		return PM_RET_SUCCESS;
+		status = PM_RET_SUCCESS;
+		break;
 	case PM_GET_API_VERSION:
 	case PM_GET_DEVICE_STATUS:
 	case PM_GET_OP_CHARACTERISTIC:
@@ -992,25 +1003,36 @@
 	case PM_SET_MAX_LATENCY:
 	case PM_REGISTER_NOTIFIER:
 		*version = (PM_API_BASE_VERSION << 16);
+		status = PM_RET_SUCCESS;
 		break;
 	case PM_QUERY_DATA:
 		*version = (PM_API_QUERY_DATA_VERSION << 16);
+		status = PM_RET_SUCCESS;
 		break;
 	default:
 		*version = 0U;
-		return PM_RET_ERROR_NOFEATURE;
+		status = PM_RET_ERROR_NOFEATURE;
+		break;
 	}
 
+	if (status != PM_RET_SUCCESS) {
+		goto done;
+	}
+
 	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag,
 			 PM_FEATURE_CHECK, api_id);
 
 	status = pm_ipi_send_sync(primary_proc, payload, &fw_api_version, 1);
-	if (status != PM_RET_SUCCESS)
-		return status;
+	if (status != PM_RET_SUCCESS) {
+		goto done;
+	}
 
 	*version |= fw_api_version;
 
-	return PM_RET_SUCCESS;
+	status = PM_RET_SUCCESS;
+
+done:
+	return status;
 }
 
 /**
diff --git a/plat/xilinx/versal/pm_service/pm_client.c b/plat/xilinx/versal/pm_service/pm_client.c
index f6c3148..77ec20e 100644
--- a/plat/xilinx/versal/pm_service/pm_client.c
+++ b/plat/xilinx/versal/pm_service/pm_client.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2019-2021, Xilinx, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -23,8 +23,8 @@
 #include "pm_client.h"
 
 #define UNDEFINED_CPUID		(~0)
-#define IRQ_MAX		142
-#define NUM_GICD_ISENABLER	((IRQ_MAX >> 5) + 1)
+#define IRQ_MAX		142U
+#define NUM_GICD_ISENABLER	((IRQ_MAX >> 5U) + 1U)
 
 DEFINE_BAKERY_LOCK(pm_client_secure_lock);
 
@@ -122,36 +122,38 @@
 	uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX];
 	uintptr_t isenabler1 = PLAT_VERSAL_GICD_BASE + GICD_ISENABLER + 4;
 
-	zeromem(&pm_wakeup_nodes_set, sizeof(pm_wakeup_nodes_set));
+	zeromem(&pm_wakeup_nodes_set, (u_register_t)sizeof(pm_wakeup_nodes_set));
 
-	for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) {
+	for (reg_num = 0U; reg_num < NUM_GICD_ISENABLER; reg_num++) {
 		uint32_t base_irq = reg_num << ISENABLER_SHIFT;
 		uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2));
 
-		if (!reg)
+		if (reg == 0U) {
 			continue;
+		}
 
-		while (reg) {
+		while (reg != 0U) {
 			enum pm_device_node_idx node_idx;
-			uint32_t idx, ret, irq, lowest_set = reg & (-reg);
-
+			uint32_t idx, irq, lowest_set = reg & (-reg);
+			enum pm_ret_status ret;
 			idx = __builtin_ctz(lowest_set);
 			irq = base_irq + idx;
 
-			if (irq > IRQ_MAX)
+			if (irq > IRQ_MAX) {
 				break;
+			}
 
 			node_idx = irq_to_pm_node_idx(irq);
 			reg &= ~lowest_set;
 
 			if ((node_idx != XPM_NODEIDX_DEV_MIN) &&
-			    (!pm_wakeup_nodes_set[node_idx])) {
+			    (pm_wakeup_nodes_set[node_idx] == 0U)) {
 				/* Get device ID from node index */
 				device_id = PERIPH_DEVID(node_idx);
 				ret = pm_set_wakeup_source(node_id,
 							   device_id, 1,
 							   SECURE_FLAG);
-				pm_wakeup_nodes_set[node_idx] = !ret;
+				pm_wakeup_nodes_set[node_idx] = (uint8_t)(!ret);
 			}
 		}
 	}
@@ -168,12 +170,13 @@
 {
 	bakery_lock_get(&pm_client_secure_lock);
 
-	if (state == PM_STATE_SUSPEND_TO_RAM)
-		pm_client_set_wakeup_sources(proc->node_id);
+	if (state == PM_STATE_SUSPEND_TO_RAM) {
+		pm_client_set_wakeup_sources((uint32_t)proc->node_id);
+	}
 
 	/* Set powerdown request */
 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
-		      proc->pwrdn_mask);
+		      (uint32_t)proc->pwrdn_mask);
 
 	bakery_lock_release(&pm_client_secure_lock);
 }
@@ -193,7 +196,7 @@
 
 	/* Clear powerdown request */
 	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
-		      ~primary_proc->pwrdn_mask);
+		      ~((uint32_t)primary_proc->pwrdn_mask));
 
 	bakery_lock_release(&pm_client_secure_lock);
 }
@@ -206,9 +209,10 @@
  */
 static unsigned int pm_get_cpuid(uint32_t nid)
 {
-	for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
-		if (pm_procs_all[i].node_id == nid)
+	for (size_t i = 0U; i < ARRAY_SIZE(pm_procs_all); i++) {
+		if (pm_procs_all[i].node_id == nid) {
 			return i;
+		}
 	}
 	return UNDEFINED_CPUID;
 }
@@ -223,8 +227,9 @@
 {
 	unsigned int cpuid = pm_get_cpuid(proc->node_id);
 
-	if (cpuid == UNDEFINED_CPUID)
+	if (cpuid == UNDEFINED_CPUID) {
 		return;
+	}
 
 	bakery_lock_get(&pm_client_secure_lock);
 
@@ -244,8 +249,9 @@
  */
 const struct pm_proc *pm_get_proc(unsigned int cpuid)
 {
-	if (cpuid < ARRAY_SIZE(pm_procs_all))
+	if (cpuid < ARRAY_SIZE(pm_procs_all)) {
 		return &pm_procs_all[cpuid];
+	}
 
 	return NULL;
 }
diff --git a/plat/xilinx/versal/pm_service/pm_defs.h b/plat/xilinx/versal/pm_service/pm_defs.h
index ccb2617..08b46e2 100644
--- a/plat/xilinx/versal/pm_service/pm_defs.h
+++ b/plat/xilinx/versal/pm_service/pm_defs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2019-2021, Xilinx, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -33,8 +33,8 @@
 				       XPM_NODESUBCL_DEV_PERIPH, \
 				       XPM_NODETYPE_DEV_PERIPH, (IDX))
 
-#define PM_GET_CALLBACK_DATA		0xa01
-#define PM_GET_TRUSTZONE_VERSION	0xa03
+#define PM_GET_CALLBACK_DATA		0xa01U
+#define PM_GET_TRUSTZONE_VERSION	0xa03U
 
 /* PM API Versions */
 #define PM_API_BASE_VERSION		1U
@@ -88,11 +88,11 @@
 #define PM_LOAD_PDI			0x701U
 
 /* IOCTL IDs for clock driver */
-#define IOCTL_SET_PLL_FRAC_MODE		8
-#define	IOCTL_GET_PLL_FRAC_MODE		9
-#define	IOCTL_SET_PLL_FRAC_DATA		10
-#define	IOCTL_GET_PLL_FRAC_DATA		11
-#define	IOCTL_SET_SGI			25
+#define IOCTL_SET_PLL_FRAC_MODE		8U
+#define	IOCTL_GET_PLL_FRAC_MODE		9U
+#define	IOCTL_SET_PLL_FRAC_DATA		10U
+#define	IOCTL_GET_PLL_FRAC_DATA		11U
+#define	IOCTL_SET_SGI			25U
 
 /* Parameter ID for PLL IOCTLs */
 /* Fractional data portion for PLL */
diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.c b/plat/xilinx/versal/pm_service/pm_svc_main.c
index 87ba732..b082acb 100644
--- a/plat/xilinx/versal/pm_service/pm_svc_main.c
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2019-2021, Xilinx, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -20,24 +20,24 @@
 #include <drivers/arm/gicv3.h>
 
 #define XSCUGIC_SGIR_EL1_INITID_SHIFT    24U
-#define INVALID_SGI    0xFF
+#define INVALID_SGI    0xFFU
 DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6)
 
 /* pm_up = true - UP, pm_up = false - DOWN */
 static bool pm_up;
-static unsigned int sgi = INVALID_SGI;
+static unsigned int sgi = (unsigned int)INVALID_SGI;
 
 static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle,
 				void *cookie)
 {
-	int cpu;
+	unsigned int cpu;
 	unsigned int reg;
 
 	(void)plat_ic_acknowledge_interrupt();
-	cpu = plat_my_core_pos() + 1;
+	cpu = plat_my_core_pos() + 1U;
 
-	if (sgi != INVALID_SGI) {
-		reg = (cpu | (sgi << XSCUGIC_SGIR_EL1_INITID_SHIFT));
+	if ((unsigned int)sgi != (unsigned int)INVALID_SGI) {
+		reg = (cpu | ((unsigned int)sgi << (unsigned int)XSCUGIC_SGIR_EL1_INITID_SHIFT));
 		write_icc_asgi1r_el1(reg);
 	}
 
@@ -60,7 +60,7 @@
  */
 int pm_register_sgi(unsigned int sgi_num)
 {
-	if (sgi != INVALID_SGI) {
+	if ((unsigned int)sgi != (unsigned int)INVALID_SGI) {
 		return -EBUSY;
 	}
 
@@ -68,7 +68,7 @@
 		return -EINVAL;
 	}
 
-	sgi = sgi_num;
+	sgi = (unsigned int)sgi_num;
 	return 0;
 }
 
@@ -107,7 +107,7 @@
 	pm_ipi_irq_enable(primary_proc);
 
 	ret = request_intr_type_el3(PLAT_VERSAL_IPI_IRQ, ipi_fiq_handler);
-	if (ret) {
+	if (ret != 0) {
 		WARN("BL31: registering IPI interrupt failed\n");
 	}
 	return ret;
@@ -138,8 +138,9 @@
 	uint32_t security_flag = SECURE_FLAG;
 
 	/* Handle case where PM wasn't initialized properly */
-	if (!pm_up)
+	if (pm_up == false) {
 		SMC_RET1(handle, SMC_UNK);
+	}
 
 	pm_arg[0] = (uint32_t)x1;
 	pm_arg[1] = (uint32_t)(x1 >> 32);
@@ -150,7 +151,7 @@
 	 * Mark BIT24 payload (i.e 1st bit of pm_arg[3] ) as non-secure (1)
 	 * if smc called is non secure
 	 */
-	if (is_caller_non_secure(flags)) {
+	if (is_caller_non_secure(flags) != 0) {
 		security_flag = NON_SECURE_FLAG;
 	}
 
@@ -207,8 +208,8 @@
 		uint32_t api_version;
 
 		ret = pm_get_api_version(&api_version, security_flag);
-		SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
-				 ((uint64_t)api_version << 32));
+		SMC_RET1(handle, (u_register_t)PM_RET_SUCCESS |
+				 ((u_register_t)api_version << 32));
 	}
 
 	case PM_GET_DEVICE_STATUS:
@@ -216,8 +217,8 @@
 		uint32_t buff[3];
 
 		ret = pm_get_device_status(pm_arg[0], buff, security_flag);
-		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buff[0] << 32),
-			 (uint64_t)buff[1] | ((uint64_t)buff[2] << 32));
+		SMC_RET2(handle, (u_register_t)ret | ((u_register_t)buff[0] << 32),
+			 (u_register_t)buff[1] | ((u_register_t)buff[2] << 32));
 	}
 
 	case PM_RESET_ASSERT:
@@ -230,8 +231,8 @@
 
 		ret = pm_reset_get_status(pm_arg[0], &reset_status,
 					  security_flag);
-		SMC_RET1(handle, (uint64_t)ret |
-			 ((uint64_t)reset_status << 32));
+		SMC_RET1(handle, (u_register_t)ret |
+			 ((u_register_t)reset_status << 32));
 	}
 
 	case PM_INIT_FINALIZE:
@@ -244,8 +245,8 @@
 
 		pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag);
 		SMC_RET2(handle,
-			 (uint64_t)result[0] | ((uint64_t)result[1] << 32),
-			 (uint64_t)result[2] | ((uint64_t)result[3] << 32));
+			 (u_register_t)result[0] | ((u_register_t)result[1] << 32),
+			 (u_register_t)result[2] | ((u_register_t)result[3] << 32));
 	}
 
 	case PM_PINCTRL_REQUEST:
@@ -261,7 +262,7 @@
 		uint32_t value = 0;
 
 		ret = pm_pinctrl_get_function(pm_arg[0], &value, security_flag);
-		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+		SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value) << 32);
 	}
 
 	case PM_PINCTRL_SET_FUNCTION:
@@ -275,7 +276,7 @@
 
 		ret = pm_pinctrl_get_pin_param(pm_arg[0], pm_arg[1], &value,
 					       security_flag);
-		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+		SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value) << 32);
 	}
 
 	case PM_PINCTRL_CONFIG_PARAM_SET:
@@ -289,7 +290,7 @@
 
 		ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2],
 				   pm_arg[3], &value, security_flag);
-		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+		SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value) << 32);
 	}
 
 	case PM_QUERY_DATA:
@@ -299,8 +300,8 @@
 		ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
 				      pm_arg[3], data, security_flag);
 
-		SMC_RET2(handle, (uint64_t)ret  | ((uint64_t)data[0] << 32),
-				 (uint64_t)data[1] | ((uint64_t)data[2] << 32));
+		SMC_RET2(handle, (u_register_t)ret  | ((u_register_t)data[0] << 32),
+				 (u_register_t)data[1] | ((u_register_t)data[2] << 32));
 
 	}
 	case PM_CLOCK_ENABLE:
@@ -316,7 +317,7 @@
 		uint32_t value;
 
 		ret = pm_clock_get_state(pm_arg[0], &value, security_flag);
-		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+		SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value) << 32);
 	}
 
 	case PM_CLOCK_SETDIVIDER:
@@ -328,7 +329,7 @@
 		uint32_t value;
 
 		ret = pm_clock_get_divider(pm_arg[0], &value, security_flag);
-		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+		SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value) << 32);
 	}
 
 	case PM_CLOCK_SETPARENT:
@@ -340,7 +341,7 @@
 		uint32_t value;
 
 		ret = pm_clock_get_parent(pm_arg[0], &value, security_flag);
-		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+		SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value) << 32);
 	}
 
 	case PM_CLOCK_GETRATE:
@@ -348,8 +349,8 @@
 		uint32_t rate[2] = { 0 };
 
 		ret = pm_clock_get_rate(pm_arg[0], rate, security_flag);
-		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)rate[0] << 32),
-			 rate[1]);
+		SMC_RET2(handle, (u_register_t)ret | ((u_register_t)rate[0] << 32),
+			 (u_register_t)rate[1] | ((u_register_t)0U << 32));
 	}
 
 	case PM_PLL_SET_PARAMETER:
@@ -363,7 +364,7 @@
 
 		ret = pm_pll_get_param(pm_arg[0], pm_arg[1], &value,
 				       security_flag);
-		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32));
+		SMC_RET1(handle, (u_register_t)ret | ((u_register_t)value << 32));
 	}
 
 	case PM_PLL_SET_MODE:
@@ -375,7 +376,7 @@
 		uint32_t mode;
 
 		ret = pm_pll_get_mode(pm_arg[0], &mode, security_flag);
-		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32));
+		SMC_RET1(handle, (u_register_t)ret | ((u_register_t)mode << 32));
 	}
 
 	case PM_GET_TRUSTZONE_VERSION:
@@ -387,8 +388,8 @@
 		uint32_t result[2];
 
 		ret = pm_get_chipid(result, security_flag);
-		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32),
-			 result[1]);
+		SMC_RET2(handle, (u_register_t)ret | ((u_register_t)result[0] << 32),
+			 (u_register_t)result[1] | ((u_register_t)0U << 32));
 	}
 
 	case PM_FEATURE_CHECK:
@@ -396,14 +397,14 @@
 		uint32_t version;
 
 		ret = pm_feature_check(pm_arg[0], &version, security_flag);
-		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)version << 32));
+		SMC_RET1(handle, (u_register_t)ret | ((u_register_t)version << 32));
 	}
 
 	case PM_LOAD_PDI:
 	{
 		ret = pm_load_pdi(pm_arg[0], pm_arg[1], pm_arg[2],
 				  security_flag);
-		SMC_RET1(handle, (uint64_t)ret);
+		SMC_RET1(handle, (u_register_t)ret);
 	}
 
 	case PM_GET_OP_CHARACTERISTIC:
@@ -412,20 +413,20 @@
 
 		ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1], &result,
 					       security_flag);
-		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result << 32));
+		SMC_RET1(handle, (u_register_t)ret | ((u_register_t)result << 32));
 	}
 
 	case PM_SET_MAX_LATENCY:
 	{
 		ret = pm_set_max_latency(pm_arg[0], pm_arg[1], security_flag);
-		SMC_RET1(handle, (uint64_t)ret);
+		SMC_RET1(handle, (u_register_t)ret);
 	}
 
 	case PM_REGISTER_NOTIFIER:
 	{
 		ret = pm_register_notifier(pm_arg[0], pm_arg[1], pm_arg[2],
 					   pm_arg[3], security_flag);
-		SMC_RET1(handle, (uint64_t)ret);
+		SMC_RET1(handle, (u_register_t)ret);
 	}
 
 	default:
diff --git a/plat/xilinx/versal/sip_svc_setup.c b/plat/xilinx/versal/sip_svc_setup.c
index bc7d8b7..6f2ff94 100644
--- a/plat/xilinx/versal/sip_svc_setup.c
+++ b/plat/xilinx/versal/sip_svc_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,13 +14,13 @@
 #include "pm_svc_main.h"
 
 /* SMC function IDs for SiP Service queries */
-#define VERSAL_SIP_SVC_CALL_COUNT	0x8200ff00
-#define VERSAL_SIP_SVC_UID		0x8200ff01
-#define VERSAL_SIP_SVC_VERSION		0x8200ff03
+#define VERSAL_SIP_SVC_CALL_COUNT	U(0x8200ff00)
+#define VERSAL_SIP_SVC_UID		U(0x8200ff01)
+#define VERSAL_SIP_SVC_VERSION		U(0x8200ff03)
 
 /* SiP Service Calls version numbers */
-#define SIP_SVC_VERSION_MAJOR	0
-#define SIP_SVC_VERSION_MINOR	1
+#define SIP_SVC_VERSION_MAJOR	U(0)
+#define SIP_SVC_VERSION_MINOR	U(1)
 
 /* These macros are used to identify PM calls from the SMC function ID */
 #define PM_FID_MASK	0xf000u
@@ -31,8 +31,8 @@
 
 /* SiP Service UUID */
 DEFINE_SVC_UUID2(versal_sip_uuid,
-		0x2ab9e4ec, 0x93b9, 0x11e7, 0xa0, 0x19,
-		0xdf, 0xe0, 0xdb, 0xad, 0x0a, 0xe0);
+		0x2ab9e4ecU, 0x93b9U, 0x11e7U, 0xa0U, 0x19U,
+		0xdfU, 0xe0U, 0xdbU, 0xadU, 0x0aU, 0xe0U);
 
 /**
  * sip_svc_setup() - Setup SiP Service
@@ -42,7 +42,7 @@
 static int32_t sip_svc_setup(void)
 {
 	/* PM implementation as SiP Service */
-	pm_setup();
+	(void)pm_setup();
 
 	return 0;
 }
diff --git a/plat/xilinx/versal/versal_ipi.c b/plat/xilinx/versal/versal_ipi.c
index 27541ff..f99af82 100644
--- a/plat/xilinx/versal/versal_ipi.c
+++ b/plat/xilinx/versal/versal_ipi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2019-2021, Xilinx, Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -24,49 +24,49 @@
 	[IPI_ID_APU] = {
 		.ipi_bit_mask = IPI0_TRIG_BIT,
 		.ipi_reg_base = IPI0_REG_BASE,
-		.secure_only = 0,
+		.secure_only = 0U,
 	},
 
 	/* PMC IPI */
 	[IPI_ID_PMC] = {
 		.ipi_bit_mask = PMC_IPI_TRIG_BIT,
 		.ipi_reg_base = IPI0_REG_BASE,
-		.secure_only = 0,
+		.secure_only = 0U,
 	},
 
 	/* RPU0 IPI */
 	[IPI_ID_RPU0] = {
 		.ipi_bit_mask = IPI1_TRIG_BIT,
 		.ipi_reg_base = IPI1_REG_BASE,
-		.secure_only = 0,
+		.secure_only = 0U,
 	},
 
 	/* RPU1 IPI */
 	[IPI_ID_RPU1] = {
 		.ipi_bit_mask = IPI2_TRIG_BIT,
 		.ipi_reg_base = IPI2_REG_BASE,
-		.secure_only = 0,
+		.secure_only = 0U,
 	},
 
 	/* IPI3 IPI */
 	[IPI_ID_3] = {
 		.ipi_bit_mask = IPI3_TRIG_BIT,
 		.ipi_reg_base = IPI3_REG_BASE,
-		.secure_only = 0,
+		.secure_only = 0U,
 	},
 
 	/* IPI4 IPI */
 	[IPI_ID_4] = {
 		.ipi_bit_mask = IPI4_TRIG_BIT,
 		.ipi_reg_base = IPI4_REG_BASE,
-		.secure_only = 0,
+		.secure_only = 0U,
 	},
 
 	/* IPI5 IPI */
 	[IPI_ID_5] = {
 		.ipi_bit_mask = IPI5_TRIG_BIT,
 		.ipi_reg_base = IPI5_REG_BASE,
-		.secure_only = 0,
+		.secure_only = 0U,
 	},
 };
 
diff --git a/services/std_svc/rmmd/rmmd_main.c b/services/std_svc/rmmd/rmmd_main.c
index 7f85b63..e9004c7 100644
--- a/services/std_svc/rmmd/rmmd_main.c
+++ b/services/std_svc/rmmd/rmmd_main.c
@@ -48,10 +48,6 @@
  * Static function declaration.
  ******************************************************************************/
 static int32_t rmm_init(void);
-static uint64_t rmmd_smc_forward(uint32_t smc_fid, uint32_t src_sec_state,
-					uint32_t dst_sec_state, uint64_t x1,
-					uint64_t x2, uint64_t x3, uint64_t x4,
-					void *handle);
 
 /*******************************************************************************
  * This function takes an RMM context pointer and performs a synchronous entry
@@ -191,10 +187,10 @@
 /*******************************************************************************
  * Forward SMC to the other security state
  ******************************************************************************/
-static uint64_t	rmmd_smc_forward(uint32_t smc_fid, uint32_t src_sec_state,
-					uint32_t dst_sec_state, uint64_t x1,
-					uint64_t x2, uint64_t x3, uint64_t x4,
-					void *handle)
+static uint64_t	rmmd_smc_forward(uint32_t src_sec_state,
+					uint32_t dst_sec_state, uint64_t x0,
+					uint64_t x1, uint64_t x2, uint64_t x3,
+					uint64_t x4, void *handle)
 {
 	/* Save incoming security state */
 	cm_el1_sysregs_context_save(src_sec_state);
@@ -205,10 +201,20 @@
 	cm_el2_sysregs_context_restore(dst_sec_state);
 	cm_set_next_eret_context(dst_sec_state);
 
-	SMC_RET8(cm_get_context(dst_sec_state), smc_fid, x1, x2, x3, x4,
-			SMC_GET_GP(handle, CTX_GPREG_X5),
-			SMC_GET_GP(handle, CTX_GPREG_X6),
-			SMC_GET_GP(handle, CTX_GPREG_X7));
+	/*
+	 * As per SMCCCv1.1, we need to preserve x4 to x7 unless
+	 * being used as return args. Hence we differentiate the
+	 * onward and backward path. Support upto 8 args in the
+	 * onward path and 4 args in return path.
+	 */
+	if (src_sec_state == NON_SECURE) {
+		SMC_RET8(cm_get_context(dst_sec_state), x0, x1, x2, x3, x4,
+				SMC_GET_GP(handle, CTX_GPREG_X5),
+				SMC_GET_GP(handle, CTX_GPREG_X6),
+				SMC_GET_GP(handle, CTX_GPREG_X7));
+	} else {
+		SMC_RET4(cm_get_context(dst_sec_state), x0, x1, x2, x3);
+	}
 }
 
 /*******************************************************************************
@@ -237,7 +243,7 @@
 	 */
 	if (src_sec_state == SMC_FROM_NON_SECURE) {
 		VERBOSE("RMM: RMI call from non-secure world.\n");
-		return rmmd_smc_forward(smc_fid, NON_SECURE, REALM,
+		return rmmd_smc_forward(NON_SECURE, REALM, smc_fid,
 					x1, x2, x3, x4, handle);
 	}
 
@@ -250,7 +256,7 @@
 			rmmd_rmm_sync_exit(x1);
 		}
 
-		return rmmd_smc_forward(x1, REALM, NON_SECURE,
+		return rmmd_smc_forward(REALM, NON_SECURE, x1,
 					x2, x3, x4, 0, handle);
 
 	default: