Merge "aarch32: stop speculative execution past exception returns" into integration
diff --git a/Makefile b/Makefile
index 03f9fc6..3d5b395 100644
--- a/Makefile
+++ b/Makefile
@@ -159,6 +159,14 @@
 endif
 endif
 
+ifneq (${DECRYPTION_SUPPORT},none)
+ENC_ARGS += -f ${FW_ENC_STATUS}
+ENC_ARGS += -k ${ENC_KEY}
+ENC_ARGS += -n ${ENC_NONCE}
+FIP_DEPS += enctool
+FWU_FIP_DEPS += enctool
+endif
+
 ################################################################################
 # Toolchain
 ################################################################################
@@ -412,40 +420,48 @@
 ################################################################################
 
 ifneq (${SPD},none)
-ifeq (${ARCH},aarch32)
+    ifeq (${ARCH},aarch32)
         $(error "Error: SPD is incompatible with AArch32.")
-endif
-ifdef EL3_PAYLOAD_BASE
+    endif
+
+    ifdef EL3_PAYLOAD_BASE
         $(warning "SPD and EL3_PAYLOAD_BASE are incompatible build options.")
         $(warning "The SPD and its BL32 companion will be present but ignored.")
-endif
-	ifeq (${SPD},spmd)
-		# SPMD is located in std_svc directory
-		SPD_DIR := std_svc
-	else
-		# All other SPDs in spd directory
-		SPD_DIR := spd
-	endif
-
-	# We expect to locate an spd.mk under the specified SPD directory
-	SPD_MAKE	:=	$(wildcard services/${SPD_DIR}/${SPD}/${SPD}.mk)
+    endif
 
+    ifeq (${SPD},spmd)
+        $(warning "SPMD is an experimental feature")
+        # SPMD is located in std_svc directory
+        SPD_DIR := std_svc
 
-        ifeq (${SPD_MAKE},)
-                $(error Error: No services/${SPD_DIR}/${SPD}/${SPD}.mk located)
+        ifeq ($(SPMD_SPM_AT_SEL2),1)
+            ifeq ($(CTX_INCLUDE_EL2_REGS),0)
+                $(error SPMD with SPM at S-EL2 requires CTX_INCLUDE_EL2_REGS option)
+            endif
         endif
-        $(info Including ${SPD_MAKE})
-        include ${SPD_MAKE}
+    else
+        # All other SPDs in spd directory
+        SPD_DIR := spd
+    endif
+
+    # We expect to locate an spd.mk under the specified SPD directory
+    SPD_MAKE	:=	$(wildcard services/${SPD_DIR}/${SPD}/${SPD}.mk)
+
+    ifeq (${SPD_MAKE},)
+        $(error Error: No services/${SPD_DIR}/${SPD}/${SPD}.mk located)
+    endif
+    $(info Including ${SPD_MAKE})
+    include ${SPD_MAKE}
 
-        # If there's BL32 companion for the chosen SPD, we expect that the SPD's
-        # Makefile would set NEED_BL32 to "yes". In this case, the build system
-        # supports two mutually exclusive options:
-        # * BL32 is built from source: then BL32_SOURCES must contain the list
-        #   of source files to build BL32
-        # * BL32 is a prebuilt binary: then BL32 must point to the image file
-        #   that will be included in the FIP
-        # If both BL32_SOURCES and BL32 are defined, the binary takes precedence
-        # over the sources.
+    # If there's BL32 companion for the chosen SPD, we expect that the SPD's
+    # Makefile would set NEED_BL32 to "yes". In this case, the build system
+    # supports two mutually exclusive options:
+    # * BL32 is built from source: then BL32_SOURCES must contain the list
+    #   of source files to build BL32
+    # * BL32 is a prebuilt binary: then BL32 must point to the image file
+    #   that will be included in the FIP
+    # If both BL32_SOURCES and BL32 are defined, the binary takes precedence
+    # over the sources.
 endif
 
 ################################################################################
@@ -615,7 +631,7 @@
 
 ifeq ($(MEASURED_BOOT),1)
     ifneq (${TRUSTED_BOARD_BOOT},1)
-        $(error MEASURED_BOOT requires TRUSTED_BOARD_BOOT=1")
+        $(error MEASURED_BOOT requires TRUSTED_BOARD_BOOT=1)
     else
         $(info MEASURED_BOOT is an experimental feature)
     endif
@@ -627,6 +643,14 @@
     endif
 endif
 
+ifneq (${DECRYPTION_SUPPORT},none)
+    ifeq (${TRUSTED_BOARD_BOOT}, 0)
+        $(error TRUSTED_BOARD_BOOT must be enabled for DECRYPTION_SUPPORT to be set)
+    else
+        $(info DECRYPTION_SUPPORT is an experimental feature)
+    endif
+endif
+
 ################################################################################
 # Process platform overrideable behaviour
 ################################################################################
@@ -700,6 +724,10 @@
 CRTTOOLPATH		?=	tools/cert_create
 CRTTOOL			?=	${CRTTOOLPATH}/cert_create${BIN_EXT}
 
+# Variables for use with Firmware Encryption Tool
+ENCTOOLPATH		?=	tools/encrypt_fw
+ENCTOOL			?=	${ENCTOOLPATH}/encrypt_fw${BIN_EXT}
+
 # Variables for use with Firmware Image Package
 FIPTOOLPATH		?=	tools/fiptool
 FIPTOOL			?=	${FIPTOOLPATH}/fiptool${BIN_EXT}
@@ -761,6 +789,7 @@
 $(eval $(call assert_boolean,CTX_INCLUDE_FPREGS))
 $(eval $(call assert_boolean,CTX_INCLUDE_PAUTH_REGS))
 $(eval $(call assert_boolean,CTX_INCLUDE_MTE_REGS))
+$(eval $(call assert_boolean,CTX_INCLUDE_EL2_REGS))
 $(eval $(call assert_boolean,DEBUG))
 $(eval $(call assert_boolean,DYN_DISABLE_AUTH))
 $(eval $(call assert_boolean,EL3_EXCEPTION_HANDLING))
@@ -793,6 +822,7 @@
 $(eval $(call assert_boolean,SEPARATE_NOBITS_REGION))
 $(eval $(call assert_boolean,SPIN_ON_BL1_EXIT))
 $(eval $(call assert_boolean,SPM_MM))
+$(eval $(call assert_boolean,SPMD_SPM_AT_SEL2))
 $(eval $(call assert_boolean,TRUSTED_BOARD_BOOT))
 $(eval $(call assert_boolean,USE_COHERENT_MEM))
 $(eval $(call assert_boolean,USE_DEBUGFS))
@@ -804,10 +834,13 @@
 $(eval $(call assert_boolean,BL2_IN_XIP_MEM))
 $(eval $(call assert_boolean,BL2_INV_DCACHE))
 $(eval $(call assert_boolean,USE_SPINLOCK_CAS))
+$(eval $(call assert_boolean,ENCRYPT_BL31))
+$(eval $(call assert_boolean,ENCRYPT_BL32))
 
 $(eval $(call assert_numeric,ARM_ARCH_MAJOR))
 $(eval $(call assert_numeric,ARM_ARCH_MINOR))
 $(eval $(call assert_numeric,BRANCH_PROTECTION))
+$(eval $(call assert_numeric,FW_ENC_STATUS))
 
 ifdef KEY_SIZE
         $(eval $(call assert_numeric,KEY_SIZE))
@@ -832,6 +865,8 @@
 $(eval $(call add_define,CTX_INCLUDE_PAUTH_REGS))
 $(eval $(call add_define,EL3_EXCEPTION_HANDLING))
 $(eval $(call add_define,CTX_INCLUDE_MTE_REGS))
+$(eval $(call add_define,CTX_INCLUDE_EL2_REGS))
+$(eval $(call add_define,DECRYPTION_SUPPORT_${DECRYPTION_SUPPORT}))
 $(eval $(call add_define,ENABLE_AMU))
 $(eval $(call add_define,ENABLE_ASSERTIONS))
 $(eval $(call add_define,ENABLE_BTI))
@@ -843,6 +878,8 @@
 $(eval $(call add_define,ENABLE_RUNTIME_INSTRUMENTATION))
 $(eval $(call add_define,ENABLE_SPE_FOR_LOWER_ELS))
 $(eval $(call add_define,ENABLE_SVE_FOR_NS))
+$(eval $(call add_define,ENCRYPT_BL31))
+$(eval $(call add_define,ENCRYPT_BL32))
 $(eval $(call add_define,ERROR_DEPRECATED))
 $(eval $(call add_define,FAULT_INJECTION_SUPPORT))
 $(eval $(call add_define,GICV2_G0_FOR_EL3))
@@ -863,6 +900,7 @@
 $(eval $(call add_define,SPD_${SPD}))
 $(eval $(call add_define,SPIN_ON_BL1_EXIT))
 $(eval $(call add_define,SPM_MM))
+$(eval $(call add_define,SPMD_SPM_AT_SEL2))
 $(eval $(call add_define,TRUSTED_BOARD_BOOT))
 $(eval $(call add_define,USE_COHERENT_MEM))
 $(eval $(call add_define,USE_DEBUGFS))
@@ -914,7 +952,7 @@
 # Build targets
 ################################################################################
 
-.PHONY:	all msg_start clean realclean distclean cscope locate-checkpatch checkcodebase checkpatch fiptool sptool fip sp fwu_fip certtool dtbs memmap doc
+.PHONY:	all msg_start clean realclean distclean cscope locate-checkpatch checkcodebase checkpatch fiptool sptool fip sp fwu_fip certtool dtbs memmap doc enctool
 .SUFFIXES:
 
 all: msg_start
@@ -962,9 +1000,14 @@
 
 ifeq (${NEED_BL31},yes)
 BL31_SOURCES += ${SPD_SOURCES}
+ifneq (${DECRYPTION_SUPPORT},none)
+$(if ${BL31}, $(eval $(call TOOL_ADD_IMG,bl31,--soc-fw,,$(ENCRYPT_BL31))),\
+	$(eval $(call MAKE_BL,31,soc-fw,,$(ENCRYPT_BL31))))
+else
 $(if ${BL31}, $(eval $(call TOOL_ADD_IMG,bl31,--soc-fw)),\
 	$(eval $(call MAKE_BL,31,soc-fw)))
 endif
+endif
 
 # If a BL32 image is needed but neither BL32 nor BL32_SOURCES is defined, the
 # build system will call TOOL_ADD_IMG to print a warning message and abort the
@@ -973,9 +1016,14 @@
 
 BUILD_BL32 := $(if $(BL32),,$(if $(BL32_SOURCES),1))
 
+ifneq (${DECRYPTION_SUPPORT},none)
+$(if ${BUILD_BL32}, $(eval $(call MAKE_BL,32,tos-fw,,$(ENCRYPT_BL32))),\
+	$(eval $(call TOOL_ADD_IMG,bl32,--tos-fw,,$(ENCRYPT_BL32))))
+else
 $(if ${BUILD_BL32}, $(eval $(call MAKE_BL,32,tos-fw)),\
 	$(eval $(call TOOL_ADD_IMG,bl32,--tos-fw)))
 endif
+endif
 
 # Add the BL33 image if required by the platform
 ifeq (${NEED_BL33},yes)
@@ -1017,6 +1065,7 @@
 	$(call SHELL_REMOVE_DIR,${BUILD_PLAT})
 	${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
 	${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean
+	${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${ENCTOOLPATH} clean
 	${Q}${MAKE} --no-print-directory -C ${ROMLIBPATH} clean
 
 realclean distclean:
@@ -1026,6 +1075,7 @@
 	${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
 	${Q}${MAKE} --no-print-directory -C ${SPTOOLPATH} clean
 	${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean
+	${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${ENCTOOLPATH} realclean
 	${Q}${MAKE} --no-print-directory -C ${ROMLIBPATH} clean
 
 checkcodebase:		locate-checkpatch
@@ -1127,6 +1177,15 @@
 	@echo "  BUILD DOCUMENTATION"
 	${Q}${MAKE} --no-print-directory -C ${DOCS_PATH} html
 
+enctool: ${ENCTOOL}
+
+.PHONY: ${ENCTOOL}
+${ENCTOOL}:
+	${Q}${MAKE} PLAT=${PLAT} BUILD_INFO=0 --no-print-directory -C ${ENCTOOLPATH}
+	@${ECHO_BLANK_LINE}
+	@echo "Built $@ successfully"
+	@${ECHO_BLANK_LINE}
+
 cscope:
 	@echo "  CSCOPE"
 	${Q}find ${CURDIR} -name "*.[chsS]" > cscope.files
@@ -1163,6 +1222,7 @@
 	@echo "  cscope         Generate cscope index"
 	@echo "  distclean      Remove all build artifacts for all platforms"
 	@echo "  certtool       Build the Certificate generation tool"
+	@echo "  enctool        Build the Firmware encryption tool"
 	@echo "  fiptool        Build the Firmware Image Package (FIP) creation tool"
 	@echo "  sp             Build the Secure Partition Packages"
 	@echo "  sptool         Build the Secure Partition Package creation tool"
diff --git a/bl32/tsp/tsp_main.c b/bl32/tsp/tsp_main.c
index e1d961c..9da2f9a 100644
--- a/bl32/tsp/tsp_main.c
+++ b/bl32/tsp/tsp_main.c
@@ -273,11 +273,11 @@
 	spin_lock(&console_lock);
 	INFO("TSP: cpu 0x%lx resumed. maximum off power level %lld\n",
 	     read_mpidr(), max_off_pwrlvl);
-	INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu suspend requests\n",
+	INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu resume requests\n",
 		read_mpidr(),
 		tsp_stats[linear_id].smc_count,
 		tsp_stats[linear_id].eret_count,
-		tsp_stats[linear_id].cpu_suspend_count);
+		tsp_stats[linear_id].cpu_resume_count);
 	spin_unlock(&console_lock);
 #endif
 	/* Indicate to the SPD that we have completed this request */
diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst
index 802dafc..2bf5eb7 100644
--- a/docs/about/maintainers.rst
+++ b/docs/about/maintainers.rst
@@ -53,7 +53,6 @@
 :M: Remi Pommarel <repk@triplefau.lt>
 :G: `remi-triplefault`_
 :F: docs/plat/meson-gxl.rst
-:F: drivers/amlogic/gxl
 :F: plat/amlogic/gxl/
 
 Amlogic Meson S905X2 (G12A) platform port
@@ -61,7 +60,6 @@
 :M: Carlo Caione <ccaione@baylibre.com>
 :G: `carlocaione`_
 :F: docs/plat/meson-g12a.rst
-:F: drivers/amlogic/g12a
 :F: plat/amlogic/g12a/
 
 Amlogic Meson A113D (AXG) platform port
@@ -69,7 +67,6 @@
 :M: Carlo Caione <ccaione@baylibre.com>
 :G: `carlocaione`_
 :F: docs/plat/meson-axg.rst
-:F: drivers/amlogic/axg
 :F: plat/amlogic/axg/
 
 Armv7-A architecture port
@@ -152,7 +149,7 @@
 --------------------------------------
 :M: Konstantin Porotchkin <kostap@marvell.com>
 :G: `kostapr`_
-:F: docs/marvell/
+:F: docs/plat/marvell/
 :F: plat/marvell/
 :F: drivers/marvell/
 :F: tools/marvell/
@@ -197,14 +194,14 @@
 ------------------------
 :M: Jacky Bai <ping.bai@nxp.com>
 :G: `JackyBai`_
-:F: doc/plat/imx8m.rst
+:F: docs/plat/imx8m.rst
 :F: plat/imx/imx8m/
 
 OP-TEE dispatcher
 -----------------
 :M: Jens Wiklander <jens.wiklander@linaro.org>
 :G: `jenswi-linaro`_
-:F: docs/spd/optee-dispatcher.rst
+:F: docs/components/spd/optee-dispatcher.rst
 :F: services/spd/opteed/
 
 QEMU platform port
@@ -219,7 +216,7 @@
 :M: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
 :G: `grandpaul`_
 :F: docs/plat/rpi3.rst
-:F: plat/rpi3/
+:F: plat/rpi/rpi3/
 :F: drivers/rpi3/
 :F: include/drivers/rpi3/
 
@@ -273,8 +270,8 @@
 --------------------------
 :M: Varun Wadekar <vwadekar@nvidia.com>
 :G: `vwadekar`_
-:F: docs/spd/tlk-dispatcher.rst
-:F: docs/spd/trusty-dispatcher.rst
+:F: docs/components/spd/tlk-dispatcher.rst
+:F: docs/components/spd/trusty-dispatcher.rst
 :F: include/bl32/payloads/tlk.h
 :F: services/spd/tlkd/
 :F: services/spd/trusty/
diff --git a/docs/change-log-upcoming.rst b/docs/change-log-upcoming.rst
index c4e8bb0..15f39de 100644
--- a/docs/change-log-upcoming.rst
+++ b/docs/change-log-upcoming.rst
@@ -46,6 +46,7 @@
 
 - Security
    - Example: "UBSAN support and handlers"
+   - Add support for optional firmware encryption feature (experimental).
 
 - Tools
    - Example: "fiptool: Add support to build fiptool on Windows."
diff --git a/docs/design/auth-framework.rst b/docs/design/auth-framework.rst
index 93f691b..1a53e22 100644
--- a/docs/design/auth-framework.rst
+++ b/docs/design/auth-framework.rst
@@ -621,7 +621,7 @@
 
 The CoT can be found in ``drivers/auth/tbbr/tbbr_cot.c``. This CoT consists of
 an array of pointers to image descriptors and it is registered in the framework
-using the macro ``REGISTER_COT(cot_desc)``, where 'cot_desc' must be the name
+using the macro ``REGISTER_COT(cot_desc)``, where ``cot_desc`` must be the name
 of the array (passing a pointer or any other type of indirection will cause the
 registration process to fail).
 
@@ -870,32 +870,32 @@
 Trusted World public key needs to be extracted from the certificate. A new entry
 is created in the ``authenticated_data`` array for that purpose. In that entry,
 the corresponding parameter descriptor must be specified along with the buffer
-address to store the parameter value. In this case, the ``tz_world_pk`` descriptor
-is used to extract the public key from an x509v3 extension with OID
+address to store the parameter value. In this case, the ``trusted_world_pk``
+descriptor is used to extract the public key from an x509v3 extension with OID
 ``TRUSTED_WORLD_PK_OID``. The BL31 key certificate will use this descriptor as
 parameter in the signature authentication method. The key is stored in the
-``plat_tz_world_pk_buf`` buffer.
+``trusted_world_pk_buf`` buffer.
 
 The **BL31 Key certificate** is authenticated by checking its digital signature
 using the Trusted World public key obtained previously from the Trusted Key
 certificate. In the image descriptor, we specify a single authentication method
-by signature whose public key is the ``tz_world_pk``. Once this certificate has
-been authenticated, we have to extract the BL31 public key, stored in the
-extension specified by ``bl31_content_pk``. This key will be copied to the
-``plat_content_pk`` buffer.
+by signature whose public key is the ``trusted_world_pk``. Once this certificate
+has been authenticated, we have to extract the BL31 public key, stored in the
+extension specified by ``soc_fw_content_pk``. This key will be copied to the
+``content_pk_buf`` buffer.
 
 The **BL31 certificate** is authenticated by checking its digital signature
 using the BL31 public key obtained previously from the BL31 Key certificate.
-We specify the authentication method using ``bl31_content_pk`` as public key.
+We specify the authentication method using ``soc_fw_content_pk`` as public key.
 After authentication, we need to extract the BL31 hash, stored in the extension
-specified by ``bl31_hash``. This hash will be copied to the ``plat_bl31_hash_buf``
-buffer.
+specified by ``soc_fw_hash``. This hash will be copied to the
+``soc_fw_hash_buf`` buffer.
 
 The **BL31 image** is authenticated by calculating its hash and matching it
 with the hash obtained from the BL31 certificate. The image descriptor contains
 a single authentication method by hash. The parameters to the hash method are
-the reference hash, ``bl31_hash``, and the data to be hashed. In this case, it is
-the whole image, so we specify ``raw_data``.
+the reference hash, ``soc_fw_hash``, and the data to be hashed. In this case,
+it is the whole image, so we specify ``raw_data``.
 
 The image parser library
 ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -934,7 +934,7 @@
 based on mbed TLS, which can be found in
 ``drivers/auth/mbedtls/mbedtls_crypto.c``. This library is registered in the
 authentication framework using the macro ``REGISTER_CRYPTO_LIB()`` and exports
-three functions:
+four functions:
 
 .. code:: c
 
@@ -945,6 +945,11 @@
                          void *pk_ptr, unsigned int pk_len);
     int verify_hash(void *data_ptr, unsigned int data_len,
                     void *digest_info_ptr, unsigned int digest_info_len);
+    int auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr,
+                     size_t len, const void *key, unsigned int key_len,
+                     unsigned int key_flags, const void *iv,
+                     unsigned int iv_len, const void *tag,
+                     unsigned int tag_len)
 
 The mbedTLS library algorithm support is configured by both the
 ``TF_MBEDTLS_KEY_ALG`` and ``TF_MBEDTLS_KEY_SIZE`` variables.
@@ -957,6 +962,9 @@
 -  ``TF_MBEDTLS_KEY_SIZE`` sets the supported RSA key size for TFA. Valid values
    include 1024, 2048, 3072 and 4096.
 
+-  ``TF_MBEDTLS_USE_AES_GCM`` enables the authenticated decryption support based
+   on AES-GCM algorithm. Valid values are 0 and 1.
+
 .. note::
    If code size is a concern, the build option ``MBEDTLS_SHA256_SMALLER`` can
    be defined in the platform Makefile. It will make mbed TLS use an
@@ -965,6 +973,6 @@
 
 --------------
 
-*Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.*
+*Copyright (c) 2017-2020, Arm Limited and Contributors. All rights reserved.*
 
 .. _TBBR-Client specification: https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a
diff --git a/docs/design/trusted-board-boot.rst b/docs/design/trusted-board-boot.rst
index 49e8adb..4802c97 100644
--- a/docs/design/trusted-board-boot.rst
+++ b/docs/design/trusted-board-boot.rst
@@ -229,6 +229,34 @@
 Instructions for building and using the tool can be found at
 :ref:`tools_build_cert_create`.
 
+Authenticated Encryption Framework
+----------------------------------
+
+The authenticated encryption framework included in TF-A provides support to
+implement the optional firmware encryption feature. This feature can be
+optionally enabled on platforms to implement the optional requirement:
+R060_TBBR_FUNCTION as specified in the `Trusted Board Boot Requirements (TBBR)`_
+document.
+
+Note that due to security considerations and complexity of this feature, it is
+marked as experimental.
+
+Firmware Encryption Tool
+------------------------
+
+The ``encrypt_fw`` tool is built and runs on the host machine as part of the
+TF-A build process when ``DECRYPTION_SUPPORT != none``. It takes the plain
+firmware image as input and generates the encrypted firmware image which can
+then be passed as input to the ``fiptool`` utility for creating the FIP.
+
+The encrypted firmwares are also stored individually in the output build
+directory.
+
+The tool resides in the ``tools/encrypt_fw`` directory. It uses OpenSSL SSL
+library version 1.0.1 or later to do authenticated encryption operation.
+Instructions for building and using the tool can be found in the
+:ref:`tools_build_enctool`.
+
 --------------
 
 *Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.*
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index da5dcbf..f138feb 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -160,6 +160,12 @@
 -  ``DEBUG``: Chooses between a debug and release build. It can take either 0
    (release) or 1 (debug) as values. 0 is the default.
 
+-  ``DECRYPTION_SUPPORT``: This build flag enables the user to select the
+   authenticated decryption algorithm to be used to decrypt firmware/s during
+   boot. It accepts 2 values: ``aes_gcm`` and ``none``. The default value of
+   this flag is ``none`` to disable firmware decryption which is an optional
+   feature as per TBBR. Also, it is an experimental feature.
+
 -  ``DISABLE_BIN_GENERATION``: Boolean option to disable the generation
    of the binary image. If set to 1, then only the ELF image is built.
    0 is the default.
@@ -257,6 +263,22 @@
    platform hook needs to be implemented. The value is passed as the last
    component of the option ``-fstack-protector-$ENABLE_STACK_PROTECTOR``.
 
+-  ``ENCRYPT_BL31``: Binary flag to enable encryption of BL31 firmware. This
+   flag depends on ``DECRYPTION_SUPPORT`` build flag which is marked as
+   experimental.
+
+-  ``ENCRYPT_BL32``: Binary flag to enable encryption of Secure BL32 payload.
+   This flag depends on ``DECRYPTION_SUPPORT`` build flag which is marked as
+   experimental.
+
+-  ``ENC_KEY``: A 32-byte (256-bit) symmetric key in hex string format. It could
+   either be SSK or BSSK depending on ``FW_ENC_STATUS`` flag. This value depends
+   on ``DECRYPTION_SUPPORT`` build flag which is marked as experimental.
+
+-  ``ENC_NONCE``: A 12-byte (96-bit) encryption nonce or Initialization Vector
+   (IV) in hex string format. This value depends on ``DECRYPTION_SUPPORT``
+   build flag which is marked as experimental.
+
 -  ``ERROR_DEPRECATED``: This option decides whether to treat the usage of
    deprecated platform APIs, helper functions or drivers within Trusted
    Firmware as error. It can take the value 1 (flag the use of deprecated
@@ -281,6 +303,18 @@
 -  ``FWU_FIP_NAME``: This is an optional build option which specifies the FWU
    FIP filename for the ``fwu_fip`` target. Default is ``fwu_fip.bin``.
 
+-  ``FW_ENC_STATUS``: Top level firmware's encryption numeric flag, values:
+
+   ::
+
+     0: Encryption is done with Secret Symmetric Key (SSK) which is common
+        for a class of devices.
+     1: Encryption is done with Binding Secret Symmetric Key (BSSK) which is
+        unique per device.
+
+   This flag depends on ``DECRYPTION_SUPPORT`` build flag which is marked as
+   experimental.
+
 -  ``GENERATE_COT``: Boolean flag used to build and execute the ``cert_create``
    tool to create certificates as per the Chain of Trust described in
    :ref:`Trusted Board Boot`. The build system then calls ``fiptool`` to
diff --git a/docs/getting_started/porting-guide.rst b/docs/getting_started/porting-guide.rst
index e8357b3..d634d2e 100644
--- a/docs/getting_started/porting-guide.rst
+++ b/docs/getting_started/porting-guide.rst
@@ -872,6 +872,35 @@
 
 On success the function should return 0 and a negative error code otherwise.
 
+Function : plat_get_enc_key_info() [when FW_ENC_STATUS == 0 or 1]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Arguments : enum fw_enc_status_t fw_enc_status, uint8_t *key,
+                size_t *key_len, unsigned int *flags, const uint8_t *img_id,
+                size_t img_id_len
+    Return    : int
+
+This function provides a symmetric key (either SSK or BSSK depending on
+fw_enc_status) which is invoked during runtime decryption of encrypted
+firmware images. `plat/common/plat_bl_common.c` provides a dummy weak
+implementation for testing purposes which must be overridden by the platform
+trying to implement a real world firmware encryption use-case.
+
+It also allows the platform to pass symmetric key identifier rather than
+actual symmetric key which is useful in cases where the crypto backend provides
+secure storage for the symmetric key. So in this case ``ENC_KEY_IS_IDENTIFIER``
+flag must be set in ``flags``.
+
+In addition to above a platform may also choose to provide an image specific
+symmetric key/identifier using img_id.
+
+On success the function should return 0 and a negative error code otherwise.
+
+Note that this API depends on ``DECRYPTION_SUPPORT`` build flag which is
+marked as experimental.
+
 Common optional modifications
 -----------------------------
 
diff --git a/docs/getting_started/tools-build.rst b/docs/getting_started/tools-build.rst
index bb707cb..c050f58 100644
--- a/docs/getting_started/tools-build.rst
+++ b/docs/getting_started/tools-build.rst
@@ -135,6 +135,33 @@
 
     ./tools/cert_create/cert_create -h
 
+.. _tools_build_enctool:
+
+Building the Firmware Encryption Tool
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``encrypt_fw`` tool is built as part of the TF-A build process when the
+``fip`` make target is specified, DECRYPTION_SUPPORT and TBB are enabled, but
+it can also be built separately with the following command:
+
+.. code:: shell
+
+    make PLAT=<platform> [DEBUG=1] [V=1] enctool
+
+``DEBUG=1`` builds the tool in debug mode. ``V=1`` makes the build process more
+verbose. The following command should be used to obtain help about the tool:
+
+.. code:: shell
+
+    ./tools/encrypt_fw/encrypt_fw -h
+
+Note that the enctool in its current implementation only supports encryption
+key to be provided in plain format. A typical implementation can very well
+extend this tool to support custom techniques to protect encryption key.
+
+Also, a user may choose to provide encryption key or nonce as an input file
+via using ``cat <filename>`` instead of a hex string.
+
 --------------
 
 *Copyright (c) 2019, Arm Limited. All rights reserved.*
diff --git a/docs/plat/qemu.rst b/docs/plat/qemu.rst
index 88196bc..afa32c1 100644
--- a/docs/plat/qemu.rst
+++ b/docs/plat/qemu.rst
@@ -21,11 +21,13 @@
 
 -  Only cold boot is supported
 -  No build instructions for QEMU\_EFI.fd and rootfs-arm64.cpio.gz
--  No instructions for how to load a BL32 (Secure Payload)
 
 ``QEMU_EFI.fd`` can be dowloaded from
 http://snapshots.linaro.org/components/kernel/leg-virt-tianocore-edk2-upstream/latest/QEMU-KERNEL-AARCH64/RELEASE_GCC5/QEMU_EFI.fd
 
+Booting via semi-hosting option
+-------------------------------
+
 Boot binaries, except BL1, are primarily loaded via semi-hosting so all
 binaries has to reside in the same directory as QEMU is started from. This
 is conveniently achieved with symlinks the local names as:
@@ -50,3 +52,52 @@
         -append "console=ttyAMA0,38400 keep_bootcon root=/dev/vda2"   \
         -initrd rootfs-arm64.cpio.gz -smp 2 -m 1024 -bios bl1.bin   \
         -d unimp -semihosting-config enable,target=native
+
+Booting via flash based firmwares
+---------------------------------
+
+Boot firmwares are loaded via secure FLASH0 device so ``bl1.bin`` and
+``fip.bin`` should be concatenated to create a ``flash.bin`` that is flashed
+onto secure FLASH0.
+
+-  ``bl32.bin`` -> BL32 (``tee-header_v2.bin``)
+-  ``bl32_extra1.bin`` -> BL32 Extra1 (``tee-pager_v2.bin``)
+-  ``bl32_extra2.bin`` -> BL32 Extra2 (``tee-pageable_v2.bin``)
+-  ``bl33.bin`` -> BL33 (``QEMU_EFI.fd``)
+-  ``Image`` -> linux/arch/arm64/boot/Image
+
+To build:
+
+.. code:: shell
+
+    make CROSS_COMPILE=aarch64-linux-gnu- PLAT=qemu BL32=bl32.bin \
+        BL32_EXTRA1=bl32_extra1.bin BL32_EXTRA2=bl32_extra2.bin \
+        BL33=bl33.bin BL32_RAM_LOCATION=tdram SPD=opteed all fip
+
+To build with TBBR enabled, BL31 and BL32 encrypted with test key:
+
+.. code:: shell
+
+    make CROSS_COMPILE=aarch64-linux-gnu- PLAT=qemu BL32=bl32.bin \
+        BL32_EXTRA1=bl32_extra1.bin BL32_EXTRA2=bl32_extra2.bin \
+        BL33=bl33.bin BL32_RAM_LOCATION=tdram SPD=opteed all fip \
+        MBEDTLS_DIR=<path-to-mbedtls-repo> TRUSTED_BOARD_BOOT=1 \
+        GENERATE_COT=1 DECRYPTION_SUPPORT=aes_gcm FW_ENC_STATUS=0 \
+        ENCRYPT_BL31=1 ENCRYPT_BL32=1
+
+To build flash.bin:
+
+.. code:: shell
+
+    dd if=build/qemu/release/bl1.bin of=flash.bin bs=4096 conv=notrunc
+    dd if=build/qemu/release/fip.bin of=flash.bin seek=64 bs=4096 conv=notrunc
+
+To start (QEMU v2.6.0):
+
+.. code:: shell
+
+    qemu-system-aarch64 -nographic -machine virt,secure=on -cpu cortex-a57  \
+        -kernel Image -no-acpi                     \
+        -append 'console=ttyAMA0,38400 keep_bootcon root=/dev/vda2'  \
+        -initrd rootfs-arm64.cpio.gz -smp 2 -m 1024 -bios flash.bin   \
+        -d unimp
diff --git a/drivers/arm/css/scp/css_pm_scmi.c b/drivers/arm/css/scp/css_pm_scmi.c
index 097d2eb..aeb7eda 100644
--- a/drivers/arm/css/scp/css_pm_scmi.c
+++ b/drivers/arm/css/scp/css_pm_scmi.c
@@ -224,8 +224,8 @@
 
 	SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
 
-	core_pos = plat_core_pos_by_mpidr(mpidr);
-	assert(core_pos >= 0 && (core_pos < PLATFORM_CORE_COUNT));
+	core_pos = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+	assert(core_pos < PLATFORM_CORE_COUNT);
 
 	css_scp_core_pos_to_scmi_channel(core_pos, &domain_id,
 			&channel_id);
@@ -256,8 +256,8 @@
 		return PSCI_E_INVALID_PARAMS;
 	}
 
-	cpu_idx = plat_core_pos_by_mpidr(mpidr);
-	assert(cpu_idx > -1);
+	cpu_idx = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+	assert(cpu_idx < PLATFORM_CORE_COUNT);
 
 	css_scp_core_pos_to_scmi_channel(cpu_idx, &domain_id, &channel_id);
 	ret = scmi_pwr_state_get(scmi_handles[channel_id],
diff --git a/drivers/auth/crypto_mod.c b/drivers/auth/crypto_mod.c
index 110c504..c63ff08 100644
--- a/drivers/auth/crypto_mod.c
+++ b/drivers/auth/crypto_mod.c
@@ -124,3 +124,35 @@
 	return crypto_lib_desc.calc_hash(alg, data_ptr, data_len, output);
 }
 #endif	/* MEASURED_BOOT */
+
+/*
+ * Authenticated decryption of data
+ *
+ * Parameters:
+ *
+ *   dec_algo: authenticated decryption algorithm
+ *   data_ptr, len: data to be decrypted (inout param)
+ *   key, key_len, key_flags: symmetric decryption key
+ *   iv, iv_len: initialization vector
+ *   tag, tag_len: authentication tag
+ */
+int crypto_mod_auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr,
+			    size_t len, const void *key, unsigned int key_len,
+			    unsigned int key_flags, const void *iv,
+			    unsigned int iv_len, const void *tag,
+			    unsigned int tag_len)
+{
+	assert(crypto_lib_desc.auth_decrypt != NULL);
+	assert(data_ptr != NULL);
+	assert(len != 0U);
+	assert(key != NULL);
+	assert(key_len != 0U);
+	assert(iv != NULL);
+	assert((iv_len != 0U) && (iv_len <= CRYPTO_MAX_IV_SIZE));
+	assert(tag != NULL);
+	assert((tag_len != 0U) && (tag_len <= CRYPTO_MAX_TAG_SIZE));
+
+	return crypto_lib_desc.auth_decrypt(dec_algo, data_ptr, len, key,
+					    key_len, key_flags, iv, iv_len, tag,
+					    tag_len);
+}
diff --git a/drivers/auth/cryptocell/712/cryptocell_crypto.c b/drivers/auth/cryptocell/712/cryptocell_crypto.c
index 25eb6bc..cf43175 100644
--- a/drivers/auth/cryptocell/712/cryptocell_crypto.c
+++ b/drivers/auth/cryptocell/712/cryptocell_crypto.c
@@ -301,5 +301,5 @@
 /*
  * Register crypto library descriptor
  */
-REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash);
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL);
 
diff --git a/drivers/auth/mbedtls/mbedtls_common.mk b/drivers/auth/mbedtls/mbedtls_common.mk
index 4b83015..044b368 100644
--- a/drivers/auth/mbedtls/mbedtls_common.mk
+++ b/drivers/auth/mbedtls/mbedtls_common.mk
@@ -23,13 +23,17 @@
 
 
 LIBMBEDTLS_SRCS		:= $(addprefix ${MBEDTLS_DIR}/library/,	\
+					aes.c 					\
 					asn1parse.c 				\
 					asn1write.c 				\
+					cipher.c 				\
+					cipher_wrap.c 				\
 					memory_buffer_alloc.c			\
 					oid.c 					\
 					platform.c 				\
 					platform_util.c				\
 					bignum.c				\
+					gcm.c 					\
 					md.c					\
 					md_wrap.c				\
 					pk.c 					\
@@ -87,11 +91,17 @@
     $(error "TF_MBEDTLS_KEY_ALG=${TF_MBEDTLS_KEY_ALG} not supported on mbed TLS")
 endif
 
+ifeq (${DECRYPTION_SUPPORT}, aes_gcm)
+    TF_MBEDTLS_USE_AES_GCM	:=	1
+else
+    TF_MBEDTLS_USE_AES_GCM	:=	0
+endif
+
 # Needs to be set to drive mbed TLS configuration correctly
 $(eval $(call add_define,TF_MBEDTLS_KEY_ALG_ID))
 $(eval $(call add_define,TF_MBEDTLS_KEY_SIZE))
 $(eval $(call add_define,TF_MBEDTLS_HASH_ALG_ID))
-
+$(eval $(call add_define,TF_MBEDTLS_USE_AES_GCM))
 
 $(eval $(call MAKE_LIB,mbedtls))
 
diff --git a/drivers/auth/mbedtls/mbedtls_crypto.c b/drivers/auth/mbedtls/mbedtls_crypto.c
index 04fbc64..2a98014 100644
--- a/drivers/auth/mbedtls/mbedtls_crypto.c
+++ b/drivers/auth/mbedtls/mbedtls_crypto.c
@@ -4,10 +4,12 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <assert.h>
 #include <stddef.h>
 #include <string.h>
 
 /* mbed TLS headers */
+#include <mbedtls/gcm.h>
 #include <mbedtls/md.h>
 #include <mbedtls/memory_buffer_alloc.h>
 #include <mbedtls/oid.h>
@@ -17,6 +19,7 @@
 #include <drivers/auth/crypto_mod.h>
 #include <drivers/auth/mbedtls/mbedtls_common.h>
 #include <drivers/auth/mbedtls/mbedtls_config.h>
+#include <plat/common/platform.h>
 
 #define LIB_NAME		"mbed TLS"
 
@@ -226,11 +229,121 @@
 }
 #endif /* MEASURED_BOOT */
 
+#if TF_MBEDTLS_USE_AES_GCM
+/*
+ * Stack based buffer allocation for decryption operation. It could
+ * be configured to balance stack usage vs execution speed.
+ */
+#define DEC_OP_BUF_SIZE		128
+
+static int aes_gcm_decrypt(void *data_ptr, size_t len, const void *key,
+			   unsigned int key_len, const void *iv,
+			   unsigned int iv_len, const void *tag,
+			   unsigned int tag_len)
+{
+	mbedtls_gcm_context ctx;
+	mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES;
+	unsigned char buf[DEC_OP_BUF_SIZE];
+	unsigned char tag_buf[CRYPTO_MAX_TAG_SIZE];
+	unsigned char *pt = data_ptr;
+	size_t dec_len;
+	int diff, i, rc;
+
+	mbedtls_gcm_init(&ctx);
+
+	rc = mbedtls_gcm_setkey(&ctx, cipher, key, key_len * 8);
+	if (rc != 0) {
+		rc = CRYPTO_ERR_DECRYPTION;
+		goto exit_gcm;
+	}
+
+	rc = mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_DECRYPT, iv, iv_len, NULL, 0);
+	if (rc != 0) {
+		rc = CRYPTO_ERR_DECRYPTION;
+		goto exit_gcm;
+	}
+
+	while (len > 0) {
+		dec_len = MIN(sizeof(buf), len);
+
+		rc = mbedtls_gcm_update(&ctx, dec_len, pt, buf);
+		if (rc != 0) {
+			rc = CRYPTO_ERR_DECRYPTION;
+			goto exit_gcm;
+		}
+
+		memcpy(pt, buf, dec_len);
+		pt += dec_len;
+		len -= dec_len;
+	}
+
+	rc = mbedtls_gcm_finish(&ctx, tag_buf, sizeof(tag_buf));
+	if (rc != 0) {
+		rc = CRYPTO_ERR_DECRYPTION;
+		goto exit_gcm;
+	}
+
+	/* Check tag in "constant-time" */
+	for (diff = 0, i = 0; i < tag_len; i++)
+		diff |= ((const unsigned char *)tag)[i] ^ tag_buf[i];
+
+	if (diff != 0) {
+		rc = CRYPTO_ERR_DECRYPTION;
+		goto exit_gcm;
+	}
+
+	/* GCM decryption success */
+	rc = CRYPTO_SUCCESS;
+
+exit_gcm:
+	mbedtls_gcm_free(&ctx);
+	return rc;
+}
+
+/*
+ * Authenticated decryption of an image
+ */
+static int auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr,
+			size_t len, const void *key, unsigned int key_len,
+			unsigned int key_flags, const void *iv,
+			unsigned int iv_len, const void *tag,
+			unsigned int tag_len)
+{
+	int rc;
+
+	assert((key_flags & ENC_KEY_IS_IDENTIFIER) == 0);
+
+	switch (dec_algo) {
+	case CRYPTO_GCM_DECRYPT:
+		rc = aes_gcm_decrypt(data_ptr, len, key, key_len, iv, iv_len,
+				     tag, tag_len);
+		if (rc != 0)
+			return rc;
+		break;
+	default:
+		return CRYPTO_ERR_DECRYPTION;
+	}
+
+	return CRYPTO_SUCCESS;
+}
+#endif /* TF_MBEDTLS_USE_AES_GCM */
+
 /*
  * Register crypto library descriptor
  */
 #if MEASURED_BOOT
-REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash);
+#if TF_MBEDTLS_USE_AES_GCM
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash,
+		    auth_decrypt);
+#else
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, calc_hash,
+		    NULL);
+#endif
+#else /* MEASURED_BOOT */
+#if TF_MBEDTLS_USE_AES_GCM
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash,
+		    auth_decrypt);
 #else
-REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash);
+REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL);
+#endif
 #endif /* MEASURED_BOOT */
diff --git a/drivers/io/io_encrypted.c b/drivers/io/io_encrypted.c
new file mode 100644
index 0000000..744ca83
--- /dev/null
+++ b/drivers/io/io_encrypted.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2020, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <platform_def.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/io/io_driver.h>
+#include <drivers/io/io_encrypted.h>
+#include <drivers/io/io_storage.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <tools_share/firmware_encrypted.h>
+#include <tools_share/uuid.h>
+
+static uintptr_t backend_dev_handle;
+static uintptr_t backend_dev_spec;
+static uintptr_t backend_handle;
+static uintptr_t backend_image_spec;
+
+static io_dev_info_t enc_dev_info;
+
+/* Encrypted firmware driver functions */
+static int enc_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+static int enc_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
+			  io_entity_t *entity);
+static int enc_file_len(io_entity_t *entity, size_t *length);
+static int enc_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+			  size_t *length_read);
+static int enc_file_close(io_entity_t *entity);
+static int enc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params);
+static int enc_dev_close(io_dev_info_t *dev_info);
+
+static inline int is_valid_header(struct fw_enc_hdr *header)
+{
+	if (header->magic == ENC_HEADER_MAGIC)
+		return 1;
+	else
+		return 0;
+}
+
+static io_type_t device_type_enc(void)
+{
+	return IO_TYPE_ENCRYPTED;
+}
+
+static const io_dev_connector_t enc_dev_connector = {
+	.dev_open = enc_dev_open
+};
+
+static const io_dev_funcs_t enc_dev_funcs = {
+	.type = device_type_enc,
+	.open = enc_file_open,
+	.seek = NULL,
+	.size = enc_file_len,
+	.read = enc_file_read,
+	.write = NULL,
+	.close = enc_file_close,
+	.dev_init = enc_dev_init,
+	.dev_close = enc_dev_close,
+};
+
+static int enc_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
+{
+	assert(dev_info != NULL);
+
+	enc_dev_info.funcs = &enc_dev_funcs;
+	*dev_info = &enc_dev_info;
+
+	return 0;
+}
+
+static int enc_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params)
+{
+	int result;
+	unsigned int image_id = (unsigned int)init_params;
+
+	/* Obtain a reference to the image by querying the platform layer */
+	result = plat_get_image_source(image_id, &backend_dev_handle,
+				       &backend_dev_spec);
+	if (result != 0) {
+		WARN("Failed to obtain reference to image id=%u (%i)\n",
+			image_id, result);
+		return -ENOENT;
+	}
+
+	return result;
+}
+
+static int enc_dev_close(io_dev_info_t *dev_info)
+{
+	backend_dev_handle = (uintptr_t)NULL;
+	backend_dev_spec = (uintptr_t)NULL;
+
+	return 0;
+}
+
+static int enc_file_open(io_dev_info_t *dev_info, const uintptr_t spec,
+			 io_entity_t *entity)
+{
+	int result;
+
+	assert(spec != 0);
+	assert(entity != NULL);
+
+	backend_image_spec = spec;
+
+	result = io_open(backend_dev_handle, backend_image_spec,
+			 &backend_handle);
+	if (result != 0) {
+		WARN("Failed to open backend device (%i)\n", result);
+		result = -ENOENT;
+	}
+
+	return result;
+}
+
+static int enc_file_len(io_entity_t *entity, size_t *length)
+{
+	int result;
+
+	assert(entity != NULL);
+	assert(length != NULL);
+
+	result = io_size(backend_handle, length);
+	if (result != 0) {
+		WARN("Failed to read blob length (%i)\n", result);
+		return -ENOENT;
+	}
+
+	/*
+	 * Encryption header is attached at the beginning of the encrypted file
+	 * and is not considered a part of the payload.
+	 */
+	if (*length < sizeof(struct fw_enc_hdr))
+		return -EIO;
+
+	*length -= sizeof(struct fw_enc_hdr);
+
+	return result;
+}
+
+static int enc_file_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+			 size_t *length_read)
+{
+	int result;
+	struct fw_enc_hdr header;
+	enum fw_enc_status_t fw_enc_status;
+	size_t bytes_read;
+	uint8_t key[ENC_MAX_KEY_SIZE];
+	size_t key_len = sizeof(key);
+	unsigned int key_flags = 0;
+	const io_uuid_spec_t *uuid_spec = (io_uuid_spec_t *)backend_image_spec;
+
+	assert(entity != NULL);
+	assert(length_read != NULL);
+
+	result = io_read(backend_handle, (uintptr_t)&header, sizeof(header),
+			 &bytes_read);
+	if (result != 0) {
+		WARN("Failed to read encryption header (%i)\n", result);
+		return -ENOENT;
+	}
+
+	if (!is_valid_header(&header)) {
+		WARN("Encryption header check failed.\n");
+		return -ENOENT;
+	}
+
+	VERBOSE("Encryption header looks OK.\n");
+	fw_enc_status = header.flags & FW_ENC_STATUS_FLAG_MASK;
+
+	if ((header.iv_len > ENC_MAX_IV_SIZE) ||
+	    (header.tag_len > ENC_MAX_TAG_SIZE)) {
+		WARN("Incorrect IV or tag length\n");
+		return -ENOENT;
+	}
+
+	result = io_read(backend_handle, buffer, length, &bytes_read);
+	if (result != 0) {
+		WARN("Failed to read encrypted payload (%i)\n", result);
+		return -ENOENT;
+	}
+
+	*length_read = bytes_read;
+
+	result = plat_get_enc_key_info(fw_enc_status, key, &key_len, &key_flags,
+				       (uint8_t *)&uuid_spec->uuid,
+				       sizeof(uuid_t));
+	if (result != 0) {
+		WARN("Failed to obtain encryption key (%i)\n", result);
+		return -ENOENT;
+	}
+
+	result = crypto_mod_auth_decrypt(header.dec_algo,
+					 (void *)buffer, *length_read, key,
+					 key_len, key_flags, header.iv,
+					 header.iv_len, header.tag,
+					 header.tag_len);
+	memset(key, 0, key_len);
+
+	if (result != 0) {
+		ERROR("File decryption failed (%i)\n", result);
+		return -ENOENT;
+	}
+
+	return result;
+}
+
+static int enc_file_close(io_entity_t *entity)
+{
+	io_close(backend_handle);
+
+	backend_image_spec = (uintptr_t)NULL;
+	entity->info = 0;
+
+	return 0;
+}
+
+/* Exported functions */
+
+/* Register the Encrypted Firmware driver with the IO abstraction */
+int register_io_dev_enc(const io_dev_connector_t **dev_con)
+{
+	int result;
+
+	assert(dev_con != NULL);
+
+	result = io_register_device(&enc_dev_info);
+	if (result == 0)
+		*dev_con = &enc_dev_connector;
+
+	return result;
+}
diff --git a/fdts/a5ds.dts b/fdts/a5ds.dts
index 31d635a..7334c45 100644
--- a/fdts/a5ds.dts
+++ b/fdts/a5ds.dts
@@ -136,4 +136,23 @@
 			reg = <0x1a050000 0x1000>;
 		};
 	};
+	v2m_fixed_3v3: fixed-regulator-0 {
+		compatible = "regulator-fixed";
+		regulator-name = "3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
+	ethernet@4020000 {
+		compatible = "smsc,lan9220", "smsc,lan9115";
+		reg = <0x40200000 0x10000>;
+		interrupt-parent = <&gic>;
+		interrupts = <0 43 0xf04>;
+		reg-io-width = <4>;
+		phy-mode = "mii";
+		smsc,irq-active-high;
+		vdd33a-supply = <&v2m_fixed_3v3>;
+		vddvario-supply = <&v2m_fixed_3v3>;
+       };
 };
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 1faddbe..b0c2650 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -97,6 +97,32 @@
 #define ICC_SGI0R_EL1		S3_0_c12_c11_7
 
 /*******************************************************************************
+ * Definitions for EL2 system registers for save/restore routine
+ ******************************************************************************/
+
+#define CNTPOFF_EL2		S3_4_C14_C0_6
+#define HAFGRTR_EL2		S3_4_C3_C1_6
+#define HDFGRTR_EL2		S3_4_C3_C1_4
+#define HDFGWTR_EL2		S3_4_C3_C1_5
+#define HFGITR_EL2		S3_4_C1_C1_6
+#define HFGRTR_EL2		S3_4_C1_C1_4
+#define HFGWTR_EL2		S3_4_C1_C1_5
+#define ICH_HCR_EL2		S3_4_C12_C11_0
+#define ICH_VMCR_EL2		S3_4_C12_C11_7
+#define MPAMVPM0_EL2		S3_4_C10_C5_0
+#define MPAMVPM1_EL2		S3_4_C10_C5_1
+#define MPAMVPM2_EL2		S3_4_C10_C5_2
+#define MPAMVPM3_EL2		S3_4_C10_C5_3
+#define MPAMVPM4_EL2		S3_4_C10_C5_4
+#define MPAMVPM5_EL2		S3_4_C10_C5_5
+#define MPAMVPM6_EL2		S3_4_C10_C5_6
+#define MPAMVPM7_EL2		S3_4_C10_C5_7
+#define MPAMVPMV_EL2		S3_4_C10_C4_1
+#define TRFCR_EL2		S3_4_C1_C2_1
+#define PMSCR_EL2		S3_4_C9_C9_0
+#define TFSR_EL2		S3_4_C5_C6_0
+
+/*******************************************************************************
  * Generic timer memory mapped registers & offsets
  ******************************************************************************/
 #define CNTCR_OFF			U(0x000)
diff --git a/include/drivers/auth/crypto_mod.h b/include/drivers/auth/crypto_mod.h
index f211035..71cf673 100644
--- a/include/drivers/auth/crypto_mod.h
+++ b/include/drivers/auth/crypto_mod.h
@@ -13,9 +13,18 @@
 	CRYPTO_ERR_INIT,
 	CRYPTO_ERR_HASH,
 	CRYPTO_ERR_SIGNATURE,
+	CRYPTO_ERR_DECRYPTION,
 	CRYPTO_ERR_UNKNOWN
 };
 
+#define CRYPTO_MAX_IV_SIZE		16U
+#define CRYPTO_MAX_TAG_SIZE		16U
+
+/* Decryption algorithm */
+enum crypto_dec_algo {
+	CRYPTO_GCM_DECRYPT = 0
+};
+
 /*
  * Cryptographic library descriptor
  */
@@ -44,6 +53,15 @@
 			 unsigned int data_len, unsigned char *output);
 #endif /* MEASURED_BOOT */
 
+	/*
+	 * Authenticated decryption. Return one of the
+	 * 'enum crypto_ret_value' options.
+	 */
+	int (*auth_decrypt)(enum crypto_dec_algo dec_algo, void *data_ptr,
+			    size_t len, const void *key, unsigned int key_len,
+			    unsigned int key_flags, const void *iv,
+			    unsigned int iv_len, const void *tag,
+			    unsigned int tag_len);
 } crypto_lib_desc_t;
 
 /* Public functions */
@@ -54,6 +72,11 @@
 				void *pk_ptr, unsigned int pk_len);
 int crypto_mod_verify_hash(void *data_ptr, unsigned int data_len,
 			   void *digest_info_ptr, unsigned int digest_info_len);
+int crypto_mod_auth_decrypt(enum crypto_dec_algo dec_algo, void *data_ptr,
+			    size_t len, const void *key, unsigned int key_len,
+			    unsigned int key_flags, const void *iv,
+			    unsigned int iv_len, const void *tag,
+			    unsigned int tag_len);
 
 #if MEASURED_BOOT
 int crypto_mod_calc_hash(unsigned int alg, void *data_ptr,
@@ -61,21 +84,24 @@
 
 /* Macro to register a cryptographic library */
 #define REGISTER_CRYPTO_LIB(_name, _init, _verify_signature, _verify_hash, \
-							     _calc_hash) \
+			    _calc_hash, _auth_decrypt) \
 	const crypto_lib_desc_t crypto_lib_desc = { \
 		.name = _name, \
 		.init = _init, \
 		.verify_signature = _verify_signature, \
 		.verify_hash = _verify_hash, \
-		.calc_hash = _calc_hash \
+		.calc_hash = _calc_hash, \
+		.auth_decrypt = _auth_decrypt \
 	}
 #else
-#define REGISTER_CRYPTO_LIB(_name, _init, _verify_signature, _verify_hash) \
+#define REGISTER_CRYPTO_LIB(_name, _init, _verify_signature, _verify_hash, \
+			    _auth_decrypt) \
 	const crypto_lib_desc_t crypto_lib_desc = { \
 		.name = _name, \
 		.init = _init, \
 		.verify_signature = _verify_signature, \
-		.verify_hash = _verify_hash \
+		.verify_hash = _verify_hash, \
+		.auth_decrypt = _auth_decrypt \
 	}
 #endif	/* MEASURED_BOOT */
 
diff --git a/include/drivers/auth/mbedtls/mbedtls_config.h b/include/drivers/auth/mbedtls/mbedtls_config.h
index 6e179bb..dc00da7 100644
--- a/include/drivers/auth/mbedtls/mbedtls_config.h
+++ b/include/drivers/auth/mbedtls/mbedtls_config.h
@@ -79,6 +79,12 @@
 #define MBEDTLS_X509_USE_C
 #define MBEDTLS_X509_CRT_PARSE_C
 
+#if TF_MBEDTLS_USE_AES_GCM
+#define MBEDTLS_AES_C
+#define MBEDTLS_CIPHER_C
+#define MBEDTLS_GCM_C
+#endif
+
 /* MPI / BIGNUM options */
 #define MBEDTLS_MPI_WINDOW_SIZE			2
 
diff --git a/include/drivers/io/io_encrypted.h b/include/drivers/io/io_encrypted.h
new file mode 100644
index 0000000..9dcf061
--- /dev/null
+++ b/include/drivers/io/io_encrypted.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2020, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IO_ENCRYPTED_H
+#define IO_ENCRYPTED_H
+
+struct io_dev_connector;
+
+int register_io_dev_enc(const struct io_dev_connector **dev_con);
+
+#endif /* IO_ENCRYPTED_H */
diff --git a/include/drivers/io/io_storage.h b/include/drivers/io/io_storage.h
index a301ad5..f2d641c 100644
--- a/include/drivers/io/io_storage.h
+++ b/include/drivers/io/io_storage.h
@@ -25,6 +25,7 @@
 	IO_TYPE_MTD,
 	IO_TYPE_MMC,
 	IO_TYPE_STM32IMAGE,
+	IO_TYPE_ENCRYPTED,
 	IO_TYPE_MAX
 } io_type_t;
 
diff --git a/include/export/common/tbbr/tbbr_img_def_exp.h b/include/export/common/tbbr/tbbr_img_def_exp.h
index ff0d16c..89dbc58 100644
--- a/include/export/common/tbbr/tbbr_img_def_exp.h
+++ b/include/export/common/tbbr/tbbr_img_def_exp.h
@@ -85,7 +85,15 @@
 /* Binary with STM32 header */
 #define STM32_IMAGE_ID			U(29)
 
+/* Encrypted image identifier */
+#define ENC_IMAGE_ID			U(30)
+
 /* Define size of the array */
-#define MAX_NUMBER_IDS			U(30)
+#if defined(SPD_spmd)
+#define MAX_SP_IDS			U(8)
+#define MAX_NUMBER_IDS			MAX_SP_IDS + U(31)
+#else
+#define MAX_NUMBER_IDS			U(31)
+#endif
 
 #endif /* ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_TBBR_TBBR_IMG_DEF_EXP_H */
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index 4158c02..e061950 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -68,7 +68,7 @@
  * registers are only 32-bits wide but are stored as 64-bit values for
  * convenience
  ******************************************************************************/
-#define CTX_SYSREGS_OFFSET	(CTX_EL3STATE_OFFSET + CTX_EL3STATE_END)
+#define CTX_EL1_SYSREGS_OFFSET	(CTX_EL3STATE_OFFSET + CTX_EL3STATE_END)
 #define CTX_SPSR_EL1		U(0x0)
 #define CTX_ELR_EL1		U(0x8)
 #define CTX_SCTLR_EL1		U(0x10)
@@ -138,13 +138,118 @@
 /*
  * End of system registers.
  */
-#define CTX_SYSREGS_END		CTX_MTE_REGS_END
+#define CTX_EL1_SYSREGS_END		CTX_MTE_REGS_END
+
+/*
+ * EL2 register set
+ */
+
+#if CTX_INCLUDE_EL2_REGS
+/* For later discussion
+ * ICH_AP0R<n>_EL2
+ * ICH_AP1R<n>_EL2
+ * AMEVCNTVOFF0<n>_EL2
+ * AMEVCNTVOFF1<n>_EL2
+ * ICH_LR<n>_EL2
+ */
+#define CTX_EL2_SYSREGS_OFFSET	(CTX_EL1_SYSREGS_OFFSET + CTX_EL1_SYSREGS_END)
+
+#define CTX_ACTLR_EL2		U(0x0)
+#define CTX_AFSR0_EL2		U(0x8)
+#define CTX_AFSR1_EL2		U(0x10)
+#define CTX_AMAIR_EL2		U(0x18)
+#define CTX_CNTHCTL_EL2		U(0x20)
+#define CTX_CNTHP_CTL_EL2	U(0x28)
+#define CTX_CNTHP_CVAL_EL2	U(0x30)
+#define CTX_CNTHP_TVAL_EL2	U(0x38)
+#define CTX_CNTVOFF_EL2		U(0x40)
+#define CTX_CPTR_EL2		U(0x48)
+#define CTX_DBGVCR32_EL2	U(0x50)
+#define CTX_ELR_EL2		U(0x58)
+#define CTX_ESR_EL2		U(0x60)
+#define CTX_FAR_EL2		U(0x68)
+#define CTX_FPEXC32_EL2		U(0x70)
+#define CTX_HACR_EL2		U(0x78)
+#define CTX_HCR_EL2		U(0x80)
+#define CTX_HPFAR_EL2		U(0x88)
+#define CTX_HSTR_EL2		U(0x90)
+#define CTX_ICC_SRE_EL2		U(0x98)
+#define CTX_ICH_HCR_EL2		U(0xa0)
+#define CTX_ICH_VMCR_EL2	U(0xa8)
+#define CTX_MAIR_EL2		U(0xb0)
+#define CTX_MDCR_EL2		U(0xb8)
+#define CTX_PMSCR_EL2		U(0xc0)
+#define CTX_SCTLR_EL2		U(0xc8)
+#define CTX_SPSR_EL2		U(0xd0)
+#define CTX_SP_EL2		U(0xd8)
+#define CTX_TCR_EL2		U(0xe0)
+#define CTX_TRFCR_EL2		U(0xe8)
+#define CTX_TTBR0_EL2		U(0xf0)
+#define CTX_VBAR_EL2		U(0xf8)
+#define CTX_VMPIDR_EL2		U(0x100)
+#define CTX_VPIDR_EL2		U(0x108)
+#define CTX_VTCR_EL2		U(0x110)
+#define CTX_VTTBR_EL2		U(0x118)
+
+// Only if MTE registers in use
+#define CTX_TFSR_EL2		U(0x120)
+
+// Only if ENABLE_MPAM_FOR_LOWER_ELS==1
+#define CTX_MPAM2_EL2		U(0x128)
+#define CTX_MPAMHCR_EL2		U(0x130)
+#define CTX_MPAMVPM0_EL2	U(0x138)
+#define CTX_MPAMVPM1_EL2	U(0x140)
+#define CTX_MPAMVPM2_EL2	U(0x148)
+#define CTX_MPAMVPM3_EL2	U(0x150)
+#define CTX_MPAMVPM4_EL2	U(0x158)
+#define CTX_MPAMVPM5_EL2	U(0x160)
+#define CTX_MPAMVPM6_EL2	U(0x168)
+#define CTX_MPAMVPM7_EL2	U(0x170)
+#define CTX_MPAMVPMV_EL2	U(0x178)
+
+// Starting with Armv8.6
+#define CTX_HAFGRTR_EL2		U(0x180)
+#define CTX_HDFGRTR_EL2		U(0x188)
+#define CTX_HDFGWTR_EL2		U(0x190)
+#define CTX_HFGITR_EL2		U(0x198)
+#define CTX_HFGRTR_EL2		U(0x1a0)
+#define CTX_HFGWTR_EL2		U(0x1a8)
+#define CTX_CNTPOFF_EL2		U(0x1b0)
+
+// Starting with Armv8.4
+#define CTX_CNTHPS_CTL_EL2	U(0x1b8)
+#define CTX_CNTHPS_CVAL_EL2	U(0x1c0)
+#define CTX_CNTHPS_TVAL_EL2	U(0x1c8)
+#define CTX_CNTHVS_CTL_EL2	U(0x1d0)
+#define CTX_CNTHVS_CVAL_EL2	U(0x1d8)
+#define CTX_CNTHVS_TVAL_EL2	U(0x1e0)
+#define CTX_CNTHV_CTL_EL2	U(0x1e8)
+#define CTX_CNTHV_CVAL_EL2	U(0x1f0)
+#define CTX_CNTHV_TVAL_EL2	U(0x1f8)
+#define CTX_CONTEXTIDR_EL2	U(0x200)
+#define CTX_SDER32_EL2		U(0x208)
+#define CTX_TTBR1_EL2		U(0x210)
+#define CTX_VDISR_EL2		U(0x218)
+#define CTX_VNCR_EL2		U(0x220)
+#define CTX_VSESR_EL2		U(0x228)
+#define CTX_VSTCR_EL2		U(0x230)
+#define CTX_VSTTBR_EL2		U(0x238)
+
+// Starting with Armv8.5
+#define CTX_SCXTNUM_EL2		U(0x240)
+/* Align to the next 16 byte boundary */
+#define CTX_EL2_SYSREGS_END	U(0x250)
+#endif /* CTX_INCLUDE_EL2_REGS */
 
 /*******************************************************************************
  * Constants that allow assembler code to access members of and the 'fp_regs'
  * structure at their correct offsets.
  ******************************************************************************/
-#define CTX_FPREGS_OFFSET	(CTX_SYSREGS_OFFSET + CTX_SYSREGS_END)
+#if CTX_INCLUDE_EL2_REGS
+# define CTX_FPREGS_OFFSET	(CTX_EL2_SYSREGS_OFFSET + CTX_EL2_SYSREGS_END)
+#else
+# define CTX_FPREGS_OFFSET	(CTX_EL1_SYSREGS_OFFSET + CTX_EL1_SYSREGS_END)
+#endif
 #if CTX_INCLUDE_FPREGS
 #define CTX_FP_Q0		U(0x0)
 #define CTX_FP_Q1		U(0x10)
@@ -235,7 +340,10 @@
 
 /* Constants to determine the size of individual context structures */
 #define CTX_GPREG_ALL		(CTX_GPREGS_END >> DWORD_SHIFT)
-#define CTX_SYSREG_ALL		(CTX_SYSREGS_END >> DWORD_SHIFT)
+#define CTX_EL1_SYSREGS_ALL	(CTX_EL1_SYSREGS_END >> DWORD_SHIFT)
+#if CTX_INCLUDE_EL2_REGS
+# define CTX_EL2_SYSREGS_ALL	(CTX_EL2_SYSREGS_END >> DWORD_SHIFT)
+#endif
 #if CTX_INCLUDE_FPREGS
 # define CTX_FPREG_ALL		(CTX_FPREGS_END >> DWORD_SHIFT)
 #endif
@@ -256,10 +364,18 @@
 
 /*
  * AArch64 EL1 system register context structure for preserving the
- * architectural state during switches from one security state to
- * another in EL1.
+ * architectural state during world switches.
  */
-DEFINE_REG_STRUCT(el1_sys_regs, CTX_SYSREG_ALL);
+DEFINE_REG_STRUCT(el1_sysregs, CTX_EL1_SYSREGS_ALL);
+
+
+/*
+ * AArch64 EL2 system register context structure for preserving the
+ * architectural state during world switches.
+ */
+#if CTX_INCLUDE_EL2_REGS
+DEFINE_REG_STRUCT(el2_sysregs, CTX_EL2_SYSREGS_ALL);
+#endif
 
 /*
  * AArch64 floating point register context structure for preserving
@@ -304,7 +420,10 @@
 typedef struct cpu_context {
 	gp_regs_t gpregs_ctx;
 	el3_state_t el3state_ctx;
-	el1_sys_regs_t sysregs_ctx;
+	el1_sysregs_t el1_sysregs_ctx;
+#if CTX_INCLUDE_EL2_REGS
+	el2_sysregs_t el2_sysregs_ctx;
+#endif
 #if CTX_INCLUDE_FPREGS
 	fp_regs_t fpregs_ctx;
 #endif
@@ -319,7 +438,10 @@
 #if CTX_INCLUDE_FPREGS
 # define get_fpregs_ctx(h)	(&((cpu_context_t *) h)->fpregs_ctx)
 #endif
-#define get_sysregs_ctx(h)	(&((cpu_context_t *) h)->sysregs_ctx)
+#define get_el1_sysregs_ctx(h)	(&((cpu_context_t *) h)->el1_sysregs_ctx)
+#if CTX_INCLUDE_EL2_REGS
+# define get_el2_sysregs_ctx(h)	(&((cpu_context_t *) h)->el2_sysregs_ctx)
+#endif
 #define get_gpregs_ctx(h)	(&((cpu_context_t *) h)->gpregs_ctx)
 #define get_cve_2018_3639_ctx(h)	(&((cpu_context_t *) h)->cve_2018_3639_ctx)
 #if CTX_INCLUDE_PAUTH_REGS
@@ -333,8 +455,12 @@
  */
 CASSERT(CTX_GPREGS_OFFSET == __builtin_offsetof(cpu_context_t, gpregs_ctx), \
 	assert_core_context_gp_offset_mismatch);
-CASSERT(CTX_SYSREGS_OFFSET == __builtin_offsetof(cpu_context_t, sysregs_ctx), \
-	assert_core_context_sys_offset_mismatch);
+CASSERT(CTX_EL1_SYSREGS_OFFSET == __builtin_offsetof(cpu_context_t, el1_sysregs_ctx), \
+	assert_core_context_el1_sys_offset_mismatch);
+#if CTX_INCLUDE_EL2_REGS
+CASSERT(CTX_EL2_SYSREGS_OFFSET == __builtin_offsetof(cpu_context_t, el2_sysregs_ctx), \
+	assert_core_context_el2_sys_offset_mismatch);
+#endif
 #if CTX_INCLUDE_FPREGS
 CASSERT(CTX_FPREGS_OFFSET == __builtin_offsetof(cpu_context_t, fpregs_ctx), \
 	assert_core_context_fp_offset_mismatch);
@@ -387,8 +513,14 @@
 /*******************************************************************************
  * Function prototypes
  ******************************************************************************/
-void el1_sysregs_context_save(el1_sys_regs_t *regs);
-void el1_sysregs_context_restore(el1_sys_regs_t *regs);
+void el1_sysregs_context_save(el1_sysregs_t *regs);
+void el1_sysregs_context_restore(el1_sysregs_t *regs);
+
+#if CTX_INCLUDE_EL2_REGS
+void el2_sysregs_context_save(el2_sysregs_t *regs);
+void el2_sysregs_context_restore(el2_sysregs_t *regs);
+#endif
+
 #if CTX_INCLUDE_FPREGS
 void fpregs_context_save(fp_regs_t *regs);
 void fpregs_context_restore(fp_regs_t *regs);
diff --git a/include/lib/el3_runtime/context_mgmt.h b/include/lib/el3_runtime/context_mgmt.h
index 17955e3..b36cd3d 100644
--- a/include/lib/el3_runtime/context_mgmt.h
+++ b/include/lib/el3_runtime/context_mgmt.h
@@ -36,6 +36,11 @@
 void cm_prepare_el3_exit(uint32_t security_state);
 
 #ifdef __aarch64__
+#if CTX_INCLUDE_EL2_REGS
+void cm_el2_sysregs_context_save(uint32_t security_state);
+void cm_el2_sysregs_context_restore(uint32_t security_state);
+#endif
+
 void cm_el1_sysregs_context_save(uint32_t security_state);
 void cm_el1_sysregs_context_restore(uint32_t security_state);
 void cm_set_elr_el3(uint32_t security_state, uintptr_t entrypoint);
diff --git a/include/plat/arm/common/fconf_arm_sp_getter.h b/include/plat/arm/common/fconf_arm_sp_getter.h
new file mode 100644
index 0000000..38c30fb
--- /dev/null
+++ b/include/plat/arm/common/fconf_arm_sp_getter.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FCONF_ARM_SP_GETTER_H
+#define FCONF_ARM_SP_GETTER_H
+
+#include <lib/fconf/fconf.h>
+#include <tools_share/uuid.h>
+
+/* arm_sp getter */
+#define arm__sp_getter(prop)	arm_sp.prop
+
+#define ARM_SP_MAX_SIZE		U(0x10000)
+
+struct arm_sp_t {
+	unsigned int		number_of_sp;
+	union uuid_helper_t	uuids[MAX_SP_IDS];
+	uintptr_t		load_addr[MAX_SP_IDS];
+};
+
+int fconf_populate_arm_sp(uintptr_t config);
+
+extern struct arm_sp_t arm_sp;
+
+extern bl_mem_params_node_t sp_mem_params_descs[MAX_SP_IDS];
+
+#endif /* FCONF_ARM_SP_GETTER_H */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index f5bd298..5b5ebb9 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -27,6 +27,7 @@
 struct mmap_region;
 struct spm_mm_boot_info;
 struct sp_res_desc;
+enum fw_enc_status_t;
 
 /*******************************************************************************
  * plat_get_rotpk_info() flags
@@ -37,6 +38,15 @@
 #define ROTPK_NOT_DEPLOYED		(1 << 1)
 
 /*******************************************************************************
+ * plat_get_enc_key_info() flags
+ ******************************************************************************/
+/*
+ * Flag used to notify caller that information provided in key buffer is an
+ * identifier rather than an actual key.
+ */
+#define ENC_KEY_IS_IDENTIFIER		(1 << 0)
+
+/*******************************************************************************
  * Function declarations
  ******************************************************************************/
 /*******************************************************************************
@@ -265,6 +275,9 @@
 int plat_set_nv_ctr2(void *cookie, const struct auth_img_desc_s *img_desc,
 		unsigned int nv_ctr);
 int get_mbedtls_heap_helper(void **heap_addr, size_t *heap_size);
+int plat_get_enc_key_info(enum fw_enc_status_t fw_enc_status, uint8_t *key,
+			  size_t *key_len, unsigned int *flags,
+			  const uint8_t *img_id, size_t img_id_len);
 
 /*******************************************************************************
  * Secure Partitions functions
diff --git a/include/services/spm_core_manifest.h b/include/services/spm_core_manifest.h
index 06ecc13..7874882 100644
--- a/include/services/spm_core_manifest.h
+++ b/include/services/spm_core_manifest.h
@@ -21,13 +21,6 @@
 	uint32_t minor_version;
 
 	/*
-	 * Run-Time Exception Level (mandatory):
-	 * - 1: SEL1
-	 * - 2: SEL2
-	 */
-	uint32_t runtime_el;
-
-	/*
 	 * Run-Time Execution state (optional):
 	 * - 0: AArch64 (default)
 	 * - 1: AArch32
diff --git a/include/services/spmd_svc.h b/include/services/spmd_svc.h
index 6e4caf2..a766dcf 100644
--- a/include/services/spmd_svc.h
+++ b/include/services/spmd_svc.h
@@ -11,7 +11,7 @@
 #include <services/spci_svc.h>
 #include <stdint.h>
 
-int32_t spmd_setup(void);
+int spmd_setup(void);
 uint64_t spmd_smc_handler(uint32_t smc_fid,
 			  uint64_t x1,
 			  uint64_t x2,
diff --git a/include/tools_share/firmware_encrypted.h b/include/tools_share/firmware_encrypted.h
new file mode 100644
index 0000000..7ca634f
--- /dev/null
+++ b/include/tools_share/firmware_encrypted.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FIRMWARE_ENCRYPTED_H
+#define FIRMWARE_ENCRYPTED_H
+
+#include <stdint.h>
+
+/* This is used as a signature to validate the encryption header */
+#define ENC_HEADER_MAGIC		0xAA640001U
+
+/* Firmware encryption status flag mask */
+#define FW_ENC_STATUS_FLAG_MASK		0x1
+
+/*
+ * SSK: Secret Symmetric Key
+ * BSSK: Binding Secret Symmetric Key
+ */
+enum fw_enc_status_t {
+	FW_ENC_WITH_SSK = 0,
+	FW_ENC_WITH_BSSK = 1,
+};
+
+#define ENC_MAX_IV_SIZE			16U
+#define ENC_MAX_TAG_SIZE		16U
+#define ENC_MAX_KEY_SIZE		32U
+
+struct fw_enc_hdr {
+	uint32_t magic;
+	uint16_t dec_algo;
+	uint16_t flags;
+	uint16_t iv_len;
+	uint16_t tag_len;
+	uint8_t iv[ENC_MAX_IV_SIZE];
+	uint8_t tag[ENC_MAX_TAG_SIZE];
+};
+
+#endif /* FIRMWARE_ENCRYPTED_H */
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index 9bd25ba..30ad7b7 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,6 +9,11 @@
 #include <assert_macros.S>
 #include <context.h>
 
+#if CTX_INCLUDE_EL2_REGS
+	.global	el2_sysregs_context_save
+	.global	el2_sysregs_context_restore
+#endif
+
 	.global	el1_sysregs_context_save
 	.global	el1_sysregs_context_restore
 #if CTX_INCLUDE_FPREGS
@@ -19,6 +24,385 @@
 	.global	restore_gp_pmcr_pauth_regs
 	.global	el3_exit
 
+#if CTX_INCLUDE_EL2_REGS
+
+/* -----------------------------------------------------
+ * The following function strictly follows the AArch64
+ * PCS to use x9-x17 (temporary caller-saved registers)
+ * to save EL2 system register context. It assumes that
+ * 'x0' is pointing to a 'el2_sys_regs' structure where
+ * the register context will be saved.
+ *
+ * The following registers are not added.
+ * AMEVCNTVOFF0<n>_EL2
+ * AMEVCNTVOFF1<n>_EL2
+ * ICH_AP0R<n>_EL2
+ * ICH_AP1R<n>_EL2
+ * ICH_LR<n>_EL2
+ * -----------------------------------------------------
+ */
+
+func el2_sysregs_context_save
+	mrs	x9, actlr_el2
+	mrs	x10, afsr0_el2
+	stp	x9, x10, [x0, #CTX_ACTLR_EL2]
+
+	mrs	x11, afsr1_el2
+	mrs	x12, amair_el2
+	stp	x11, x12, [x0, #CTX_AFSR1_EL2]
+
+	mrs	x13, cnthctl_el2
+	mrs	x14, cnthp_ctl_el2
+	stp	x13, x14, [x0, #CTX_CNTHCTL_EL2]
+
+	mrs	x15, cnthp_cval_el2
+	mrs	x16, cnthp_tval_el2
+	stp	x15, x16, [x0, #CTX_CNTHP_CVAL_EL2]
+
+	mrs	x17, cntvoff_el2
+	mrs	x9, cptr_el2
+	stp	x17, x9, [x0, #CTX_CNTVOFF_EL2]
+
+	mrs	x10, dbgvcr32_el2
+	mrs	x11, elr_el2
+	stp	x10, x11, [x0, #CTX_DBGVCR32_EL2]
+
+	mrs	x14, esr_el2
+	mrs	x15, far_el2
+	stp	x14, x15, [x0, #CTX_ESR_EL2]
+
+	mrs	x16, fpexc32_el2
+	mrs	x17, hacr_el2
+	stp	x16, x17, [x0, #CTX_FPEXC32_EL2]
+
+	mrs	x9, hcr_el2
+	mrs	x10, hpfar_el2
+	stp	x9, x10, [x0, #CTX_HCR_EL2]
+
+	mrs	x11, hstr_el2
+	mrs	x12, ICC_SRE_EL2
+	stp	x11, x12, [x0, #CTX_HSTR_EL2]
+
+	mrs	x13, ICH_HCR_EL2
+	mrs	x14, ICH_VMCR_EL2
+	stp	x13, x14, [x0, #CTX_ICH_HCR_EL2]
+
+	mrs	x15, mair_el2
+	mrs	x16, mdcr_el2
+	stp	x15, x16, [x0, #CTX_MAIR_EL2]
+
+	mrs	x17, PMSCR_EL2
+	mrs	x9, sctlr_el2
+	stp	x17, x9, [x0, #CTX_PMSCR_EL2]
+
+	mrs	x10, spsr_el2
+	mrs	x11, sp_el2
+	stp	x10, x11, [x0, #CTX_SPSR_EL2]
+
+	mrs	x12, tcr_el2
+	mrs	x13, TRFCR_EL2
+	stp	x12, x13, [x0, #CTX_TCR_EL2]
+
+	mrs	x14, ttbr0_el2
+	mrs	x15, vbar_el2
+	stp	x14, x15, [x0, #CTX_TTBR0_EL2]
+
+	mrs	x16, vmpidr_el2
+	mrs	x17, vpidr_el2
+	stp	x16, x17, [x0, #CTX_VMPIDR_EL2]
+
+	mrs	x9, vtcr_el2
+	mrs	x10, vttbr_el2
+	stp	x9, x10, [x0, #CTX_VTCR_EL2]
+
+#if CTX_INCLUDE_MTE_REGS
+	mrs	x11, TFSR_EL2
+	str	x11, [x0, #CTX_TFSR_EL2]
+#endif
+
+#if ENABLE_MPAM_FOR_LOWER_ELS
+	mrs	x9, MPAM2_EL2
+	mrs	x10, MPAMHCR_EL2
+	stp	x9, x10, [x0, #CTX_MPAM2_EL2]
+
+	mrs	x11, MPAMVPM0_EL2
+	mrs	x12, MPAMVPM1_EL2
+	stp	x11, x12, [x0, #CTX_MPAMVPM0_EL2]
+
+	mrs	x13, MPAMVPM2_EL2
+	mrs	x14, MPAMVPM3_EL2
+	stp	x13, x14, [x0, #CTX_MPAMVPM2_EL2]
+
+	mrs	x15, MPAMVPM4_EL2
+	mrs	x16, MPAMVPM5_EL2
+	stp	x15, x16, [x0, #CTX_MPAMVPM4_EL2]
+
+	mrs	x17, MPAMVPM6_EL2
+	mrs	x9, MPAMVPM7_EL2
+	stp	x17, x9, [x0, #CTX_MPAMVPM6_EL2]
+
+	mrs	x10, MPAMVPMV_EL2
+	str	x10, [x0, #CTX_MPAMVPMV_EL2]
+#endif
+
+
+#if ARM_ARCH_AT_LEAST(8, 6)
+	mrs	x11, HAFGRTR_EL2
+	mrs	x12, HDFGRTR_EL2
+	stp	x11, x12, [x0, #CTX_HAFGRTR_EL2]
+
+	mrs	x13, HDFGWTR_EL2
+	mrs	x14, HFGITR_EL2
+	stp	x13, x14, [x0, #CTX_HDFGWTR_EL2]
+
+	mrs	x15, HFGRTR_EL2
+	mrs	x16, HFGWTR_EL2
+	stp	x15, x16, [x0, #CTX_HFGRTR_EL2]
+
+	mrs	x17, CNTPOFF_EL2
+	str	x17, [x0, #CTX_CNTPOFF_EL2]
+#endif
+
+#if ARM_ARCH_AT_LEAST(8, 4)
+	mrs	x9, cnthps_ctl_el2
+	mrs	x10, cnthps_cval_el2
+	stp	x9, x10, [x0, #CTX_CNTHPS_CTL_EL2]
+
+	mrs	x11, cnthps_tval_el2
+	mrs	x12, cnthvs_ctl_el2
+	stp	x11, x12, [x0, #CTX_CNTHPS_TVAL_EL2]
+
+	mrs	x13, cnthvs_cval_el2
+	mrs	x14, cnthvs_tval_el2
+	stp	x13, x14, [x0, #CTX_CNTHVS_CVAL_EL2]
+
+	mrs	x15, cnthv_ctl_el2
+	mrs	x16, cnthv_cval_el2
+	stp	x15, x16, [x0, #CTX_CNTHV_CTL_EL2]
+
+	mrs	x17, cnthv_tval_el2
+	mrs	x9, contextidr_el2
+	stp	x17, x9, [x0, #CTX_CNTHV_TVAL_EL2]
+
+	mrs	x10, sder32_el2
+	str	x10, [x0, #CTX_SDER32_EL2]
+
+	mrs	x11, ttbr1_el2
+	str	x11, [x0, #CTX_TTBR1_EL2]
+
+	mrs	x12, vdisr_el2
+	str	x12, [x0, #CTX_VDISR_EL2]
+
+	mrs	x13, vncr_el2
+	str	x13, [x0, #CTX_VNCR_EL2]
+
+	mrs	x14, vsesr_el2
+	str	x14, [x0, #CTX_VSESR_EL2]
+
+	mrs	x15, vstcr_el2
+	str	x15, [x0, #CTX_VSTCR_EL2]
+
+	mrs	x16, vsttbr_el2
+	str	x16, [x0, #CTX_VSTTBR_EL2]
+#endif
+
+#if ARM_ARCH_AT_LEAST(8, 5)
+	mrs	x17, scxtnum_el2
+	str	x17, [x0, #CTX_SCXTNUM_EL2]
+#endif
+
+	ret
+endfunc el2_sysregs_context_save
+
+/* -----------------------------------------------------
+ * The following function strictly follows the AArch64
+ * PCS to use x9-x17 (temporary caller-saved registers)
+ * to restore EL2 system register context.  It assumes
+ * that 'x0' is pointing to a 'el2_sys_regs' structure
+ * from where the register context will be restored
+
+ * The following registers are not restored
+ * AMEVCNTVOFF0<n>_EL2
+ * AMEVCNTVOFF1<n>_EL2
+ * ICH_AP0R<n>_EL2
+ * ICH_AP1R<n>_EL2
+ * ICH_LR<n>_EL2
+ * -----------------------------------------------------
+ */
+func el2_sysregs_context_restore
+
+	ldp	x9, x10, [x0, #CTX_ACTLR_EL2]
+	msr	actlr_el2, x9
+	msr	afsr0_el2, x10
+
+	ldp	x11, x12, [x0, #CTX_AFSR1_EL2]
+	msr	afsr1_el2, x11
+	msr	amair_el2, x12
+
+	ldp	x13, x14, [x0, #CTX_CNTHCTL_EL2]
+	msr	cnthctl_el2, x13
+	msr	cnthp_ctl_el2, x14
+
+	ldp	x15, x16, [x0, #CTX_CNTHP_CVAL_EL2]
+	msr	cnthp_cval_el2, x15
+	msr	cnthp_tval_el2, x16
+
+	ldp	x17, x9, [x0, #CTX_CNTVOFF_EL2]
+	msr	cntvoff_el2, x17
+	msr	cptr_el2, x9
+
+	ldp	x10, x11, [x0, #CTX_DBGVCR32_EL2]
+	msr	dbgvcr32_el2, x10
+	msr	elr_el2, x11
+
+	ldp	x14, x15, [x0, #CTX_ESR_EL2]
+	msr	esr_el2, x14
+	msr	far_el2, x15
+
+	ldp	x16, x17, [x0, #CTX_FPEXC32_EL2]
+	msr	fpexc32_el2, x16
+	msr	hacr_el2, x17
+
+	ldp	x9, x10, [x0, #CTX_HCR_EL2]
+	msr	hcr_el2, x9
+	msr	hpfar_el2, x10
+
+	ldp	x11, x12, [x0, #CTX_HSTR_EL2]
+	msr	hstr_el2, x11
+	msr	ICC_SRE_EL2, x12
+
+	ldp	x13, x14, [x0, #CTX_ICH_HCR_EL2]
+	msr	ICH_HCR_EL2, x13
+	msr	ICH_VMCR_EL2, x14
+
+	ldp	x15, x16, [x0, #CTX_MAIR_EL2]
+	msr	mair_el2, x15
+	msr	mdcr_el2, x16
+
+	ldp	x17, x9, [x0, #CTX_PMSCR_EL2]
+	msr	PMSCR_EL2, x17
+	msr	sctlr_el2, x9
+
+	ldp	x10, x11, [x0, #CTX_SPSR_EL2]
+	msr	spsr_el2, x10
+	msr	sp_el2, x11
+
+	ldp	x12, x13, [x0, #CTX_TCR_EL2]
+	msr	tcr_el2, x12
+	msr	TRFCR_EL2, x13
+
+	ldp	x14, x15, [x0, #CTX_TTBR0_EL2]
+	msr	ttbr0_el2, x14
+	msr	vbar_el2, x15
+
+	ldp	x16, x17, [x0, #CTX_VMPIDR_EL2]
+	msr	vmpidr_el2, x16
+	msr	vpidr_el2, x17
+
+	ldp	x9, x10, [x0, #CTX_VTCR_EL2]
+	msr	vtcr_el2, x9
+	msr	vttbr_el2, x10
+
+#if CTX_INCLUDE_MTE_REGS
+	ldr	x11, [x0, #CTX_TFSR_EL2]
+	msr	TFSR_EL2, x11
+#endif
+
+#if ENABLE_MPAM_FOR_LOWER_ELS
+	ldp	x9, x10, [x0, #CTX_MPAM2_EL2]
+	msr	MPAM2_EL2, x9
+	msr	MPAMHCR_EL2, x10
+
+	ldp	x11, x12, [x0, #CTX_MPAMVPM0_EL2]
+	msr	MPAMVPM0_EL2, x11
+	msr	MPAMVPM1_EL2, x12
+
+	ldp	x13, x14, [x0, #CTX_MPAMVPM2_EL2]
+	msr	MPAMVPM2_EL2, x13
+	msr	MPAMVPM3_EL2, x14
+
+	ldp	x15, x16, [x0, #CTX_MPAMVPM4_EL2]
+	msr	MPAMVPM4_EL2, x15
+	msr	MPAMVPM5_EL2, x16
+
+	ldp	x17, x9, [x0, #CTX_MPAMVPM6_EL2]
+	msr	MPAMVPM6_EL2, x17
+	msr	MPAMVPM7_EL2, x9
+
+	ldr	x10, [x0, #CTX_MPAMVPMV_EL2]
+	msr	MPAMVPMV_EL2, x10
+#endif
+
+#if ARM_ARCH_AT_LEAST(8, 6)
+	ldp	x11, x12, [x0, #CTX_HAFGRTR_EL2]
+	msr	HAFGRTR_EL2, x11
+	msr	HDFGRTR_EL2, x12
+
+	ldp	x13, x14, [x0, #CTX_HDFGWTR_EL2]
+	msr	HDFGWTR_EL2, x13
+	msr	HFGITR_EL2, x14
+
+	ldp	x15, x16, [x0, #CTX_HFGRTR_EL2]
+	msr	HFGRTR_EL2, x15
+	msr	HFGWTR_EL2, x16
+
+	ldr	x17, [x0, #CTX_CNTPOFF_EL2]
+	msr	CNTPOFF_EL2, x17
+#endif
+
+#if ARM_ARCH_AT_LEAST(8, 4)
+	ldp	x9, x10, [x0, #CTX_CNTHPS_CTL_EL2]
+	msr	cnthps_ctl_el2, x9
+	msr	cnthps_cval_el2, x10
+
+	ldp	x11, x12, [x0, #CTX_CNTHPS_TVAL_EL2]
+	msr	cnthps_tval_el2, x11
+	msr	cnthvs_ctl_el2, x12
+
+	ldp	x13, x14, [x0, #CTX_CNTHVS_CVAL_EL2]
+	msr	cnthvs_cval_el2, x13
+	msr	cnthvs_tval_el2, x14
+
+	ldp	x15, x16, [x0, #CTX_CNTHV_CTL_EL2]
+	msr	cnthv_ctl_el2, x15
+	msr	cnthv_cval_el2, x16
+
+	ldp	x17, x9, [x0, #CTX_CNTHV_TVAL_EL2]
+	msr	cnthv_tval_el2, x17
+	msr	contextidr_el2, x9
+
+	ldr	x10, [x0, #CTX_SDER32_EL2]
+	msr	sder32_el2, x10
+
+	ldr	x11, [x0, #CTX_TTBR1_EL2]
+	msr	ttbr1_el2, x11
+
+	ldr	x12, [x0, #CTX_VDISR_EL2]
+	msr	vdisr_el2, x12
+
+	ldr	x13, [x0, #CTX_VNCR_EL2]
+	msr	vncr_el2, x13
+
+	ldr	x14, [x0, #CTX_VSESR_EL2]
+	msr	vsesr_el2, x14
+
+	ldr	x15, [x0, #CTX_VSTCR_EL2]
+	msr	vstcr_el2, x15
+
+	ldr	x16, [x0, #CTX_VSTTBR_EL2]
+	msr	vsttbr_el2, x16
+#endif
+
+#if ARM_ARCH_AT_LEAST(8, 5)
+	ldr	x17, [x0, #CTX_SCXTNUM_EL2]
+	msr	scxtnum_el2, x17
+#endif
+
+	ret
+endfunc el2_sysregs_context_restore
+
+#endif /* CTX_INCLUDE_EL2_REGS */
+
 /* ------------------------------------------------------------------
  * The following function strictly follows the AArch64 PCS to use
  * x9-x17 (temporary caller-saved registers) to save EL1 system
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 546e39e..0314a85 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -234,7 +234,7 @@
 	 * and other EL2 registers are set up by cm_prepare_ns_entry() as they
 	 * are not part of the stored cpu_context.
 	 */
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_elx);
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_elx);
 
 	/*
 	 * Base the context ACTLR_EL1 on the current value, as it is
@@ -244,7 +244,7 @@
 	 * be zero.
 	 */
 	actlr_elx = read_actlr_el1();
-	write_ctx_reg((get_sysregs_ctx(ctx)), (CTX_ACTLR_EL1), (actlr_elx));
+	write_ctx_reg((get_el1_sysregs_ctx(ctx)), (CTX_ACTLR_EL1), (actlr_elx));
 
 	/*
 	 * Populate EL3 state so that we've the right context
@@ -336,7 +336,7 @@
 						 CTX_SCR_EL3);
 		if ((scr_el3 & SCR_HCE_BIT) != 0U) {
 			/* Use SCTLR_EL1.EE value to initialise sctlr_el2 */
-			sctlr_elx = read_ctx_reg(get_sysregs_ctx(ctx),
+			sctlr_elx = read_ctx_reg(get_el1_sysregs_ctx(ctx),
 							   CTX_SCTLR_EL1);
 			sctlr_elx &= SCTLR_EE_BIT;
 			sctlr_elx |= SCTLR_EL2_RES1;
@@ -530,6 +530,52 @@
 	cm_set_next_eret_context(security_state);
 }
 
+#if CTX_INCLUDE_EL2_REGS
+/*******************************************************************************
+ * Save EL2 sysreg context
+ ******************************************************************************/
+void cm_el2_sysregs_context_save(uint32_t security_state)
+{
+	u_register_t scr_el3 = read_scr();
+
+	/*
+	 * Always save the non-secure EL2 context, only save the
+	 * S-EL2 context if S-EL2 is enabled.
+	 */
+	if ((security_state == NON_SECURE) ||
+	    ((scr_el3 & SCR_EEL2_BIT) != 0U)) {
+		cpu_context_t *ctx;
+
+		ctx = cm_get_context(security_state);
+		assert(ctx != NULL);
+
+		el2_sysregs_context_save(get_el2_sysregs_ctx(ctx));
+	}
+}
+
+/*******************************************************************************
+ * Restore EL2 sysreg context
+ ******************************************************************************/
+void cm_el2_sysregs_context_restore(uint32_t security_state)
+{
+	u_register_t scr_el3 = read_scr();
+
+	/*
+	 * Always restore the non-secure EL2 context, only restore the
+	 * S-EL2 context if S-EL2 is enabled.
+	 */
+	if ((security_state == NON_SECURE) ||
+	    ((scr_el3 & SCR_EEL2_BIT) != 0U)) {
+		cpu_context_t *ctx;
+
+		ctx = cm_get_context(security_state);
+		assert(ctx != NULL);
+
+		el2_sysregs_context_restore(get_el2_sysregs_ctx(ctx));
+	}
+}
+#endif /* CTX_INCLUDE_EL2_REGS */
+
 /*******************************************************************************
  * The next four functions are used by runtime services to save and restore
  * EL1 context on the 'cpu_context' structure for the specified security
@@ -542,7 +588,7 @@
 	ctx = cm_get_context(security_state);
 	assert(ctx != NULL);
 
-	el1_sysregs_context_save(get_sysregs_ctx(ctx));
+	el1_sysregs_context_save(get_el1_sysregs_ctx(ctx));
 
 #if IMAGE_BL31
 	if (security_state == SECURE)
@@ -559,7 +605,7 @@
 	ctx = cm_get_context(security_state);
 	assert(ctx != NULL);
 
-	el1_sysregs_context_restore(get_sysregs_ctx(ctx));
+	el1_sysregs_context_restore(get_el1_sysregs_ctx(ctx));
 
 #if IMAGE_BL31
 	if (security_state == SECURE)
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
index 032e42c..20a36fe 100644
--- a/make_helpers/build_macros.mk
+++ b/make_helpers/build_macros.mk
@@ -109,6 +109,22 @@
     ${BUILD_PLAT}/bl$(1).bin
 endef
 
+# IMG_ENC_BIN defines the default encrypted image file corresponding to a
+# BL stage
+#   $(1) = BL stage (2, 30, 31, 32, 33)
+define IMG_ENC_BIN
+    ${BUILD_PLAT}/bl$(1)_enc.bin
+endef
+
+# ENCRYPT_FW invokes enctool to encrypt firmware binary
+#   $(1) = input firmware binary
+#   $(2) = output encrypted firmware binary
+define ENCRYPT_FW
+$(2): $(1) enctool
+	$$(ECHO) "  ENC     $$<"
+	$$(Q)$$(ENCTOOL) $$(ENC_ARGS) -i $$< -o $$@
+endef
+
 # TOOL_ADD_PAYLOAD appends the command line arguments required by fiptool to
 # package a new payload and/or by cert_create to generate certificate.
 # Optionally, it adds the dependency on this payload
@@ -116,11 +132,17 @@
 #   $(2) = command line option for the specified payload (i.e. --soc-fw)
 #   $(3) = tool target dependency (optional) (ex. build/fvp/release/bl31.bin)
 #   $(4) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip)
+#   $(5) = encrypted payload (optional) (ex. build/fvp/release/bl31_enc.bin)
 define TOOL_ADD_PAYLOAD
+ifneq ($(5),)
+    $(4)FIP_ARGS += $(2) $(5)
+    $(if $(3),$(4)CRT_DEPS += $(1))
+else
     $(4)FIP_ARGS += $(2) $(1)
+    $(if $(3),$(4)CRT_DEPS += $(3))
+endif
     $(if $(3),$(4)FIP_DEPS += $(3))
     $(4)CRT_ARGS += $(2) $(1)
-    $(if $(3),$(4)CRT_DEPS += $(3))
 endef
 
 # TOOL_ADD_IMG_PAYLOAD works like TOOL_ADD_PAYLOAD, but applies image filters
@@ -130,6 +152,7 @@
 #   $(3) = command line option for the specified payload (ex. --soc-fw)
 #   $(4) = tool target dependency (optional) (ex. build/fvp/release/bl31.bin)
 #   $(5) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip)
+#   $(6) = encrypted payload (optional) (ex. build/fvp/release/bl31_enc.bin)
 
 define TOOL_ADD_IMG_PAYLOAD
 
@@ -143,10 +166,10 @@
 
 $(PROCESSED_PATH): $(4)
 
-$(call TOOL_ADD_PAYLOAD,$(PROCESSED_PATH),$(3),$(PROCESSED_PATH),$(5))
+$(call TOOL_ADD_PAYLOAD,$(PROCESSED_PATH),$(3),$(PROCESSED_PATH),$(5),$(6))
 
 else
-$(call TOOL_ADD_PAYLOAD,$(2),$(3),$(4),$(5))
+$(call TOOL_ADD_PAYLOAD,$(2),$(3),$(4),$(5),$(6))
 endif
 endef
 
@@ -164,6 +187,7 @@
 #   $(1) = image_type (scp_bl2, bl33, etc.)
 #   $(2) = command line option for fiptool (--scp-fw, --nt-fw, etc)
 #   $(3) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip)
+#   $(4) = Image encryption flag (optional) (0, 1)
 # Example:
 #   $(eval $(call TOOL_ADD_IMG,bl33,--nt-fw))
 define TOOL_ADD_IMG
@@ -173,7 +197,14 @@
 
     $(3)CRT_DEPS += check_$(1)
     $(3)FIP_DEPS += check_$(1)
+ifeq ($(4),1)
+    $(eval ENC_BIN := ${BUILD_PLAT}/$(1)_enc.bin)
+    $(call ENCRYPT_FW,$(value $(_V)),$(ENC_BIN))
+    $(call TOOL_ADD_IMG_PAYLOAD,$(1),$(value $(_V)),$(2),$(ENC_BIN),$(3), \
+		$(ENC_BIN))
+else
     $(call TOOL_ADD_IMG_PAYLOAD,$(1),$(value $(_V)),$(2),,$(3))
+endif
 
 .PHONY: check_$(1)
 check_$(1):
@@ -390,6 +421,7 @@
 #   $(1) = BL stage (1, 2, 2u, 31, 32)
 #   $(2) = FIP command line option (if empty, image will not be included in the FIP)
 #   $(3) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip)
+#   $(4) = BL encryption flag (optional) (0, 1)
 define MAKE_BL
         $(eval BUILD_DIR  := ${BUILD_PLAT}/bl$(1))
         $(eval BL_SOURCES := $(BL$(call uppercase,$(1))_SOURCES))
@@ -400,6 +432,7 @@
         $(eval ELF        := $(call IMG_ELF,$(1)))
         $(eval DUMP       := $(call IMG_DUMP,$(1)))
         $(eval BIN        := $(call IMG_BIN,$(1)))
+        $(eval ENC_BIN    := $(call IMG_ENC_BIN,$(1)))
         $(eval BL_LINKERFILE := $(BL$(call uppercase,$(1))_LINKERFILE))
         $(eval BL_LIBS    := $(BL$(call uppercase,$(1))_LIBS))
         # We use sort only to get a list of unique object directory names.
@@ -480,7 +513,13 @@
 
 all: bl$(1)
 
+ifeq ($(4),1)
+$(call ENCRYPT_FW,$(BIN),$(ENC_BIN))
+$(if $(2),$(call TOOL_ADD_IMG_PAYLOAD,bl$(1),$(BIN),--$(2),$(ENC_BIN),$(3), \
+		$(ENC_BIN)))
+else
 $(if $(2),$(call TOOL_ADD_IMG_PAYLOAD,bl$(1),$(BIN),--$(2),$(BIN),$(3)))
+endif
 
 endef
 
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 60958a1..03322db 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -65,6 +65,9 @@
 # Debug build
 DEBUG				:= 0
 
+# By default disable authenticated decryption support.
+DECRYPTION_SUPPORT		:= none
+
 # Build platform
 DEFAULT_PLAT			:= fvp
 
@@ -106,6 +109,18 @@
 # Use BRANCH_PROTECTION to enable PAUTH.
 ENABLE_PAUTH			:= 0
 
+# By default BL31 encryption disabled
+ENCRYPT_BL31			:= 0
+
+# By default BL32 encryption disabled
+ENCRYPT_BL32			:= 0
+
+# Default dummy firmware encryption key
+ENC_KEY	:= 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
+
+# Default dummy nonce for firmware encryption
+ENC_NONCE			:= 1234567890abcdef12345678
+
 # Build flag to treat usage of deprecated platform and framework APIs as error.
 ERROR_DEPRECATED		:= 0
 
@@ -121,6 +136,9 @@
 # Default FWU_FIP file name
 FWU_FIP_NAME			:= fwu_fip.bin
 
+# By default firmware encryption with SSK
+FW_ENC_STATUS			:= 0
+
 # For Chain of Trust
 GENERATE_COT			:= 0
 
@@ -188,6 +206,9 @@
 # Enable the Management Mode (MM)-based Secure Partition Manager implementation
 SPM_MM				:= 0
 
+# Use SPM at S-EL2 as a default config for SPMD
+SPMD_SPM_AT_SEL2		:= 1
+
 # Flag to introduce an infinite loop in BL1 just before it exits into the next
 # image. This is meant to help debugging the post-BL2 phase.
 SPIN_ON_BL1_EXIT		:= 0
@@ -262,3 +283,8 @@
 
 # Enable Link Time Optimization
 ENABLE_LTO			:= 0
+
+# Build flag to include EL2 registers in cpu context save and restore during
+# S-EL2 firmware entry/exit. This flag is to be used with SPD=spmd option.
+# Default is 0.
+CTX_INCLUDE_EL2_REGS		:= 0
diff --git a/plat/arm/board/fvp/fdts/fvp_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_fw_config.dts
index d0f6033..9a4a057 100644
--- a/plat/arm/board/fvp/fdts/fvp_fw_config.dts
+++ b/plat/arm/board/fvp/fdts/fvp_fw_config.dts
@@ -69,6 +69,12 @@
 		mbedtls_heap_size = <0x0>;
 	};
 
+	/*
+	 * Though TF-A is UUID RFC 4122 compliant meaning fields are stored in
+	 * network order (big endian), UUID's mentioned in this file are are
+	 * stored in machine order (little endian).
+	 * This will be fixed in future.
+	 */
 	arm-io_policies {
 		fip-handles {
 			compatible = "arm,io-fip-handle";
@@ -93,4 +99,17 @@
 			nt_fw_content_cert_uuid = <0xf3c1c48e 0x11e4635d 0xee87a9a7 0xa73fb240>;
 		};
 	};
+
+	secure-partitions {
+		compatible = "arm,sp";
+		cactus {
+			uuid = <0x1e67b5b4 0xe14f904a 0x13fb1fb8 0xcbdae1da>;
+			load-address = <0x7000000>;
+		};
+
+		ivy {
+			uuid = <0x092358d1 0xb94723f0 0x64447c82 0xc88f57f5>;
+			load-address = <0x7100000>;
+		};
+	};
 };
diff --git a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
index e1c106f..c94a209 100644
--- a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
+++ b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
@@ -11,7 +11,6 @@
 	attribute {
 		maj_ver = <0x0>;
 		min_ver = <0x9>;
-		runtime_el = <0x1>;
 		exec_state = <0x0>;
 		load_address = <0x0 0x6000000>;
 		entrypoint = <0x0 0x6000000>;
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index dd39208..136e65a 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -205,6 +205,13 @@
  ******************************************************************************/
 int arm_bl2_plat_handle_post_image_load(unsigned int image_id)
 {
+#if defined(SPD_spmd)
+	/* For Secure Partitions we don't need post processing */
+	if ((image_id >= (MAX_NUMBER_IDS - MAX_SP_IDS)) &&
+		(image_id < MAX_NUMBER_IDS)) {
+		return 0;
+	}
+#endif
 	return arm_bl2_handle_post_image_load(image_id);
 }
 
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 17058d1..4fb85fb 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -182,6 +182,9 @@
 else
 ARM_IO_SOURCES		+=	plat/arm/common/arm_fconf_io_storage.c		\
 				plat/arm/common/fconf/arm_fconf_io.c
+ifeq (${SPD},spmd)
+ARM_IO_SOURCES		+=	plat/arm/common/fconf/arm_fconf_sp.c
+endif
 endif
 
 BL1_SOURCES		+=	drivers/io/io_fip.c				\
diff --git a/plat/arm/common/arm_image_load.c b/plat/arm/common/arm_image_load.c
index 2faaa76..593199d 100644
--- a/plat/arm/common/arm_image_load.c
+++ b/plat/arm/common/arm_image_load.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,6 +7,9 @@
 #include <assert.h>
 #include <common/bl_common.h>
 #include <common/desc_image_load.h>
+#if defined(SPD_spmd)
+#include <plat/arm/common/fconf_arm_sp_getter.h>
+#endif
 #include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
 
@@ -29,12 +32,62 @@
 		next_bl_params_cpy_ptr);
 }
 
+#if defined(SPD_spmd)
+/*******************************************************************************
+ * This function appends Secure Partitions to list of loadable images.
+ ******************************************************************************/
+void plat_add_sp_images_load_info(struct bl_load_info *load_info)
+{
+	bl_load_info_node_t *node_info = load_info->head;
+	unsigned int index = 0;
+
+	if (sp_mem_params_descs[index].image_id == 0) {
+		ERROR("No Secure Partition Image available\n");
+		return;
+	}
+
+	/* Traverse through the bl images list */
+	do {
+		node_info = node_info->next_load_info;
+	} while (node_info->next_load_info != NULL);
+
+	for (; index < MAX_SP_IDS; index++) {
+		/* Populate the image information */
+		node_info->image_id = sp_mem_params_descs[index].image_id;
+		node_info->image_info = &sp_mem_params_descs[index].image_info;
+
+		if ((index + 1U) == MAX_SP_IDS) {
+			INFO("Reached Max number of SPs\n");
+			return;
+		}
+
+		if (sp_mem_params_descs[index + 1U].image_id == 0) {
+			return;
+		}
+
+		node_info->next_load_info =
+			&sp_mem_params_descs[index + 1U].load_node_mem;
+		node_info = node_info->next_load_info;
+
+	}
+}
+#endif
+
 /*******************************************************************************
  * This function returns the list of loadable images.
  ******************************************************************************/
 struct bl_load_info *plat_get_bl_image_load_info(void)
 {
+#if defined(SPD_spmd)
+	bl_load_info_t *bl_load_info;
+
+	bl_load_info = get_bl_load_info_from_mem_params_desc();
+	plat_add_sp_images_load_info(bl_load_info);
+
+	return bl_load_info;
+#else
 	return get_bl_load_info_from_mem_params_desc();
+#endif
 }
 
 /*******************************************************************************
diff --git a/plat/arm/common/fconf/arm_fconf_sp.c b/plat/arm/common/fconf/arm_fconf_sp.c
new file mode 100644
index 0000000..bb88aff
--- /dev/null
+++ b/plat/arm/common/fconf/arm_fconf_sp.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/desc_image_load.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/io/io_storage.h>
+#include <lib/object_pool.h>
+#include <libfdt.h>
+#include <plat/arm/common/arm_fconf_getter.h>
+#include <plat/arm/common/arm_fconf_io_storage.h>
+#include <plat/arm/common/fconf_arm_sp_getter.h>
+#include <platform_def.h>
+#include <tools_share/firmware_image_package.h>
+
+#ifdef IMAGE_BL2
+
+bl_mem_params_node_t sp_mem_params_descs[MAX_SP_IDS];
+
+struct arm_sp_t arm_sp;
+
+int fconf_populate_arm_sp(uintptr_t config)
+{
+	int sp_node, node, err;
+	union uuid_helper_t uuid_helper;
+	unsigned int index = 0;
+	const unsigned int sp_start_index = MAX_NUMBER_IDS - MAX_SP_IDS;
+
+	/* As libfdt use void *, we can't avoid this cast */
+	const void *dtb = (void *)config;
+
+	/* Assert the node offset point to "arm,sp" compatible property */
+	const char *compatible_str = "arm,sp";
+
+	node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+	if (node < 0) {
+		ERROR("FCONF: Can't find %s in dtb\n", compatible_str);
+		return node;
+	}
+
+	fdt_for_each_subnode(sp_node, dtb, node) {
+		err = fdtw_read_array(dtb, sp_node, "uuid", 4,
+				      &uuid_helper.word);
+		if (err < 0) {
+			ERROR("FCONF: cannot read SP uuid\n");
+			return -1;
+		}
+
+		arm_sp.uuids[index] = uuid_helper;
+
+		err = fdtw_read_cells(dtb, sp_node, "load-address", 1,
+			&arm_sp.load_addr[index]);
+		if (err < 0) {
+			ERROR("FCONF: cannot read SP load address\n");
+			return -1;
+		}
+
+		VERBOSE("FCONF: %s UUID %x-%x-%x-%x load_addr=%lx\n",
+			__func__,
+			uuid_helper.word[0],
+			uuid_helper.word[1],
+			uuid_helper.word[2],
+			uuid_helper.word[3],
+			arm_sp.load_addr[index]);
+
+		/* Add SP information in mem param descriptor */
+		sp_mem_params_descs[index].image_id = sp_start_index + index;
+		SET_PARAM_HEAD(&sp_mem_params_descs[index].image_info,
+					PARAM_IMAGE_BINARY, VERSION_2, 0);
+		sp_mem_params_descs[index].image_info.image_max_size =
+							ARM_SP_MAX_SIZE;
+		sp_mem_params_descs[index].next_handoff_image_id =
+							INVALID_IMAGE_ID;
+		sp_mem_params_descs[index].image_info.image_base =
+							arm_sp.load_addr[index];
+
+		/* Add SP information in IO policies structure */
+		policies[sp_start_index + index].image_spec =
+						(uintptr_t)&arm_sp.uuids[index];
+		policies[sp_start_index + index].dev_handle = &fip_dev_handle;
+		policies[sp_start_index + index].check = open_fip;
+
+		index++;
+
+		if (index >= MAX_SP_IDS) {
+			ERROR("FCONF: reached max number of SPs\n");
+			return -1;
+		}
+	}
+
+	if ((sp_node < 0) && (sp_node != -FDT_ERR_NOTFOUND)) {
+		ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node);
+		return sp_node;
+	}
+
+	arm_sp.number_of_sp = index;
+	return 0;
+}
+
+FCONF_REGISTER_POPULATOR(arm_sp, fconf_populate_arm_sp);
+
+#endif /* IMAGE_BL2 */
diff --git a/plat/common/plat_bl_common.c b/plat/common/plat_bl_common.c
index 6070db2..de6c1d1 100644
--- a/plat/common/plat_bl_common.c
+++ b/plat/common/plat_bl_common.c
@@ -11,6 +11,7 @@
 #include <common/debug.h>
 #include <lib/xlat_tables/xlat_tables_compat.h>
 #include <plat/common/platform.h>
+#include <tools_share/firmware_encrypted.h>
 
 /*
  * The following platform functions are weakly defined. The Platforms
@@ -22,6 +23,7 @@
 #pragma weak bl2_plat_handle_pre_image_load
 #pragma weak bl2_plat_handle_post_image_load
 #pragma weak plat_try_next_boot_source
+#pragma weak plat_get_enc_key_info
 
 void bl2_el3_plat_prepare_exit(void)
 {
@@ -53,6 +55,31 @@
 }
 
 /*
+ * Weak implementation to provide dummy decryption key only for test purposes,
+ * platforms must override this API for any real world firmware encryption
+ * use-case.
+ */
+int plat_get_enc_key_info(enum fw_enc_status_t fw_enc_status, uint8_t *key,
+			  size_t *key_len, unsigned int *flags,
+			  const uint8_t *img_id, size_t img_id_len)
+{
+#define DUMMY_FIP_ENC_KEY { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, \
+			    0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, \
+			    0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, \
+			    0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef }
+
+	const uint8_t dummy_key[] = DUMMY_FIP_ENC_KEY;
+
+	assert(*key_len >= sizeof(dummy_key));
+
+	*key_len = sizeof(dummy_key);
+	memcpy(key, dummy_key, *key_len);
+	*flags = 0;
+
+	return 0;
+}
+
+/*
  * Set up the page tables for the generic and platform-specific memory regions.
  * The size of the Trusted SRAM seen by the BL image must be specified as well
  * as an array specifying the generic memory regions which can be;
diff --git a/plat/common/plat_spmd_manifest.c b/plat/common/plat_spmd_manifest.c
index 4c78979..9c3dc71 100644
--- a/plat/common/plat_spmd_manifest.c
+++ b/plat/common/plat_spmd_manifest.c
@@ -37,12 +37,6 @@
 		return -ENOENT;
 	}
 
-	rc = fdtw_read_cells(fdt, node, "runtime_el", 1, &attr->runtime_el);
-	if (rc) {
-		ERROR("Missing SPM core runtime EL in manifest.\n");
-		return -ENOENT;
-	}
-
 	rc = fdtw_read_cells(fdt, node, "exec_state", 1, &attr->exec_state);
 	if (rc)
 		NOTICE("Execution state not specified in SPM core manifest.\n");
@@ -61,7 +55,6 @@
 
 	VERBOSE("SPM core manifest attribute section:\n");
 	VERBOSE("  version: %x.%x\n", attr->major_version, attr->minor_version);
-	VERBOSE("  runtime_el: 0x%x\n", attr->runtime_el);
 	VERBOSE("  binary_size: 0x%x\n", attr->binary_size);
 	VERBOSE("  load_address: 0x%llx\n", attr->load_address);
 	VERBOSE("  entrypoint: 0x%llx\n", attr->entrypoint);
diff --git a/plat/imx/common/aarch32/imx_uart_console.S b/plat/imx/common/aarch32/imx_uart_console.S
index 1c729b1..1a1229a 100644
--- a/plat/imx/common/aarch32/imx_uart_console.S
+++ b/plat/imx/common/aarch32/imx_uart_console.S
@@ -20,7 +20,7 @@
 	mov	r4, r3
 	cmp	r4, #0
 	beq	register_fail
-	str	r0, [r4, #CONSOLE_T_DRVDATA]
+	str	r0, [r4, #CONSOLE_T_BASE]
 
 	bl	console_imx_uart_core_init
 	cmp	r0, #0
@@ -35,16 +35,16 @@
 endfunc console_imx_uart_register
 
 func console_imx_uart_putc
-	ldr	r1, [r1, #CONSOLE_T_DRVDATA]
+	ldr	r1, [r1, #CONSOLE_T_BASE]
 	b console_imx_uart_core_putc
 endfunc console_imx_uart_putc
 
 func console_imx_uart_getc
-	ldr	r0, [r0, #CONSOLE_T_DRVDATA]
+	ldr	r0, [r0, #CONSOLE_T_BASE]
 	b console_imx_uart_core_getc
 endfunc console_imx_uart_getc
 
 func console_imx_uart_flush
-	ldr	r0, [r0, #CONSOLE_T_DRVDATA]
+	ldr	r0, [r0, #CONSOLE_T_BASE]
 	b console_imx_uart_core_flush
 endfunc console_imx_uart_flush
diff --git a/plat/imx/common/imx_uart_console.S b/plat/imx/common/imx_uart_console.S
index 3bdeea2..0cb4fb8 100644
--- a/plat/imx/common/imx_uart_console.S
+++ b/plat/imx/common/imx_uart_console.S
@@ -25,7 +25,7 @@
 	mov	x7, x30
 	mov	x6, x3
 	cbz	x6, register_fail
-	str	x0, [x6, #CONSOLE_T_DRVDATA]
+	str	x0, [x6, #CONSOLE_T_BASE]
 
 	bl	console_imx_uart_init
 	cbz	x0, register_fail
@@ -44,7 +44,7 @@
 endfunc console_imx_uart_init
 
 func console_imx_uart_putc
-	ldr	x1, [x1, #CONSOLE_T_DRVDATA]
+	ldr	x1, [x1, #CONSOLE_T_BASE]
 	cbz	x1, putc_error
 
 	/* Prepare '\r' to '\n' */
@@ -68,7 +68,7 @@
 endfunc console_imx_uart_putc
 
 func console_imx_uart_getc
-	ldr	x0, [x0, #CONSOLE_T_DRVDATA]
+	ldr	x0, [x0, #CONSOLE_T_BASE]
 	cbz	x0, getc_error
 1:
 	ldr	w1, [x0, #UTS]
diff --git a/plat/imx/common/lpuart_console.S b/plat/imx/common/lpuart_console.S
index d8dac2c..98b3588 100644
--- a/plat/imx/common/lpuart_console.S
+++ b/plat/imx/common/lpuart_console.S
@@ -20,7 +20,7 @@
 	mov	x7, x30
 	mov	x6, x3
 	cbz	x6, register_fail
-	str	x0, [x6, #CONSOLE_T_DRVDATA]
+	str	x0, [x6, #CONSOLE_T_BASE]
 
 	bl	console_lpuart_init
 	cbz	x0, register_fail
@@ -39,7 +39,7 @@
 endfunc console_lpuart_init
 
 func console_lpuart_putc
-	ldr	x1, [x1, #CONSOLE_T_DRVDATA]
+	ldr	x1, [x1, #CONSOLE_T_BASE]
 	cbz	x1, putc_error
 	/* Prepare '\r' to '\n' */
 	cmp	w0, #0xA
@@ -62,7 +62,7 @@
 endfunc console_lpuart_putc
 
 func console_lpuart_getc
-	ldr	x0, [x0, #CONSOLE_T_DRVDATA]
+	ldr	x0, [x0, #CONSOLE_T_BASE]
 	cbz	x0, getc_error
 	/* Check if the receive FIFO state */
 	ret
diff --git a/plat/nvidia/tegra/common/drivers/spe/shared_console.S b/plat/nvidia/tegra/common/drivers/spe/shared_console.S
index c783373..6df73ec 100644
--- a/plat/nvidia/tegra/common/drivers/spe/shared_console.S
+++ b/plat/nvidia/tegra/common/drivers/spe/shared_console.S
@@ -69,7 +69,7 @@
 	check_if_console_is_ready x0, x1, x2, register_fail
 
 	cbz	x3, register_fail
-	str	x0, [x3, #CONSOLE_T_DRVDATA]
+	str	x0, [x3, #CONSOLE_T_BASE]
 	mov	x0, x3
 	finish_console_register spe putc=1, getc=1, flush=1
 
@@ -132,7 +132,7 @@
 	 * --------------------------------------------------------
 	 */
 func console_spe_putc
-	ldr	x1, [x1, #CONSOLE_T_DRVDATA]
+	ldr	x1, [x1, #CONSOLE_T_BASE]
 	b	console_spe_core_putc
 endfunc console_spe_putc
 
@@ -183,6 +183,6 @@
 	 * ---------------------------------------------
 	 */
 func console_spe_flush
-	ldr	x0, [x0, #CONSOLE_T_DRVDATA]
+	ldr	x0, [x0, #CONSOLE_T_BASE]
 	b	console_spe_core_flush
 endfunc console_spe_flush
diff --git a/plat/nvidia/tegra/common/tegra_fiq_glue.c b/plat/nvidia/tegra/common/tegra_fiq_glue.c
index 60b5595..8e198ae 100644
--- a/plat/nvidia/tegra/common/tegra_fiq_glue.c
+++ b/plat/nvidia/tegra/common/tegra_fiq_glue.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -155,7 +155,7 @@
 {
 	cpu_context_t *ctx = cm_get_context(NON_SECURE);
 	gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx);
-	const el1_sys_regs_t *el1state_ctx = get_sysregs_ctx(ctx);
+	const el1_sysregs_t *el1state_ctx = get_el1_sysregs_ctx(ctx);
 	uint32_t cpu = plat_my_core_pos();
 	uint64_t val;
 
diff --git a/plat/qemu/common/qemu_io_storage.c b/plat/qemu/common/qemu_io_storage.c
index 0e81cd1..1107e44 100644
--- a/plat/qemu/common/qemu_io_storage.c
+++ b/plat/qemu/common/qemu_io_storage.c
@@ -12,6 +12,7 @@
 #include <common/bl_common.h>
 #include <common/debug.h>
 #include <drivers/io/io_driver.h>
+#include <drivers/io/io_encrypted.h>
 #include <drivers/io/io_fip.h>
 #include <drivers/io/io_memmap.h>
 #include <drivers/io/io_semihosting.h>
@@ -47,6 +48,10 @@
 static uintptr_t memmap_dev_handle;
 static const io_dev_connector_t *sh_dev_con;
 static uintptr_t sh_dev_handle;
+#ifndef DECRYPTION_SUPPORT_none
+static const io_dev_connector_t *enc_dev_con;
+static uintptr_t enc_dev_handle;
+#endif
 
 static const io_block_spec_t fip_block_spec = {
 	.offset = PLAT_QEMU_FIP_BASE,
@@ -172,10 +177,11 @@
 #endif /* TRUSTED_BOARD_BOOT */
 };
 
-
-
 static int open_fip(const uintptr_t spec);
 static int open_memmap(const uintptr_t spec);
+#ifndef DECRYPTION_SUPPORT_none
+static int open_enc_fip(const uintptr_t spec);
+#endif
 
 struct plat_io_policy {
 	uintptr_t *dev_handle;
@@ -190,16 +196,46 @@
 		(uintptr_t)&fip_block_spec,
 		open_memmap
 	},
+	[ENC_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)NULL,
+		open_fip
+	},
 	[BL2_IMAGE_ID] = {
 		&fip_dev_handle,
 		(uintptr_t)&bl2_uuid_spec,
 		open_fip
 	},
+#if ENCRYPT_BL31 && !defined(DECRYPTION_SUPPORT_none)
+	[BL31_IMAGE_ID] = {
+		&enc_dev_handle,
+		(uintptr_t)&bl31_uuid_spec,
+		open_enc_fip
+	},
+#else
 	[BL31_IMAGE_ID] = {
 		&fip_dev_handle,
 		(uintptr_t)&bl31_uuid_spec,
 		open_fip
 	},
+#endif
+#if ENCRYPT_BL32 && !defined(DECRYPTION_SUPPORT_none)
+	[BL32_IMAGE_ID] = {
+		&enc_dev_handle,
+		(uintptr_t)&bl32_uuid_spec,
+		open_enc_fip
+	},
+	[BL32_EXTRA1_IMAGE_ID] = {
+		&enc_dev_handle,
+		(uintptr_t)&bl32_extra1_uuid_spec,
+		open_enc_fip
+	},
+	[BL32_EXTRA2_IMAGE_ID] = {
+		&enc_dev_handle,
+		(uintptr_t)&bl32_extra2_uuid_spec,
+		open_enc_fip
+	},
+#else
 	[BL32_IMAGE_ID] = {
 		&fip_dev_handle,
 		(uintptr_t)&bl32_uuid_spec,
@@ -215,6 +251,7 @@
 		(uintptr_t)&bl32_extra2_uuid_spec,
 		open_fip
 	},
+#endif
 	[BL33_IMAGE_ID] = {
 		&fip_dev_handle,
 		(uintptr_t)&bl33_uuid_spec,
@@ -271,7 +308,7 @@
 
 	/* See if a Firmware Image Package is available */
 	result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
-	if (result == 0) {
+	if (result == 0 && spec != (uintptr_t)NULL) {
 		result = io_open(fip_dev_handle, spec, &local_image_handle);
 		if (result == 0) {
 			VERBOSE("Using FIP\n");
@@ -281,6 +318,25 @@
 	return result;
 }
 
+#ifndef DECRYPTION_SUPPORT_none
+static int open_enc_fip(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	/* See if an encrypted FIP is available */
+	result = io_dev_init(enc_dev_handle, (uintptr_t)ENC_IMAGE_ID);
+	if (result == 0) {
+		result = io_open(enc_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			VERBOSE("Using encrypted FIP\n");
+			io_close(local_image_handle);
+		}
+	}
+	return result;
+}
+#endif
+
 static int open_memmap(const uintptr_t spec)
 {
 	int result;
@@ -333,6 +389,15 @@
 				&memmap_dev_handle);
 	assert(io_result == 0);
 
+#ifndef DECRYPTION_SUPPORT_none
+	io_result = register_io_dev_enc(&enc_dev_con);
+	assert(io_result == 0);
+
+	io_result = io_dev_open(enc_dev_con, (uintptr_t)NULL,
+				&enc_dev_handle);
+	assert(io_result == 0);
+#endif
+
 	/* Register the additional IO devices on this platform */
 	io_result = register_io_dev_sh(&sh_dev_con);
 	assert(io_result == 0);
diff --git a/plat/qemu/qemu/include/platform_def.h b/plat/qemu/qemu/include/platform_def.h
index cce992f..ed4b748 100644
--- a/plat/qemu/qemu/include/platform_def.h
+++ b/plat/qemu/qemu/include/platform_def.h
@@ -172,7 +172,7 @@
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
 #define MAX_MMAP_REGIONS		11
 #define MAX_XLAT_TABLES			6
-#define MAX_IO_DEVICES			3
+#define MAX_IO_DEVICES			4
 #define MAX_IO_HANDLES			4
 
 /*
@@ -196,8 +196,8 @@
 #define QEMU_FLASH1_BASE		0x04000000
 #define QEMU_FLASH1_SIZE		0x04000000
 
-#define PLAT_QEMU_FIP_BASE		QEMU_FLASH1_BASE
-#define PLAT_QEMU_FIP_MAX_SIZE		QEMU_FLASH1_SIZE
+#define PLAT_QEMU_FIP_BASE		0x00040000
+#define PLAT_QEMU_FIP_MAX_SIZE		0x00400000
 
 #define DEVICE0_BASE			0x08000000
 #define DEVICE0_SIZE			0x01000000
diff --git a/plat/qemu/qemu/platform.mk b/plat/qemu/qemu/platform.mk
index bc10569..928d69a 100644
--- a/plat/qemu/qemu/platform.mk
+++ b/plat/qemu/qemu/platform.mk
@@ -128,6 +128,11 @@
 BL2_SOURCES		+=	lib/optee/optee_utils.c
 endif
 
+ifneq (${DECRYPTION_SUPPORT},none)
+BL1_SOURCES		+=	drivers/io/io_encrypted.c
+BL2_SOURCES		+=	drivers/io/io_encrypted.c
+endif
+
 QEMU_GICV2_SOURCES	:=	drivers/arm/gic/v2/gicv2_helpers.c	\
 				drivers/arm/gic/v2/gicv2_main.c		\
 				drivers/arm/gic/common/gic_common.c	\
@@ -165,11 +170,19 @@
 # Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images
 # in the FIP if the platform requires.
 ifneq ($(BL32_EXTRA1),)
+ifneq (${DECRYPTION_SUPPORT},none)
+$(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1,,$(ENCRYPT_BL32)))
+else
 $(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1))
 endif
+endif
 ifneq ($(BL32_EXTRA2),)
+ifneq (${DECRYPTION_SUPPORT},none)
+$(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2,,$(ENCRYPT_BL32)))
+else
 $(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2))
 endif
+endif
 
 SEPARATE_CODE_AND_RODATA := 1
 ENABLE_STACK_PROTECTOR	 := 0
diff --git a/plat/socionext/uniphier/uniphier_io_storage.c b/plat/socionext/uniphier/uniphier_io_storage.c
index e89c835..77d1eaf 100644
--- a/plat/socionext/uniphier/uniphier_io_storage.c
+++ b/plat/socionext/uniphier/uniphier_io_storage.c
@@ -21,7 +21,7 @@
 #include "uniphier.h"
 
 #define UNIPHIER_ROM_REGION_BASE	0x00000000ULL
-#define UNIPHIER_ROM_REGION_SIZE	0x10000000ULL
+#define UNIPHIER_ROM_REGION_SIZE	0x04000000ULL
 
 #define UNIPHIER_OCM_REGION_SIZE	0x00040000ULL
 
diff --git a/services/spd/trusty/trusty.c b/services/spd/trusty/trusty.c
index 092ffa8..ba2f4a6 100644
--- a/services/spd/trusty/trusty.c
+++ b/services/spd/trusty/trusty.c
@@ -150,9 +150,9 @@
 	(void)memcpy(&ctx->fiq_gpregs, get_gpregs_ctx(handle), sizeof(ctx->fiq_gpregs));
 	ctx->fiq_pc = SMC_GET_EL3(handle, CTX_ELR_EL3);
 	ctx->fiq_cpsr = SMC_GET_EL3(handle, CTX_SPSR_EL3);
-	ctx->fiq_sp_el1 = read_ctx_reg(get_sysregs_ctx(handle), CTX_SP_EL1);
+	ctx->fiq_sp_el1 = read_ctx_reg(get_el1_sysregs_ctx(handle), CTX_SP_EL1);
 
-	write_ctx_reg(get_sysregs_ctx(handle), CTX_SP_EL1, ctx->fiq_handler_sp);
+	write_ctx_reg(get_el1_sysregs_ctx(handle), CTX_SP_EL1, ctx->fiq_handler_sp);
 	cm_set_elr_spsr_el3(NON_SECURE, ctx->fiq_handler_pc, (uint32_t)ctx->fiq_handler_cpsr);
 
 	SMC_RET0(handle);
@@ -211,7 +211,7 @@
 	 */
 	(void)memcpy(get_gpregs_ctx(handle), &ctx->fiq_gpregs, sizeof(ctx->fiq_gpregs));
 	ctx->fiq_handler_active = 0;
-	write_ctx_reg(get_sysregs_ctx(handle), CTX_SP_EL1, ctx->fiq_sp_el1);
+	write_ctx_reg(get_el1_sysregs_ctx(handle), CTX_SP_EL1, ctx->fiq_sp_el1);
 	cm_set_elr_spsr_el3(NON_SECURE, ctx->fiq_pc, (uint32_t)ctx->fiq_cpsr);
 
 	SMC_RET0(handle);
diff --git a/services/std_svc/spm_mm/spm_mm_setup.c b/services/std_svc/spm_mm/spm_mm_setup.c
index ccb2f90..468e5b3 100644
--- a/services/std_svc/spm_mm/spm_mm_setup.c
+++ b/services/std_svc/spm_mm/spm_mm_setup.c
@@ -116,17 +116,17 @@
 		      xlat_ctx->pa_max_address, xlat_ctx->va_max_address,
 		      EL1_EL0_REGIME);
 
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_MAIR_EL1,
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_MAIR_EL1,
 		      mmu_cfg_params[MMU_CFG_MAIR]);
 
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_TCR_EL1,
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TCR_EL1,
 		      mmu_cfg_params[MMU_CFG_TCR]);
 
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_TTBR0_EL1,
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TTBR0_EL1,
 		      mmu_cfg_params[MMU_CFG_TTBR0]);
 
 	/* Setup SCTLR_EL1 */
-	u_register_t sctlr_el1 = read_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1);
+	u_register_t sctlr_el1 = read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1);
 
 	sctlr_el1 |=
 		/*SCTLR_EL1_RES1 |*/
@@ -160,7 +160,7 @@
 		SCTLR_UMA_BIT
 	);
 
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1);
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1);
 
 	/*
 	 * Setup other system registers
@@ -168,10 +168,10 @@
 	 */
 
 	/* Shim Exception Vector Base Address */
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_VBAR_EL1,
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_VBAR_EL1,
 			SPM_SHIM_EXCEPTIONS_PTR);
 
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_CNTKCTL_EL1,
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_CNTKCTL_EL1,
 		      EL0PTEN_BIT | EL0VTEN_BIT | EL0PCTEN_BIT | EL0VCTEN_BIT);
 
 	/*
@@ -181,7 +181,7 @@
 	 * TTA: Enable access to trace registers.
 	 * ZEN (v8.2): Trap SVE instructions and access to SVE registers.
 	 */
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_CPACR_EL1,
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_CPACR_EL1,
 			CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE));
 
 	/*
diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c
index 677f639..2cdf4f5 100644
--- a/services/std_svc/spmd/spmd_main.c
+++ b/services/std_svc/spmd/spmd_main.c
@@ -33,9 +33,25 @@
 /*******************************************************************************
  * SPM Core attribute information read from its manifest.
  ******************************************************************************/
-spmc_manifest_sect_attribute_t spmc_attrs;
+static spmc_manifest_sect_attribute_t spmc_attrs;
 
 /*******************************************************************************
+ * SPM Core entry point information. Discovered on the primary core and reused
+ * on secondary cores.
+ ******************************************************************************/
+static entry_point_info_t *spmc_ep_info;
+
+/*******************************************************************************
+ * Static function declaration.
+ ******************************************************************************/
+static int32_t	spmd_init(void);
+static int	spmd_spmc_init(void *rd_base, size_t rd_size);
+static uint64_t	spmd_spci_error_return(void *handle, int error_code);
+static uint64_t	spmd_smc_forward(uint32_t smc_fid, bool secure_origin,
+				 uint64_t x1, uint64_t x2, uint64_t x3,
+				 uint64_t x4, void *handle);
+
+/*******************************************************************************
  * This function takes an SP context pointer and performs a synchronous entry
  * into it.
  ******************************************************************************/
@@ -49,17 +65,19 @@
 
 	/* Restore the context assigned above */
 	cm_el1_sysregs_context_restore(SECURE);
+#if SPMD_SPM_AT_SEL2
+	cm_el2_sysregs_context_restore(SECURE);
+#endif
 	cm_set_next_eret_context(SECURE);
 
-	/* Invalidate TLBs at EL1. */
-	tlbivmalle1();
-	dsbish();
-
-	/* Enter Secure Partition */
+	/* Enter SPMC */
 	rc = spmd_spm_core_enter(&spmc_ctx->c_rt_ctx);
 
 	/* Save secure state */
 	cm_el1_sysregs_context_save(SECURE);
+#if SPMD_SPM_AT_SEL2
+	cm_el2_sysregs_context_save(SECURE);
+#endif
 
 	return rc;
 }
@@ -109,63 +127,21 @@
 }
 
 /*******************************************************************************
- * Initialize context of SPM core.
+ * Load SPMC manifest, init SPMC.
  ******************************************************************************/
-int32_t spmd_setup(void)
+static int spmd_spmc_init(void *rd_base, size_t rd_size)
 {
 	int rc;
-	void *rd_base;
-	size_t rd_size;
-	entry_point_info_t *spmc_ep_info;
-	uintptr_t rd_base_align;
-	uintptr_t rd_size_align;
 	uint32_t ep_attr;
-
-	spmc_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
-	if (!spmc_ep_info) {
-		WARN("No SPM core image provided by BL2 boot loader, Booting "
-		     "device without SP initialization. SMC`s destined for SPM "
-		     "core will return SMC_UNK\n");
-		return 1;
-	}
-
-	/* Under no circumstances will this parameter be 0 */
-	assert(spmc_ep_info->pc != 0U);
-
-	/*
-	 * Check if BL32 ep_info has a reference to 'tos_fw_config'. This will
-	 * be used as a manifest for the SPM core at the next lower EL/mode.
-	 */
-	if (spmc_ep_info->args.arg0 == 0U || spmc_ep_info->args.arg2 == 0U) {
-		ERROR("Invalid or absent SPM core manifest\n");
-		panic();
-	}
-
-	/* Obtain whereabouts of SPM core manifest */
-	rd_base = (void *) spmc_ep_info->args.arg0;
-	rd_size = spmc_ep_info->args.arg2;
-
-	rd_base_align = page_align((uintptr_t) rd_base, DOWN);
-	rd_size_align = page_align((uintptr_t) rd_size, UP);
-
-	/* Map the manifest in the SPMD translation regime first */
-	VERBOSE("SPM core manifest base : 0x%lx\n", rd_base_align);
-	VERBOSE("SPM core manifest size : 0x%lx\n", rd_size_align);
-	rc = mmap_add_dynamic_region((unsigned long long) rd_base_align,
-				     (uintptr_t) rd_base_align,
-				     rd_size_align,
-				     MT_RO_DATA);
-	if (rc < 0) {
-		ERROR("Error while mapping SPM core manifest (%d).\n", rc);
-		panic();
-	}
+	unsigned int linear_id = plat_my_core_pos();
+	spmd_spm_core_context_t *spm_ctx = &spm_core_context[linear_id];
 
 	/* Load the SPM core manifest */
 	rc = plat_spm_core_manifest_load(&spmc_attrs, rd_base, rd_size);
-	if (rc < 0) {
+	if (rc != 0) {
 		WARN("No or invalid SPM core manifest image provided by BL2 "
 		     "boot loader. ");
-		goto error;
+		return 1;
 	}
 
 	/*
@@ -177,22 +153,14 @@
 		WARN("Unsupported SPCI version (%x.%x) specified in SPM core "
 		     "manifest image provided by BL2 boot loader.\n",
 		     spmc_attrs.major_version, spmc_attrs.minor_version);
-		goto error;
+		return 1;
 	}
 
 	INFO("SPCI version (%x.%x).\n", spmc_attrs.major_version,
 	     spmc_attrs.minor_version);
 
-	/* Validate the SPM core runtime EL */
-	if ((spmc_attrs.runtime_el != MODE_EL1) &&
-	    (spmc_attrs.runtime_el != MODE_EL2)) {
-		WARN("Unsupported SPM core run time EL%x specified in "
-		     "manifest image provided by BL2 boot loader.\n",
-		     spmc_attrs.runtime_el);
-		goto error;
-	}
-
-	INFO("SPM core run time EL%x.\n", spmc_attrs.runtime_el);
+	INFO("SPM core run time EL%x.\n",
+	     SPMD_SPM_AT_SEL2 ? MODE_EL2 : MODE_EL1);
 
 	/* Validate the SPM core execution state */
 	if ((spmc_attrs.exec_state != MODE_RW_64) &&
@@ -200,42 +168,39 @@
 		WARN("Unsupported SPM core execution state %x specified in "
 		     "manifest image provided by BL2 boot loader.\n",
 		     spmc_attrs.exec_state);
-		goto error;
+		return 1;
 	}
 
 	INFO("SPM core execution state %x.\n", spmc_attrs.exec_state);
 
-	/* Ensure manifest has not requested S-EL2 in AArch32 state */
-	if ((spmc_attrs.exec_state == MODE_RW_32) &&
-	    (spmc_attrs.runtime_el == MODE_EL2)) {
-		WARN("Invalid combination of SPM core execution state (%x) "
-		     "and run time EL (%x).\n", spmc_attrs.exec_state,
-		     spmc_attrs.runtime_el);
-		goto error;
+#if SPMD_SPM_AT_SEL2
+	/* Ensure manifest has not requested AArch32 state in S-EL2 */
+	if (spmc_attrs.exec_state == MODE_RW_32) {
+		WARN("AArch32 state at S-EL2 is not supported.\n");
+		return 1;
 	}
 
 	/*
 	 * Check if S-EL2 is supported on this system if S-EL2
 	 * is required for SPM
 	 */
-	if (spmc_attrs.runtime_el == MODE_EL2) {
-		uint64_t sel2 = read_id_aa64pfr0_el1();
+	uint64_t sel2 = read_id_aa64pfr0_el1();
 
-		sel2 >>= ID_AA64PFR0_SEL2_SHIFT;
-		sel2 &= ID_AA64PFR0_SEL2_MASK;
+	sel2 >>= ID_AA64PFR0_SEL2_SHIFT;
+	sel2 &= ID_AA64PFR0_SEL2_MASK;
 
-		if (!sel2) {
-			WARN("SPM core run time EL: S-EL%x is not supported "
-			     "but specified in manifest image provided by "
-			     "BL2 boot loader.\n", spmc_attrs.runtime_el);
-			goto error;
-		}
+	if (!sel2) {
+		WARN("SPM core run time S-EL2 is not supported.");
+		return 1;
 	}
+#endif /* SPMD_SPM_AT_SEL2 */
 
 	/* Initialise an entrypoint to set up the CPU context */
 	ep_attr = SECURE | EP_ST_ENABLE;
-	if (read_sctlr_el3() & SCTLR_EE_BIT)
+	if (read_sctlr_el3() & SCTLR_EE_BIT) {
 		ep_attr |= EP_EE_BIG;
+	}
+
 	SET_PARAM_HEAD(spmc_ep_info, PARAM_EP, VERSION_1, ep_attr);
 	assert(spmc_ep_info->pc == BL32_BASE);
 
@@ -250,14 +215,22 @@
 						 DAIF_IRQ_BIT |
 						 DAIF_ABT_BIT);
 	} else {
-		spmc_ep_info->spsr = SPSR_64(spmc_attrs.runtime_el,
+
+#if SPMD_SPM_AT_SEL2
+		static const uint32_t runtime_el = MODE_EL2;
+#else
+		static const uint32_t runtime_el = MODE_EL1;
+#endif
+		spmc_ep_info->spsr = SPSR_64(runtime_el,
 					     MODE_SP_ELX,
 					     DISABLE_ALL_EXCEPTIONS);
 	}
 
 	/* Initialise SPM core context with this entry point information */
-	cm_setup_context(&(spm_core_context[plat_my_core_pos()].cpu_ctx),
-			 spmc_ep_info);
+	cm_setup_context(&spm_ctx->cpu_ctx, spmc_ep_info);
+
+	/* Reuse PSCI affinity states to mark this SPMC context as off */
+	spm_ctx->state = AFF_STATE_OFF;
 
 	INFO("SPM core setup done.\n");
 
@@ -265,23 +238,122 @@
 	bl31_register_bl32_init(&spmd_init);
 
 	return 0;
+}
 
-error:
-	WARN("Booting device without SPM initialization. "
-	     "SPCI SMCs destined for SPM core will return "
-	     "ENOTSUPPORTED\n");
+/*******************************************************************************
+ * Initialize context of SPM core.
+ ******************************************************************************/
+int spmd_setup(void)
+{
+	int rc;
+	void *rd_base;
+	size_t rd_size;
+	uintptr_t rd_base_align;
+	uintptr_t rd_size_align;
 
-	rc = mmap_remove_dynamic_region(rd_base_align, rd_size_align);
-	if (rc < 0) {
-		ERROR("Error while unmapping SPM core manifest (%d).\n",
-		      rc);
+	spmc_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+	if (!spmc_ep_info) {
+		WARN("No SPM core image provided by BL2 boot loader, Booting "
+		     "device without SP initialization. SMC`s destined for SPM "
+		     "core will return SMC_UNK\n");
+		return 1;
+	}
+
+	/* Under no circumstances will this parameter be 0 */
+	assert(spmc_ep_info->pc != 0U);
+
+	/*
+	 * Check if BL32 ep_info has a reference to 'tos_fw_config'. This will
+	 * be used as a manifest for the SPM core at the next lower EL/mode.
+	 */
+	if (spmc_ep_info->args.arg0 == 0U || spmc_ep_info->args.arg2 == 0U) {
+		ERROR("Invalid or absent SPM core manifest\n");
 		panic();
 	}
 
-	return 1;
+	/* Obtain whereabouts of SPM core manifest */
+	rd_base = (void *) spmc_ep_info->args.arg0;
+	rd_size = spmc_ep_info->args.arg2;
+
+	rd_base_align = page_align((uintptr_t) rd_base, DOWN);
+	rd_size_align = page_align((uintptr_t) rd_size, UP);
+
+	/* Map the manifest in the SPMD translation regime first */
+	VERBOSE("SPM core manifest base : 0x%lx\n", rd_base_align);
+	VERBOSE("SPM core manifest size : 0x%lx\n", rd_size_align);
+	rc = mmap_add_dynamic_region((unsigned long long) rd_base_align,
+				     (uintptr_t) rd_base_align,
+				     rd_size_align,
+				     MT_RO_DATA);
+	if (rc != 0) {
+		ERROR("Error while mapping SPM core manifest (%d).\n", rc);
+		panic();
+	}
+
+	/* Load manifest, init SPMC */
+	rc = spmd_spmc_init(rd_base, rd_size);
+	if (rc != 0) {
+		int mmap_rc;
+
+		WARN("Booting device without SPM initialization. "
+		     "SPCI SMCs destined for SPM core will return "
+		     "ENOTSUPPORTED\n");
+
+		mmap_rc = mmap_remove_dynamic_region(rd_base_align,
+						     rd_size_align);
+		if (mmap_rc != 0) {
+			ERROR("Error while unmapping SPM core manifest (%d).\n",
+			      mmap_rc);
+			panic();
+		}
+
+		return rc;
+	}
+
+	return 0;
 }
 
 /*******************************************************************************
+ * Forward SMC to the other security state
+ ******************************************************************************/
+static uint64_t spmd_smc_forward(uint32_t smc_fid, bool secure_origin,
+				 uint64_t x1, uint64_t x2, uint64_t x3,
+				 uint64_t x4, void *handle)
+{
+	uint32_t secure_state_in = (secure_origin) ? SECURE : NON_SECURE;
+	uint32_t secure_state_out = (!secure_origin) ? SECURE : NON_SECURE;
+
+	/* Save incoming security state */
+	cm_el1_sysregs_context_save(secure_state_in);
+#if SPMD_SPM_AT_SEL2
+	cm_el2_sysregs_context_save(secure_state_in);
+#endif
+
+	/* Restore outgoing security state */
+	cm_el1_sysregs_context_restore(secure_state_out);
+#if SPMD_SPM_AT_SEL2
+	cm_el2_sysregs_context_restore(secure_state_out);
+#endif
+	cm_set_next_eret_context(secure_state_out);
+
+	SMC_RET8(cm_get_context(secure_state_out), 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));
+}
+
+/*******************************************************************************
+ * Return SPCI_ERROR with specified error code
+ ******************************************************************************/
+static uint64_t spmd_spci_error_return(void *handle, int error_code)
+{
+	SMC_RET8(handle, SPCI_ERROR,
+		 SPCI_TARGET_INFO_MBZ, error_code,
+		 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ, SPCI_PARAM_MBZ,
+		 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ);
+}
+
+/*******************************************************************************
  * This function handles all SMCs in the range reserved for SPCI. Each call is
  * either forwarded to the other security state or handled by the SPM dispatcher
  ******************************************************************************/
@@ -289,19 +361,12 @@
 			  uint64_t x3, uint64_t x4, void *cookie, void *handle,
 			  uint64_t flags)
 {
-	uint32_t in_sstate;
-	uint32_t out_sstate;
-	int32_t ret;
 	spmd_spm_core_context_t *ctx = &spm_core_context[plat_my_core_pos()];
+	bool secure_origin;
+	int32_t ret;
 
 	/* Determine which security state this SMC originated from */
-	if (is_caller_secure(flags)) {
-		in_sstate = SECURE;
-		out_sstate = NON_SECURE;
-	} else {
-		in_sstate = NON_SECURE;
-		out_sstate = SECURE;
-	}
+	secure_origin = is_caller_secure(flags);
 
 	INFO("SPM: 0x%x, 0x%llx, 0x%llx, 0x%llx, 0x%llx, "
 	     "0x%llx, 0x%llx, 0x%llx\n",
@@ -316,20 +381,12 @@
 		 * this CPU. If so, then indicate that the SPM core initialised
 		 * unsuccessfully.
 		 */
-		if ((in_sstate == SECURE) && (ctx->state == SPMC_STATE_RESET))
+		if (secure_origin && (ctx->state == SPMC_STATE_RESET)) {
 			spmd_spm_core_sync_exit(x2);
-
-		/* Save incoming security state */
-		cm_el1_sysregs_context_save(in_sstate);
-
-		/* Restore outgoing security state */
-		cm_el1_sysregs_context_restore(out_sstate);
-		cm_set_next_eret_context(out_sstate);
+		}
 
-		SMC_RET8(cm_get_context(out_sstate), 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));
+		return spmd_smc_forward(smc_fid, secure_origin,
+					x1, x2, x3, x4, handle);
 		break; /* not reached */
 
 	case SPCI_VERSION:
@@ -353,29 +410,18 @@
 		 */
 
 		/*
-		 * Check if w1 holds a valid SPCI fid. This is an
+		 * Check if x1 holds a valid SPCI fid. This is an
 		 * optimization.
 		 */
-		if (!is_spci_fid(x1))
-			SMC_RET8(handle, SPCI_ERROR,
-				 SPCI_TARGET_INFO_MBZ, SPCI_ERROR_NOT_SUPPORTED,
-				 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ, SPCI_PARAM_MBZ,
-				 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ);
+		if (!is_spci_fid(x1)) {
+			return spmd_spci_error_return(handle,
+						      SPCI_ERROR_NOT_SUPPORTED);
+		}
 
 		/* Forward SMC from Normal world to the SPM core */
-		if (in_sstate == NON_SECURE) {
-			/* Save incoming security state */
-			cm_el1_sysregs_context_save(in_sstate);
-
-			/* Restore outgoing security state */
-			cm_el1_sysregs_context_restore(out_sstate);
-			cm_set_next_eret_context(out_sstate);
-
-			SMC_RET8(cm_get_context(out_sstate), 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));
+		if (!secure_origin) {
+			return spmd_smc_forward(smc_fid, secure_origin,
+						x1, x2, x3, x4, handle);
 		} else {
 			/*
 			 * Return success if call was from secure world i.e. all
@@ -387,6 +433,7 @@
 				 SMC_GET_GP(handle, CTX_GPREG_X6),
 				 SMC_GET_GP(handle, CTX_GPREG_X7));
 		}
+
 		break; /* not reached */
 
 	case SPCI_RX_RELEASE:
@@ -395,11 +442,9 @@
 	case SPCI_RXTX_UNMAP:
 	case SPCI_MSG_RUN:
 		/* This interface must be invoked only by the Normal world */
-		if (in_sstate == SECURE) {
-			SMC_RET8(handle, SPCI_ERROR,
-				 SPCI_TARGET_INFO_MBZ, SPCI_ERROR_NOT_SUPPORTED,
-				 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ, SPCI_PARAM_MBZ,
-				 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ);
+		if (secure_origin) {
+			return spmd_spci_error_return(handle,
+						      SPCI_ERROR_NOT_SUPPORTED);
 		}
 
 		/* Fall through to forward the call to the other world */
@@ -430,17 +475,8 @@
 		 * simply forward the call to the Normal world.
 		 */
 
-		/* Save incoming security state */
-		cm_el1_sysregs_context_save(in_sstate);
-
-		/* Restore outgoing security state */
-		cm_el1_sysregs_context_restore(out_sstate);
-		cm_set_next_eret_context(out_sstate);
-
-		SMC_RET8(cm_get_context(out_sstate), 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));
+		return spmd_smc_forward(smc_fid, secure_origin,
+					x1, x2, x3, x4, handle);
 		break; /* not reached */
 
 	case SPCI_MSG_WAIT:
@@ -449,39 +485,25 @@
 		 * this CPU from the Secure world. If so, then indicate that the
 		 * SPM core initialised successfully.
 		 */
-		if ((in_sstate == SECURE) && (ctx->state == SPMC_STATE_RESET)) {
+		if (secure_origin && (ctx->state == SPMC_STATE_RESET)) {
 			spmd_spm_core_sync_exit(0);
 		}
 
-		/* Intentional fall-through */
+		/* Fall through to forward the call to the other world */
 
 	case SPCI_MSG_YIELD:
 		/* This interface must be invoked only by the Secure world */
-		if (in_sstate == NON_SECURE) {
-			SMC_RET8(handle, SPCI_ERROR,
-				 SPCI_TARGET_INFO_MBZ, SPCI_ERROR_NOT_SUPPORTED,
-				 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ, SPCI_PARAM_MBZ,
-				 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ);
+		if (!secure_origin) {
+			return spmd_spci_error_return(handle,
+						      SPCI_ERROR_NOT_SUPPORTED);
 		}
 
-		/* Save incoming security state */
-		cm_el1_sysregs_context_save(in_sstate);
-
-		/* Restore outgoing security state */
-		cm_el1_sysregs_context_restore(out_sstate);
-		cm_set_next_eret_context(out_sstate);
-
-		SMC_RET8(cm_get_context(out_sstate), 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));
+		return spmd_smc_forward(smc_fid, secure_origin,
+					x1, x2, x3, x4, handle);
 		break; /* not reached */
 
 	default:
 		WARN("SPM: Unsupported call 0x%08x\n", smc_fid);
-		SMC_RET8(handle, SPCI_ERROR,
-			 SPCI_TARGET_INFO_MBZ, SPCI_ERROR_NOT_SUPPORTED,
-			 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ, SPCI_PARAM_MBZ,
-			 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ);
+		return spmd_spci_error_return(handle, SPCI_ERROR_NOT_SUPPORTED);
 	}
 }
diff --git a/tools/encrypt_fw/Makefile b/tools/encrypt_fw/Makefile
new file mode 100644
index 0000000..cb81d0b
--- /dev/null
+++ b/tools/encrypt_fw/Makefile
@@ -0,0 +1,65 @@
+#
+# Copyright (c) 2019, Linaro Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+PROJECT		:= encrypt_fw
+V		?= 0
+BUILD_INFO	?= 1
+DEBUG		:= 0
+BINARY		:= ${PROJECT}${BIN_EXT}
+OPENSSL_DIR	:= /usr
+
+OBJECTS := src/encrypt.o \
+           src/cmd_opt.o \
+           src/main.o
+
+HOSTCCFLAGS := -Wall -std=c99
+
+MAKE_HELPERS_DIRECTORY := ../../make_helpers/
+include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
+include ${MAKE_HELPERS_DIRECTORY}build_env.mk
+
+ifeq (${DEBUG},1)
+  HOSTCCFLAGS += -g -O0 -DDEBUG -DLOG_LEVEL=40
+else
+ifeq (${BUILD_INFO},1)
+  HOSTCCFLAGS += -O2 -DLOG_LEVEL=20
+else
+  HOSTCCFLAGS += -O2 -DLOG_LEVEL=10
+endif
+endif
+ifeq (${V},0)
+  Q := @
+else
+  Q :=
+endif
+
+# Make soft links and include from local directory otherwise wrong headers
+# could get pulled in from firmware tree.
+INC_DIR := -I ./include -I ../../include/tools_share -I ${OPENSSL_DIR}/include
+LIB_DIR := -L ${OPENSSL_DIR}/lib
+LIB := -lssl -lcrypto
+
+HOSTCC ?= gcc
+
+.PHONY: all clean realclean
+
+all: clean ${BINARY}
+
+${BINARY}: ${OBJECTS} Makefile
+	@echo "  HOSTLD  $@"
+	@echo 'const char build_msg[] = "Built : "__TIME__", "__DATE__;' | \
+                ${HOSTCC} -c ${HOSTCCFLAGS} -xc - -o src/build_msg.o
+	${Q}${HOSTCC} src/build_msg.o ${OBJECTS} ${LIB_DIR} ${LIB} -o $@
+
+%.o: %.c
+	@echo "  HOSTCC  $<"
+	${Q}${HOSTCC} -c ${HOSTCCFLAGS} ${INC_DIR} $< -o $@
+
+clean:
+	$(call SHELL_DELETE_ALL, src/build_msg.o ${OBJECTS})
+
+realclean: clean
+	$(call SHELL_DELETE,${BINARY})
diff --git a/tools/encrypt_fw/include/cmd_opt.h b/tools/encrypt_fw/include/cmd_opt.h
new file mode 100644
index 0000000..bd7d31f
--- /dev/null
+++ b/tools/encrypt_fw/include/cmd_opt.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CMD_OPT_H
+#define CMD_OPT_H
+
+#include <getopt.h>
+
+#define CMD_OPT_MAX_NUM			64
+
+/* Supported long command line option types */
+enum {
+	CMD_OPT_FW
+};
+
+/* Structure to define a command line option */
+typedef struct cmd_opt_s {
+	struct option long_opt;
+	const char *help_msg;
+} cmd_opt_t;
+
+/* Exported API*/
+void cmd_opt_add(const cmd_opt_t *cmd_opt);
+const struct option *cmd_opt_get_array(void);
+const char *cmd_opt_get_name(int idx);
+const char *cmd_opt_get_help_msg(int idx);
+
+#endif /* CMD_OPT_H */
diff --git a/tools/encrypt_fw/include/debug.h b/tools/encrypt_fw/include/debug.h
new file mode 100644
index 0000000..ee8f1f5
--- /dev/null
+++ b/tools/encrypt_fw/include/debug.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdio.h>
+
+/* The log output macros print output to the console. These macros produce
+ * compiled log output only if the LOG_LEVEL defined in the makefile (or the
+ * make command line) is greater or equal than the level required for that
+ * type of log output.
+ * The format expected is the same as for printf(). For example:
+ * INFO("Info %s.\n", "message")    -> INFO:    Info message.
+ * WARN("Warning %s.\n", "message") -> WARNING: Warning message.
+ */
+
+#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
+
+
+#if LOG_LEVEL >= LOG_LEVEL_NOTICE
+# define NOTICE(...)	printf("NOTICE:  " __VA_ARGS__)
+#else
+# define NOTICE(...)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_ERROR
+# define ERROR(...)	printf("ERROR:   " __VA_ARGS__)
+#else
+# define ERROR(...)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_WARNING
+# define WARN(...)	printf("WARNING: " __VA_ARGS__)
+#else
+# define WARN(...)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+# define INFO(...)	printf("INFO:    " __VA_ARGS__)
+#else
+# define INFO(...)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+# define VERBOSE(...)	printf("VERBOSE: " __VA_ARGS__)
+#else
+# define VERBOSE(...)
+#endif
+
+#endif /* DEBUG_H */
diff --git a/tools/encrypt_fw/include/encrypt.h b/tools/encrypt_fw/include/encrypt.h
new file mode 100644
index 0000000..25d3011
--- /dev/null
+++ b/tools/encrypt_fw/include/encrypt.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ENCRYPT_H
+#define ENCRYPT_H
+
+/* Supported key algorithms */
+enum {
+	KEY_ALG_GCM		/* AES-GCM (default) */
+};
+
+int encrypt_file(unsigned short fw_enc_status, int enc_alg, char *key_string,
+		 char *nonce_string, const char *ip_name, const char *op_name);
+
+#endif /* ENCRYPT_H */
diff --git a/tools/encrypt_fw/src/cmd_opt.c b/tools/encrypt_fw/src/cmd_opt.c
new file mode 100644
index 0000000..64180d1
--- /dev/null
+++ b/tools/encrypt_fw/src/cmd_opt.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cmd_opt.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "debug.h"
+
+/* Command line options */
+static struct option long_opt[CMD_OPT_MAX_NUM+1];
+static const char *help_msg[CMD_OPT_MAX_NUM+1];
+static int num_reg_opt;
+
+void cmd_opt_add(const cmd_opt_t *cmd_opt)
+{
+	assert(cmd_opt != NULL);
+
+	if (num_reg_opt >= CMD_OPT_MAX_NUM) {
+		ERROR("Out of memory. Please increase CMD_OPT_MAX_NUM\n");
+		exit(1);
+	}
+
+	long_opt[num_reg_opt].name = cmd_opt->long_opt.name;
+	long_opt[num_reg_opt].has_arg = cmd_opt->long_opt.has_arg;
+	long_opt[num_reg_opt].flag = 0;
+	long_opt[num_reg_opt].val = cmd_opt->long_opt.val;
+
+	help_msg[num_reg_opt] = cmd_opt->help_msg;
+
+	num_reg_opt++;
+}
+
+const struct option *cmd_opt_get_array(void)
+{
+	return long_opt;
+}
+
+const char *cmd_opt_get_name(int idx)
+{
+	if (idx >= num_reg_opt) {
+		return NULL;
+	}
+
+	return long_opt[idx].name;
+}
+
+const char *cmd_opt_get_help_msg(int idx)
+{
+	if (idx >= num_reg_opt) {
+		return NULL;
+	}
+
+	return help_msg[idx];
+}
diff --git a/tools/encrypt_fw/src/encrypt.c b/tools/encrypt_fw/src/encrypt.c
new file mode 100644
index 0000000..18a514c
--- /dev/null
+++ b/tools/encrypt_fw/src/encrypt.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <firmware_encrypted.h>
+#include <openssl/evp.h>
+#include <stdio.h>
+#include <string.h>
+#include "debug.h"
+#include "encrypt.h"
+
+#define BUFFER_SIZE		256
+#define IV_SIZE			12
+#define IV_STRING_SIZE		24
+#define TAG_SIZE		16
+#define KEY_SIZE		32
+#define KEY_STRING_SIZE		64
+
+static int gcm_encrypt(unsigned short fw_enc_status, char *key_string,
+		       char *nonce_string, const char *ip_name,
+		       const char *op_name)
+{
+	FILE *ip_file;
+	FILE *op_file;
+	EVP_CIPHER_CTX *ctx;
+	unsigned char data[BUFFER_SIZE], enc_data[BUFFER_SIZE];
+	unsigned char key[KEY_SIZE], iv[IV_SIZE], tag[TAG_SIZE];
+	int bytes, enc_len = 0, i, j, ret = 0;
+	struct fw_enc_hdr header;
+
+	memset(&header, 0, sizeof(struct fw_enc_hdr));
+
+	if (strlen(key_string) != KEY_STRING_SIZE) {
+		ERROR("Unsupported key size: %lu\n", strlen(key_string));
+		return -1;
+	}
+
+	for (i = 0, j = 0; i < KEY_SIZE; i++, j += 2) {
+		if (sscanf(&key_string[j], "%02hhx", &key[i]) != 1) {
+			ERROR("Incorrect key format\n");
+			return -1;
+		}
+	}
+
+	if (strlen(nonce_string) != IV_STRING_SIZE) {
+		ERROR("Unsupported IV size: %lu\n", strlen(nonce_string));
+		return -1;
+	}
+
+	for (i = 0, j = 0; i < IV_SIZE; i++, j += 2) {
+		if (sscanf(&nonce_string[j], "%02hhx", &iv[i]) != 1) {
+			ERROR("Incorrect IV format\n");
+			return -1;
+		}
+	}
+
+	ip_file = fopen(ip_name, "rb");
+	if (ip_file == NULL) {
+		ERROR("Cannot read %s\n", ip_name);
+		return -1;
+	}
+
+	op_file = fopen(op_name, "wb");
+	if (op_file == NULL) {
+		ERROR("Cannot write %s\n", op_name);
+		fclose(ip_file);
+		return -1;
+	}
+
+	ret = fseek(op_file, sizeof(struct fw_enc_hdr), SEEK_SET);
+	if (ret) {
+		ERROR("fseek failed\n");
+		goto out_file;
+	}
+
+	ctx = EVP_CIPHER_CTX_new();
+	if (ctx == NULL) {
+		ERROR("EVP_CIPHER_CTX_new failed\n");
+		ret = -1;
+		goto out_file;
+	}
+
+	ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
+	if (ret != 1) {
+		ERROR("EVP_EncryptInit_ex failed\n");
+		ret = -1;
+		goto out;
+	}
+
+	ret = EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv);
+	if (ret != 1) {
+		ERROR("EVP_EncryptInit_ex failed\n");
+		goto out;
+	}
+
+	while ((bytes = fread(data, 1, BUFFER_SIZE, ip_file)) != 0) {
+		ret = EVP_EncryptUpdate(ctx, enc_data, &enc_len, data, bytes);
+		if (ret != 1) {
+			ERROR("EVP_EncryptUpdate failed\n");
+			ret = -1;
+			goto out;
+		}
+
+		fwrite(enc_data, 1, enc_len, op_file);
+	}
+
+	ret = EVP_EncryptFinal_ex(ctx, enc_data, &enc_len);
+	if (ret != 1) {
+		ERROR("EVP_EncryptFinal_ex failed\n");
+		ret = -1;
+		goto out;
+	}
+
+	ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAG_SIZE, tag);
+	if (ret != 1) {
+		ERROR("EVP_CIPHER_CTX_ctrl failed\n");
+		ret = -1;
+		goto out;
+	}
+
+	header.magic = ENC_HEADER_MAGIC;
+	header.flags |= fw_enc_status & FW_ENC_STATUS_FLAG_MASK;
+	header.dec_algo = KEY_ALG_GCM;
+	header.iv_len = IV_SIZE;
+	header.tag_len = TAG_SIZE;
+	memcpy(header.iv, iv, IV_SIZE);
+	memcpy(header.tag, tag, TAG_SIZE);
+
+	ret = fseek(op_file, 0, SEEK_SET);
+	if (ret) {
+		ERROR("fseek failed\n");
+		goto out;
+	}
+
+	fwrite(&header, 1, sizeof(struct fw_enc_hdr), op_file);
+
+out:
+	EVP_CIPHER_CTX_free(ctx);
+
+out_file:
+	fclose(ip_file);
+	fclose(op_file);
+
+	/*
+	 * EVP_* APIs returns 1 as success but enctool considers
+	 * 0 as success.
+	 */
+	if (ret == 1)
+		ret = 0;
+
+	return ret;
+}
+
+int encrypt_file(unsigned short fw_enc_status, int enc_alg, char *key_string,
+		 char *nonce_string, const char *ip_name, const char *op_name)
+{
+	switch (enc_alg) {
+	case KEY_ALG_GCM:
+		return gcm_encrypt(fw_enc_status, key_string, nonce_string,
+				   ip_name, op_name);
+	default:
+		return -1;
+	}
+}
diff --git a/tools/encrypt_fw/src/main.c b/tools/encrypt_fw/src/main.c
new file mode 100644
index 0000000..39b7af7
--- /dev/null
+++ b/tools/encrypt_fw/src/main.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <openssl/conf.h>
+
+#include "cmd_opt.h"
+#include "debug.h"
+#include "encrypt.h"
+#include "firmware_encrypted.h"
+
+#define NUM_ELEM(x)			((sizeof(x)) / (sizeof(x[0])))
+#define HELP_OPT_MAX_LEN		128
+
+/* Global options */
+
+/* Info messages created in the Makefile */
+extern const char build_msg[];
+
+static char *key_algs_str[] = {
+	[KEY_ALG_GCM] = "gcm",
+};
+
+static void print_help(const char *cmd, const struct option *long_opt)
+{
+	int rem, i = 0;
+	const struct option *opt;
+	char line[HELP_OPT_MAX_LEN];
+	char *p;
+
+	assert(cmd != NULL);
+	assert(long_opt != NULL);
+
+	printf("\n\n");
+	printf("The firmware encryption tool loads the binary image and\n"
+	       "outputs encrypted binary image using an encryption key\n"
+	       "provided as an input hex string.\n");
+	printf("\n");
+	printf("Usage:\n");
+	printf("\t%s [OPTIONS]\n\n", cmd);
+
+	printf("Available options:\n");
+	opt = long_opt;
+	while (opt->name) {
+		p = line;
+		rem = HELP_OPT_MAX_LEN;
+		if (isalpha(opt->val)) {
+			/* Short format */
+			sprintf(p, "-%c,", (char)opt->val);
+			p += 3;
+			rem -= 3;
+		}
+		snprintf(p, rem, "--%s %s", opt->name,
+			 (opt->has_arg == required_argument) ? "<arg>" : "");
+		printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i));
+		opt++;
+		i++;
+	}
+	printf("\n");
+}
+
+static int get_key_alg(const char *key_alg_str)
+{
+	int i;
+
+	for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
+		if (strcmp(key_alg_str, key_algs_str[i]) == 0) {
+			return i;
+		}
+	}
+
+	return -1;
+}
+
+static void parse_fw_enc_status_flag(const char *arg,
+				     unsigned short *fw_enc_status)
+{
+	unsigned long flag;
+	char *endptr;
+
+	flag = strtoul(arg, &endptr, 16);
+	if (*endptr != '\0' || flag > FW_ENC_WITH_BSSK) {
+		ERROR("Invalid fw_enc_status flag '%s'\n", arg);
+		exit(1);
+	}
+
+	*fw_enc_status = flag & FW_ENC_STATUS_FLAG_MASK;
+}
+
+/* Common command line options */
+static const cmd_opt_t common_cmd_opt[] = {
+	{
+		{ "help", no_argument, NULL, 'h' },
+		"Print this message and exit"
+	},
+	{
+		{ "fw-enc-status", required_argument, NULL, 'f' },
+		"Firmware encryption status flag (with SSK=0 or BSSK=1)."
+	},
+	{
+		{ "key-alg", required_argument, NULL, 'a' },
+		"Encryption key algorithm: 'gcm' (default)"
+	},
+	{
+		{ "key", required_argument, NULL, 'k' },
+		"Encryption key (for supported algorithm)."
+	},
+	{
+		{ "nonce", required_argument, NULL, 'n' },
+		"Nonce or Initialization Vector (for supported algorithm)."
+	},
+	{
+		{ "in", required_argument, NULL, 'i' },
+		"Input filename to be encrypted."
+	},
+	{
+		{ "out", required_argument, NULL, 'o' },
+		"Encrypted output filename."
+	},
+};
+
+int main(int argc, char *argv[])
+{
+	int i, key_alg, ret;
+	int c, opt_idx = 0;
+	const struct option *cmd_opt;
+	char *key = NULL;
+	char *nonce = NULL;
+	char *in_fn = NULL;
+	char *out_fn = NULL;
+	unsigned short fw_enc_status = 0;
+
+	NOTICE("Firmware Encryption Tool: %s\n", build_msg);
+
+	/* Set default options */
+	key_alg = KEY_ALG_GCM;
+
+	/* Add common command line options */
+	for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
+		cmd_opt_add(&common_cmd_opt[i]);
+	}
+
+	/* Get the command line options populated during the initialization */
+	cmd_opt = cmd_opt_get_array();
+
+	while (1) {
+		/* getopt_long stores the option index here. */
+		c = getopt_long(argc, argv, "a:f:hi:k:n:o:", cmd_opt, &opt_idx);
+
+		/* Detect the end of the options. */
+		if (c == -1) {
+			break;
+		}
+
+		switch (c) {
+		case 'a':
+			key_alg = get_key_alg(optarg);
+			if (key_alg < 0) {
+				ERROR("Invalid key algorithm '%s'\n", optarg);
+				exit(1);
+			}
+			break;
+		case 'f':
+			parse_fw_enc_status_flag(optarg, &fw_enc_status);
+			break;
+		case 'k':
+			key = optarg;
+			break;
+		case 'i':
+			in_fn = optarg;
+			break;
+		case 'o':
+			out_fn = optarg;
+			break;
+		case 'n':
+			nonce = optarg;
+			break;
+		case 'h':
+			print_help(argv[0], cmd_opt);
+			exit(0);
+		case '?':
+		default:
+			print_help(argv[0], cmd_opt);
+			exit(1);
+		}
+	}
+
+	if (!key) {
+		ERROR("Key must not be NULL\n");
+		exit(1);
+	}
+
+	if (!nonce) {
+		ERROR("Nonce must not be NULL\n");
+		exit(1);
+	}
+
+	if (!in_fn) {
+		ERROR("Input filename must not be NULL\n");
+		exit(1);
+	}
+
+	if (!out_fn) {
+		ERROR("Output filename must not be NULL\n");
+		exit(1);
+	}
+
+	ret = encrypt_file(fw_enc_status, key_alg, key, nonce, in_fn, out_fn);
+
+	CRYPTO_cleanup_all_ex_data();
+
+	return ret;
+}