Merge pull request #1792 from satheesbalya-arm/sb1/sb1_2159_v84_xlat

lib/xlat_tables: Add support for ARMv8.4-TTST
diff --git a/Makefile b/Makefile
index ad1ba15..4e606a2 100644
--- a/Makefile
+++ b/Makefile
@@ -242,6 +242,7 @@
 TF_LDFLAGS		+=	$(TF_LDFLAGS_$(ARCH))
 
 DTC_FLAGS		+=	-I dts -O dtb
+DTC_CPPFLAGS		+=	-nostdinc -Iinclude -undef -x assembler-with-cpp
 
 ################################################################################
 # Common sources and include directories
diff --git a/docs/coding-guidelines.rst b/docs/coding-guidelines.rst
new file mode 100644
index 0000000..5a30e91
--- /dev/null
+++ b/docs/coding-guidelines.rst
@@ -0,0 +1,553 @@
+Trusted Firmware-A Coding Guidelines
+====================================
+
+.. section-numbering::
+    :suffix: .
+
+.. contents::
+
+The following sections contain TF coding guidelines. They are continually
+evolving and should not be considered "set in stone". Feel free to question them
+and provide feedback.
+
+Some of the guidelines may also apply to other codebases.
+
+**Note:** the existing TF codebase does not necessarily comply with all the
+below guidelines but the intent is for it to do so eventually.
+
+Checkpatch overrides
+--------------------
+
+Some checkpatch warnings in the TF codebase are deliberately ignored. These
+include:
+
+- ``**WARNING: line over 80 characters**``: Although the codebase should
+  generally conform to the 80 character limit this is overly restrictive in some
+  cases.
+
+- ``**WARNING: Use of volatile is usually wrong``: see
+  `Why the “volatile” type class should not be used`_ . Although this document
+  contains some very useful information, there are several legimate uses of the
+  volatile keyword within the TF codebase.
+
+Headers and inclusion
+---------------------
+
+Header guards
+^^^^^^^^^^^^^
+
+For a header file called "some_driver.h" the style used by the Trusted Firmware
+is:
+
+.. code:: c
+
+  #ifndef SOME_DRIVER_H
+  #define SOME_DRIVER_H
+
+  <header content>
+
+  #endif /* SOME_DRIVER_H */
+
+Include statement ordering
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+All header files that are included by a source file must use the following,
+grouped ordering. This is to improve readability (by making it easier to quickly
+read through the list of headers) and maintainability.
+
+#. *System* includes: Header files from the standard *C* library, such as
+   ``stddef.h`` and ``string.h``.
+
+#. *Project* includes: Header files under the ``include/`` directory within TF
+   are *project* includes.
+
+#. *Platform* includes: Header files relating to a single, specific platform,
+   and which are located under the ``plat/<platform_name>`` directory within TF,
+   are *platform* includes.
+
+Within each group, ``#include`` statements must be in alphabetical order,
+taking both the file and directory names into account.
+
+Groups must be separated by a single blank line for clarity.
+
+The example below illustrates the ordering rules using some contrived header
+file names; this type of name reuse should be otherwise avoided.
+.. code:: c
+
+  #include <string.h>
+
+  #include <a_dir/example/a_header.h>
+  #include <a_dir/example/b_header.h>
+  #include <a_dir/test/a_header.h>
+  #include <b_dir/example/a_header.h>
+
+  #include "./a_header.h"
+
+Include statement variants
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Two variants of the ``#include`` directive are acceptable in the TF codebase.
+Correct use of the two styles improves readability by suggesting the location
+of the included header and reducing ambiguity in cases where generic and
+platform-specific headers share a name.
+
+For header files that are in the same directory as the source file that is
+including them, use the ``"..."`` variant.
+
+For header files that are **not** in the same directory as the source file that
+is including them, use the ``<...>`` variant.
+
+Example (bl1_fwu.c):
+.. code:: c
+
+  #include <assert.h>
+  #include <errno.h>
+  #include <string.h>
+
+  #include "bl1_private.h"
+
+Platform include paths
+^^^^^^^^^^^^^^^^^^^^^^
+
+Platforms are allowed to add more include paths to be passed to the compiler.
+The ``PLAT_INCLUDES`` variable is used for this purpose. This is needed in
+particular for the file ``platform_def.h``.
+
+Example:
+.. code:: c
+
+  PLAT_INCLUDES  += -Iinclude/plat/myplat/include
+
+Types and typedefs
+------------------
+
+Use of built-in *C* and *libc* data types
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The TF codebase should be kept as portable as possible, especially since both
+64-bit and 32-bit platforms are supported. To help with this, the following data
+type usage guidelines should be followed:
+
+- Where possible, use the built-in *C* data types for variable storage (for
+  example, ``char``, ``int``, ``long long``, etc) instead of the standard *C99*
+  types. Most code is typically only concerned with the minimum size of the
+  data stored, which the built-in *C* types guarantee.
+
+- Avoid using the exact-size standard *C99* types in general (for example,
+  ``uint16_t``, ``uint32_t``, ``uint64_t``, etc) since they can prevent the
+  compiler from making optimizations. There are legitimate uses for them,
+  for example to represent data of a known structure. When using them in struct
+  definitions, consider how padding in the struct will work across architectures.
+  For example, extra padding may be introduced in AArch32 systems if a struct
+  member crosses a 32-bit boundary.
+
+- Use ``int`` as the default integer type - it's likely to be the fastest on all
+  systems. Also this can be assumed to be 32-bit as a consequence of the
+  `Procedure Call Standard for the Arm Architecture`_ and the `Procedure Call
+  Standard for the Arm 64-bit Architecture`_ .
+
+- Avoid use of ``short`` as this may end up being slower than ``int`` in some
+  systems. If a variable must be exactly 16-bit, use ``int16_t`` or
+  ``uint16_t``.
+
+- Avoid use of ``long``. This is guaranteed to be at least 32-bit but, given
+  that `int` is 32-bit on Arm platforms, there is no use for it. For integers of
+  at least 64-bit, use ``long long``.
+
+- Use ``char`` for storing text. Use ``uint8_t`` for storing other 8-bit data.
+
+- Use ``unsigned`` for integers that can never be negative (counts,
+  indices, sizes, etc). TF intends to comply with MISRA "essential type" coding
+  rules (10.X), where signed and unsigned types are considered different
+  essential types. Choosing the correct type will aid this. MISRA static
+  analysers will pick up any implicit signed/unsigned conversions that may lead
+  to unexpected behaviour.
+
+- For pointer types:
+
+  - If an argument in a function declaration is pointing to a known type then
+    simply use a pointer to that type (for example: ``struct my_struct *``).
+
+  - If a variable (including an argument in a function declaration) is pointing
+    to a general, memory-mapped address, an array of pointers or another
+    structure that is likely to require pointer arithmetic then use
+    ``uintptr_t``. This will reduce the amount of casting required in the code.
+    Avoid using ``unsigned long`` or ``unsigned long long`` for this purpose; it
+    may work but is less portable.
+
+  - For other pointer arguments in a function declaration, use ``void *``. This
+    includes pointers to types that are abstracted away from the known API and
+    pointers to arbitrary data. This allows the calling function to pass a
+    pointer argument to the function without any explicit casting (the cast to
+    ``void *`` is implicit). The function implementation can then do the
+    appropriate casting to a specific type.
+
+  - Use ``ptrdiff_t`` to compare the difference between 2 pointers.
+
+- Use ``size_t`` when storing the ``sizeof()`` something.
+
+- Use ``ssize_t`` when returning the ``sizeof()`` something from a function that
+  can also return an error code; the signed type allows for a negative return
+  code in case of error. This practice should be used sparingly.
+
+- Use ``u_register_t`` when it's important to store the contents of a register
+  in its native size (32-bit in AArch32 and 64-bit in AArch64). This is not a
+  standard *C99* type but is widely available in libc implementations,
+  including the FreeBSD version included with the TF codebase. Where possible,
+  cast the variable to a more appropriate type before interpreting the data. For
+  example, the following struct in ``ep_info.h`` could use this type to minimize
+  the storage required for the set of registers:
+
+.. code:: c
+
+    typedef struct aapcs64_params {
+            u_register_t arg0;
+            u_register_t arg1;
+            u_register_t arg2;
+            u_register_t arg3;
+            u_register_t arg4;
+            u_register_t arg5;
+            u_register_t arg6;
+            u_register_t arg7;
+    } aapcs64_params_t;
+
+
+    If some code wants to operate on ``arg0`` and knows that it represents a
+    32-bit unsigned integer on all systems, cast it to ``unsigned int``.
+
+These guidelines should be updated if additional types are needed.
+
+Avoid anonymous typedefs of structs/enums in headers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For example, the following definition:
+
+.. code:: c
+
+  typedef struct {
+          int arg1;
+          int arg2;
+  } my_struct_t;
+
+
+is better written as:
+
+.. code:: c
+
+  struct my_struct {
+          int arg1;
+          int arg2;
+  };
+
+This allows function declarations in other header files that depend on the
+struct/enum to forward declare the struct/enum instead of including the
+entire header:
+
+.. code:: c
+
+  #include <my_struct.h>
+  void my_func(my_struct_t *arg);
+
+instead of:
+
+.. code:: c
+
+  struct my_struct;
+  void my_func(struct my_struct *arg);
+
+Some TF definitions use both a struct/enum name **and** a typedef name. This
+is discouraged for new definitions as it makes it difficult for TF to comply
+with MISRA rule 8.3, which states that "All declarations of an object or
+function shall use the same names and type qualifiers".
+
+The Linux coding standards also discourage new typedefs and checkpatch emits
+a warning for this.
+
+Existing typedefs will be retained for compatibility.
+
+Error handling and robustness
+-----------------------------
+
+Using CASSERT to check for compile time data errors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Where possible, use the ``CASSERT`` macro to check the validity of data known at
+compile time instead of checking validity at runtime, to avoid unnecessary
+runtime code.
+
+For example, this can be used to check that the assembler's and compiler's views
+of the size of an array is the same.
+
+.. code:: c
+
+  #include <cassert.h>
+
+  define MY_STRUCT_SIZE 8 /* Used by assembler source files */
+
+  struct my_struct {
+      uint32_t arg1;
+      uint32_t arg2;
+  };
+
+  CASSERT(MY_STRUCT_SIZE == sizeof(struct my_struct), assert_my_struct_size_mismatch);
+
+
+If ``MY_STRUCT_SIZE`` in the above example were wrong then the compiler would
+emit an error like this:
+
+.. code:: c
+
+  my_struct.h:10:1: error: size of array ‘assert_my_struct_size_mismatch’ is negative
+
+
+Using assert() to check for programming errors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In general, each secure world TF image (BL1, BL2, BL31 and BL32) should be
+treated as a tightly integrated package; the image builder should be aware of
+and responsible for all functionality within the image, even if code within that
+image is provided by multiple entities. This allows us to be more aggressive in
+interpreting invalid state or bad function arguments as programming errors using
+``assert()``, including arguments passed across platform porting interfaces.
+This is in contrast to code in a Linux environment, which is less tightly
+integrated and may attempt to be more defensive by passing the error back up the
+call stack.
+
+Where possible, badly written TF code should fail early using ``assert()``. This
+helps reduce the amount of untested conditional code. By default these
+statements are not compiled into release builds, although this can be overridden
+using the ``ENABLE_ASSERTIONS`` build flag.
+
+Examples:
+
+- Bad argument supplied to library function
+- Bad argument provided by platform porting function
+- Internal secure world image state is inconsistent
+
+
+Handling integration errors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Each secure world image may be provided by a different entity (for example, a
+Trusted Boot vendor may provide the BL2 image, a TEE vendor may provide the BL32
+image and the OEM/SoC vendor may provide the other images).
+
+An image may contain bugs that are only visible when the images are integrated.
+The system integrator may not even have access to the debug variants of all the
+images in order to check if asserts are firing. For example, the release variant
+of BL1 may have already been burnt into the SoC. Therefore, TF code that detects
+an integration error should _not_ consider this a programming error, and should
+always take action, even in release builds.
+
+If an integration error is considered non-critical it should be treated as a
+recoverable error. If the error is considered critical it should be treated as
+an unexpected unrecoverable error.
+
+Handling recoverable errors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The secure world **must not** crash when supplied with bad data from an external
+source. For example, data from the normal world or a hardware device. Similarly,
+the secure world **must not** crash if it detects a non-critical problem within
+itself or the system. It must make every effort to recover from the problem by
+emitting a ``WARN`` message, performing any necessary error handling and
+continuing.
+
+Examples:
+
+- Secure world receives SMC from normal world with bad arguments.
+- Secure world receives SMC from normal world at an unexpected time.
+- BL31 receives SMC from BL32 with bad arguments.
+- BL31 receives SMC from BL32 at unexpected time.
+- Secure world receives recoverable error from hardware device. Retrying the
+  operation may help here.
+- Non-critical secure world service is not functioning correctly.
+- BL31 SPD discovers minor configuration problem with corresponding SP.
+
+Handling unrecoverable errors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In some cases it may not be possible for the secure world to recover from an
+error. This situation should be handled in one of the following ways:
+
+1. If the unrecoverable error is unexpected then emit an ``ERROR`` message and
+   call ``panic()``. This will end up calling the platform-specific function
+   ``plat_panic_handler()``.
+2. If the unrecoverable error is expected to occur in certain circumstances,
+   then emit an ``ERROR`` message and call the platform-specific function
+   ``plat_error_handler()``.
+
+Cases 1 and 2 are subtly different. A platform may implement ``plat_panic_handler``
+and ``plat_error_handler`` in the same way (for example, by waiting for a secure
+watchdog to time-out or by invoking an interface on the platform's power
+controller to reset the platform). However, ``plat_error_handler`` may take
+additional action for some errors (for example, it may set a flag so the
+platform resets into a different mode). Also, ``plat_panic_handler()`` may
+implement additional debug functionality (for example, invoking a hardware
+breakpoint).
+
+Examples of unexpected unrecoverable errors:
+
+- BL32 receives an unexpected SMC response from BL31 that it is unable to
+  recover from.
+- BL31 Trusted OS SPD code discovers that BL2 has not loaded the corresponding
+  Trusted OS, which is critical for platform operation.
+- Secure world discovers that a critical hardware device is an unexpected and
+  unrecoverable state.
+- Secure world receives an unexpected and unrecoverable error from a critical
+  hardware device.
+- Secure world discovers that it is running on unsupported hardware.
+
+Examples of expected unrecoverable errors:
+
+- BL1/BL2 fails to load the next image due to missing/corrupt firmware on disk.
+- BL1/BL2 fails to authenticate the next image due to an invalid certificate.
+- Secure world continuously receives recoverable errors from a hardware device
+  but is unable to proceed without a valid response.
+
+Handling critical unresponsiveness
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If the secure world is waiting for a response from an external source (for
+example, the normal world or a hardware device) which is critical for continued
+operation, it must not wait indefinitely. It must have a mechanism (for example,
+a secure watchdog) for resetting itself and/or the external source to prevent
+the system from executing in this state indefinitely.
+
+Examples:
+
+- BL1 is waiting for the normal world to raise an SMC to proceed to the next
+  stage of the secure firmware update process.
+- A Trusted OS is waiting for a response from a proxy in the normal world that
+  is critical for continued operation.
+- Secure world is waiting for a hardware response that is critical for continued
+  operation.
+
+Security considerations
+-----------------------
+
+Part of the security of a platform is handling errors correctly, as described in
+the previous section. There are several other security considerations covered in
+this section.
+
+Do not leak secrets to the normal world
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The secure world **must not** leak secrets to the normal world, for example in
+response to an SMC.
+
+Handling Denial of Service attacks
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The secure world **should never** crash or become unusable due to receiving too
+many normal world requests (a *Denial of Service* or *DoS* attack). It should
+have a mechanism for throttling or ignoring normal world requests.
+
+Performance considerations
+--------------------------
+
+Avoid printf and use logging macros
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``debug.h`` provides logging macros (for example, ``WARN`` and ``ERROR``)
+which wrap ``tf_log`` and which allow the logging call to be compiled-out
+depending on the ``make`` command. Use these macros to avoid print statements
+being compiled unconditionally into the binary.
+
+Each logging macro has a numerical log level:
+
+.. code:: c
+
+  #define LOG_LEVEL_NONE    0
+  #define LOG_LEVEL_ERROR   10
+  #define LOG_LEVEL_NOTICE  20
+  #define LOG_LEVEL_WARNING 30
+  #define LOG_LEVEL_INFO    40
+  #define LOG_LEVEL_VERBOSE 50
+
+
+By default, all logging statements with a log level ``<= LOG_LEVEL_INFO`` will
+be compiled into debug builds and all statements with a log level
+``<= LOG_LEVEL_NOTICE`` will be compiled into release builds. This can be
+overridden from the command line or by the platform makefile (although it may be
+necessary to clean the build directory first). For example, to enable
+``VERBOSE`` logging on FVP:
+
+``make PLAT=fvp LOG_LEVEL=50 all``
+
+Use const data where possible
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For example, the following code:
+
+.. code:: c
+
+  struct my_struct {
+          int arg1;
+          int arg2;
+  };
+
+  void init(struct my_struct *ptr);
+
+  void main(void)
+  {
+          struct my_struct x;
+          x.arg1 = 1;
+          x.arg2 = 2;
+          init(&x);
+  }
+
+is better written as:
+
+.. code:: c
+
+  struct my_struct {
+          int arg1;
+          int arg2;
+  };
+
+  void init(const struct my_struct *ptr);
+
+  void main(void)
+  {
+          const struct my_struct x = { 1, 2 };
+          init(&x);
+  }
+
+This allows the linker to put the data in a read-only data section instead of a
+writeable data section, which may result in a smaller and faster binary. Note
+that this may require dependent functions (``init()`` in the above example) to
+have ``const`` arguments, assuming they don't need to modify the data.
+
+Library and driver code
+-----------------------
+
+TF library code (under ``lib/`` and ``include/lib``) is any code that provides a
+reusable interface to other code, potentially even to code outside of TF.
+
+In some systems drivers must conform to a specific driver framework to provide
+services to the rest of the system. TF has no driver framework and the
+distinction between a driver and library is somewhat subjective.
+
+A driver (under ``drivers/`` and ``include/drivers/``) is defined as code that
+interfaces with hardware via a memory mapped interface.
+
+Some drivers (for example, the Arm CCI driver in ``include/drivers/arm/cci.h``)
+provide a general purpose API to that specific hardware. Other drivers (for
+example, the Arm PL011 console driver in ``drivers/arm/pl011/pl011_console.S``)
+provide a specific hardware implementation of a more abstract library API. In
+the latter case there may potentially be multiple drivers for the same hardware
+device.
+
+Neither libraries nor drivers should depend on platform-specific code. If they
+require platform-specific data (for example, a base address) to operate then
+they should provide an initialization function that takes the platform-specific
+data as arguments.
+
+TF common code (under ``common/`` and ``include/common/``) is code that is re-used
+by other generic (non-platform-specific) TF code. It is effectively internal
+library code.
+
+.. _`Why the “volatile” type class should not be used`: https://www.kernel.org/doc/html/latest/process/volatile-considered-harmful.html
+.. _`Procedure Call Standard for the Arm Architecture`: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf
+.. _`Procedure Call Standard for the Arm 64-bit Architecture`: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
diff --git a/docs/user-guide.rst b/docs/user-guide.rst
index b50de37..e22733e 100644
--- a/docs/user-guide.rst
+++ b/docs/user-guide.rst
@@ -86,6 +86,46 @@
 
     git clone https://github.com/ARM-software/arm-trusted-firmware.git
 
+Checking source code style
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Trusted Firmware follows the `Linux Coding Style`_ . When making changes to the
+source, for submission to the project, the source must be in compliance with
+this style guide.
+
+Additional, project-specific guidelines are defined in the `Trusted Firmware-A
+Coding Guidelines`_ document.
+
+To assist with coding style compliance, the project Makefile contains two
+targets which both utilise the `checkpatch.pl` script that ships with the Linux
+source tree. The project also defines certain *checkpatch* options in the
+``.checkpatch.conf`` file in the top-level directory.
+
+**Note:** Checkpatch errors will gate upstream merging of pull requests.
+Checkpatch warnings will not gate merging but should be reviewed and fixed if
+possible.
+
+To check the entire source tree, you must first download copies of
+``checkpatch.pl``, ``spelling.txt`` and ``const_structs.checkpatch`` available
+in the `Linux master tree`_ *scripts* directory, then set the ``CHECKPATCH``
+environment variable to point to ``checkpatch.pl`` (with the other 2 files in
+the same directory) and build the `checkcodebase` target:
+
+::
+
+    make CHECKPATCH=<path-to-linux>/linux/scripts/checkpatch.pl checkcodebase
+
+To just check the style on the files that differ between your local branch and
+the remote master, use:
+
+::
+
+    make CHECKPATCH=<path-to-linux>/linux/scripts/checkpatch.pl checkpatch
+
+If you wish to check your patch against something other than the remote master,
+set the ``BASE_COMMIT`` variable to your desired branch. By default, ``BASE_COMMIT``
+is set to ``origin/master``.
+
 Building TF-A
 -------------
 
@@ -930,34 +970,6 @@
 
     build/<platform>/<build-type>/bl32.bin
 
-Checking source code style
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When making changes to the source for submission to the project, the source
-must be in compliance with the Linux style guide, and to assist with this check
-the project Makefile contains two targets, which both utilise the
-``checkpatch.pl`` script that ships with the Linux source tree.
-
-To check the entire source tree, you must first download copies of
-``checkpatch.pl``, ``spelling.txt`` and ``const_structs.checkpatch`` available
-in the `Linux master tree`_ scripts directory, then set the ``CHECKPATCH``
-environment variable to point to ``checkpatch.pl`` (with the other 2 files in
-the same directory) and build the target checkcodebase:
-
-::
-
-    make CHECKPATCH=<path-to-linux>/linux/scripts/checkpatch.pl checkcodebase
-
-To just check the style on the files that differ between your local branch and
-the remote master, use:
-
-::
-
-    make CHECKPATCH=<path-to-linux>/linux/scripts/checkpatch.pl checkpatch
-
-If you wish to check your patch against something other than the remote master,
-set the ``BASE_COMMIT`` variable to your desired branch. By default, ``BASE_COMMIT``
-is set to ``origin/master``.
 
 Building and using the FIP tool
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2054,6 +2066,7 @@
 .. _Instructions for using Linaro's deliverables on Juno: https://community.arm.com/dev-platforms/w/docs/303/juno
 .. _Arm Platforms Portal: https://community.arm.com/dev-platforms/
 .. _Development Studio 5 (DS-5): http://www.arm.com/products/tools/software-tools/ds-5/index.php
+.. _`Linux Coding Style`: https://www.kernel.org/doc/html/latest/process/coding-style.html
 .. _Linux master tree: https://github.com/torvalds/linux/tree/master/
 .. _Dia: https://wiki.gnome.org/Apps/Dia/Download
 .. _here: psci-lib-integration-guide.rst
@@ -2069,3 +2082,4 @@
 .. _Juno Getting Started Guide: http://infocenter.arm.com/help/topic/com.arm.doc.dui0928e/DUI0928E_juno_arm_development_platform_gsg.pdf
 .. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf
 .. _Secure Partition Manager Design guide: secure-partition-manager-design.rst
+.. _`Trusted Firmware-A Coding Guidelines`: coding-guidelines.rst
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 450bd0b..77d683c 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -300,7 +300,7 @@
 		break;
 	}
 
-	if (ret != 0) {
+	if (ret < 0) {
 		return ret;
 	}
 
diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c
index 630c1d8..6fa3df0 100644
--- a/drivers/partition/partition.c
+++ b/drivers/partition/partition.c
@@ -16,7 +16,7 @@
 #include <plat/common/platform.h>
 
 static uint8_t mbr_sector[PARTITION_BLOCK_SIZE];
-partition_entry_list_t list;
+static partition_entry_list_t list;
 
 #if LOG_LEVEL >= LOG_LEVEL_VERBOSE
 static void dump_entries(int num)
diff --git a/drivers/rpi3/gpio/rpi3_gpio.c b/drivers/rpi3/gpio/rpi3_gpio.c
new file mode 100644
index 0000000..b39808f
--- /dev/null
+++ b/drivers/rpi3/gpio/rpi3_gpio.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2019, Linaro Limited
+ * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <lib/mmio.h>
+#include <drivers/delay_timer.h>
+#include <drivers/rpi3/gpio/rpi3_gpio.h>
+
+static struct rpi3_gpio_params rpi3_gpio_params;
+
+static int rpi3_gpio_get_direction(int gpio);
+static void rpi3_gpio_set_direction(int gpio, int direction);
+static int rpi3_gpio_get_value(int gpio);
+static void rpi3_gpio_set_value(int gpio, int value);
+static void rpi3_gpio_set_pull(int gpio, int pull);
+
+static const gpio_ops_t rpi3_gpio_ops = {
+	.get_direction  = rpi3_gpio_get_direction,
+	.set_direction  = rpi3_gpio_set_direction,
+	.get_value      = rpi3_gpio_get_value,
+	.set_value      = rpi3_gpio_set_value,
+	.set_pull       = rpi3_gpio_set_pull,
+};
+
+/**
+ * Get selection of GPIO pinmux settings.
+ *
+ * @param gpio The pin number of GPIO. From 0 to 53.
+ * @return The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
+ *                                  RPI3_GPIO_FUNC_OUTPUT: output,
+ *                                  RPI3_GPIO_FUNC_ALT0: alt-0,
+ *                                  RPI3_GPIO_FUNC_ALT1: alt-1,
+ *                                  RPI3_GPIO_FUNC_ALT2: alt-2,
+ *                                  RPI3_GPIO_FUNC_ALT3: alt-3,
+ *                                  RPI3_GPIO_FUNC_ALT4: alt-4,
+ *                                  RPI3_GPIO_FUNC_ALT5: alt-5
+ */
+int rpi3_gpio_get_select(int gpio)
+{
+	int ret;
+	uintptr_t reg_base = rpi3_gpio_params.reg_base;
+	int regN = gpio / 10;
+	int shift = 3 * (gpio % 10);
+	uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
+	uint32_t sel = mmio_read_32(reg_sel);
+
+	ret = (sel >> shift) & 0x07;
+
+	return ret;
+}
+
+/**
+ * Set selection of GPIO pinmux settings.
+ *
+ * @param gpio The pin number of GPIO. From 0 to 53.
+ * @param fsel The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
+ *                                      RPI3_GPIO_FUNC_OUTPUT: output,
+ *                                      RPI3_GPIO_FUNC_ALT0: alt-0,
+ *                                      RPI3_GPIO_FUNC_ALT1: alt-1,
+ *                                      RPI3_GPIO_FUNC_ALT2: alt-2,
+ *                                      RPI3_GPIO_FUNC_ALT3: alt-3,
+ *                                      RPI3_GPIO_FUNC_ALT4: alt-4,
+ *                                      RPI3_GPIO_FUNC_ALT5: alt-5
+ */
+void rpi3_gpio_set_select(int gpio, int fsel)
+{
+	uintptr_t reg_base = rpi3_gpio_params.reg_base;
+	int regN = gpio / 10;
+	int shift = 3 * (gpio % 10);
+	uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
+	uint32_t sel = mmio_read_32(reg_sel);
+	uint32_t mask = U(0x07) << shift;
+
+	sel = (sel & (~mask)) | ((fsel << shift) & mask);
+	mmio_write_32(reg_sel, sel);
+}
+
+static int rpi3_gpio_get_direction(int gpio)
+{
+	int result = rpi3_gpio_get_select(gpio);
+
+	if (result == RPI3_GPIO_FUNC_INPUT)
+		return GPIO_DIR_IN;
+	else if (result == RPI3_GPIO_FUNC_OUTPUT)
+		return GPIO_DIR_OUT;
+
+	return GPIO_DIR_IN;
+}
+
+static void rpi3_gpio_set_direction(int gpio, int direction)
+{
+	switch (direction) {
+	case GPIO_DIR_IN:
+		rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_INPUT);
+		break;
+	case GPIO_DIR_OUT:
+		rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_OUTPUT);
+		break;
+	}
+}
+
+static int rpi3_gpio_get_value(int gpio)
+{
+	uintptr_t reg_base = rpi3_gpio_params.reg_base;
+	int regN = gpio / 32;
+	int shift = gpio % 32;
+	uintptr_t reg_lev = reg_base + RPI3_GPIO_GPLEV(regN);
+	uint32_t value = mmio_read_32(reg_lev);
+
+	if ((value >> shift) & 0x01)
+		return GPIO_LEVEL_HIGH;
+	return GPIO_LEVEL_LOW;
+}
+
+static void rpi3_gpio_set_value(int gpio, int value)
+{
+	uintptr_t reg_base = rpi3_gpio_params.reg_base;
+	int regN = gpio / 32;
+	int shift = gpio % 32;
+	uintptr_t reg_set = reg_base + RPI3_GPIO_GPSET(regN);
+	uintptr_t reg_clr = reg_base + RPI3_GPIO_GPSET(regN);
+
+	switch (value) {
+	case GPIO_LEVEL_LOW:
+		mmio_write_32(reg_clr, U(1) << shift);
+		break;
+	case GPIO_LEVEL_HIGH:
+		mmio_write_32(reg_set, U(1) << shift);
+		break;
+	}
+}
+
+static void rpi3_gpio_set_pull(int gpio, int pull)
+{
+	uintptr_t reg_base = rpi3_gpio_params.reg_base;
+	int regN = gpio / 32;
+	int shift = gpio % 32;
+	uintptr_t reg_pud = reg_base + RPI3_GPIO_GPPUD;
+	uintptr_t reg_clk = reg_base + RPI3_GPIO_GPPUDCLK(regN);
+
+	switch (pull) {
+	case GPIO_PULL_NONE:
+		mmio_write_32(reg_pud, 0x0);
+		break;
+	case GPIO_PULL_UP:
+		mmio_write_32(reg_pud, 0x2);
+		break;
+	case GPIO_PULL_DOWN:
+		mmio_write_32(reg_pud, 0x1);
+		break;
+	}
+	mdelay(150);
+	mmio_write_32(reg_clk, U(1) << shift);
+	mdelay(150);
+	mmio_write_32(reg_clk, 0x0);
+	mmio_write_32(reg_pud, 0x0);
+}
+
+void rpi3_gpio_init(struct rpi3_gpio_params *params)
+{
+	assert(params != 0);
+	memcpy(&rpi3_gpio_params, params, sizeof(struct rpi3_gpio_params));
+	gpio_init(&rpi3_gpio_ops);
+}
diff --git a/drivers/synopsys/ufs/dw_ufs.c b/drivers/synopsys/ufs/dw_ufs.c
index c7c8fc2..6bed981 100644
--- a/drivers/synopsys/ufs/dw_ufs.c
+++ b/drivers/synopsys/ufs/dw_ufs.c
@@ -183,7 +183,7 @@
 	return 0;
 }
 
-const ufs_ops_t dw_ufs_ops = {
+static const ufs_ops_t dw_ufs_ops = {
 	.phy_init		= dwufs_phy_init,
 	.phy_set_pwr_mode	= dwufs_phy_set_pwr_mode,
 };
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
index 2351c9b..b2c1046 100644
--- a/drivers/ufs/ufs.c
+++ b/drivers/ufs/ufs.c
@@ -591,7 +591,7 @@
 	ufs_query(QUERY_WRITE_DESC, idn, index, 0, buf, size);
 }
 
-void ufs_read_capacity(int lun, unsigned int *num, unsigned int *size)
+static void ufs_read_capacity(int lun, unsigned int *num, unsigned int *size)
 {
 	utp_utrd_t utrd;
 	resp_upiu_t *resp;
diff --git a/include/drivers/rpi3/gpio/rpi3_gpio.h b/include/drivers/rpi3/gpio/rpi3_gpio.h
new file mode 100644
index 0000000..159a2e0
--- /dev/null
+++ b/include/drivers/rpi3/gpio/rpi3_gpio.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019, Linaro Limited
+ * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPI3_GPIO_H
+#define RPI3_GPIO_H
+
+#include <stdint.h>
+#include <drivers/gpio.h>
+
+struct rpi3_gpio_params {
+	uintptr_t       reg_base;
+};
+
+void rpi3_gpio_init(struct rpi3_gpio_params *params);
+int rpi3_gpio_get_select(int gpio);
+void rpi3_gpio_set_select(int gpio, int fsel);
+
+#define RPI3_GPIO_GPFSEL(n)	((n) * U(0x04))
+#define RPI3_GPIO_GPSET(n)	(((n) * U(0x04)) + U(0x1C))
+#define RPI3_GPIO_GPCLR(n)	(((n) * U(0x04)) + U(0x28))
+#define RPI3_GPIO_GPLEV(n) 	(((n) * U(0x04)) + U(0x34))
+#define RPI3_GPIO_GPPUD		U(0x94)
+#define RPI3_GPIO_GPPUDCLK(n)	(((n) * U(0x04)) + U(0x98))
+
+#define RPI3_GPIO_FUNC_INPUT	U(0)
+#define RPI3_GPIO_FUNC_OUTPUT	U(1)
+#define RPI3_GPIO_FUNC_ALT0	U(4)
+#define RPI3_GPIO_FUNC_ALT1	U(5)
+#define RPI3_GPIO_FUNC_ALT2	U(6)
+#define RPI3_GPIO_FUNC_ALT3	U(7)
+#define RPI3_GPIO_FUNC_ALT4	U(3)
+#define RPI3_GPIO_FUNC_ALT5	U(2)
+
+#endif  /* RPI3_GPIO_H */
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
index 961cabf..73b84c3 100644
--- a/make_helpers/build_macros.mk
+++ b/make_helpers/build_macros.mk
@@ -464,7 +464,7 @@
 $(DOBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | fdt_dirs
 	$${ECHO} "  CPP     $$<"
 	$(eval DTBS       := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2))))
-	$$(Q)$$(CPP) $$(CPPFLAGS) -x assembler-with-cpp -MT $(DTBS) -MMD -MF $(DTSDEP) -o $(DPRE) $$<
+	$$(Q)$$(PP) $$(DTC_CPPFLAGS) -MT $(DTBS) -MMD -MF $(DTSDEP) -o $(DPRE) $$<
 	$${ECHO} "  DTC     $$<"
 	$$(Q)$$(DTC) $$(DTC_FLAGS) -i fdts -d $(DTBDEP) -o $$@ $(DPRE)
 
diff --git a/plat/imx/common/imx8_psci.c b/plat/imx/common/imx8_psci.c
index 588d8b4..91d3370 100644
--- a/plat/imx/common/imx8_psci.c
+++ b/plat/imx/common/imx8_psci.c
@@ -32,8 +32,22 @@
 int imx_validate_power_state(unsigned int power_state,
 			 psci_power_state_t *req_state)
 {
-	/* TODO */
-	return PSCI_E_INVALID_PARAMS;
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int pwr_type = psci_get_pstate_type(power_state);
+	int state_id = psci_get_pstate_id(power_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	if (pwr_type == PSTATE_TYPE_POWERDOWN) {
+		req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+		if (!state_id)
+			req_state->pwr_domain_state[MPIDR_AFFLVL1] = PLAT_MAX_RET_STATE;
+		else
+			req_state->pwr_domain_state[MPIDR_AFFLVL1] = PLAT_MAX_OFF_STATE;
+	}
+
+	return PSCI_E_SUCCESS;
 }
 
 void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
diff --git a/plat/imx/common/include/plat_imx8.h b/plat/imx/common/include/plat_imx8.h
index 952ad53..be99b97 100644
--- a/plat/imx/common/include/plat_imx8.h
+++ b/plat/imx/common/include/plat_imx8.h
@@ -10,6 +10,11 @@
 #include <drivers/arm/gicv3.h>
 #include <lib/psci/psci.h>
 
+struct plat_gic_ctx {
+	gicv3_redist_ctx_t rdist_ctx[PLATFORM_CORE_COUNT];
+	gicv3_dist_ctx_t dist_ctx;
+};
+
 unsigned int plat_calc_core_pos(uint64_t mpidr);
 void imx_mailbox_init(uintptr_t base_addr);
 void plat_gic_driver_init(void);
@@ -24,5 +29,7 @@
 			psci_power_state_t *req_state);
 void imx_get_sys_suspend_power_state(psci_power_state_t *req_state);
 bool imx_is_wakeup_src_irqsteer(void);
+void plat_gic_save(unsigned int proc_num, struct plat_gic_ctx *ctx);
+void plat_gic_restore(unsigned int proc_num, struct plat_gic_ctx *ctx);
 
 #endif /* PLAT_IMX8_H */
diff --git a/plat/imx/common/plat_imx8_gic.c b/plat/imx/common/plat_imx8_gic.c
index aec0b6c..27c525b 100644
--- a/plat/imx/common/plat_imx8_gic.c
+++ b/plat/imx/common/plat_imx8_gic.c
@@ -73,3 +73,19 @@
 {
 	gicv3_rdistif_init(plat_my_core_pos());
 }
+
+void plat_gic_save(unsigned int proc_num, struct plat_gic_ctx *ctx)
+{
+	/* save the gic rdist/dist context */
+	for (int i = 0; i < PLATFORM_CORE_COUNT; i++)
+		gicv3_rdistif_save(i, &ctx->rdist_ctx[i]);
+	gicv3_distif_save(&ctx->dist_ctx);
+}
+
+void plat_gic_restore(unsigned int proc_num, struct plat_gic_ctx *ctx)
+{
+	/* restore the gic rdist/dist context */
+	gicv3_distif_init_restore(&ctx->dist_ctx);
+	for (int i = 0; i < PLATFORM_CORE_COUNT; i++)
+		gicv3_rdistif_init_restore(i, &ctx->rdist_ctx[i]);
+}
diff --git a/plat/imx/common/sci/imx8_mu.c b/plat/imx/common/sci/imx8_mu.c
index 26d9bdf..66e956d 100644
--- a/plat/imx/common/sci/imx8_mu.c
+++ b/plat/imx/common/sci/imx8_mu.c
@@ -8,6 +8,21 @@
 
 #include "imx8_mu.h"
 
+void MU_Resume(uint32_t base)
+{
+	uint32_t reg, i;
+
+	reg = mmio_read_32(base + MU_ACR_OFFSET1);
+	/* Clear GIEn, RIEn, TIEn, GIRn and ABFn. */
+	reg &= ~(MU_CR_GIEn_MASK1 | MU_CR_RIEn_MASK1 | MU_CR_TIEn_MASK1
+			| MU_CR_GIRn_MASK1 | MU_CR_Fn_MASK1);
+	mmio_write_32(base + MU_ACR_OFFSET1, reg);
+
+	/* Enable all RX interrupts */
+	for (i = 0; i < MU_RR_COUNT; i++)
+		MU_EnableRxFullInt(base, i);
+}
+
 void MU_EnableRxFullInt(uint32_t base, uint32_t index)
 {
 	uint32_t reg = mmio_read_32(base + MU_ACR_OFFSET1);
diff --git a/plat/imx/common/sci/imx8_mu.h b/plat/imx/common/sci/imx8_mu.h
index 8c78877..edcac7b 100644
--- a/plat/imx/common/sci/imx8_mu.h
+++ b/plat/imx/common/sci/imx8_mu.h
@@ -33,3 +33,4 @@
 void MU_ReceiveMsg(uint32_t base, uint32_t regIndex, uint32_t *msg);
 void MU_EnableGeneralInt(uint32_t base, uint32_t index);
 void MU_EnableRxFullInt(uint32_t base, uint32_t index);
+void MU_Resume(uint32_t base);
diff --git a/plat/imx/imx8qm/imx8qm_bl31_setup.c b/plat/imx/imx8qm/imx8qm_bl31_setup.c
index a00695c..c76de64 100644
--- a/plat/imx/imx8qm/imx8qm_bl31_setup.c
+++ b/plat/imx/imx8qm/imx8qm_bl31_setup.c
@@ -49,11 +49,7 @@
 };
 
 static const mmap_region_t imx_mmap[] = {
-	MAP_REGION_FLAT(IMX_BOOT_UART_BASE, IMX_BOOT_UART_SIZE, MT_DEVICE | MT_RW),
-	MAP_REGION_FLAT(SC_IPC_BASE, SC_IPC_SIZE, MT_DEVICE | MT_RW),
-	MAP_REGION_FLAT(PLAT_GICD_BASE, PLAT_GICD_SIZE, MT_DEVICE | MT_RW),
-	MAP_REGION_FLAT(PLAT_GICR_BASE, PLAT_GICR_SIZE, MT_DEVICE | MT_RW),
-	MAP_REGION_FLAT(PLAT_CCI_BASE, PLAT_CCI_SIZE, MT_DEVICE | MT_RW),
+	MAP_REGION_FLAT(IMX_REG_BASE, IMX_REG_SIZE, MT_DEVICE | MT_RW),
 	{0}
 };
 
@@ -324,6 +320,10 @@
 
 	/* turn on MU1 for non-secure OS/Hypervisor */
 	sc_pm_set_resource_power_mode(ipc_handle, SC_R_MU_1A, SC_PM_PW_MODE_ON);
+	/* Turn on GPT_0's power & clock for non-secure OS/Hypervisor */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON);
+	sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0);
+	mmio_write_32(IMX_GPT_LPCG_BASE, mmio_read_32(IMX_GPT_LPCG_BASE) | (1 << 25));
 
 	/*
 	 * create new partition for non-secure OS/Hypervisor
diff --git a/plat/imx/imx8qm/imx8qm_psci.c b/plat/imx/imx8qm/imx8qm_psci.c
index 833048d..bdba37c 100644
--- a/plat/imx/imx8qm/imx8qm_psci.c
+++ b/plat/imx/imx8qm/imx8qm_psci.c
@@ -17,6 +17,8 @@
 #include <plat_imx8.h>
 #include <sci/sci.h>
 
+#include "../../common/sci/imx8_mu.h"
+
 #define CORE_PWR_STATE(state) \
 	((state)->pwr_domain_state[MPIDR_AFFLVL0])
 #define CLUSTER_PWR_STATE(state) \
@@ -29,44 +31,70 @@
 	SC_R_A53_3, SC_R_A72_0, SC_R_A72_1,
 };
 
+/* save gic dist/redist context when GIC is poewr down */
+static struct plat_gic_ctx imx_gicv3_ctx;
+static unsigned int gpt_lpcg, gpt_reg[2];
+
+static void imx_enable_irqstr_wakeup(void)
+{
+	uint32_t irq_mask;
+	gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx;
+
+	/* put IRQSTR into ON mode */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
+
+	/* enable the irqsteer to handle wakeup irq */
+	mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x1);
+	for (int i = 0; i < 15; i++) {
+		irq_mask = dist_ctx->gicd_isenabler[i];
+		mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 0x4 * i, irq_mask);
+	}
+
+	/* set IRQSTR low power mode */
+	if (imx_is_wakeup_src_irqsteer())
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY);
+	else
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
+}
+
+static void imx_disable_irqstr_wakeup(void)
+{
+	/* put IRQSTR into ON from STBY mode */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
+
+	/* disable the irqsteer */
+	mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x0);
+	for (int i = 0; i < 16; i++)
+		mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x4 + 0x4 * i, 0x0);
+
+	/* put IRQSTR into OFF mode */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
+}
+
 int imx_pwr_domain_on(u_register_t mpidr)
 {
 	int ret = PSCI_E_SUCCESS;
-	unsigned int cluster_id, cpu_id;
-
-	cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
-	cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+	unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
+	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
 
-	printf("imx_pwr_domain_on cluster_id %d, cpu_id %d\n", cluster_id, cpu_id);
+	sc_pm_set_resource_power_mode(ipc_handle, cluster_id == 0 ?
+		SC_R_A53 : SC_R_A72, SC_PM_PW_MODE_ON);
 
-	if (cluster_id == 0) {
-		sc_pm_set_resource_power_mode(ipc_handle, SC_R_A53,
-			SC_PM_PW_MODE_ON);
-		if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id],
-			SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
-			ERROR("cluster0 core %d power on failed!\n", cpu_id);
-			ret = PSCI_E_INTERN_FAIL;
-		}
+	if (cluster_id == 1)
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON);
 
-		if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id],
-			true, BL31_BASE) != SC_ERR_NONE) {
-			ERROR("boot cluster0 core %d failed!\n", cpu_id);
-			ret = PSCI_E_INTERN_FAIL;
-		}
-	} else {
-		sc_pm_set_resource_power_mode(ipc_handle, SC_R_A72,
-			SC_PM_PW_MODE_ON);
-		if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id + 4],
-			SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
-			ERROR(" cluster1 core %d power on failed!\n", cpu_id);
-			ret = PSCI_E_INTERN_FAIL;
-		}
+	if (sc_pm_set_resource_power_mode(ipc_handle,
+		ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+		SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
+		ERROR("core %d power on failed!\n", cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id);
+		ret = PSCI_E_INTERN_FAIL;
+	}
 
-		if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id + 4],
-			true, BL31_BASE) != SC_ERR_NONE) {
-			ERROR("boot cluster1 core %d failed!\n", cpu_id);
-			ret = PSCI_E_INTERN_FAIL;
-		}
+	if (sc_pm_cpu_start(ipc_handle,
+		ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+		true, BL31_BASE) != SC_ERR_NONE) {
+		ERROR("boot core %d failed!\n", cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id);
+		ret = PSCI_E_INTERN_FAIL;
 	}
 
 	return ret;
@@ -91,11 +119,14 @@
 
 	plat_gic_cpuif_disable();
 	sc_pm_req_cpu_low_power_mode(ipc_handle,
-		ap_core_index[cpu_id + cluster_id * 4],
-		SC_PM_PW_MODE_OFF,
-		SC_PM_WAKE_SRC_NONE);
-	if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
-		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+		ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+		SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_NONE);
+
+	if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
+		cci_disable_snoop_dvm_reqs(cluster_id);
+		if (cluster_id == 1)
+			sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF);
+	}
 	printf("turn off cluster:%d core:%d\n", cluster_id, cpu_id);
 }
 
@@ -105,24 +136,148 @@
 	unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
 	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
 
-	plat_gic_cpuif_disable();
+	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+		plat_gic_cpuif_disable();
+		sc_pm_set_cpu_resume(ipc_handle,
+			ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+			true, BL31_BASE);
+		sc_pm_req_cpu_low_power_mode(ipc_handle,
+			ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+			SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC);
+	} else {
+		dsb();
+		write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
+		isb();
+	}
 
-	cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+	if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
+		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+		if (cluster_id == 1)
+			sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF);
+	}
 
-	sc_pm_set_cpu_resume_addr(ipc_handle,
-		ap_core_index[cpu_id + cluster_id * 4], BL31_BASE);
-	sc_pm_req_cpu_low_power_mode(ipc_handle,
-		ap_core_index[cpu_id + cluster_id * 4],
-		SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC);
+	if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
+		plat_gic_cpuif_disable();
+
+		/* save gic context */
+		plat_gic_save(cpu_id, &imx_gicv3_ctx);
+		/* enable the irqsteer for wakeup */
+		imx_enable_irqstr_wakeup();
+
+		cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+
+		/* Put GIC in LP mode. */
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF);
+		/* Save GPT clock and registers, then turn off its power */
+		gpt_lpcg = mmio_read_32(IMX_GPT_LPCG_BASE);
+		gpt_reg[0] = mmio_read_32(IMX_GPT_BASE);
+		gpt_reg[1] = mmio_read_32(IMX_GPT_BASE + 0x4);
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_OFF);
+
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_OFF);
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF);
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF);
+
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF);
+
+		sc_pm_set_cpu_resume(ipc_handle,
+			ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+			true, BL31_BASE);
+		if (imx_is_wakeup_src_irqsteer())
+			sc_pm_req_cpu_low_power_mode(ipc_handle,
+				ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+				SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER);
+		else
+			sc_pm_req_cpu_low_power_mode(ipc_handle,
+				ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+				SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU);
+	}
 }
 
 void imx_domain_suspend_finish(const psci_power_state_t *target_state)
 {
 	u_register_t mpidr = read_mpidr_el1();
+	unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
+	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
 
-	cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+	/* check the system level status */
+	if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
+		MU_Resume(SC_IPC_BASE);
 
-	plat_gic_cpuif_enable();
+		sc_pm_req_cpu_low_power_mode(ipc_handle,
+			ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+			SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
+
+		/* Put GIC/IRQSTR back to high power mode. */
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON);
+
+		/* Turn GPT power and restore its clock and registers */
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON);
+		sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0);
+		mmio_write_32(IMX_GPT_BASE, gpt_reg[0]);
+		mmio_write_32(IMX_GPT_BASE + 0x4, gpt_reg[1]);
+		mmio_write_32(IMX_GPT_LPCG_BASE, gpt_lpcg);
+
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON);
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON);
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON);
+
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON);
+
+		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+
+		/* restore gic context */
+		plat_gic_restore(cpu_id, &imx_gicv3_ctx);
+		/* disable the irqsteer wakeup */
+		imx_disable_irqstr_wakeup();
+
+		plat_gic_cpuif_enable();
+	}
+
+	/* check the cluster level power status */
+	if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
+		cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
+		if (cluster_id == 1)
+			sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON);
+	}
+
+	/* check the core level power status */
+	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+		sc_pm_set_cpu_resume(ipc_handle,
+			ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+			false, BL31_BASE);
+		sc_pm_req_cpu_low_power_mode(ipc_handle,
+			ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
+			SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
+		plat_gic_cpuif_enable();
+	} else {
+		write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
+		isb();
+	}
 }
 
 int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
@@ -149,26 +304,23 @@
 	imx_mailbox_init(sec_entrypoint);
 	*psci_ops = &imx_plat_psci_ops;
 
-	/* Request low power mode for cluster/cci, only need to do once */
-	sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF);
-	sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_OFF);
-	sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF);
+	/* make sure system sources power ON in low power mode by default */
+	sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON);
+	sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON);
+	sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON);
 
-	/* Request RUN and LP modes for DDR, system interconnect etc. */
-	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53,
-		SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
-	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72,
-		SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
-	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53,
-		SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
-	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72,
-		SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
-	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53,
-		SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON,
-		SC_PM_PW_MODE_STBY);
-	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72,
-		SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON,
-		SC_PM_PW_MODE_STBY);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
 
 	return 0;
 }
diff --git a/plat/imx/imx8qm/include/platform_def.h b/plat/imx/imx8qm/include/platform_def.h
index 1d0bdf9..946be76 100644
--- a/plat/imx/imx8qm/include/platform_def.h
+++ b/plat/imx/imx8qm/include/platform_def.h
@@ -36,22 +36,22 @@
 #define BL31_LIMIT			0x80020000
 
 #define PLAT_GICD_BASE			0x51a00000
-#define PLAT_GICD_SIZE			0x10000
 #define PLAT_GICR_BASE			0x51b00000
-#define PLAT_GICR_SIZE			0xc0000
 #define PLAT_CCI_BASE			0x52090000
-#define PLAT_CCI_SIZE			0x10000
 #define CLUSTER0_CCI_SLVAE_IFACE	3
 #define CLUSTER1_CCI_SLVAE_IFACE	4
 #define IMX_BOOT_UART_BASE		0x5a060000
-#define IMX_BOOT_UART_SIZE		0x1000
 #define IMX_BOOT_UART_BAUDRATE		115200
 #define IMX_BOOT_UART_CLK_IN_HZ		24000000
 #define PLAT_CRASH_UART_BASE		IMX_BOOT_UART_BASE
 #define PLAT__CRASH_UART_CLK_IN_HZ	24000000
 #define IMX_CONSOLE_BAUDRATE		115200
 #define SC_IPC_BASE			0x5d1b0000
-#define SC_IPC_SIZE			0x10000
+#define IMX_GPT_LPCG_BASE		0x5d540000
+#define IMX_GPT_BASE			0x5d140000
+#define IMX_WUP_IRQSTR_BASE		0x51090000
+#define IMX_REG_BASE			0x50000000
+#define IMX_REG_SIZE			0x10000000
 
 #define COUNTER_FREQUENCY		8000000 /* 8MHz */
 
diff --git a/plat/imx/imx8qm/include/sec_rsrc.h b/plat/imx/imx8qm/include/sec_rsrc.h
index a623cd3..d16d051 100644
--- a/plat/imx/imx8qm/include/sec_rsrc.h
+++ b/plat/imx/imx8qm/include/sec_rsrc.h
@@ -19,12 +19,14 @@
 	SC_R_GIC_SMMU,
 	SC_R_CCI,
 	SC_R_SYSTEM,
-	SC_R_IRQSTR_SCU2
+	SC_R_IRQSTR_SCU2,
+	SC_R_GPT_0
 };
 
 /* resources that have register access for non-secure domain */
 sc_rsrc_t ns_access_allowed[] = {
 	SC_R_GIC,
 	SC_R_GIC_SMMU,
-	SC_R_CCI
+	SC_R_CCI,
+	SC_R_GPT_0
 };
diff --git a/plat/imx/imx8qx/imx8qx_bl31_setup.c b/plat/imx/imx8qx/imx8qx_bl31_setup.c
index c90794a..bfe4052 100644
--- a/plat/imx/imx8qx/imx8qx_bl31_setup.c
+++ b/plat/imx/imx8qx/imx8qx_bl31_setup.c
@@ -44,10 +44,7 @@
 			(SC_PAD_28FDSOI_PS_PD << PADRING_PULL_SHIFT))
 
 static const mmap_region_t imx_mmap[] = {
-	MAP_REGION_FLAT(IMX_BOOT_UART_BASE, IMX_BOOT_UART_SIZE, MT_DEVICE | MT_RW),
-	MAP_REGION_FLAT(SC_IPC_BASE, SC_IPC_SIZE, MT_DEVICE | MT_RW),
-	MAP_REGION_FLAT(PLAT_GICD_BASE, PLAT_GICD_SIZE, MT_DEVICE | MT_RW),
-	MAP_REGION_FLAT(PLAT_GICR_BASE, PLAT_GICR_SIZE, MT_DEVICE | MT_RW),
+	MAP_REGION_FLAT(IMX_REG_BASE, IMX_REG_SIZE, MT_DEVICE | MT_RW),
 	{0}
 };
 
@@ -281,6 +278,11 @@
 	/* Turn on MU1 for non-secure OS/Hypervisor */
 	sc_pm_set_resource_power_mode(ipc_handle, SC_R_MU_1A, SC_PM_PW_MODE_ON);
 
+	/* Turn on GPT_0's power & clock for non-secure OS/Hypervisor */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON);
+	sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0);
+	mmio_write_32(IMX_GPT0_LPCG_BASE, mmio_read_32(IMX_GPT0_LPCG_BASE) | (1 << 25));
+
 	/*
 	 * create new partition for non-secure OS/Hypervisor
 	 * uses global structs defined in sec_rsrc.h
diff --git a/plat/imx/imx8qx/imx8qx_psci.c b/plat/imx/imx8qx/imx8qx_psci.c
index 94c2e2b..aab3a2d 100644
--- a/plat/imx/imx8qx/imx8qx_psci.c
+++ b/plat/imx/imx8qx/imx8qx_psci.c
@@ -16,10 +16,52 @@
 #include <plat_imx8.h>
 #include <sci/sci.h>
 
+#include "../../common/sci/imx8_mu.h"
+
 const static int ap_core_index[PLATFORM_CORE_COUNT] = {
 	SC_R_A35_0, SC_R_A35_1, SC_R_A35_2, SC_R_A35_3
 };
 
+/* save gic dist/redist context when GIC is power down */
+static struct plat_gic_ctx imx_gicv3_ctx;
+static unsigned int gpt_lpcg, gpt_reg[2];
+
+static void imx_enable_irqstr_wakeup(void)
+{
+	uint32_t irq_mask;
+	gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx;
+
+	/* put IRQSTR into ON mode */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
+
+	/* enable the irqsteer to handle wakeup irq */
+	mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x1);
+	for (int i = 0; i < 15; i++) {
+		irq_mask = dist_ctx->gicd_isenabler[i];
+		mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 0x4 * i, irq_mask);
+	}
+
+	/* set IRQSTR low power mode */
+	if (imx_is_wakeup_src_irqsteer())
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY);
+	else
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
+}
+
+static void imx_disable_irqstr_wakeup(void)
+{
+	/* Put IRQSTEER back to ON mode */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
+
+	/* disable the irqsteer */
+	mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x0);
+	for (int i = 0; i < 16; i++)
+		mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x4 + 0x4 * i, 0x0);
+
+	/* Put IRQSTEER into OFF mode */
+	sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
+}
+
 int imx_pwr_domain_on(u_register_t mpidr)
 {
 	int ret = PSCI_E_SUCCESS;
@@ -71,11 +113,52 @@
 	u_register_t mpidr = read_mpidr_el1();
 	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
 
-	plat_gic_cpuif_disable();
+	if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL0])) {
+		plat_gic_cpuif_disable();
+		sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id], true, BL31_BASE);
+		sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+			SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC);
+	} else {
+		dsb();
+		write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
+		isb();
+	}
 
-	sc_pm_set_cpu_resume_addr(ipc_handle, ap_core_index[cpu_id], BL31_BASE);
-	sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
-		SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC);
+	if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL1]))
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF);
+
+	if (is_local_state_retn(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL])) {
+		plat_gic_cpuif_disable();
+
+		/* save gic context */
+		plat_gic_save(cpu_id, &imx_gicv3_ctx);
+		/* enable the irqsteer for wakeup */
+		imx_enable_irqstr_wakeup();
+
+		/* Save GPT clock and registers, then turn off its power */
+		gpt_lpcg = mmio_read_32(IMX_GPT0_LPCG_BASE);
+		gpt_reg[0] = mmio_read_32(IMX_GPT0_BASE);
+		gpt_reg[1] = mmio_read_32(IMX_GPT0_BASE + 0x4);
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_OFF);
+
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
+
+		/* Put GIC in OFF mode. */
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF);
+		sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id], true, BL31_BASE);
+		if (imx_is_wakeup_src_irqsteer())
+			sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+				SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER);
+		else
+			sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+				SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU);
+	}
 }
 
 void imx_domain_suspend_finish(const psci_power_state_t *target_state)
@@ -83,10 +166,51 @@
 	u_register_t mpidr = read_mpidr_el1();
 	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
 
-	sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id],
-		SC_PM_PW_MODE_ON);
+	if (is_local_state_retn(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL])) {
+		MU_Resume(SC_IPC_BASE);
 
-	plat_gic_cpuif_enable();
+		sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_ON);
+		sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+			SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
+
+		/* Put GIC back to high power mode. */
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON);
+
+		/* restore gic context */
+		plat_gic_restore(cpu_id, &imx_gicv3_ctx);
+
+		/* Turn on GPT power and restore its clock and registers */
+		sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON);
+		sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0);
+		mmio_write_32(IMX_GPT0_BASE, gpt_reg[0]);
+		mmio_write_32(IMX_GPT0_BASE + 0x4, gpt_reg[1]);
+		mmio_write_32(IMX_GPT0_LPCG_BASE, gpt_lpcg);
+
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+		sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT,
+			SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+
+		/* disable the irqsteer wakeup */
+		imx_disable_irqstr_wakeup();
+
+		plat_gic_cpuif_enable();
+	}
+
+	if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL1]))
+		sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON);
+
+	if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL0])) {
+		sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
+			SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
+		plat_gic_cpuif_enable();
+	} else {
+		write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
+		isb();
+	}
 }
 
 static const plat_psci_ops_t imx_plat_psci_ops = {
@@ -108,17 +232,15 @@
 	imx_mailbox_init(sec_entrypoint);
 	*psci_ops = &imx_plat_psci_ops;
 
-	/* Request low power mode for A35 cluster, only need to do once */
-	sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF);
+	/* make sure system sources power ON in low power mode by default */
+	sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON);
 
-	/* Request RUN and LP modes for DDR, system interconnect etc. */
-	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35,
-		SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
-	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35,
-		SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
-	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35,
-		SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON,
-		SC_PM_PW_MODE_STBY);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
+	sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT,
+		SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
 
 	return 0;
 }
diff --git a/plat/imx/imx8qx/include/platform_def.h b/plat/imx/imx8qx/include/platform_def.h
index 1239340..3a3fac8 100644
--- a/plat/imx/imx8qx/include/platform_def.h
+++ b/plat/imx/imx8qx/include/platform_def.h
@@ -37,18 +37,19 @@
 #define MAX_MMAP_REGIONS		8
 
 #define PLAT_GICD_BASE			0x51a00000
-#define PLAT_GICD_SIZE			0x10000
 #define PLAT_GICR_BASE			0x51b00000
-#define PLAT_GICR_SIZE			0xc0000
 #define IMX_BOOT_UART_BASE		0x5a060000
-#define IMX_BOOT_UART_SIZE		0x1000
 #define IMX_BOOT_UART_BAUDRATE		115200
 #define IMX_BOOT_UART_CLK_IN_HZ		24000000
 #define PLAT_CRASH_UART_BASE		IMX_BOOT_UART_BASE
 #define PLAT__CRASH_UART_CLK_IN_HZ	24000000
 #define IMX_CONSOLE_BAUDRATE		115200
 #define SC_IPC_BASE			0x5d1b0000
-#define SC_IPC_SIZE			0x10000
+#define IMX_GPT0_LPCG_BASE		0x5d540000
+#define IMX_GPT0_BASE			0x5d140000
+#define IMX_WUP_IRQSTR_BASE		0x51090000
+#define IMX_REG_BASE			0x50000000
+#define IMX_REG_SIZE			0x10000000
 
 #define COUNTER_FREQUENCY		8000000
 
diff --git a/plat/imx/imx8qx/include/sec_rsrc.h b/plat/imx/imx8qx/include/sec_rsrc.h
index 37c9f66..b7fe0e8 100644
--- a/plat/imx/imx8qx/include/sec_rsrc.h
+++ b/plat/imx/imx8qx/include/sec_rsrc.h
@@ -14,10 +14,12 @@
 	SC_R_A35_3,
 	SC_R_GIC,
 	SC_R_SYSTEM,
-	SC_R_IRQSTR_SCU2
+	SC_R_IRQSTR_SCU2,
+	SC_R_GPT_0
 };
 
 /* resources that have register access for non-secure domain */
 sc_rsrc_t ns_access_allowed[] = {
 	SC_R_GIC,
+	SC_R_GPT_0
 };
diff --git a/plat/rockchip/common/rockchip_gicv2.c b/plat/rockchip/common/rockchip_gicv2.c
index 222a882..8db2b30 100644
--- a/plat/rockchip/common/rockchip_gicv2.c
+++ b/plat/rockchip/common/rockchip_gicv2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -22,11 +22,10 @@
 #pragma weak plat_rockchip_gic_pcpu_init
 
 /******************************************************************************
- * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
- * interrupts.
+ * List of interrupts.
  *****************************************************************************/
 static const interrupt_prop_t g0_interrupt_props[] = {
-	PLAT_RK_GICV2_G1S_IRQS
+	PLAT_RK_GICV2_G0_IRQS
 };
 
 /*
diff --git a/plat/rockchip/rk3328/rk3328_def.h b/plat/rockchip/rk3328/rk3328_def.h
index 4704a72..0ce13ad 100644
--- a/plat/rockchip/rk3328/rk3328_def.h
+++ b/plat/rockchip/rk3328/rk3328_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -131,15 +131,13 @@
 #define RK_IRQ_SEC_SGI_7	15
 
 /*
- * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
- * terminology. On a GICv2 system or mode, the lists will be merged and treated
- * as Group 0 interrupts.
+ * Define a list of Group 0 interrupts.
  */
-#define PLAT_RK_GICV2_G1S_IRQS						\
+#define PLAT_RK_GICV2_G0_IRQS						\
 	INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,	\
-		       GICV2_INTR_GROUP1, GIC_INTR_CFG_LEVEL),		\
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL),		\
 	INTR_PROP_DESC(RK_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,	\
-		       GICV2_INTR_GROUP1, GIC_INTR_CFG_LEVEL)
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL)
 
 #define SHARE_MEM_BASE          0x100000/* [1MB, 1MB+60K]*/
 #define SHARE_MEM_PAGE_NUM      15
diff --git a/plat/rockchip/rk3368/rk3368_def.h b/plat/rockchip/rk3368/rk3368_def.h
index a7be7c3..10ac77b 100644
--- a/plat/rockchip/rk3368/rk3368_def.h
+++ b/plat/rockchip/rk3368/rk3368_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -96,12 +96,10 @@
 #define RK_IRQ_SEC_SGI_7	15
 
 /*
- * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
- * terminology. On a GICv2 system or mode, the lists will be merged and treated
- * as Group 0 interrupts.
+ * Define a list of Group 0 interrupts.
  */
-#define PLAT_RK_GICV2_G1S_IRQS						\
+#define PLAT_RK_GICV2_G0_IRQS						\
 	INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,	\
-		       GICV2_INTR_GROUP1, GIC_INTR_CFG_LEVEL)
+		       GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL)
 
 #endif /* RK3368_DEF_H */
diff --git a/plat/rpi3/platform.mk b/plat/rpi3/platform.mk
index 5e76345..ded92bd 100644
--- a/plat/rpi3/platform.mk
+++ b/plat/rpi3/platform.mk
@@ -27,6 +27,10 @@
 				drivers/io/io_fip.c			\
 				drivers/io/io_memmap.c			\
 				drivers/io/io_storage.c			\
+				drivers/gpio/gpio.c			\
+				drivers/delay_timer/delay_timer.c	\
+				drivers/delay_timer/generic_delay_timer.c \
+				drivers/rpi3/gpio/rpi3_gpio.c		\
 				plat/common/aarch64/platform_mp_stack.S	\
 				plat/rpi3/aarch64/plat_helpers.S	\
 				plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c \
diff --git a/plat/rpi3/rpi3_bl2_setup.c b/plat/rpi3/rpi3_bl2_setup.c
index 53a2c72..09f0562 100644
--- a/plat/rpi3/rpi3_bl2_setup.c
+++ b/plat/rpi3/rpi3_bl2_setup.c
@@ -15,12 +15,25 @@
 #include <lib/optee_utils.h>
 #include <lib/xlat_tables/xlat_mmu_helpers.h>
 #include <lib/xlat_tables/xlat_tables_defs.h>
+#include <drivers/generic_delay_timer.h>
+#include <drivers/rpi3/gpio/rpi3_gpio.h>
 
 #include "rpi3_private.h"
 
 /* Data structure which holds the extents of the trusted SRAM for BL2 */
 static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE);
 
+/* rpi3 GPIO setup function. */
+static void rpi3_gpio_setup(void)
+{
+	struct rpi3_gpio_params params;
+
+	memset(&params, 0, sizeof(struct rpi3_gpio_params));
+	params.reg_base = RPI3_GPIO_BASE;
+
+	rpi3_gpio_init(&params);
+}
+
 /*******************************************************************************
  * BL1 has passed the extents of the trusted SRAM that should be visible to BL2
  * in x0. This memory layout is sitting at the base of the free trusted SRAM.
@@ -35,6 +48,12 @@
 	/* Initialize the console to provide early debug support */
 	rpi3_console_init();
 
+	/* Enable arch timer */
+	generic_delay_timer_init();
+
+	/* Setup GPIO driver */
+	rpi3_gpio_setup();
+
 	/* Setup the BL2 memory layout */
 	bl2_tzram_layout = *mem_layout;
 
diff --git a/plat/rpi3/rpi3_hw.h b/plat/rpi3/rpi3_hw.h
index 9d86eb8..61d1837 100644
--- a/plat/rpi3/rpi3_hw.h
+++ b/plat/rpi3/rpi3_hw.h
@@ -84,6 +84,12 @@
 #define RPI3_MINI_UART_CLK_IN_HZ	ULL(500000000)
 
 /*
+ * GPIO controller
+ */
+#define RPI3_IO_GPIO_OFFSET		ULL(0x00200000)
+#define RPI3_GPIO_BASE			(RPI3_IO_BASE + RPI3_IO_GPIO_OFFSET)
+
+/*
  * Local interrupt controller
  */
 #define RPI3_INTC_BASE_ADDRESS			ULL(0x40000000)
diff --git a/plat/rpi3/rpi3_io_storage.c b/plat/rpi3/rpi3_io_storage.c
index 7e66deb..49c6a76 100644
--- a/plat/rpi3/rpi3_io_storage.c
+++ b/plat/rpi3/rpi3_io_storage.c
@@ -133,11 +133,6 @@
 		(uintptr_t)&bl32_uuid_spec,
 		open_fip
 	},
-	[BL32_IMAGE_ID] = {
-		&fip_dev_handle,
-		(uintptr_t)&bl32_uuid_spec,
-		open_fip
-	},
 	[BL32_EXTRA1_IMAGE_ID] = {
 		&fip_dev_handle,
 		(uintptr_t)&bl32_extra1_uuid_spec,
diff --git a/plat/rpi3/rpi3_pm.c b/plat/rpi3/rpi3_pm.c
index 3a077d3..4f586b5 100644
--- a/plat/rpi3/rpi3_pm.c
+++ b/plat/rpi3/rpi3_pm.c
@@ -140,7 +140,7 @@
  * being turned off earlier. The target_state encodes the low power state that
  * each level has woken up from.
  ******************************************************************************/
-void rpi3_pwr_domain_on_finish(const psci_power_state_t *target_state)
+static void rpi3_pwr_domain_on_finish(const psci_power_state_t *target_state)
 {
 	assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] ==
 					PLAT_LOCAL_STATE_OFF);
diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c
index 0d4f929..80b498e 100644
--- a/tools/fiptool/fiptool.c
+++ b/tools/fiptool/fiptool.c
@@ -271,10 +271,10 @@
 	    &u->node[2], &u->node[3],
 	    &u->node[4], &u->node[5]);
 	/*
-	 * Given the format specifier above, we expect 11 items to be scanned
+	 * Given the format specifier above, we expect 16 items to be scanned
 	 * for a properly formatted UUID.
 	 */
-	if (n != 11)
+	if (n != 16)
 		log_errx("Invalid UUID: %s", s);
 }